public static bool ReadMultipleReportsFromDevice(ref byte[] inputReportBuffer, int numberOfReports, ref DeviceInformationStructure deviceInformation)
        {
            var success = false;
            var numberOfBytesRead = 0;
            long pointerToBuffer = 0;

            // Define a temporary buffer for assembling partial data reads into the completed inputReportBuffer
            var temporaryBuffer = new Byte[inputReportBuffer.Length];

            // Range check the number of reports
            if (numberOfReports == 0)
            {
                Debug.WriteLine(
                    "usbGenericHidCommunication:readMultipleReportsFromDevice(): -> ERROR: You cannot request 0 reports!");
                return false;
            }

            if (numberOfReports > 128)
            {
                Debug.WriteLine(
                    "usbGenericHidCommunication:readMultipleReportsFromDevice(): -> ERROR: Reference application testing does not verify the code for more than 128 reports");
                return false;
            }

            // The size of our inputReportBuffer must be at least the same size as the input report multiplied by the number of reports requested.
            if (inputReportBuffer.Length != (deviceInformation.Capabilities.InputReportByteLength * numberOfReports))
            {
                // inputReportBuffer is not the right length!
                Debug.WriteLine(
                    "usbGenericHidCommunication:readMultipleReportsFromDevice(): -> ERROR: The referenced inputReportBuffer size is incorrect for the number of input reports requested!");
                return false;
            }

            // The readRawReportFromDevice method will fill the passed read buffer or return false
            while (pointerToBuffer != (deviceInformation.Capabilities.InputReportByteLength * numberOfReports))
            {
                Debug.WriteLine(
                    "usbGenericHidCommunication:readMultipleReportsFromDevice(): -> Reading from device...");
                success = ReadRawReportFromDevice(ref temporaryBuffer, ref numberOfBytesRead, ref deviceInformation);

                // Was the read successful?
                if (!success)
                {
                    return false;
                }

                // Copy the received data into the referenced input buffer
                Array.Copy(temporaryBuffer, 0, inputReportBuffer, pointerToBuffer, numberOfBytesRead);
                pointerToBuffer += numberOfBytesRead;
            }

            return success;
        }
Exemplo 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);
                }
            }
        }
