// Protected implementation of Dispose pattern. protected virtual void Dispose(bool disposing) { if (disposed) { return; } if (disposing) { // Free any other managed objects here. if (asyncReadOn) { asyncReadOn = false; readThread.Join(readTimeoutInMillisecs); if (readThread.IsAlive) { readThread.Abort(); } } } // Free any UN-managed objects here. // so we are not reading or writing as the device gets closed lock (syncLock) { if (isOpen) { HidApi.hid_close(DeviceHandle); DeviceHandle = IntPtr.Zero; } } HidApi.hid_exit(); // mark object as having been disposed disposed = true; }
public string GetErrorString() { AssertValidDev(); IntPtr ret = HidApi.hid_error(DeviceHandle); // I can not find the info in the docs, but guess this frees // the ret pointer after we created a managed string object // else this would be a memory leak return(Marshal.PtrToStringAuto(ret)); }
// HIDAPI does not provide any way to get or parse the HID Report Descriptor, // This means you must know in advance what it the report size for your device. // For this reason, reportLen is a necessary parameter to the constructor. // // Serial Number is optional, pass null (do NOT pass an empty string) if it is unknown. // public USBDevice(ushort VendorID , ushort ProductID , string serial_number , bool HasReportIDs = true , int defaultInputReportLen = -1) { DeviceHandle = HidApi.hid_open(VendorID, ProductID, serial_number); AssertValidDev(); DefaultInputReportLength = defaultInputReportLen; hasReportIds = HasReportIDs; }
public void GetFeatureReport(byte[] buffer, int length = -1) { AssertValidDev(); if (length < 0) { length = buffer.Length; } if (HidApi.hid_get_feature_report(DeviceHandle, buffer, (uint)length) < 0) { throw new Exception("failed to get feature report"); } }
// All the string functions are in a little bit of trouble becasue // wchar_t is 2 bytes on windows and 4 bytes on linux. // So we should just alloc a hell load of space for the return buffer. // // We must divide Capacity / 4 because this takes the buffer length in multiples of // wchar_t whoose length is 4 on Linux and 2 on Windows. So we allocate a big // buffer beforehand and just divide the capacity by 4. public string GetIndexedString(int index) { lock (syncLock) { AssertValidDev(); if (HidApi.hid_get_indexed_string(DeviceHandle, index, pOutBuf, (uint)pOutBuf.Capacity / 4) < 0) { throw new Exception("failed to get indexed string"); } return(pOutBuf.ToString()); } }
// Meaning OutputReport private void WriteRaw(byte[] buffer, int length = -1) { AssertValidDev(); if (length < 0) { length = buffer.Length; } if (HidApi.hid_write(DeviceHandle, buffer, (uint)length) < 0) { throw new Exception("Failed to write."); } }
public string GetSerialNumberString() { lock (syncLock) { AssertValidDev(); pOutBuf.Clear(); if (HidApi.hid_get_serial_number_string(DeviceHandle, pOutBuf, (uint)pOutBuf.Capacity / 4) < 0) { throw new Exception("failed to get serial number string"); } return(pOutBuf.ToString()); } }
public string GetProductString() { lock (syncLock) { AssertValidDev(); pOutBuf.Clear(); if (HidApi.hid_get_product_string(DeviceHandle, pOutBuf, (uint)pOutBuf.Capacity / 4) < 0) { throw new Exception("failed to get product string"); } return(pOutBuf.ToString()); } }
// either everything is good, or throw exception // Meaning InputReport // This function is slightly different, as we must return the number of bytes read. private int ReadRaw(byte[] buffer, int length = -1) { AssertValidDev(); if (length < 0) { length = buffer.Length; } int bytes_read = HidApi.hid_read_timeout(DeviceHandle, buffer, (uint)length, readTimeoutInMillisecs); if (bytes_read < 0) { throw new Exception("Failed to Read."); } return(bytes_read); }
// Meaning OutputReport private int WriteRaw(byte[] buffer, int length = -1) { int byte_written = 0; AssertValidDev(); if (length < 0) { length = buffer.Length; } byte_written = HidApi.hid_write(DeviceHandle, buffer, (uint)length); if (byte_written < 0) { throw new Exception("Failed to write."); } return(byte_written); }
private void ScanLoop() { var culture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; // The read has a timeout parameter, so every X milliseconds // we check if the user wants us to continue scanning. while (asyncScanOn) { try { IntPtr device_info = HidApi.hid_enumerate(vendorId, productId); bool device_on_bus = device_info != IntPtr.Zero; // freeing the enumeration releases the device, // do it as soon as you can, so we dont block device from others HidApi.hid_free_enumeration(device_info); if (device_on_bus && !deviceConnected) { // just found new device deviceConnected = true; if (DeviceArrived != null) { DeviceArrived(this, EventArgs.Empty); } } if (!device_on_bus && deviceConnected) { // just lost device connection deviceConnected = false; if (DeviceRemoved != null) { DeviceRemoved(this, EventArgs.Empty); } } } catch (Exception e) { // stop scan, user can manually restart again with StartAsyncScan() asyncScanOn = false; } // when read 0 bytes, sleep and read again Thread.Sleep(ScanIntervalInMillisecs); } }
// scanning for device when it is open by another process will return false public static bool ScanOnce(ushort vid, ushort pid) { return(HidApi.hid_enumerate(vid, pid) != IntPtr.Zero); }