trezor / cython-hidapi

:snake: Python wrapper for the HIDAPI
Other
287 stars 110 forks source link

Possible issue with get_input_report #174

Open Ultrawipf opened 7 months ago

Ultrawipf commented 7 months ago

When calling get_input_report (with a length of 25) it does not return any actual data. Only a list with the requested ID as the first and only entry no matter if the device actually has sent data with this id or not.

When instead reading all reports with device.read() until a report with the correct ID in the first byte is received i can confirm that the device actually sends the requested data.

Not sure if this is an issue with the python library or the underlying hidapi.

OS: Windows 10 Version: 0.14.0 Python 3.11.1

prusnak commented 7 months ago

Can you please share your code and describe which HW are you using for testing?

Ultrawipf commented 7 months ago

I am using a custom device (OpenFFBoard) that was previously used with pywinusb successfully. The sequence is to send a Output packet with ID 0xA1 and the device will reply with an input packet of ID 0xA1. In pywinusb this was received via a callback function but for linux compatibility i would like to test hidapi instead.

This is the descriptor section for this report: https://github.com/Ultrawipf/OpenFFBoard/blob/master/Firmware/FFBoard/UserExtensions/Src/usb_hid_1ffb_desc.c#L49 In case there is an incompatibility with the descriptor i missed it can be modified but previously it did work well with other HID libraries.

This is the section of the code that builds and sends the packet and waits for the reply:

  self.device.set_nonblocking(False) # The opened hid device
  buffer = bytearray() # Constructing the raw request buffer.
  buffer += bytearray(struct.pack('B',0xA1)) # HIDCMD ID --> This is also read as an input report for the reply
  buffer += bytearray(struct.pack('B',type)) # type. (0 = write, 1 = read)
  buffer += bytearray(struct.pack('<H',cls))
  buffer += bytearray(struct.pack('B',inst))
  buffer += bytearray(struct.pack('<L',cmd))
  buffer += bytearray(struct.pack('<Q',data))
  buffer += bytearray(struct.pack('<Q',adr if adr else 0 ))
  self.device.write(buffer) # Send raw packet. The device does correctly receive the packet and responds so the packet is valid at this point.
  reply = self.device.get_input_report(0xA1,25) # Here it should receive the reply as an input report. Reply is actually just [0xA1] no matter where this function is called.
# It should receive a packet with 25 bytes.

What actually does work is just getting all packets until the right one is found so i know that the packet is being sent at the right time and received:

while not found:
  reply = self.device.read(25)
  if reply[0] == 0xA1:
    break 

But this is not a good solution as the device will be sending gamepad data at the same time which would be received here too.