/* IDTech USB Bridge for UWP Applications * * This USB Bridge class will allow IDTechSDK.dll to utilize * USB communication on UWP Applications * * Requires IDtechSDK_STD library from NuGet, Version 2.1.2.156 or later * https://www.nuget.org/packages/IDTechSDK_STD/ * * Project Page at IDTech: * https://atlassian.idtechproducts.com/confluence/display/KB/Universal+Library+for+Visual+Studio+-+Home?desktop=true¯oName=attachments * * This class will only communicate IDTech USB Devices in HID mode. This class will not allow * communication with IDTech USB Devices Operating in KB mode * * Usage: * 1. Add IDTechSDK_STD from NuGet into your project (2.1.2.156 or later) * 2. Add this class IDT_UsbBridge to your UWP project * 3. As per standard implementation, set the callback for IDTechSDK * 4. After setting the callback, create an instance to this class * * IDT_Device.setCallbackIP(MessageCallBack); * IDT_UsbBridge bridge = new IDT_UsbBridge(); * * 5. Configure your Package.appxmanifest to allow communication with Human Interface Devices * * * * * * * */ using IDTechSDK; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Windows.Devices.Enumeration; using Windows.Devices.HumanInterfaceDevice; using Windows.Storage; using Windows.Storage.Streams; namespace IDT_USBBridge { class IDT_UsbBridge { static Dictionary usbList = new Dictionary(); static Dictionary receiveQueue = new Dictionary(); static Dictionary deviceDict = new Dictionary(); bool inEnum = false; public IDT_UsbBridge() { IDT_Device.checkUwpUsbCallback = checkUwpUsb; IDT_Device.uwpWriteKBCallback = UWPwriteKB; IDT_Device.uwpWriteHIDCallback = UWPwriteHID; IDT_Device.uwpReadKBCallback = UWPreadKB; IDT_Device.uwpReadHIDCallback = UWPreadHID; IDT_Device.uwpOpenDeviceCallback = UWPopenDevice; IDT_Device.uwpCloseDeviceCallback = UWPcloseDevice; IDT_Device.startUSBMonitoring(); } private void checkUwpUsb() { if (inEnum) return; enumerateDevice(); } private void UWPcloseDevice(string ident) { HidDevice dev = getDevice(ident.ToUpper()); if (dev == null) return; dev.Dispose(); deviceDict.Remove(ident.ToUpper()); usbList.Remove(ident.ToUpper()); if (receiveQueue.ContainsKey(ident)) { receiveQueue[ident].Close(); } receiveQueue.Remove(ident.ToUpper()); } private bool UWPopenDevice(string ident) { return deviceDict.ContainsKey(ident.ToUpper()); } HidDevice getDevice(string ident) { if (deviceDict.ContainsKey(ident.ToUpper())) return deviceDict[ident.ToUpper()]; return null; } private void UWPwriteKB(byte[] data, string ident) { //KB Device Functionality disabled HidDevice dev = getDevice(ident.ToUpper()); if (dev == null) return; } private static UInt32 sendOutputReportSync(HidOutputReport outputReport, HidDevice dev ) { uint outputReportSent = 0; // Send the command to the device synchronously Task task = new Task(async () => { try { await dev.SendOutputReportAsync(outputReport); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Sending output report error: " + ex); outputReportSent = 1; } }); task.RunSynchronously(); return outputReportSent; } private static IBuffer getDataBufferFromBytes(byte[] data) { // Convert the byte array into an IBuffer IBuffer dataBuffer = null; DataWriter dataWriter = new DataWriter(); dataWriter.WriteBytes(data); dataBuffer = dataWriter.DetachBuffer(); //dataWriter.Dispose(); return dataBuffer; } private UInt32 UWPwriteHID(byte[] data, string ident) { if (data == null) return 1; HidDevice dev = getDevice(ident.ToUpper()); if (dev == null) return 1; IDTechComm comm = Profile.getComm(ident.ToUpper()); if (comm == null) return 1; DEVICE_PROTOCOL_Types type = comm.getDeviceProtocol(); HidOutputReport outputReport = dev.CreateOutputReport(); outputReport.Data = getDataBufferFromBytes(data); return sendOutputReportSync(outputReport, dev); } private byte[] UWPreadKB(string ident) { //KB Device Functionality disabled HidDevice dev = getDevice(ident.ToUpper()); if (dev == null) return null; return null; } private byte[] UWPreadHID(string ident) { HidDevice dev = getDevice(ident.ToUpper()); if (dev == null) return null; ReceiveQueue q = receiveQueue[ident.ToUpper()]; byte[] val = q.Dequeue(); return val; } private async void enumerateDevice() { inEnum = true; bool listChanged = false; string selector = "System.Devices.InterfaceClassGuid:=\"{4D1E55B2-F16F-11CF-88CB-001111000030}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True"; var devices = await DeviceInformation.FindAllAsync(selector); if (devices.Count == 0) return; foreach (DeviceInformation dev in devices) { //add any new devices if (!deviceDict.ContainsKey(dev.Id.ToUpper())) { if (dev.Id.IndexOf("VID_") > 0 && dev.Id.IndexOf("PID_") > 0) { int vidValue = int.Parse(dev.Id.Substring(dev.Id.IndexOf("VID_") + 4, 4), System.Globalization.NumberStyles.HexNumber); int pidValue = int.Parse(dev.Id.Substring(dev.Id.IndexOf("PID_") + 4, 4), System.Globalization.NumberStyles.HexNumber); foreach (IDTechDevices idt in IDTechSDK.Profile.idtechDevices) { if (idt.vid == vidValue && idt.pid == pidValue) { HidDevice device = await HidDevice.FromIdAsync(dev.Id, FileAccessMode.ReadWrite); if (device != null) { device.InputReportReceived += inputReportReceivedEvent; listChanged = true; ReceiveQueue queue = new ReceiveQueue(); lock (receiveQueue) { receiveQueue.Add(dev.Id.ToUpper(), queue); } deviceDict.Add(dev.Id.ToUpper(), device); usbList.Add(dev.Id.ToUpper(), idt); } } } } } } List removedDevices = new List(); foreach (KeyValuePair hid in deviceDict) { bool foundMatch = false; foreach (DeviceInformation dev in devices) { if (dev.Id.ToUpper().Equals(hid.Key.ToUpper())) foundMatch = true; } if (!foundMatch) removedDevices.Add(hid.Key.ToUpper()); } foreach (string str in removedDevices) { listChanged = true; deviceDict.Remove(str.ToUpper()); usbList.Remove(str.ToUpper()); lock (receiveQueue) { receiveQueue.Remove(str.ToUpper()); } } if (listChanged) IDT_Device.UwpUsbListChanged(usbList); inEnum = false; } class ReceiveQueue { bool validQueue = true; Queue queue = null; public ReceiveQueue() { queue = new Queue(); } public void Enqueue(byte[] data) { lock (queue) { queue.Enqueue(data); } } public byte[] Dequeue() { while (validQueue) { lock (queue) { if (queue.Count > 0) return queue.Dequeue(); } Thread.Sleep(50); } return null; } public void Close() { validQueue = false; } } private static void inputReportReceivedEvent(HidDevice sender, HidInputReportReceivedEventArgs eventArgs) { if (deviceDict.Count == 0) return; HidInputReport inputReport = eventArgs.Report; string ident = null; foreach (KeyValuePair device in deviceDict) { if (device.Value == sender) ident = device.Key; } if (ident == null) ident = deviceDict.ElementAt(0).Key; // Check if input report is empty if (inputReport != null) { // Create new byte array with the size of the input report's data length byte[] inputReportDataBytes = new byte[inputReport.Data.Length]; IBuffer newBuf = inputReport.Data; DataReader dataReader = DataReader.FromBuffer(newBuf); dataReader.ReadBytes(inputReportDataBytes); ReceiveQueue q = receiveQueue[ident]; if (q != null) q.Enqueue(inputReportDataBytes); } } } }