hid_read / hid_read_timeout reads more bytes than the report has #210

Closed
opened 2020-11-14 10:35:26 -06:00 by JoergAtGithub · 13 comments
JoergAtGithub commented 2020-11-14 10:35:26 -06:00 (Migrated from github.com)

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.

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.
Youw commented 2021-01-05 05:16:06 -06:00 (Migrated from github.com)

This may be a Windows backend limitation.

This may be a Windows backend limitation.
mcuee commented 2021-06-13 07:59:37 -05:00 (Migrated from github.com)

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.

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.
JoergAtGithub commented 2021-06-13 08:33:12 -05:00 (Migrated from github.com)

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).

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).
mcuee commented 2021-06-13 08:51:58 -05:00 (Migrated from github.com)

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.

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 commented 2021-06-14 02:18:37 -05:00 (Migrated from github.com)

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
 }

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 commented 2021-06-15 21:58:30 -05:00 (Migrated from github.com)

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).

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 commented 2021-06-15 21:59:44 -05:00 (Migrated from github.com)

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.

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 commented 2021-06-15 22:26:02 -05:00 (Migrated from github.com)

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 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.
Youw commented 2021-06-16 07:49:24 -05:00 (Migrated from github.com)

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.

> 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.
mcuee commented 2023-05-01 22:34:23 -05:00 (Migrated from github.com)

@Youw

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

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

@Youw Now that #249 has been closed after the merge of #451. Just wondering if we can do something for this issue now.
Youw commented 2023-05-02 02:17:27 -05:00 (Migrated from github.com)

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.

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.
mcuee commented 2023-05-02 03:03:12 -05:00 (Migrated from github.com)

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?

> 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?
Youw commented 2023-05-02 05:17:56 -05:00 (Migrated from github.com)

I guess so.

I guess so.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-libusb/hidapi#210
No description provided.