Esempio n. 1
0
        public static bool QueryDeviceCapabilities(ref DeviceInformationStructure deviceInformation)
        {
            var preparsedData = new IntPtr();

            try
            {
                Hid.HidD_GetPreparsedData(deviceInformation.HidHandle, ref preparsedData);
                Hid.HidP_GetCaps(preparsedData, ref deviceInformation.Capabilities);
            }
            catch
            {
                Debug.WriteLine("QueryDeviceCapabilities failed with error {0}", Marshal.GetLastWin32Error());
                return(false);
            }
            finally
            {
                // Free up the memory before finishing
                Hid.HidD_FreePreparsedData(preparsedData);
            }
            return(true);
        }
Esempio n. 2
0
        public static void QueryDeviceCapabilities(ref DeviceInformationStructure deviceInformation)
        {
            var preparsedData = new IntPtr();

            try
            {
                // Get the preparsed data from the HID driver
                Hid.HidD_GetPreparsedData(deviceInformation.HidHandle, ref preparsedData);

                // Get the HID device's capabilities
                var result = Hid.HidP_GetCaps(preparsedData, ref deviceInformation.Capabilities);
                if ((result == 0))
                {
                    return;
                }

                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> Device query results:");
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Usage: {0}",
                                Convert.ToString(deviceInformation.Capabilities.Usage, 16));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Usage Page: {0}",
                                Convert.ToString(deviceInformation.Capabilities.UsagePage, 16));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Input Report Byte Length: {0}",
                                deviceInformation.Capabilities.InputReportByteLength.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Output Report Byte Length: {0}",
                                deviceInformation.Capabilities.OutputReportByteLength.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Feature Report Byte Length: {0}",
                                deviceInformation.Capabilities.FeatureReportByteLength.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Link Collection Nodes: {0}",
                                deviceInformation.Capabilities.NumberLinkCollectionNodes.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Input Button Caps: {0}",
                                deviceInformation.Capabilities.NumberInputButtonCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Input Value Caps: {0}",
                                deviceInformation.Capabilities.NumberInputValueCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Input Data Indices: {0}",
                                deviceInformation.Capabilities.NumberInputDataIndices.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Output Button Caps: {0}",
                                deviceInformation.Capabilities.NumberOutputButtonCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Output Value Caps: {0}",
                                deviceInformation.Capabilities.NumberOutputValueCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Output Data Indices: {0}",
                                deviceInformation.Capabilities.NumberOutputDataIndices.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Feature Button Caps: {0}",
                                deviceInformation.Capabilities.NumberFeatureButtonCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Feature Value Caps: {0}",
                                deviceInformation.Capabilities.NumberFeatureValueCaps.ToString(CultureInfo.InvariantCulture));
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() ->     Number of Feature Data Indices: {0}",
                                deviceInformation.Capabilities.NumberFeatureDataIndices.ToString(CultureInfo.InvariantCulture));
            }
            catch (Exception)
            {
                // Something went badly wrong... this shouldn't happen, so we throw an exception
                Debug.WriteLine("usbGenericHidCommunication:queryDeviceCapabilities() -> EXECEPTION: An unrecoverable error has occurred!");
                throw;
            }
            finally
            {
                // Free up the memory before finishing
                if (preparsedData != IntPtr.Zero)
                {
                    Hid.HidD_FreePreparsedData(preparsedData);
                }
            }
        }