Exemplo n.º 3
0
        public static bool FindTargetDevice(ref DeviceInformationStructure deviceInformation)
        {
            Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Method called");

            var listOfDevicePathNames = new String[128]; // 128 is the maximum number of USB devices allowed on a single host
            var numberOfDevicesFound = 0;

            try
            {
                // Reset the device detection flag
                var isDeviceDetected = false;
                deviceInformation.IsDeviceAttached = false;

                // Get all the devices with the correct HID GUID
                var deviceFoundByGuid = FindHidDevices(ref listOfDevicePathNames, ref numberOfDevicesFound);

                if (deviceFoundByGuid)
                {
                    Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Devices with matching GUID found...");
                    var listIndex = 0;

                    do
                    {
                        Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Performing CreateFile to listIndex {0}", listIndex.ToString(CultureInfo.InvariantCulture));
                        deviceInformation.HidHandle = Kernel32.CreateFile(listOfDevicePathNames[listIndex], 0, Constants.FileShareRead | Constants.FileShareWrite, IntPtr.Zero, Constants.OpenExisting, 0, 0);

                        if (!deviceInformation.HidHandle.IsInvalid)
                        {
                            deviceInformation.Attributes.Size = Marshal.SizeOf(deviceInformation.Attributes);
                            var success = Hid.HidD_GetAttributes(deviceInformation.HidHandle, ref deviceInformation.Attributes);

                            if (success)
                            {
                                Debug.WriteLine(string.Format("usbGenericHidCommunication:findTargetDevice() -> Found device with VID {0}, PID {1} and Version number {2}",
                                    Convert.ToString(deviceInformation.Attributes.VendorID, 16),
                                    Convert.ToString(deviceInformation.Attributes.ProductID, 16),
                                    Convert.ToString(deviceInformation.Attributes.VersionNumber, 16)));

                                //  Do the VID and PID of the device match our target device?
                                if ((deviceInformation.Attributes.VendorID == deviceInformation.TargetVendorId) &&
                                    (deviceInformation.Attributes.ProductID == deviceInformation.TargetProductId))
                                {
                                    // Matching device found
                                    Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Device with matching VID and PID found!");
                                    isDeviceDetected = true;

                                    // Store the device's pathname in the device information
                                    deviceInformation.DevicePathName = listOfDevicePathNames[listIndex];
                                }
                                else
                                {
                                    // Wrong device, close the handle
                                    Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Device didn't match... Continuing...");
                                    deviceInformation.HidHandle.Close();
                                }
                            }
                            else
                            {
                                //  Something went rapidly south...  give up!
                                Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Something bad happened - couldn't fill the HIDD_ATTRIBUTES, giving up!");
                                deviceInformation.HidHandle.Close();
                            }
                        }

                        //  Move to the next device, or quit if there are no more devices to examine
                        listIndex++;
                    }
                    while (!((isDeviceDetected || (listIndex == numberOfDevicesFound + 1))));
                }

                // If we found a matching device then we need discover more details about the attached device
                // and then open read and write handles to the device to allow communication
                if (isDeviceDetected)
                {
                    // Query the HID device's capabilities (primarily we are only really interested in the
                    // input and output report byte lengths as this allows us to validate information sent
                    // to and from the device does not exceed the devices capabilities.
                    //
                    // We could determine the 'type' of HID device here too, but since this class is only
                    // for generic HID communication we don't care...
                    QueryDeviceCapabilities(ref deviceInformation);

                    // Open the readHandle to the device
                    Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Opening a readHandle to the device");
                    deviceInformation.ReadHandle = Kernel32.CreateFile(
                        deviceInformation.DevicePathName,
                        Constants.GenericRead,
                        Constants.FileShareRead | Constants.FileShareWrite,
                        IntPtr.Zero, Constants.OpenExisting,
                        Constants.FileFlagOverlapped,
                        0);

                    // Did we open the readHandle successfully?
                    if (deviceInformation.ReadHandle.IsInvalid)
                    {
                        Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Unable to open a readHandle to the device!");
                        return false;
                    }

                    Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Opening a writeHandle to the device");
                    deviceInformation.WriteHandle = Kernel32.CreateFile(
                        deviceInformation.DevicePathName,
                        Constants.GenericWrite,
                        Constants.FileShareRead | Constants.FileShareWrite,
                        IntPtr.Zero,
                        Constants.OpenExisting, 0, 0);

                    // Did we open the writeHandle successfully?
                    if (deviceInformation.WriteHandle.IsInvalid)
                    {
                        Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> Unable to open a writeHandle to the device!");

                        // Attempt to close the writeHandle
                        deviceInformation.WriteHandle.Close();
                        return false;
                    }

                    // Device is now discovered and ready for use, update the status
                    deviceInformation.IsDeviceAttached = true;
                    return true;
                }

                //  The device wasn't detected.
                Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> No matching device found!");
                return false;
            }
            catch (Exception)
            {
                Debug.WriteLine("usbGenericHidCommunication:findTargetDevice() -> EXCEPTION: Unknown - device not found");
                return false;
            }
        }
        public static bool ReadRawReportFromDevice(ref byte[] inputReportBuffer, ref int numberOfBytesRead, ref DeviceInformationStructure deviceInformation)
        {
            // Make sure a device is attached
            if (!deviceInformation.IsDeviceAttached)
            {
                Debug.WriteLine("usbGenericHidCommunication:readReportFromDevice(): -> No device attached!");
                return false;
            }

            IntPtr eventObject;
            var hidOverlapped = new NativeOverlapped();
            IntPtr nonManagedBuffer;
            IntPtr nonManagedOverlapped;

            try
            {
                // Prepare an event object for the overlapped ReadFile
                eventObject = Kernel32.CreateEvent(IntPtr.Zero, false, false, "");

                hidOverlapped.OffsetLow = 0;
                hidOverlapped.OffsetHigh = 0;
                hidOverlapped.EventHandle = eventObject;

                // Allocate memory for the unmanaged input buffer and overlap structure.
                nonManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
                nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
                Marshal.StructureToPtr(hidOverlapped, nonManagedOverlapped, false);

                // Read the input report buffer
                Debug.WriteLine("usbGenericHidCommunication:readReportFromDevice(): -> Attempting to ReadFile");
                var success = Kernel32.ReadFile(
                    deviceInformation.ReadHandle,
                    nonManagedBuffer,
                    inputReportBuffer.Length,
                    ref numberOfBytesRead,
                    nonManagedOverlapped);

                if (!success)
                {
                    // We are now waiting for the FileRead to complete
                    Debug.WriteLine(
                        "usbGenericHidCommunication:readReportFromDevice(): -> ReadFile started, waiting for completion...");

                    // Wait a maximum of 3 seconds for the FileRead to complete
                    var result = Kernel32.WaitForSingleObject(eventObject, 3000);

                    switch (result)
                    {
                            // Has the ReadFile completed successfully?
                        case Constants.WaitObject0:

                            // Get the number of bytes transferred
                            Kernel32.GetOverlappedResult(deviceInformation.ReadHandle, nonManagedOverlapped, ref numberOfBytesRead, false);

                            Debug.WriteLine("usbGenericHidCommunication:readReportFromDevice(): -> ReadFile successful (overlapped) {0} bytes read", numberOfBytesRead);
                            break;

                            // Did the FileRead operation timeout?
                        case Constants.WaitTimeout:

                            // Cancel the ReadFile operation
                            Kernel32.CancelIo(deviceInformation.ReadHandle);
                            if (!deviceInformation.HidHandle.IsInvalid) deviceInformation.HidHandle.Close();
                            if (!deviceInformation.ReadHandle.IsInvalid) deviceInformation.ReadHandle.Close();
                            if (!deviceInformation.WriteHandle.IsInvalid) deviceInformation.WriteHandle.Close();

                            // Detach the USB device to try to get us back in a known state
                            //detachUsbDevice();

                            Debug.WriteLine(
                                "usbGenericHidCommunication:readReportFromDevice(): -> ReadFile timedout! USB device detached");

                            return false;

                        // Some other unspecified error has occurred?
                        default:

                            // Cancel the ReadFile operation

                            // Detach the USB device to try to get us back in a known state

                            Debug.WriteLine(
                                "usbGenericHidCommunication:readReportFromDevice(): -> ReadFile unspecified error! USB device detached");
                            return false;
                    }
                }
                // Report receieved correctly, copy the unmanaged input buffer over to the managed buffer
                Marshal.Copy(nonManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
                Debug.WriteLine( "usbGenericHidCommunication:readReportFromDevice(): -> ReadFile successful {0} bytes read", numberOfBytesRead);
            }
            catch (Exception)
            {
                // An error - send out some debug and return failure
                Debug.WriteLine(
                    "usbGenericHidCommunication:readReportFromDevice(): -> EXCEPTION: When attempting to receive an input report");
                return false;
            }

            // Release non-managed objects before returning
            Marshal.FreeHGlobal(nonManagedBuffer);
            Marshal.FreeHGlobal(nonManagedOverlapped);

            // Close the file handle to release the object
            Kernel32.CloseHandle(eventObject);

            return true;
        }
        public static bool WriteRawReportToDevice(byte[] outputReportBuffer, ref DeviceInformationStructure deviceInformation)
        {
            // Make sure a device is attached
            if (!deviceInformation.IsDeviceAttached)
            {
                Debug.WriteLine("usbGenericHidCommunication:writeReportToDevice(): -> No device attached!");
                return false;
            }

            var numberOfBytesWritten = 0;

            try
            {
                // Set an output report via interrupt to the device
                var success = Kernel32.WriteFile(
                    deviceInformation.WriteHandle,
                    outputReportBuffer,
                    outputReportBuffer.Length,
                    ref numberOfBytesWritten,
                    IntPtr.Zero);

                Debug.WriteLine(success
                                    ? "usbGenericHidCommunication:writeReportToDevice(): -> Write report succeeded"
                                    : "usbGenericHidCommunication:writeReportToDevice(): -> Write report failed!");
                return success;
            }
            catch (Exception)
            {
                // An error - send out some debug and return failure
                Debug.WriteLine(
                    "usbGenericHidCommunication:writeReportToDevice(): -> EXCEPTION: When attempting to send an output report");
                return false;
            }
        }
        public static bool ReadSingleReportFromDevice(ref byte[] inputReportBuffer, ref DeviceInformationStructure deviceInformation)
        {
            var numberOfBytesRead = 0;

            // The size of our inputReportBuffer must be at least the same size as the input report.
            if (inputReportBuffer.Length != deviceInformation.Capabilities.InputReportByteLength)
            {
                // inputReportBuffer is not the right length!
                Debug.WriteLine(
                    "usbGenericHidCommunication:readSingleReportFromDevice(): -> ERROR: The referenced inputReportBuffer size is incorrect for the input report size!");
                return false;
            }

            // The readRawReportFromDevice method will fill the passed readBuffer or return false
            return ReadRawReportFromDevice(ref inputReportBuffer, ref numberOfBytesRead, ref deviceInformation);
        }
        public static bool ReadRawReportFromDeviceAsync(ref byte[] inputReportBuffer, ref int numberOfBytesRead, ref DeviceInformationStructure deviceInformation)
        {
            bool success;
            // Make sure a device is attached
            if (!deviceInformation.IsDeviceAttached)
            {
                Debug.WriteLine("usbGenericHidCommunication:readReportFromDevice(): -> No device attached!");
                return false;
            }

            IntPtr eventObject;
            var hidOverlapped = new NativeOverlapped();
            IntPtr nonManagedBuffer;
            IntPtr nonManagedOverlapped;

            try
            {
                // Prepare an event object for the overlapped ReadFile
                eventObject = Kernel32.CreateEvent(IntPtr.Zero, false, false, "");

                hidOverlapped.OffsetLow = 0;
                hidOverlapped.OffsetHigh = 0;
                hidOverlapped.EventHandle = eventObject;

                // Allocate memory for the unmanaged input buffer and overlap structure.
                nonManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
                nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
                Marshal.StructureToPtr(hidOverlapped, nonManagedOverlapped, false);

                // Read the input report buffer
                success = Kernel32.ReadFile(
                    deviceInformation.ReadHandle,
                    nonManagedBuffer,
                    inputReportBuffer.Length,
                    ref numberOfBytesRead,
                    nonManagedOverlapped);

                if(success)
                    Debug.WriteLine("usbGenericHidCommunication:readReportFromDevice(): -> Read Ok");
                // Report receieved correctly, copy the unmanaged input buffer over to the managed buffer
                Marshal.Copy(nonManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
               }
            catch (Exception)
            {
                // An error - send out some debug and return failure
                Debug.WriteLine(
                    "usbGenericHidCommunication:readReportFromDevice(): -> EXCEPTION: When attempting to receive an input report");
                return false;
            }

            // Release non-managed objects before returning
            Marshal.FreeHGlobal(nonManagedBuffer);
            Marshal.FreeHGlobal(nonManagedOverlapped);

            // Close the file handle to release the object
            Kernel32.CloseHandle(eventObject);

            return success;
        }