using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Runtime.InteropServices; using DTS.DASLib.Connection.USBFramework; using DTS.DASLib.DASResource; namespace DTS.DASLib.Connection { public class HIDUSBConnection: IConnection { public double GetCurrentDownloadRate() { return 0D; } public double GetCurrentUploadRate() { return 0D; } public const int HIDSLICE_PID = 0x0003; public const int DTS_VID = 0x1CB9; protected bool _Connected; protected int NumberOfInputBuffers = 0; protected int _HIDHandle; protected bool _MyDeviceDetected; protected HIDevice _MyHID = new HIDevice(); protected int _ReadHandle; protected int _WriteHandle; protected byte[] InputReportBuffer; protected FileIODeclarations.SECURITY_ATTRIBUTES Security; protected string Device_Name; private bool disposed; public event EventHandler OnDisconnected; public bool Connected { get { return _Connected; } } public string ConnectString { get { return Device_Name; } } public System.Net.Sockets.SocketFlags Flags { get; set; } public string GetConnectionData() { return ""; } public void Create(string ConnectString) { Device_Name = ConnectString; } ~HIDUSBConnection() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if(disposed) return; if(disposing) { try { FileIODeclarations.CloseHandle(_HIDHandle); } catch { } try { FileIODeclarations.CloseHandle(_ReadHandle); } catch { } try { FileIODeclarations.CloseHandle(_WriteHandle); } catch { } _MyHID.Dispose(); _Connected = false; } disposed = true; } public IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, Object state) { HIDUSBRecAsyncResult rar = new HIDUSBRecAsyncResult(); rar.AsyncState = state; rar.AsyncWaitHandle = new ManualResetEvent(false); rar.CompletedSynchronously = false; rar.IsCompleted = false; rar.buffer = null; rar.offset = 0; rar.size = 0; if(!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar))) { // "HIDUSBConnection.BeginDisconnect: Unable to enqueue function" throw new System.Exception(Strings.HIDUSBConnection_BeginDisconnect_Err1); } return rar; } public void EndDisconnect(IAsyncResult asyncResult) { int Result; Result = FileIODeclarations.CloseHandle(_HIDHandle); Result = FileIODeclarations.CloseHandle(_ReadHandle); Result = FileIODeclarations.CloseHandle(_WriteHandle); _Connected = false; } public IAsyncResult BeginAccept(AsyncCallback callback, Object state) { throw new NotSupportedException(); } public IConnection EndAccept(IAsyncResult asyncResult) { throw new NotSupportedException(); } public void Bind(int port) { throw new NotSupportedException(); } public void Listen(int backlog) { throw new NotSupportedException(); } // Define a class of delegates that point to the Hid.DeviceReport.Read function. // The delegate has the same parameters as Hid.DeviceReport.Read. // Used for asynchronous reads from the device. protected delegate void ReadInputReportDelegate(int readHandle, int hidHandle, int writeHandle, ref bool myDeviceDetected, ref byte[] readBuffer, ref bool success); private class AUSBRecFix { public AsyncCallback cb; public HIDUSBRecAsyncResult res; public AUSBRecFix(AsyncCallback _cb, HIDUSBRecAsyncResult _res) { cb = _cb; res = _res; } } public HIDUSBConnection() { disposed = false; Security = new FileIODeclarations.SECURITY_ATTRIBUTES(); Security.lpSecurityDescriptor = 0; Security.bInheritHandle = System.Convert.ToInt32(true); Security.nLength = Marshal.SizeOf(Security); _Connected = false; } public IAsyncResult BeginConnect(AsyncCallback cb, object state) { HIDUSBRecAsyncResult rar = new HIDUSBRecAsyncResult(); rar.AsyncState = state; rar.AsyncWaitHandle = new ManualResetEvent(false); rar.CompletedSynchronously = false; rar.IsCompleted = false; rar.buffer = null; rar.offset = 0; rar.size = 0; if(!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar))) { // "USBConnection.BeginConnect: Unable to enqueue function" throw new System.Exception(Strings.USBConnection_BeginConnect_Err1); } return rar; } private void NetCallbackFix(object obj) { try { AUSBRecFix ausbrf = obj as AUSBRecFix; ausbrf.cb(ausbrf.res); } catch(System.Exception ex) { System.Windows.Forms.MessageBox.Show("HIDUSBConnection.NetCallbackFix: Exception " + ex.Message + " " + ex.StackTrace); } } public static string GetFirstConnectString() { #region Hack to connect just one recorder by manually finding the first one ... int Result; int _HIDHandle; HIDevice _MyHID = new HIDevice(); FileIODeclarations.SECURITY_ATTRIBUTES Security; Security = new FileIODeclarations.SECURITY_ATTRIBUTES(); Security.lpSecurityDescriptor = 0; Security.bInheritHandle = System.Convert.ToInt32(true); Security.nLength = Marshal.SizeOf(Security); System.Guid HIDGuid = new Guid(); string GuidString; string[] DevicePathName = new string[128]; HIDDeclarations.HidD_GetHidGuid(ref HIDGuid); GuidString = HIDGuid.ToString(); DeviceManagement _MyDeviceManagement = new DeviceManagement(); bool DeviceFound = _MyDeviceManagement.FindDeviceFromGuid(HIDGuid, ref DevicePathName); if (true == DeviceFound) { int MemberIndex = 0; DeviceFound = false; do { //GRV - this works and is a true copy of Axelson _HIDHandle = FileIODeclarations.CreateFile(DevicePathName[MemberIndex], 0, FileIODeclarations.FILE_SHARE_READ | FileIODeclarations.FILE_SHARE_WRITE, ref Security, FileIODeclarations.OPEN_EXISTING, 0, 0); if (_HIDHandle != FileIODeclarations.INVALID_HANDLE_VALUE) { // The returned handle is valid, // so find out if this is the device we're looking for. // Set the Size property of DeviceAttributes to the number of bytes in the structure. //_MyHID.DeviceAttributes.Size = _MyHID.DeviceAttributes.ToString().Length; _MyHID.DeviceAttributes.Size = Marshal.SizeOf(_MyHID.DeviceAttributes); // *** // API function: // HidD_GetAttributes // Purpose: // Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID, // Product ID, and Product Version Number for a device. // Accepts: // A handle returned by CreateFile. // A pointer to receive a HIDD_ATTRIBUTES structure. // Returns: // True on success, False on failure. // *** Result = HIDDeclarations.HidD_GetAttributes(_HIDHandle, ref _MyHID.DeviceAttributes); if (Result != 0) { // Find out if the device matches the one we're looking for. if (_MyHID.DeviceAttributes.VendorID == DTS_VID && _MyHID.DeviceAttributes.ProductID == HIDSLICE_PID) { // It's the desired device. DeviceFound = true; // Close the device so it can be opened for real later Result = FileIODeclarations.CloseHandle(_HIDHandle); // return the device's name return DevicePathName[MemberIndex]; } else { // It's not a match, so close the handle. DeviceFound = false; Result = FileIODeclarations.CloseHandle(_HIDHandle); } } else { // There was a problem in retrieving the information. DeviceFound = false; Result = FileIODeclarations.CloseHandle(_HIDHandle); } } // Keep looking until we find the device or there are no more left to examine. MemberIndex = MemberIndex + 1; } while (!((DeviceFound == true) || (MemberIndex == DevicePathName.Length))); } return string.Empty; #endregion // Hack to connect just one recorder by manually finding the first one ... } public void EndConnect(IAsyncResult ar) { int Result; _HIDHandle = FileIODeclarations.CreateFile(ConnectString, 0, FileIODeclarations.FILE_SHARE_READ | FileIODeclarations.FILE_SHARE_WRITE, ref Security, FileIODeclarations.OPEN_EXISTING, 0, 0); if(_HIDHandle == FileIODeclarations.INVALID_HANDLE_VALUE) { // "HIDUSBConnection.EndConnect: Can't open {0} in Connect" throw new System.Exception(string.Format(Strings.HIDUSBConnection_EndConnect_Err1, ConnectString)); } // Set the Size property of DeviceAttributes to the number of bytes in the structure. _MyHID.DeviceAttributes.Size = Marshal.SizeOf(_MyHID.DeviceAttributes); // HidD_GetAttributes // Purpose: Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID, // Product ID, and Product Version Number for a device. // Accepts: A handle returned by CreateFile. // A pointer to receive a HIDD_ATTRIBUTES structure. // Returns: True on success, False on failure. Result = HIDDeclarations.HidD_GetAttributes(_HIDHandle, ref _MyHID.DeviceAttributes); // Learn the capabilities of the device. _MyHID.Capabilities = _MyHID.GetDeviceCapabilities(_HIDHandle); //Find out if device is system mouse or keyboard //GRV string HIDUsage = _MyHID.GetHIDUsage(_MyHID.Capabilities); // Get and display the Input report buffer size. GetInputReportBufferSize(); // Get another handle to use in overlapped ReadFiles (for requesting Input reports). _ReadHandle = FileIODeclarations.CreateFile(ConnectString, FileIODeclarations.GENERIC_READ, FileIODeclarations.FILE_SHARE_READ | FileIODeclarations.FILE_SHARE_WRITE, ref Security, FileIODeclarations.OPEN_EXISTING, 0, 0); _WriteHandle = FileIODeclarations.CreateFile(ConnectString, FileIODeclarations.GENERIC_WRITE, FileIODeclarations.FILE_SHARE_READ | FileIODeclarations.FILE_SHARE_WRITE, ref Security, FileIODeclarations.OPEN_EXISTING, 0, 0); // (optional) // Flush any waiting reports in the input buffer. _MyHID.FlushQueue(_ReadHandle); HIDevice.InputReport myInputReport = new HIDevice.InputReport(); // Define a delegate for the Read method of myInputReport. ReadInputReportDelegate MyReadInputReportDelegate = new ReadInputReportDelegate(myInputReport.Read); // Set the size of the Input report buffer. InputReportBuffer = new byte[_MyHID.Capabilities.InputReportByteLength]; _Connected = true; } protected void GetInputReportBufferSize() { try { // Get the number of input buffers. _MyHID.GetNumberOfInputBuffers(_HIDHandle, ref NumberOfInputBuffers); } catch(System.Exception ex) { // "HIDUSBConnection.GetInputReportBufferSize: Error during {0}" throw new ApplicationException(string.Format(Strings.HIDUSBConnection_GetInputReportBufferSize_Err1, ex.Message)); } } public class HIDUSBRecAsyncResult: IAsyncResult { public object AsyncState { get; set; } public WaitHandle AsyncWaitHandle { get; set; } public bool CompletedSynchronously { get; set; } public bool IsCompleted { get; set; } public byte[] buffer { get; set; } public int offset { get; set; } public int size { get; set; } } public IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state) { if(_ReadHandle == FileIODeclarations.INVALID_HANDLE_VALUE || _WriteHandle == FileIODeclarations.INVALID_HANDLE_VALUE) { // "HIDUSBConnection.BeginSend: Invalid read or write handle" throw new System.Exception(Strings.HIDUSBConnection_BeginSend_Err1); } HIDUSBRecAsyncResult rar = new HIDUSBRecAsyncResult(); rar.AsyncState = state; rar.AsyncWaitHandle = new ManualResetEvent(false); rar.CompletedSynchronously = false; rar.IsCompleted = false; rar.buffer = buffer; rar.offset = offset; rar.size = size; if(!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar))) { // "HIDUSBConnection.BeginSend: Unable to enqueue function" throw new System.Exception(Strings.HIDUSBConnection_BeginSend_Err2); } return rar; } public int EndSend(IAsyncResult ar) { HIDUSBRecAsyncResult rar = ar as HIDUSBRecAsyncResult; int bytesLeft = rar.size; int maxOutputReportLength = _MyHID.Capabilities.OutputReportByteLength; byte[] OutputReportBuffer = new byte[maxOutputReportLength]; OutputReportBuffer[0] = 0; for(int i = 0; i < rar.size; i += (maxOutputReportLength - 1)) { bytesLeft = rar.size - i; int bytesToCopy = ((bytesLeft < OutputReportBuffer.Length - 1) ? bytesLeft : OutputReportBuffer.Length - 1); Buffer.BlockCopy(rar.buffer, rar.offset + i, OutputReportBuffer, 1, bytesToCopy); HIDevice.OutputReport myOutputReport = new HIDevice.OutputReport(); if(!myOutputReport.Write(OutputReportBuffer, _WriteHandle)) { // "HIDUSBConnection.EndSend: Error writing report" throw new System.Exception(Strings.HIDUSBConnection_EndSend_Err1); } } return rar.size; } public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state) { if(_ReadHandle == FileIODeclarations.INVALID_HANDLE_VALUE || _WriteHandle == FileIODeclarations.INVALID_HANDLE_VALUE) { // "HIDUSBConnection.BeginReceive: Invalid read or write handle" throw new System.Exception(Strings.HIDUSBConnection_BeginReceive_Err1); } HIDUSBRecAsyncResult rar = new HIDUSBRecAsyncResult(); rar.AsyncState = state; rar.AsyncWaitHandle = new ManualResetEvent(false); rar.CompletedSynchronously = false; rar.IsCompleted = false; rar.buffer = buffer; rar.offset = offset; rar.size = size; if(!ThreadPool.QueueUserWorkItem(NetCallbackFix, new AUSBRecFix(cb, rar))) { // "HIDUSBConnection.BeginReceive: Unable to enqueue function" throw new System.Exception(Strings.HIDUSBConnection_BeginReceive_Err2); } return rar; } public int EndReceive(IAsyncResult ar) { HIDUSBRecAsyncResult rar = ar as HIDUSBRecAsyncResult; bool Success = false; HIDevice.InputReport myInputReport = new HIDevice.InputReport(); //byte[] InputBuffer = new byte[rar.size+1]; myInputReport.Read(_ReadHandle, _HIDHandle, _WriteHandle, ref _MyDeviceDetected, ref InputReportBuffer, ref Success); if(Success) { Buffer.BlockCopy(InputReportBuffer, 1, rar.buffer, rar.offset, InputReportBuffer.Length - 1); rar.IsCompleted = true; ((ManualResetEvent)rar.AsyncWaitHandle).Set(); return rar.size; } ((ManualResetEvent)rar.AsyncWaitHandle).Set(); return 0; } } }