hidapi icon indicating copy to clipboard operation
hidapi copied to clipboard

hid_read / hid_read_timeout reads more bytes than the report has

Open JoergAtGithub opened this issue 5 years ago • 9 comments

My device has two input reports: 0x01 with a size of 10Bytes 0x02 with a size of 53Bytes

If I use hid_read / hid_read_timeout I get always 53Bytes, also for report 0x01.

But the function hid_get_input_report always returns the correct number of bytes.

This occurs on Windows 7.

JoergAtGithub avatar Nov 14 '20 16:11 JoergAtGithub

This may be a Windows backend limitation.

Youw avatar Jan 05 '21 11:01 Youw

Not so sure if this is relevant. https://marc.info/?l=libusb-devel&m=131805687305661&w=2


List: libusb-devel Subject: Re: [Libusb-devel] How to obtain the output report size? From: Alan Ott <alan () signal11 ! us> Date: 2011-10-04 2:30:19 Message-ID: 4E8A6FBB.2080304 () signal11 ! us [Download RAW message or body]

On 10/03/2011 10:19 PM, Peter Stuge wrote:

Jeremy Roberson wrote:

The short answer is that libusb is not a good choice for communicating with HID class devices through the Windows HID driver. Just to clarify, I'm using LibUSB 1 on Mac and Linux. I used the reference to Windows as an example of what I'm trying to get. Sorry, I should not have written Windows in that sentence, but "kernel". libusb is not good for communication with HID class devices through the kernel HID driver on any platform.

Hi Jeremy,

While I concur that HIDAPI is good (I'm the maintainer :) ), there's not a good way get the report length from HIDAPI either.

The thing is, the report length in that windows record you mentioned is the length of the longest report of that type that the device supports, and you must send exactly that many bytes (plus one for the report number) when you send a report to the device, regardless of whether or not you're sending a report which is shorter. For example, if a device has 2 output reports, one 16 bytes and one 4 bytes, you must send 17 bytes for both. I usually pad with zeroes.

So all that to say there's really no good way to get the data, even on Windows (unless you only have one report of each type). A userspace driver of this sort should know what kind of device it's communicating with anyway. If your code knows the protocol, it should know the length of the packets, and thus you shouldn't need the library to tell you. I do understand however, that we sometimes write code for devices which we don't have any control over and are designed badly (stuff like having the same VID/PID for devices with different protocols, etc). If this is the case, maybe we can help you find a different way to differentiate between similar devices.

Make sure to grab the latest HIDAPI code from git.

Alan.

mcuee avatar Jun 13 '21 12:06 mcuee

Currently I see two options: 1.) Execute a dummy read of each input report at device intialization using hid_get_input_report which returns the correct report size and store the report size in an array. This would be a safe implementation, but it would slow down device initialization. 2.) Determine the report size from the report descriptor. This would be the more elegant solution, but would require that the report descriptor reconstructor, which I implemented in #262 would always detemine the correct size. But currently there is one edge case, where this is not the case (a multiple button bit field have the Usage 0).

JoergAtGithub avatar Jun 13 '21 13:06 JoergAtGithub

Just want to post some historical info about HIDAPI why the report desscriptor parser is not included.

https://sourceforge.net/p/libusb/mailman/message/26230365/


Re: [Libusb-devel] hidapi and HID Report Descriptor parsing From: Alan Ott <alan@si...> - 2010-09-27 12:04:13 On 09/27/2010 03:50 AM, Ludovic Rousseau wrote:

Hello,

I need to get the Report Count from my HID device to know the size I need to use in hid_write(). The hidapi does not provide anything like that. I could hardcode the size but I don't like that.

One argument that is often made is that if you're driving a HID device directly, then you already know the format of the data, including the size of each report. It's not strictly necessary to query the device. Even if you did, what do you do if the device says that its report sizes are different than you expect?

Even in the Linux kernel, fixed sizes are used for outputting data to USB devices (sizeof(), hard-coded, etc). I don't think it's a bad thing. I'm sure many on this mailing list will agree (or will explain why I am wrong).

lsusb -v gives me the information I need. It also looks like libhid can do that with the ReportCount field of the HIDParser struct. My problem is that both lsusb (from usbutils) and libhid are GPL and not LGPL. So I can't (legally) use them for my project.

Do you know a LGPL or BSD licensed HID parser?