Esempio n. 3
0
        public HidDevice(string path)
        {
            //device mutex
            lockObject = new object();

            //static buffers
            strBuffer = new StringBuilder(256);

            //open device
            //TODO why is 0x40000000 missing from FileAttribute in PInvoke?
            reference = Kernel32.CreateFile(path, Kernel32.ACCESS_MASK.GenericRight.GENERIC_WRITE, Kernel32.FileShare.FILE_SHARE_READ | Kernel32.FileShare.FILE_SHARE_WRITE, IntPtr.Zero, Kernel32.CreationDisposition.OPEN_EXISTING, Kernel32.CreateFileFlags.FILE_FLAG_OVERLAPPED, Kernel32.SafeObjectHandle.Null);

            if (reference.IsInvalid)
            {
                return;
            }

            //overlapped
            fileEvent      = new ManualResetEvent(false);
            fileOverlapped = new SafeOverlapped(fileEvent);

            //get preparsed data
            if (!Hid.HidD_GetPreparsedData(reference, out preparsedData))
            {
                return;
            }

            //transfer buffers
            capabilities  = Hid.HidP_GetCaps(preparsedData);
            inBuffer      = new byte[capabilities.InputReportByteLength];
            outBuffer     = new byte[capabilities.OutputReportByteLength];
            featureBuffer = new byte[capabilities.FeatureReportByteLength];

            //dynamic caps
            inputValueCaps   = new List <ValueCaps>();
            outputValueCaps  = new List <ValueCaps>();
            featureValueCaps = new List <ValueCaps>();

            ushort numInputCaps   = capabilities.NumberInputValueCaps;
            ushort numOutputCaps  = capabilities.NumberOutputValueCaps;
            ushort numFeatureCaps = capabilities.NumberFeatureValueCaps;

            ushort maxValueCaps = Math.Max(numInputCaps, numOutputCaps);

            maxValueCaps = Math.Max(maxValueCaps, numFeatureCaps);

            int    valueCapSize = Marshal.SizeOf <ValueCaps>();
            IntPtr valueCapPtr  = Marshal.AllocHGlobal(maxValueCaps * valueCapSize);

            HidPStatus stat = Hid.HidP_GetValueCaps(ReportType.Input, valueCapPtr, ref numInputCaps, preparsedData);

            for (int i = 0; i < numInputCaps; i++)
            {
                ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + (i * valueCapSize)));
                inputValueCaps.Add(val);
            }

            stat = Hid.HidP_GetValueCaps(ReportType.Output, valueCapPtr, ref numOutputCaps, preparsedData);

            for (int i = 0; i < numOutputCaps; i++)
            {
                ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + i * valueCapSize));
                outputValueCaps.Add(val);
            }

            stat = Hid.HidP_GetValueCaps(ReportType.Feature, valueCapPtr, ref numFeatureCaps, preparsedData);

            for (int i = 0; i < numFeatureCaps; i++)
            {
                ValueCaps val = Marshal.PtrToStructure <ValueCaps>(new IntPtr(valueCapPtr.ToInt64() + i * valueCapSize));
                featureValueCaps.Add(val);
            }

            Marshal.FreeHGlobal(valueCapPtr);
        }
