///
/// 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
}
}