I do not. I was able to do some parsing of a report descriptor myself without too much problem. The code is in HIDAPI in linux/hid.c in a function called uses_numbered_reports(). My basic parser looks for Report ID (0x85). I'm just checking for the presence of it. You could probably modify that to look for Report Size and Report Count fields ahead of the Input field.

Alan.

mcuee avatar Jun 13 '21 13:06 mcuee

Right now my test device has only one input report so I can not test this. Unfortunately my old build environment is gone (Microchip MPLAB 8.x and C18 2.4 or later) so I can not change the FW to test this out. I will see if I can find some other test device.


ROM struct{BYTE report[HID_RPT01_SIZE];}hid_rpt01={
 {
   0x06, 0x00, 0xFF,               // Usage page (Vendor Defined Page1)
   0x09, 0x01,                     // Usage (Vendor Usage 1)
   0xA1, 0x01,                     // Collection (Application)

   // Global items apply to all reports below

   0x15, 0x00,                     // Logical Minimum (0)
   0x26, 0xFF, 0x00,               // Logical Maximum (255)
   0x75, 0x08,                     // Report Size (8 bits)
   0x95, 0x02,                     // Report Count (2 fields)

   // Input report
   0x85, 0x01,                     // Report ID (1)
   0x09, 0x00,                     // Usage (Undefined)
   0x82, 0x02, 0x01,               // Input (Data,Var,Abs,Buf)

   // Output report
   0x85, 0x02,                     // Report ID (2)
   0x09, 0x00,                     // Usage (Undefined)
   0x92, 0x02, 0x01,               // Output (Data,Var,Abs,Buf)

   // Feature report
   0x85, 0x03,                     // Report ID (3)
   0x09, 0x00,                     // Usage (Undefined)
   0xB2, 0x02, 0x01,               // Feature (Data,Var,Abs,Buf)

   // Feature report
   0x85, 0x04,                     // Report ID (4)
   0x09, 0x00,                     // Usage (Undefined)
   0xB2, 0x02, 0x01,               // Feature (Data,Var,Abs,Buf)

   0xC0                            // end collection
 }

mcuee avatar Jun 14 '21 07:06 mcuee

I believe this is the solution to go.

2.) Determine the report size from the report descriptor. This would be the more elegant solution, but would require that the report descriptor reconstructor, which I implemented in #262 would always detemine the correct size. But currently there is one edge case, where this is not the case (a multiple button bit field have the Usage 0).

mcuee avatar Jun 16 '21 02:06 mcuee

Reference: answer from Tim Roberts.

On Tue, Jun 15, 2021 at 2:29 AM Tim Roberts wrote:

Xiaofan Chen wrote:

We have a question regarding the behavior of the Linux libusb (usbfs) behavior. https://github.com/libusb/hidapi/issues/274

This is not related to either libusb or usbfs.  This is all hidapi. Right?  Libusb doesn't know anything about the content of the data streams.

 From Ihor Dutchak:

I believe we can parse hid descriptor (which we already doing for some other purposes) and find out the largest report size, and use it as a length parameter passed to libusb_fill_interrupt_transfer.

Yes,  This, for example, is how the Windows HID subsystem operates.

mcuee avatar Jun 16 '21 02:06 mcuee

This is an interesting and quick solution. But I kind of like the other more elegant solution.

1.) Execute a dummy read of each input report at device intialization using hid_get_input_report which returns the correct report size and store the report size in an array. This would be a safe implementation, but it would slow down device initialization.

mcuee avatar Jun 16 '21 03:06 mcuee

This is an interesting and quick solution. But I kind of like the other more elegant solution.

1.) Execute a dummy read of each input report at device intialization using hid_get_input_report which returns the correct report size and store the report size in an array. This would be a safe implementation, but it would slow down device initialization.

This won't work for interrupt-only reports that cannot be read on demand.

Youw avatar Jun 16 '21 12:06 Youw

@Youw

Now that #249 has been closed after the merge of #451.

Just wondering if we can do something for this issue now.

mcuee avatar May 02 '23 03:05 mcuee

To be honest I wouldn't want to introduce any additional parsing/interpretation into HIDAPI.

It can be done on top of HIDAPI and I'd rather try to keep the implementation as simple as possible.

Youw avatar May 02 '23 07:05 Youw

To be honest I wouldn't want to introduce any additional parsing/interpretation into HIDAPI.

It can be done on top of HIDAPI and I'd rather try to keep the implementation as simple as possible.

In that case, shall we close this issue?

mcuee avatar May 02 '23 08:05 mcuee

I guess so.

Youw avatar May 02 '23 10:05 Youw