hid_get_input_report returns one byte more than hid_read, also how to deal with hid_get_feature_report #229
Labels
No labels
3rdparty
Android
API
Author does not respond
bsd
bug
build system/CI
ci-virtual-device
CMake
Contributions Welcome
Core
dependencies
device-specific
documentation
don't_merge
duplicate
enhancement
Example
Haiku
hidraw
hotplug
info required
invalid
libusb
macOS
Misc
Not an issue
question
Release
Test
Test GUI
Windows
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-libusb/hidapi#229
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
hid_get_input_report returns one byte more than hid_read
If I read the same report using hid_get_input_report and than with hid_read, the return value is I get different number of byes read as return value.
This is for the case of a single input report (I reported a maybe related issue about for the case of two input reports here #210 )
This occurs on Windows 7 with HIDAPI 0.10.0
The code of hid_get_input_report contains:
/* bytes_returned does not include the first byte which contains the
report ID. The data buffer actually contains one more byte than
bytes_returned. */
bytes_returned++;
I compared this with the implementation in Google Chrome (WebHID backend), and they read the data using the same API, but do not increment the byte count:
https://chromium.googlesource.com/chromium/src/+/cebcd836b83e1d48db1000b2a5878aa90bc7e88b/services/device/hid/hid_connection_win.cc
(Arriving here from a reference in another issue...)
That is the documented behavior of
hid_get_input_reportwhen report IDs are not used, which could be the case here, since there is a single report.github.com/libusb/hidapi@6a01f3b4a8/hidapi/hidapi.h (L370-L376)hid_read, indeed, follows different semantics.github.com/libusb/hidapi@6a01f3b4a8/hidapi/hidapi.h (L271-L275)Addendum
That is at least a reasonable interpretation of the documentation for
hid_get_input_report. However, the same text appears inhid_get_feature_reportwhich, in turn, seems to have conflicting implementations:HIDIOCGFEATURE, which is documented to have a different behavior: "For devices which do not use numbered reports, the report data will begin at the first byte of the returned buffer."http://janaxelson.com/hidpage.htm
Jan Axelson's page may be of some interests. Including FW codes to be used for test device.
Historical info about feature report.
https://marc.info/?l=libusb-devel&m=128378733122118&w=2
List: libusb-devel
Subject: Re: [Libusb-devel] Returned HID feature report size on windows
From: Alan Ott <alan () signal11 ! us>
Date: 2010-09-06 15:35:11
Message-ID: 4C850A2F.5090509 () signal11 ! us
[Download RAW message or body]
On 09/04/2010 10:18 PM, Xiaofan Chen wrote:
...
ReadFile() will only give input reports which came back on the
Interrupt-IN endpoint. To get a feature report and also its length, you
have to use the DeviceIoControl() call instead of HidD_GetFeature(). The
problem is, the definitions of the IOCTLs are only in the DDK, and
they're not even in the same place as the hid.dll headers. Further,
there are two sets of IOCTLs, one for kernel-space, and one for
user-space, which do many of the same things.
I was eventually able to figure it out, and if you look here:
http://github.com/signal11/hidapi/blob/master/windows/hid.cpp
at the hid_get_feature_report() function, you'll see what works.
... skipped ...
Ref from Microsoft, which is said not to be so clear.
https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/obtaining-hid-reports
Please check my test result also.
https://github.com/libusb/hidapi/pull/232
Test FW and libusb code
https://github.com/mcuee/picusb/tree/master/lvr_genhid_mod
hidapitester results: it seems input report is correct but feature report has an issue as it reads back 4 bytes.
I just purposefully send one more byte and here is the test result. No issues with the input report and feature report.
If I understand your results correctly,hid_get_input_reportactually works fine, buthid_get_feature_reportdoesn't.This makes #232 invalid.UPD: comments below.
@JoergAtGithub something I've failed to ask you earlier:
Does you device uses numbered reports?
I am using hidapitester.
https://github.com/todbot/hidapitester
Report Descriptor of the device:
Form the code of hidapitester.c, it is using hid_read_timeout() for input report and hid_get_feature_report() for feature report read.
https://github.com/todbot/hidapitester/blob/master/hidapitester.c
So based on my test result hid_read_timeout() is correct for input report. hid_get_feature_report() is a bit wrong for feature report in terms of the bytes reading. hidapitester does not test the correctness of hid_get_input_report().
That's unfortunate. Do you have other way to test it? (maybe modify
hidapitester?)I will see what I can do. I need to brush up my C skills (very low anyway).
Interesting under Linux it seems to me hid_get_feature_report() is correct. I am using Raspberry Pi 400 running Ubuntu Linux 64bit.
However I have issues with hid_read() under Linux.
No issues under macOS with my Mac Mini M1.
Yeah those are all different implementations, and the issue seem to be only with Win backend.
As for Linux read - hidraw or libusb? In both cases you shouldn't have any issues, this seem weird.
For the purpose if this test, I think the easiest way would be to replace all
hid_get_feature_reportwithhid_get_input_reportinhidapitesterI will test under Windows later, but my quick fix does not produce good result under macOS.
This means you're not using numbered reports, but your device does use them (numbered reports). Report ID need to be explicitly specified, and be non-zero.
Yes I already specified input report ID as 1 as the parameter for hidapitester. So looks like there are other problems somewhere.
Looks like my quick fix is not correct. I got the same results under Windows.
Does you device/FW support sending syncronous input reports?
I know that with the devices I use, if a report can be
hid_read(basically the device sends me interruptions on a specific events), I cannotget_input_reportit - only those that are specifically designed/implemented that way.The device supports reading input report using either interrupt transfer or control transfer. I have tested with libusb Windows HID backend.
I got the same results using hidpytoy, it also use hid_read for input reports.
https://github.com/todbot/hidpytoy/blob/master/src/main/python/main.py
And I got the same results with feature report that one extra byte is read using hidpytoy and hidapitester, so there is an issue with Windows hid_get_feature_report. I will not be surprised that hid_get_input_report has the same issue.
Yeah, no surprise 1, 2 lol.
I guess I've trusted (and didn't check so far) the original commit too much.
FYI on the device FW and libusb test program. For this paticular device FW, libusb HID backend seems to work. But there are other cases it does not work. You can see this report ID is causing lots of problem for Windows HID related codes, due to the unclear documentation from Microsoft.
https://github.com/libusb/libusb/issues/902
My picusb repo:
https://github.com/mcuee/picusb/tree/master/lvr_genhid_mod
I need to have a minor fix to build under MSYS2 MinGW-w64.
My anlaysis below and I believe hidapi current codes are wrong. I have asked in the libusb-devel mailing list to confirm.
The following article is from the Windows Hardware Developer site.
So you can see that HIDAPI is using ReadFile for the fetching of HID reports continuously with the
hid_read API. And then it does not use HidD_GetXxx routines to obtain the most current input report
and feature report, rather it uses IOCTLs to get the input report and feature report.
https://github.com/libusb/hidapi/blob/master/windows/hid.c#L56
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
Historical reasons why Alan Ott chose to use DeviceIoControl() call and not HidD_GetXxx.
https://github.com/libusb/hidapi/issues/229
So it seems to me that the Microsoft documentation may be a bit confusing to say the driver can use
the two IOCTLs. Usually driver means kernel space in this context even though there are user mode
drivers as well.
Now the question is the return data of the two IOCTLs (output buffer). From what I read, I believe
HIDAPI codes are wrong in both cases, as Microsoft documentation says that the first byte of
the buffer is unchanged (report ID or 0 if no report ID).
https://github.com/libusb/hidapi/blob/master/windows/hid.c#L933
https://github.com/libusb/hidapi/blob/master/windows/hid.c#L884
More proper fix for hidapitester:
And proposed fix to hidapi (including #232)
With the above patch, the results are the same as macOS and Linux. So unfortunately my device is not suitable to test hid_get_input_report(). But at least it confirms the issue on hid_get_feature_report.
@JoergAtGithub Did you test the device without a report ID? If that is tested, then I think #232 is good to go.
No, I tested this only with devices with Report ID. I have to check for a device without Report ID, where hid_get_input_report works. Not sure if I have such a device.
Answers from Tim Roberts (a top Windows driver expert in the wordd and USB expert) in libusb-devel mailing list.
On Wed, Jun 16, 2021 at 12:21 AM Tim Roberts wrote:
@JoergAtGithub So #232 is good to go. Is it possible for you to create another pull request for the feature report? Thanks.