/* Copyright © 2011 Brad Murry All rights reserved. BSD License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. KM_Controller.cs */ using System; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Reflection; using System.IO; using System.Windows.Forms; using System.Configuration; using System.Diagnostics; //GAC Post Build = "$(FrameworkSDKDir)bin\gacutil.exe" /i "$(TargetPath)" /f namespace KMotion_dotNet { /// /// Callback delegate for KM_Controller returns /// /// message from KM_Controller function /// public delegate int KMConsoleHandler(string message); /// /// callback for low level KMotion error messages /// public delegate void KMErrorHandler(string message); /// /// Exception class for handling specific DynoMotion.net exceptions /// public class DMException : Exception { /// /// Object where executoin of exception was encountered /// private object _Sender; /// /// Actual exception thrown /// private Exception _InnerException; /// /// Additional information about exception /// private string _Message; /// /// Object where execution of exception was encountered /// public object Sender { get { return _Sender; } } /// /// Actual exception thrown /// public new Exception InnerException { get { return _InnerException; } } /// /// Additional information about exception /// public override string Message { get { return _Message; } } /// /// Primary constructor for DM Exception /// /// Current execution object on the stack /// original exception encountered /// additional information public DMException(object sender, Exception ex, string message) { _Sender = sender; _InnerException = ex; _Message = message; } } /// /// Special Dynomotion USB Error Exception /// public class DM_USB_Exception : Exception { /// /// Special Dynomotion USB Error Exception /// /// Exception description public DM_USB_Exception(string message) : base(message) { } } /// /// Special Dynomotion KmotionServer Error Exception /// public class DM_Firmware_Exception : Exception { /// /// Special Dynomotion KmotionServer Error Exception /// /// Exception description public DM_Firmware_Exception(string message) : base(message) { } } /// /// Special Dynomotion Compiler Error Exception /// public class DM_Compiler_Exception : Exception { /// /// Special Dynomotion Compiler Error Exception /// /// Exception description public DM_Compiler_Exception(string message) : base(message) { } } /// /// Special Dynomotion Board Disconnected Exception /// public class DM_Disconnected_Exception : Exception { /// /// Special Dynomotion Board Disconnected Exception /// /// Exception description public DM_Disconnected_Exception(string message) : base(message) { } } /// /// This is the primary object for interfacing with a Dynomotion product in code /// /// You can think of this object as representing the board and an access point for features of the hardware /// /// There should only be one KM_Controller object per board, per application domain at any given time /// /// To set project to update the GAC: "$(FrameworkSdkDir)\bin\gacutil.exe" /i "$(TargetPath)" /f /// public partial class KM_Controller : IDisposable { #region Fields /// /// KMotion_DLL class instance pointer /// private IntPtr _InstanceHandle = new IntPtr(0L); /// /// Maximum allowed return error string length /// private int _ErrorLength = 100; /// /// Board USB ID /// private int _BoardID = -1; /// /// Board number (for use in multiple board scenarios) /// private int _BoardNumber = 0; /// /// Dynomotion board device type /// private int _BoardType = -1; private bool _Loaded = false; private bool _ThrowExceptions = true; /// /// Contains all messages until cleared /// private string _MessageLog = ""; /// /// Flag to determine that this object has been properly initialized /// private string _ErrorLog = ""; /// /// Internal callback handler for the c++ interop KMotion.DLL class /// /// /// /// This delegate for the callback prevents the Garbage Collector from releasing the /// unmanaged function pointer from being destroyed /// /// /// private KMConsoleHandler KMCallBackhandler; /// /// Internal error message pump for the c++ interop KMotion.DLL class /// /// /// /// This delegate for the callback prevents the Garbage Collector from releasing the /// unmanaged function pointer from being destroyed /// /// /// private KMErrorHandler KMErrorHandler; /// /// All general messages are pumped out from the internal callback handler thru this event /// public event KMConsoleHandler MessageReceived; /// /// Error Messages are routed through this event /// public event KMErrorHandler ErrorReceived; /// /// Coordinated Motion Component /// private KM_CoordMotion _CoordMotion = null; /// /// Flags whether to obtain a lock token while gathering the status data /// private bool _LockStatusOnUpdate = true; /// /// Maximum time in ms between refreshing the status /// private int _StatusUpdateInterval = 100; /// /// Locally maintained Main_Status struct /// private KM_MainStatus _CurrentStatus; #endregion #region Properties /// /// KMotion_DLL class instance pointer /// public IntPtr InstanceHandle { get { return _InstanceHandle; } } /// /// Maximum allowed return error string length /// public int MaxErrorLength { get { return _ErrorLength; } set { _ErrorLength = value; } } /// /// If this flag is true, exceptions will be generated from the ErrorMsg handler /// public bool ThrowExceptions { get { return _ThrowExceptions; } set { _ThrowExceptions = value; } } /// /// Board USB ID /// public int BoardID { get { return _BoardID; } set { _BoardID = value; } } /// /// Board number (for use in multiple board scenarios) /// public int BoardNumber { get { return _BoardNumber; } set { _BoardNumber = value; UpdateBoardID(); } } /// /// Dynomotion board device type /// public int BoardType { get { return _BoardType; } set { _BoardType = value; } } /// /// Flag to determine that this object has been properly initialized /// public bool Loaded { get { return _Loaded; } private set { _Loaded = value; } } /// /// Contains all messages until cleared /// public string MessageLog { get { return _MessageLog; } set { _MessageLog = value; } } /// /// Contains all error messages until cleared /// public string ErrorLog { get { return _ErrorLog; } set { _ErrorLog = value; } } /// /// Coordinated Motion Component /// public KM_CoordMotion CoordMotion { get { if (_CoordMotion == null) { _CoordMotion = new KM_CoordMotion(this); //Initialize.... } return _CoordMotion; } set { _CoordMotion = value; } } /// /// Flags whether to obtain a lock token while gathering the status data /// public bool LockStatusOnUpdate { get { return _LockStatusOnUpdate; } set { _LockStatusOnUpdate = value; } } /// /// Maximum time in ms between refreshing the status /// public int StatusUpdateInterval { get { return _StatusUpdateInterval; } set { _StatusUpdateInterval = value; } } /// /// Locally maintained Main_Status struct /// public KM_MainStatus CurrentStatus { get { int duration = Math.Abs(Environment.TickCount - _CurrentStatus.TicksAtUpdate); if (duration > _StatusUpdateInterval) { _CurrentStatus = GetStatus(_LockStatusOnUpdate); } return _CurrentStatus; } } #endregion #region Ctor /// /// Default constructor for the KM_Controller object /// /// Use this for single board applications /// public KM_Controller() { try { _BoardNumber = 0; KM_dotnet_Interop_New(ref _InstanceHandle, _BoardNumber); _BoardType = GetBoardType(); int boardcount = -1; var boards = GetBoards(out boardcount); _BoardID = boards[0]; _CoordMotion = new KM_CoordMotion(this); SetErrorHandler(); SetCallbackHandler(); // don't think we want to necessarily do all this communication on creation // _CurrentStatus = GetStatus(false); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } } /// /// Multiple board constructor for attaching this object to a specific board address /// /// device ID public KM_Controller(int boardnumber) { try { KM_dotnet_Interop_New(ref _InstanceHandle, boardnumber); _BoardType = GetBoardType(); int boardcount = -1; var boards = GetBoards(out boardcount); if (boardcount > 0) { if (boardnumber < boardcount) { _BoardID = boards[boardnumber]; _BoardNumber = boardnumber; } else { for (int i = 0; i < boardcount; i++) { if (boardnumber == boards[i]) { _BoardID = i; _BoardNumber = boardnumber; } } } if (boardcount == 1) { _BoardID = 0; } _CoordMotion = new KM_CoordMotion(this); } else { throw new Exception("No KMotion Devices Found!!"); } SetErrorHandler(); SetCallbackHandler(); _CurrentStatus = GetStatus(false); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KM_Controller")); } } #endregion #region Scripting Command Communications /// /// Sends a console command to the board and waits for the return value /// /// script command to send /// return value (if any) public string WriteLineReadLine(string command) { string response = ""; try { MarshalPre(ref response); KM_dotnet_Interop_WriteLineReadLine(_InstanceHandle, command, ref response); MarshalPost(ref response); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineReadLine")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineReadLine")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineReadLine")); } return response; } /// /// Sends a console command to the board /// /// script command to send public void WriteLine(string command) { try { KM_dotnet_Interop_WriteLine(_InstanceHandle, command); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLine")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLine")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLine")); } } /// /// Sends a console command to the board while echoing commands back to the callback handler /// /// script command to send public void WriteLineWithEcho(string command) { try { KM_dotnet_Interop_WriteLineWithEcho(_InstanceHandle, command); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineWithEcho")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineWithEcho")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WriteLineWithEcho")); } } /// /// Block the calling thread while waiting for the response to complete within a specified timeout /// /// return message value /// time in ms to wait for message return to complete /// true is completed within the timeout public bool ReadLineTimeout(ref string message, int timeout_ms) { int success = -1; try { MarshalPre(ref message); success = KM_dotnet_Interop_ReadLineTimeOut(_InstanceHandle, ref message, timeout_ms); MarshalPost(ref message); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } return success == 0; } /// /// Flushes the console buffer /// /// true if successful public bool ServiceConsole() { int success = -1; try { success = KM_dotnet_Interop_ServiceConsole(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReadLineTimout")); } return success == 0; } /// /// Returns the value of a WriteLineReadLine(), converted to the requested type /// /// System.Type to convert return value to /// Console script statement /// flag determine whether or not to throw an exception /// the returned string value of the command converted to the requested type public T GetCommandValue(string command, bool throwexception) { var value = WriteLineReadLine(command); try { return (T)Convert.ChangeType(value, typeof(T)); } catch (Exception ex) { if (throwexception) { throw new Exception(String.Format("Could not convert command return value ( {0} = {1} ) to requested type ( {2} )", command, value, typeof(T).ToString()), ex); } else { return default(T); } } } #endregion #region Locking /// /// Prevents outside access to the board until ReleaseToken is commanded /// /// ms to wait /// true if lock was successful public KMOTION_TOKEN WaitToken(int timeout) { try { var result = KM_dotnet_Interop_WaitToken(_InstanceHandle, timeout); return (KMOTION_TOKEN)result; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WaitToken")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WaitToken")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "WaitToken")); } } /// /// Prevents outside access to the board /// This function is similar to the WaitToken function, except that it returns immediately (instead of waiting) if the board is already locked /// /// /// KMOTION_LOCKED=0, // (and token is locked) if KMotion is available for use /// KMOTION_IN_USE=1, // if already in use /// KMOTION_NOT_CONNECTED=2, // if error or not able to connect /// public int KMotionLock() { try { return KM_dotnet_Interop_KMotionLock(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KMotionLock")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KMotionLock")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KMotionLock")); } } /// /// Recovers controller from a motion lock state /// public void RecoverKMotionLock() { try { KM_dotnet_Interop_KMotionLockRecovery(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "KMotionLock")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReleaseKMotionLock")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReleaseKMotionLock")); } } /// /// Allow normal access to the board /// public void ReleaseToken() { try { KM_dotnet_Interop_ReleaseToken(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReleaseToken")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReleaseToken")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "ReleaseToken")); } } #endregion #region Status /// /// Tries to obtain a lock, and if a lock is obtained can execute optional actions before releasing the lock token. /// /// delegates to execute while the board is locked /// true if the lock status was not KMOTION_TOKEN.KMOTION_NOT_CONNECTED public bool CheckConnected(params Action[] actions) { var result = WaitToken(100); var conected = result != KMOTION_TOKEN.KMOTION_NOT_CONNECTED; if (result == KMOTION_TOKEN.KMOTION_LOCKED) { foreach (var action in actions) { action.Invoke(); } ReleaseToken(); } return conected; } /// /// Get Boards checks the list of connected board locations and returns the total board count /// /// returned total board count /// array of USB locations for all boards public int[] GetBoards(out int numberofboards) { try { int[] list = new int[256]; numberofboards = 0; int boards = -1; KM_dotnet_Interop_ListLocations(_InstanceHandle, ref boards, ref list[0]); numberofboards = (int)boards; return list; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoards")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoards")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoards")); } } /// /// USB tree node location /// /// USB location address public int GetUSBLocation() { try { var result = KM_dotnet_Interop_USBLocation(_InstanceHandle); return result; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetUSBLocation")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetUSBLocation")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetUSBLocation")); } } /// /// Places the controller in a failed state, prevents further commands from processing /// public void SetFailed() { try { KM_dotnet_Interop_Failed(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetFailed")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetFailed")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetFailed")); } } /// /// Disconnect the application from the board /// public void Disconnect() { try { KM_dotnet_Interop_Disconnect(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Disconnect")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Disconnect")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Disconnect")); } } /// /// Call this to check if a "Ready" response came back /// after a command was manually typed in and we don't /// know what the response will be if any /// /// Note:There is a possibility that other DSP threads are /// printing to the console screen /// /// First check if any input is available /// if not, return instantly (KMOTION_OK) /// if so, then a whole line might not be available /// but should be in transmission and be in very soon, /// so wait up to a short while to get in an entire line /// if the line doesn't come in for some reason return (KMOTION_TIMEOUT) /// check if the line should go to the console (esc) /// if so print it and repeat the above as long as /// there is still input available /// if the line is not console data, check for "Ready", /// if it is "Ready" send it to the console and return KMOTION_READY; /// otherwise send it to the console /// /// true if board has received "Ready" public KMOTION_CHECK_READY CheckIsReady() { KMOTION_CHECK_READY ready = KMOTION_CHECK_READY.ERROR; try { ready = (KMOTION_CHECK_READY)KM_dotnet_Interop_CheckForReady(_InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckIsReady")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckIsReady")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckIsReady")); } return ready; } /// /// Query device for the loaded firmware version /// /// Firmware version public int GetFirmwareVersion() { try { var result = KM_dotnet_Interop_GetFirmwareVersion(_InstanceHandle); return result; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetFirmwareVersion")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetFirmwareVersion")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetFirmwareVersion")); } } /// /// Determines and returns the section sizes of various sections in a KFLOP coff (common object file format) file /// /// file name of KFLOP coff /// variable to return the text (code) size in bytes /// variable to return the bss (global variables) size in bytes /// variable to return the data (global constants) size in bytes /// variable to return the total size of all 3 sections in bytes /// integer 0 if sucessful public int CheckCoffSize(string name, out int size_text, out int size_bss, out int size_data, out int size_total) { try { int text = 0; int bss = 0; int data = 0; int total = 0; var result = KM_dotnet_Interop_CheckCoffSize(_InstanceHandle, name, ref text, ref bss, ref data, ref total); size_text = text; size_bss = bss; size_data = data; size_total = total; return result; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckCoffSize")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckCoffSize")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CheckCoffSize")); } } /// /// Gets the board type /// 1 = KMotion /// 2 = KFlop /// /// Board Type we are talking to public int GetBoardType() { try { int result = -1; KM_dotnet_Interop_CheckKMotionVersion(_InstanceHandle, ref result, true); return result; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoardType")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoardType")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetBoardType")); } } /// /// Generates and returns an updated copy of the MAIN_STATUS structure /// /// flag to determine whether to place a lock on the card while generating the MAIN_STATUS data /// KM_MainStatus, which is member compatible with the unmanaged MAIN_STATUS struct public KM_MainStatus GetStatus(bool locked) { KM_MainStatus mainstatus = new KM_MainStatus(); try { int versionandsize = 0; int[] adc = new int[24]; int[] dac = new int[8]; int[] pwm = new int[26]; double[] position = new double[8]; double[] destination = new double[8]; int[] outputchan0 = new int[8]; int inputmodes = 0; int inputmodes2 = 0; int outputmodes = 0; int outputmodes2 = 0; int enables = 0; int axisdone = 0; int[] bitsdirection = new int[2]; int[] bitsstate = new int[2]; int snapbitsdirection0 = 0; int snapbitsdirection1 = 0; int snapbitsstate0 = 0; int snapbitsstate1 = 0; int kanalgobitsstateinputs = 0; int kanalogbitsstateoutputs = 0; int runonstartup = 0; int threadactive = 0; int stopimmediatestate = 0; double timestamp = 0; int[] pccomm = new int[8]; int virtualbits = 0; int virtualbitsex0 = 0; KM_dotnet_Interop_MainStatus_GetStatus(_InstanceHandle, locked, ref versionandsize, adc, dac, pwm, position, destination, outputchan0, ref inputmodes, ref inputmodes2, ref outputmodes, ref outputmodes2, ref enables, ref axisdone, bitsdirection, bitsstate, ref snapbitsdirection0, ref snapbitsdirection1, ref snapbitsstate0, ref snapbitsstate1, ref kanalgobitsstateinputs, ref kanalogbitsstateoutputs, ref runonstartup, ref threadactive, ref stopimmediatestate, ref timestamp, pccomm, ref virtualbits, ref virtualbitsex0); mainstatus = KM_MainStatus.GetStatus(versionandsize, adc, dac, pwm, position, destination, outputchan0, inputmodes, inputmodes2, outputmodes, outputmodes2, enables, axisdone, bitsdirection, bitsstate, snapbitsdirection0, snapbitsdirection1, snapbitsstate0, snapbitsstate1, kanalgobitsstateinputs, kanalogbitsstateoutputs, runonstartup, threadactive, stopimmediatestate, timestamp, pccomm, virtualbits, virtualbitsex0); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetStatus")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetStatus")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "GetStatus")); } return mainstatus; } /// /// Checks whether a User Program Thread is currently executing. /// /// Which User Thread 1-7 to check /// Returns true if executing, false if not executing public bool ThreadExecuting(int thread) { var val = WriteLineReadLine(String.Format("CHECKTHREAD{0}", thread)); int value = 0; if (Int32.TryParse(val, out value)) { return value == 1; } else { return false; } } /// /// Waits for a User Program Thread to finish executing. /// /// Which User Thread 1-7 to check /// time to wait in milliseconds /// Returns true if successful, false if timed out public bool WaitForThreadComplete(int thread, int timeout) { try { Stopwatch sw = new Stopwatch(); bool Executing = true; bool istimedout = false; sw.Start(); while (Executing) { Executing = ThreadExecuting(thread); if (!Executing) { break; } if (timeout > 0)//Determines whether or not to check for a timeout condition { if (timeout < sw.ElapsedMilliseconds) { istimedout = true; break; } } Thread.Sleep(1); //This should be optimized to make sure we do not clog USB traffic } return !istimedout; } catch (Exception ex) { throw new Exception(String.Format("Problem waiting for thread to complete [{0}]", thread), ex); } } #endregion #region Program Compiling and Loading /// /// Load a compiled C program into the board /// /// thread address to load into(must match the thread the C program was compiled to) /// file name of the C program public void LoadCoff(int thread, string programname) { try { KM_dotnet_Interop_LoadCoff(_InstanceHandle, thread, programname); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoff")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoff")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoff")); } } /// /// Load a compiled C program into the board (with PackToFlash arg) /// /// thread address to load into(must match the thread the C program was compiled to) /// file name of the C program /// flag for packing in special format for bootup firmware /// Returns 0 if successful public int LoadCoff(int thread, string programname, int PackToFlash) { try { return KM_dotnet_Interop_LoadCoffPack(_InstanceHandle, thread, programname, PackToFlash); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoffPack")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoffPack")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "LoadCoffPack")); } } /// /// Compiles a source file and loads it into the board /// /// thread address to load into /// file name of the C program /// determines whether to collect any error returns /// return message from the C program's execution, including any errors public string CompileAndLoadCoff(int thread, string programname, bool bypasserror) { string error = ""; try { if (!bypasserror) { MarshalPre(ref error); int result=KM_dotnet_Interop_CompileAndLoadCoff(_InstanceHandle, thread, programname, ref error, _ErrorLength); // error string may not be null terminated if error was longer then _ErrorLength. // In this case it will have a longer length (including spaces) so terminate it if (error.Length >= _ErrorLength) error = error.Substring(0, _ErrorLength - 1); if (result!=0 && error=="") error="Error Compiling and Loading Program"; MarshalPost(ref error); } else { KM_dotnet_Interop_SimpleCompileAndLoadCoff(_InstanceHandle, thread, programname); } } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CompileAndLoadCoff")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CompileAndLoadCoff")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "CompileAndLoadCoff")); } return error; } /// /// Compiles a source file /// /// thread address to load into /// file name of the C program /// program output public string Compile(int thread, string programname) { try { string error = ""; MarshalPre(ref error); int result = KM_dotnet_Interop_Compile(_InstanceHandle, _BoardType, thread, programname, ref error, _ErrorLength); // error string may not be null terminated if error was longer then _ErrorLength. // In this case it will have a longer length (including spaces) so terminate it if (error.Length >= _ErrorLength) error = error.Substring(0, _ErrorLength - 1); if (result != 0 && error == "") error = "Error Compiling and Loading Program"; MarshalPost(ref error); _ErrorLog += error; return error; } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Compile")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Compile")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Compile")); } } /// /// Executes a previously loaded program /// /// program thread in the kflop to run public void ExecuteProgram(int thread) { WriteLine(String.Format("Execute{0}", thread)); } /// /// Loads and executes a program from file /// /// program thread in the kflop to run /// complete path to th .c file to execute /// determines whether to collect any error returns /// compile data public string ExecuteProgram(int thread, string programname, bool bypasserror) { var retval = CompileAndLoadCoff(thread, programname, bypasserror); if (retval == "") WriteLine(String.Format("Execute{0}", thread)); return retval; } /// /// Halts the execution of each supplied thread /// /// threads to kill public void KillProgramThreads(params int[] threads) { if (threads != null) { for (int i = 0; i < threads.Length; i++) { if (threads[i] < 8 && threads[i] > 0) { WriteLine(String.Format("Kill{0}", threads[i])); Thread.Sleep(0); } } } } #endregion #region Feedhold /// /// Initiates Feedhold (Performs Console Command StopImmediate0) /// public void Feedhold() { WriteLine(String.Format("StopImmediate0")); } /// /// Resumes Feedhold (Performs Console Command StopImmediate1) /// public void ResumeFeedhold() { WriteLine(String.Format("StopImmediate1")); } /// /// Clears Feedhold without Resuming(Performs Console Command StopImmediate2) /// public void ClearFeedhold() { WriteLine(String.Format("StopImmediate0")); } #endregion #region UserData /// /// Sets a 32 bit word of integer user data /// /// array offset (0-199) /// 32bits of data to store public void SetUserData(int index, int data) { WriteLine(String.Format("SetPersistDec{0} {1}", index, data)); } /// /// Sets a 32 bit word with a 32-bit float of user data /// /// To get the value in KFLOP in C do: /// float f = *(float *)&persist.UserData[index]; /// /// array offset (0-199) /// 32bits float data to store public void SetUserDataFloat(int index, float fdata) { Byte[] bytes = BitConverter.GetBytes(fdata); int data = BitConverter.ToInt32(bytes, 0); WriteLine(String.Format("SetPersistDec{0} {1}", index, data)); } /// /// Sets a pair of two 32 bit words with a 64-bit double of user data /// /// To get the value in KFLOP in C do: /// double f = *(double *)&persist.UserData[index*2]; /// /// array offset (0-99) even pair of 32-bit regs /// 64bit double data to store public void SetUserDataDouble(int index, double ddata) { Byte[] bytes = BitConverter.GetBytes(ddata); int data0 = BitConverter.ToInt32(bytes, 0); int data1 = BitConverter.ToInt32(bytes, 4); WriteLine(String.Format("SetPersistDec{0} {1}", index*2, data0)); WriteLine(String.Format("SetPersistDec{0} {1}", index*2+1, data1)); } /// /// Gets a 32 bit word of user data /// /// array offset (0-199) /// Int32 data from the array public int GetUserData(int index) { int retval = 0; var val = WriteLineReadLine(String.Format("GetPersistDec {0}", index)); Int32.TryParse(val, out retval); return retval; } /// /// Gets a 32 bit float word of user data /// /// To set float value in KFLOP in C do: /// *(float *)&persist.UserData[index] = f; /// /// array offset (0-199) /// float data from the array public float GetUserDataFloat(int index) { int retval = 0; var val = WriteLineReadLine(String.Format("GetPersistDec {0}", index)); Int32.TryParse(val, out retval); Byte[] bytes = BitConverter.GetBytes(retval); return BitConverter.ToSingle(bytes, 0); } /// /// Gets a 64 bit double from a KFLOP user data pair of 32 bit vars /// /// To set double value in KFLOP in C do: /// *(double *)&persist.UserData[index*2] = d; /// /// array offset (0-99) /// double data from the array public double GetUserDataDouble(int index) { Int32 ival0 = 0; Int32 ival1 = 0; var val0 = WriteLineReadLine(String.Format("GetPersistDec {0}", index*2)); var val1 = WriteLineReadLine(String.Format("GetPersistDec {0}", index*2+1)); Int32.TryParse(val0, out ival0); Int32.TryParse(val1, out ival1); Byte[] bytes = BitConverter.GetBytes((((UInt64)((UInt32)ival1))<<32) | (UInt64)((UInt32)ival0)); return BitConverter.ToDouble(bytes, 0); } /// /// Sets all words of user data to 0 /// public void ResetUserData() { for (int i = 0; i < 200; i++) { WriteLine(String.Format("SetPersistDec{0} {1}", i, 0)); Thread.Sleep(10); } } #endregion #region Message and Error Handling /// /// Sets the internal c++ interop callback handler /// Separate delegate for this callback prevents the Garbage Collector from releasing the /// unmanaged function pointer from being destroyed /// private void SetCallbackHandler() { try { KMCallBackhandler = new KMConsoleHandler(OnKMCallback); var returnval = KM_dotnet_Interop_SetConsoleCallback(_InstanceHandle, KMCallBackhandler); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } } private void SetErrorHandler() { try { KMErrorHandler = new KMErrorHandler(OnKMError); KM_dotnet_Interop_SetErrorCallback(_InstanceHandle, KMErrorHandler); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "SetCallbackHandler")); } } /// /// Used to accept messages back from KM device /// /// message from KM device /// 0 with no errors private int OnKMCallback(string message) { OnMessage(message); return 0; } private void OnKMError(string message) { OnError(message); } /// /// Routes messages to event subscribers /// /// message receieved private void OnMessage(string message) { if (message.Trim() != "") { var temp = this.MessageReceived; if (temp != null) { temp(message); } } } /// /// Routes error messages to event subscribers /// /// error receieved private void OnError(string error) { if (error.Trim() != "") { var temp = this.ErrorReceived; if (temp != null) { temp(error); } } if (_ThrowExceptions) { if (CoordMotion.Interpreter.InterpretThreadID != CoordMotion.Interpreter.Get_InterpretWin32ThreadID() && CoordMotion.Interpreter.InvokeThreadID != CoordMotion.Interpreter.Get_InterpretWin32ThreadID()) throw new Exception(error); } } /// /// Checks if any messages are in qeue /// /// true if Message log ! = "" public bool HasMessages() { return _MessageLog.Length > 0; } /// /// Checks if any error messages are in qeue /// /// true if Error log ! = "" public bool HasErrors() { return _ErrorLog.Length > 0; } /// /// Clears the Message log /// public void ClearMessages() { _MessageLog = ""; } /// /// Clears the Error log /// public void ClearError() { _ErrorLog = ""; } /// /// Routes Error callback messages and generates specific exceptions based on the source /// /// string message from ErrorMsg callback private void GenerateException(string message) { switch (message) { case "Unable to open KMotion device": throw new DM_USB_Exception("Unable to open KMotion device"); case "KMotion Received Line too long": throw new DM_USB_Exception("KMotion Received Line too long"); case "Unable to set USB Event Character": throw new DM_USB_Exception("Unable to set USB Event Character"); case "Unable to set USB Latency timer": throw new DM_USB_Exception("Unable to set USB Latency timer"); case "KMotion present but not responding\r\rCorrect problem and restart application": throw new DM_USB_Exception("KMotion present but not responding\r\rCorrect problem and restart application"); case "Read Failed - Auto Disconnect": throw new DM_Disconnected_Exception("Read Failed - Auto Disconnect"); case "Unable to Connect to KMotion Server": throw new DM_Disconnected_Exception("Read Failed - Auto Disconnect"); case "Unable to execute:\r\rKMotionServer.exe\r\rTry re-installing software or copy this file to the same location as KMotion.exe": throw new DM_Firmware_Exception("Unable to execute:\r\rKMotionServer.exe\r\rTry re-installing software or copy this file to the same location as KMotion.exe"); case "Error Locating TCC67.exe Compiler": throw new DM_Compiler_Exception("Error Locating TCC67.exe Compiler"); default: break; } } #endregion #region IDisposable Members /// /// Releases object resources /// public void Dispose() { Disconnect(); try { this.CoordMotion.Dispose(); KM_dotnet_Interop_Free(ref _InstanceHandle); } catch (DllNotFoundException e) { throw new DMException(this, e, String.Format("Dll Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Dispose")); } catch (EntryPointNotFoundException e) { throw new DMException(this, e, String.Format("Entry Point Not Found Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Dispose")); } catch (Exception e) { throw new DMException(this, e, String.Format("General Exception thrown : Caller - [{0}] :: Member - [{1}]", this.ToString(), "Dispose")); } } #endregion #region Util /// /// formats a message begining for callback /// /// message private void MarshalPre(ref string s) { s = new string(' ', 255); } /// /// formats a message end for callback /// /// message private void MarshalPost(ref string s) { if (s != null) { if (s.Contains((char)0)) { int nullstring = s.LastIndexOf((char)0); s = s.Substring(0, nullstring - 1); } } } /// /// Assigns the board ID /// /// This is called when the BoardID property is changed /// private void UpdateBoardID() { int boardcount = -1; var boards = GetBoards(out boardcount); if (_BoardNumber < boardcount) { _BoardID = boards[_BoardNumber]; } else { _BoardID = boards[0]; _BoardNumber = 0; } } #endregion #region Components /// /// Creates a new KM_IO bit /// /// nit index /// IO type for bit /// Name of bit /// Created KM_IO public KM_IO GetIO(int bit, IO_TYPE type, string name) { return new KM_IO(this, bit, name, type); } /// /// Creates a KM_Axis object /// /// KFLOP Axis Channel /// descriptive name /// Created Axis public KM_Axis GetAxis(int channel, string name) { return new KM_Axis(this, channel, name); } /// /// Creates a KM_AxisGroup /// /// integer id /// descriptive name /// List of KM_Axis to place in the group /// Created KM_AxisGroup public KM_AxisGroup GetAxisGroup(int id, string name, params KM_Axis[] axislist) { var group = new KM_AxisGroup(this, axislist); group.Name = name; group.ID = id; return group; } #endregion } }