Esempio n. 4
0
        private void _DeviceSearchThread()
        {
            _Logger.Info("Started");
            while (_Running)
            {
                var loopStart = DateTime.Now;

                #region Device enumeration

                var devices = new List <UsbDevice>();

                var detailDataBuffer = IntPtr.Zero;
                var deviceInfoSet    = IntPtr.Zero;
                try
                {
                    int listIndex           = 0;
                    int lastError           = 0;
                    var deviceInterfaceData = new SpDeviceInterfaceData();

                    var systemHidGuid = new Guid();
                    Hid.HidD_GetHidGuid(ref systemHidGuid);
                    deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref systemHidGuid, IntPtr.Zero, IntPtr.Zero, Constants.DigcfPresent | Constants.DigcfDeviceinterface);
                    deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);

                    while (SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex++, ref deviceInterfaceData) || (lastError = Marshal.GetLastWin32Error()) != Constants.ERROR_NO_MORE_ITEMS)
                    {
                        if (lastError == 0)
                        {
                            int bufferSize = 0;
                            SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero);
                            detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
                            Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
                            if (SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero))
                            {
                                var pDevicePathName = IntPtr.Add(detailDataBuffer, 4);
                                var devicePath      = Marshal.PtrToStringAuto(pDevicePathName);

                                // Get device capabilities (to determine usage page)
                                using (var hidHandle = Kernel32.CreateFile(devicePath, 0, Constants.FileShareRead | Constants.FileShareWrite, IntPtr.Zero, Constants.OpenExisting, 0, 0))
                                {
                                    var preparsedData = IntPtr.Zero;
                                    try
                                    {
                                        preparsedData = new IntPtr();
                                        Hid.HidD_GetPreparsedData(hidHandle, ref preparsedData);
                                        var caps = new HidpCaps();
                                        Hid.HidP_GetCaps(preparsedData, ref caps);

                                        var attrs = new HiddAttributes();
                                        Hid.HidD_GetAttributes(hidHandle, ref attrs);

                                        // Only add the device if it has our VID, PID, and RAW usage page
                                        var deviceClass = FindDeviceClass(attrs.VendorID, attrs.ProductID, attrs.VersionNumber, caps.UsagePage);
                                        if (deviceClass != null)
                                        {
                                            var manufacturer = new StringBuilder(STRING_SIZE_LIMIT);
                                            var product      = new StringBuilder(STRING_SIZE_LIMIT);
                                            var serial       = new StringBuilder(STRING_SIZE_LIMIT);
                                            Hid.HidD_GetManufacturerString(hidHandle, manufacturer, STRING_SIZE_LIMIT);
                                            Hid.HidD_GetProductString(hidHandle, product, STRING_SIZE_LIMIT);
                                            Hid.HidD_GetSerialNumberString(hidHandle, serial, STRING_SIZE_LIMIT);
                                            var device = new UsbDevice(new DeviceInstance(deviceClass, devicePath, manufacturer.ToString(), product.ToString(), serial.ToString()), caps);
                                            devices.Add(device);
                                        }
                                    }
                                    finally
                                    {
                                        // Free up the memory before finishing
                                        if (preparsedData != IntPtr.Zero)
                                        {
                                            Hid.HidD_FreePreparsedData(preparsedData);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    _Logger.Error(ex, "Error scanning for devices:");
                    devices.Clear();
                }
                finally
                {
                    // Clean up the unmanaged memory allocations and free resources held by the windows API
                    if (detailDataBuffer != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(detailDataBuffer);
                    }
                    if (deviceInfoSet != IntPtr.Zero)
                    {
                        SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet);
                    }
                }

                var addedDevices   = devices.Except(_CurrentDevices);
                var removedDevices = _CurrentDevices.Except(devices);

                _CurrentDevices = devices;

                if (DeviceRemoved != null)
                {
                    foreach (var dev in removedDevices)
                    {
                        _Logger.Info("Device removed: {0}", dev);
                        DeviceRemoved(this, new DeviceEventArgs(dev.Instance));
                    }
                }
                if (DeviceAdded != null)
                {
                    foreach (var dev in addedDevices)
                    {
                        _Logger.Info("Device added: {0}", dev);
                        DeviceAdded(this, new DeviceEventArgs(dev.Instance));
                    }
                }

                #endregion

                #region Active device I/O

                // If we receive a request to change the active device while we are processing messages, we need to stop immediately because they are about to become invalid
                {
                    byte[] msg;
                    while (true)
                    {
                        byte[] response = null;

                        // Block until SetActiveDevice finishes
                        lock (_LockObject)
                        {
                            // If we created a new message queue in the call to SetActiveDevice, this will return false and we'll break out of the loop
                            if (_ActiveDevice == null || !_MessageQueue.TryDequeue(out msg))
                            {
                                break;
                            }
                            try
                            {
                                response = SendDeviceRequest(_ActiveDevice, msg);
                            }
                            catch (Exception ex)
                            {
                                _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult);
                            }
                        }

                        if (response != null)
                        {
                            ProcessResponse(msg, response);
                        }
                        else
                        {
                            _Logger.Error("Failed to read data from device. req = {0}", FormatByteArray(msg));
                        }
                    }
                }

                // Get LED config (it may have changed)
                {
                    byte[] response = null;
                    byte[] msg      = CreateSimpleMessage(hid_pkt_req.HID_PKT_REQ_CONFIG_LED_GET);

                    // Block until SetActiveDevice finishes
                    lock (_LockObject)
                    {
                        if (_ActiveDevice != null)
                        {
                            try
                            {
                                response = SendDeviceRequest(_ActiveDevice, msg);
                            }
                            catch (Exception ex)
                            {
                                _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult);
                            }
                        }
                    }

                    if (response != null)
                    {
                        ProcessResponse(msg, response);
                    }
                }

                // Get LED status
                {
                    byte[] response = null;
                    byte[] msg      = new byte[2];
                    msg[0] = (byte)hid_pkt_req.HID_PKT_REQ_LED_STATUS;
                    msg[1] = 0;

                    var ledStatuses = new List <LedColor>();

                    do
                    {
                        lock (_LockObject)
                        {
                            if (_ActiveDevice != null)
                            {
                                try
                                {
                                    response = SendDeviceRequest(_ActiveDevice, msg);
                                }
                                catch (Exception ex)
                                {
                                    _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult);
                                }
                            }
                        }

                        if (response != null)
                        {
                            // Parse response
                            for (byte i = 0; i < response[1] && i < 10; i++)
                            {
                                var led = new LedColor(
                                    response[i * 3 + 2],
                                    response[i * 3 + 3],
                                    response[i * 3 + 4]
                                    );
                                ledStatuses.Add(led);
                            }

                            msg[1] += 10;
                        }
                    } while (response != null && response[0] == (byte)hid_pkt_res.HID_PKT_RES_MORE);

                    LedStatusReceived?.Invoke(this, new LedStatusReceivedEventArgs(ledStatuses));
                }

                #endregion

                // Wait until the entire loop execution is at least 100ms
                var loopTime = DateTime.Now - loopStart;
                if (loopTime < LOOP_DELAY)
                {
                    var waitTime = LOOP_DELAY - loopTime;
                    Thread.Sleep(waitTime);
                }
            }
        }