rene-aguirre / pywinusb

USB / HID windows helper library
BSD 3-Clause "New" or "Revised" License
207 stars 63 forks source link

Set Feature Report data last byte corrupted #72

Open Hal9000Space opened 3 years ago

Hal9000Space commented 3 years ago

Hi,

First of all allow me to say thanks for maintaining this repository. It saves me a ton of work!

On Linux I use the usb library (import usb) along with the controlMsg() method for the device to send data, and this works for the particular device. On Windows 10 I'm importing the pywinusb.hid library and trying to send the same type of data. My first attempt was to use the set_raw_data() and send() methods of a feature report to send data to a device, as I did not know if there was a controlMsg() equivalent function in pywinusb. I see the data on the USB bus with my analyzer, but the last byte of the given transaction is always set to zero (0x00). The buffer for this feature report (0xE4) is 263 bytes long, which represents 256 bytes of data plus a 7 byte header.

How can I send the 263 byte data buffer without corruption? Is there another method I should be using?

Thank you.

Here is one transaction worth of data, the last byte should not be zero.

000: E4 00 00 00 00 00 01 59 00 A6 4B 09 BC 16 D3 DB 
016: E4 5D E5 DC E2 36 E3 01 28 42 99 03 43 91 05 D4 
032: C4 BC 1F D3 BC 2D D3 E4 00 E2 40 E3 C0 14 E1 00 
048: 52 72 11 0B 73 28 D2 04 E1 40 14 79 91 EB 28 C8 
064: C2 F0 C8 C1 F0 E0 07 C8 C0 F0 E0 80 C8 C2 F0 E4 
080: 12 BF 73 1D E1 01 79 98 01 B9 E1 50 E8 E0 F0 19 
096: C8 E0 F0 E1 05 E8 E1 F0 19 C8 E1 F0 E8 E0 F0 19 
112: C8 E0 F0 E8 08 FC E1 08 19 C8 08 FC E8 09 FC E1 
128: 00 19 C8 09 FC E8 0A FC C8 0A FC E8 0B FC C8 0B 
144: FC E8 58 FC E1 F9 21 C8 58 FC E8 59 FC E1 FF 21 
160: C8 59 FC E8 5A FC 21 C8 5A FC E8 5B FC 21 C8 5B 
176: FC E8 58 FC C8 58 FC E8 59 FC C8 59 FC E8 5A FC 
192: C8 5A FC E8 5B FC C8 5B FC E0 70 C8 6C FC E0 AD 
208: C8 6D FC 28 C8 6E FC C8 6F FC E1 01 E8 50 FC 19 
224: C8 50 FC E8 51 FC 19 C8 51 FC E0 D0 C8 08 FF E0 
240: 39 C8 09 FF 28 C8 0A FF C8 0B FF E8 F8 FE E1 F9 
256: 21 C8 F8 FE E8 F9 00  // <- this byte is corrupted

Here is a snippet of my Python code. The 'size' parameter from the hid caps does match the buffer size (263) in the case.

import pywinusb.hid as hid

# device open code not shown...

    def SetFeature(self, buffer):
        """Executes a set feature request to the device."""
        assert(self.IsOpen())

        size = self._hDevice.hid_caps.feature_report_byte_length
        for i in range(len(buffer), size):
            buffer.append(0)

        success = 0

        for report in self._hDevice.find_feature_reports():
            if report.report_id == buffer[0]:
                # found our feature report
                report.set_raw_data(buffer)
                report.send()
                success += 1
                break

        if success:
            return True
        else:
            return False
Hal9000Space commented 3 years ago

Well I just answered by own question! I looked through the public methods in this repository and I saw the send_feature_report() method and tried it out. This is doing what I want. Some times we just need to summarize our question in writing and then we can answer our own question. Still curious what was wrong with my set_raw_data() example, but I'm not stuck on this anymore.

mcuee commented 3 years ago

Set your buffer to be one bytes more (for the report ID).

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/hidsdi/nf-hidsdi-hidd_setfeature

BOOLEAN HidD_SetFeature(
  HANDLE HidDeviceObject,
  PVOID  ReportBuffer,
  ULONG  ReportBufferLength
);

ReportBufferLength
[in] Specifies the size, in bytes, of the report buffer. The report buffer must be large 
enough to hold the feature report -- excluding its report ID, if report IDs are used 
-- plus one additional byte that specifies a nonzero report ID or zero.
rene-aguirre commented 3 years ago

This is a current design limitation, currently, the HID class doesn't keep an internal feature type so find_feature_reports just returns a generic report, hence, send assumes the default output report.

I think your example code makes sense, it should be supported.

mcuee commented 3 years ago

This is a current design limitation, currently, the HID class doesn't keep an internal feature type so find_feature_reports just returns a generic report, hence, send assumes the default output report.

Interesting. Looking at the codes it does seem to differentiate feature report with output report, but maybe I am wrong. https://github.com/rene-aguirre/pywinusb/blob/master/pywinusb/hid/core.py