/// /// author svilen.info / svilen.de /// /// no copyright, however please cite source XD /// /// some small example, how the c -> c# marshalling works here! /// using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; namespace Zarlink.Adk.Forms { /// /// This class will deal with the USB communication /// /// Here we will cast all the ftd2xx.h functions and structure that we need /// and will add some other specific communaction protocols static class Communication { #region My Variables public static FT_STATUS status; // represents the FT status. To be updated after every action! public static IntPtr handle; // represents the FT device handle. Should be always the same, if varies then something is wrong (like more usbs) public struct Buffer { public byte[] data; // data from the last successful transfer public DateTime lastSuccessfulUse; // if connection lost, to check the date and time of the last successful data transfer } public static Buffer inBuffer; // what we received last public static Buffer outBuffer; // what we sent last #endregion My Variables #region Stupid defines from the dll // FT_OpenEx Flags private const UInt16 FT_OPEN_BY_SERIAL_NUMBER = 1; private const UInt16 FT_OPEN_BY_DESCRIPTION = 2; private const UInt16 FT_OPEN_BY_LOCATION = 4; // Baud Rates private const UInt32 FT_BAUD_300 = 300; private const UInt32 FT_BAUD_600 = 600; private const UInt32 FT_BAUD_1200 = 1200; private const UInt32 FT_BAUD_2400 = 2400; private const UInt32 FT_BAUD_4800 = 4800; private const UInt32 FT_BAUD_9600 = 9600; private const UInt32 FT_BAUD_14400 = 14400; private const UInt32 FT_BAUD_19200 = 19200; private const UInt32 FT_BAUD_38400 = 38400; private const UInt32 FT_BAUD_57600 = 57600; private const UInt32 FT_BAUD_115200 = 115200; private const UInt32 FT_BAUD_230400 = 230400; private const UInt32 FT_BAUD_460800 = 460800; private const UInt32 FT_BAUD_921600 = 921600; // Word Lengths private const byte FT_BITS_8 = 8; private const byte FT_BITS_7 = 7; private const byte FT_BITS_6 = 6; private const byte FT_BITS_5 = 5; // Stop Bits private const byte FT_STOP_BITS_1 = 0; private const byte FT_STOP_BITS_1_5 = 1; private const byte FT_STOP_BITS_2 = 2; // Parity private const byte FT_PARITY_NONE = 0; private const byte FT_PARITY_ODD = 1; private const byte FT_PARITY_EVEN = 2; private const byte FT_PARITY_MARK = 3; private const byte FT_PARITY_SPACE = 4; // Flow Control private const UInt16 FT_FLOW_NONE = 0x0000; private const UInt16 FT_FLOW_RTS_CTS = 0x0100; private const UInt16 FT_FLOW_DTR_DSR = 0x0200; private const UInt16 FT_FLOW_XON_XOFF = 0x0400; // Purge rx and tx buffers public const byte FT_PURGE_RX = 1; public const byte FT_PURGE_TX = 2; // Events public const byte FT_EVENT_RXCHAR = 1; public const byte FT_EVENT_MODEM_STATUS = 2; public const byte FT_EVENT_LINE_STATUS = 4; // Timeouts private const UInt32 FT_DEFAULT_RX_TIMEOUT = 300; private const UInt32 FT_DEFAULT_TX_TIMEOUT = 300; #endregion Stupid defines #region Stupid Marshals /// /// marshalling the structure... /// [StructLayout(LayoutKind.Sequential)] public struct LPFTDCB { public UInt32 DCBlength; /* sizeof(FTDCB) */ public UInt32 BaudRate; /* Baudrate at which running */ public UInt32 fBits; // bits layout is inportable so have the flag and take out the bits //ulong fBinary: 1; /* Binary Mode (skip EOF check) */ //ulong fParity: 1; /* Enable parity checking */ //ulong fOutxCtsFlow:1; /* CTS handshaking on output */ //ulong fOutxDsrFlow:1; /* DSR handshaking on output */ //ulong fDtrControl:2; /* DTR Flow control */ //ulong fDsrSensitivity:1; /* DSR Sensitivity */ //ulong fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */ //ulong fOutX: 1; /* Enable output X-ON/X-OFF */ //ulong fInX: 1; /* Enable input X-ON/X-OFF */ //ulong fErrorChar: 1; /* Enable Err Replacement */ //ulong fNull: 1; /* Enable Null stripping */ //ulong fRtsControl:2; /* Rts Flow control */ //ulong fAbortOnError:1; /* Abort all reads and writes on Error */ //ulong fDummy2:17; /* Reserved */ public UInt16 wReserved; /* Not currently used */ public UInt16 XonLim; /* Transmit X-ON threshold */ public UInt16 XoffLim; /* Transmit X-OFF threshold */ public byte ByteSize; /* Number of bits/byte, 4-8 */ public byte Parity; /* 0-4=None,Odd,Even,Mark,Space */ public byte StopBits; /* 0,1,2 = 1, 1.5, 2 */ public char XonChar; /* Tx and Rx X-ON character */ public char XoffChar; /* Tx and Rx X-OFF character */ public char ErrorChar; /* Error replacement char */ public char EofChar; /* End of Input character */ public char EvtChar; /* Received Event character */ public ushort wReserved1; /* Fill for now. */ } ; #endregion Stupid Marshals #region Constructors, Destructors ... static Communication() { handle = IntPtr.Zero; outBuffer = new Buffer { data = new byte[140], lastSuccessfulUse = DateTime.Now }; inBuffer = new Buffer { data = new byte[140], lastSuccessfulUse = DateTime.Now }; } //static ~Communication() //{ // Close(); //} #endregion Constructors, Destructors ... #region W32 Functions from the dll // note: W32 should not be mixed with non W32 unless explicitly stated /// /// This function gets the current device state. /// /// Cast PVOID to IntPtr to have system specific handle pointer size /// the status /// If the function is successful, the return value is nonzero [DllImport("ftd2xx")] public static extern bool FT_W32_GetCommState(IntPtr ftHandle, ref LPFTDCB lpftDcb); #endregion W32 Functions #region Normal Functions that we use from the dll [DllImport("ftd2xx")] public static extern FT_STATUS FT_ResetDevice(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_ClrDtr(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_ClrRts(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_Open(UInt32 uiPort, IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_Close(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_Read(IntPtr ftHandle, out byte[] lpBuffer, UInt32 dwBytesToRead, out UInt32 lpdwBytesReturned); [DllImport("ftd2xx")] public static extern FT_STATUS FT_Write(IntPtr ftHandle, IntPtr lpBuffer, UInt32 dwBytesToRead, ref UInt32 lpdwBytesWritten); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetLatencyTimer(IntPtr ftHandle, byte ucTimer); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetDataCharacteristics(IntPtr ftHandle, byte uWordLength, byte uStopBits, byte uParity); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetFlowControl(IntPtr ftHandle, ushort usFlowControl, byte uXon, byte uXoff); [DllImport("ftd2xx")] public static extern FT_STATUS FT_GetModemStatus(IntPtr ftHandle, ref UInt32 lpdwModemStatus); [DllImport("ftd2xx")] public static extern FT_STATUS FT_Purge(IntPtr ftHandle, UInt32 dwMask); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetBreakOn(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetBreakOff(IntPtr ftHandle); [DllImport("ftd2xx")] public static extern FT_STATUS FT_GetStatus(IntPtr ftHandle, ref UInt32 lpdwAmountInRxQueue, ref UInt32 lpdwAmountInTxQueue, ref UInt32 lpdwEventStatus); [DllImport("ftd2xx")] public static extern FT_STATUS FT_SetDivisor(IntPtr ftHandle, char usDivisor); #endregion Normal Functions #region Functions written by Svilen ;) public static void DebugInformation(string step = "") { Debug.WriteLine(step + " status: " + status); Debug.WriteLine("handle address: " + handle); unsafe { if (handle != null) { Debug.WriteLine("handle value: " + *(uint*) handle.ToPointer()); // to use in unsafed code } } //Debug.WriteLine("handle value: " + *(uint *)handle.ToPointer()); // to use in unsafed code } public static void Init() { // > open > FT_Open(0, handle); DebugInformation("open"); // < open < // > reset! > FT_ResetDevice(handle); DebugInformation("reset"); // < reset! < // > set reply rate FT_SetLatencyTimer(handle, 2); DebugInformation("latency timer"); // < set reply rate < // > set same flow control FT_SetFlowControl(handle, FT_FLOW_RTS_CTS, 0, 0); DebugInformation("flow control"); // < set flow control < // > clear the buffers > FT_Purge(handle, FT_PURGE_TX + FT_PURGE_RX); DebugInformation("purge"); // < clear the buffers < } public static void ReadTest() { byte[] bytes = new byte[20]; IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length); Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length); IntPtr bytesLeft = (IntPtr)10; // FT_Read(handle, unmanagedPointer, (UInt32)bytes.Length, bytesLeft); DebugInformation("read"); Marshal.Copy(unmanagedPointer, bytes, 0, bytes.Length); ASCIIEncoding enc = new ASCIIEncoding(); Debug.WriteLine("buffer has: " + enc.GetString(bytes)); Marshal.FreeHGlobal(unmanagedPointer); } public static int ReadBuffer() { UInt32 bytesLeft; inBuffer.data = new byte[140]; FT_Read(handle, out inBuffer.data, (UInt32)inBuffer.data.Length, out bytesLeft); DebugInformation("read"); ASCIIEncoding enc = new ASCIIEncoding(); if (inBuffer.data != null) Debug.WriteLine("buffer has: " + enc.GetString(inBuffer.data)); return 0; } public static void WriteTest() { IntPtr ptr = Marshal.AllocHGlobal(4); Marshal.Copy(outBuffer.data, 0, ptr, 4); uint bytesWritten = 0; FT_Write(handle, ptr, 4, ref bytesWritten); DebugInformation("write"); } public static void Close() { if (handle == IntPtr.Zero) { FT_Close(handle); DebugInformation("close"); } } #endregion Functions #region other defines and enumerations for the communication namespace /// /// Enumaration containing the varios return status for the DLL functions. /// public enum FT_STATUS { FT_OK = 0, FT_INVALID_HANDLE, FT_DEVICE_NOT_FOUND, FT_DEVICE_NOT_OPENED, FT_IO_ERROR, FT_INSUFFICIENT_RESOURCES, FT_INVALID_PARAMETER, FT_INVALID_BAUD_RATE, FT_DEVICE_NOT_OPENED_FOR_ERASE, FT_DEVICE_NOT_OPENED_FOR_WRITE, FT_FAILED_TO_WRITE_DEVICE, FT_EEPROM_READ_FAILED, FT_EEPROM_WRITE_FAILED, FT_EEPROM_ERASE_FAILED, FT_EEPROM_NOT_PRESENT, FT_EEPROM_NOT_PROGRAMMED, FT_INVALID_ARGS, FT_OTHER_ERROR } #endregion other defines and enumerations for the communication namespace } }