-
Notifications
You must be signed in to change notification settings - Fork 397
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HIDAPI testing device with known good firmware, including using Virtual HID device for CI Testing #478
Comments
Ref: libusb project uses umockdev for Linux testing using a container. |
The alternative: |
I am not so sure if this is possible or not. |
BTW, other than CI, it is also good to see if we have some known good HID device or FW to test HIDAPI. For libusb, here is the reference, it can be the same for USB HID device development. But for Bluetooth/BLE and even I2C/SPI HID device, we need different tools.
Other than vendor provided USB stacks (sometimes with proprietary licenses), there are also Opensource MCU USB stacks.
Just wondering what is the test device you are using to test HIDAPI? For me I usually use whatever HID device I have with me like the following for general test using hidtest.
For more real tests with hidapitester or simple test codes. I do not know much about the FW development other than simple modifications of the USB PIC USB codes and maybe a little bit with USB AVRs.
Then I use some HID devices to test hidapi indirectly using avrdude and OpenOCD (CMSIS DAP v1 compliant adapters). |
Unfortunately I don't have any devices dedicated for testing, only a few of my peripherals, and a few devices from my employer (I'm under NDA not to disclose what those are), which have a few fixed input/output/interrupt reports, that I usually use for some sanity testing. |
Yeah, would be great to have 1-2 FW samples for some well known simple/cheap device to be able to test most (all?) of the HIDAPI. |
@todbot has some test firmware for hidapitester which can be used for hidapi testing as well.
TinyUSB node-hid has some examples as well. |
Jan Axelson has quite some HID examples for things like Cypress EZ-USB FX2LP and Microchip USB PIC. |
Simple test for Jan Axelson FX2HID example (0925:1234) -- loop back of Input/Output report (no report ID) using hidapitest. For this FW, I have to explicitly send output report ID 0.
Her USB PIC generic HID example has feature report loopback as well.
I have done the modification of the generic HID FW to add report ID (Input 1, Output 2, Feature OUT 3, Feature IN 4). I used that to test libusb Windows HID backend many year ago during the initial stage of the libusb Windows backend development.
|
Simple test using hidapitester for the Microchip Simple HID demo (which is the base for the FW used in hidtest). I am using the mla version for the 8bit/16bit USB PICs.
|
For libusb testing, I usually recommend Cypress EZ-USB FX3 (SuperSpeed). Then EZ-USB FX2LP (High-Speed). I think for HIDAPI testing, maybe FX3 is a bit overkill but you may want to get cheap EZ-USB FX2LP breakout from online marketplace like AliExpress at about US$5. For example, I have the following board. I just did a simple modification of Jan Axelson's fx2hid example to extend the Input/Output report size to 64 bytes.
Edit: take note that in order to develop high speed HID USB device using FX2LP with wMaxPacketSize > 64 Bytes, we can not use EP1IN or EP1OUT, as their buf size is only 64 bytes. We should probably use EP2 and EP6 (buffer size equals to 512 Bytes or 1024 Bytes). So the modification is not as simple. But if we just need to get report size >64 bytes, then it is still possible to use EP1 IN and EP1 OUT. We need to handle the fragamentation in firmware. |
For EZ-USB FX2LP, previous examples are using Keil UV2 and Keil C51 toolchain (the FW is rather small so the free 4K version bundled will work). Lastes from Cypress (now part of Infineon) is using Eclipse based IDE with Open Source SDCC toolchain. Then there are quite some open source FW library available, using sdcc. |
It should be a device, where you can program any HID ReportDescriptor, PhysicalDescriptor and StringDescriptor on low-level (byte-wise). Not something where you configure everything on high-level, because for testing it makes a difference how we order the items in the ReportDescriptor. |
I believe most of the MCU development board will allow this, including the EZ-USB FX2LP (actually the example code from Jan Axelson uses assembly language for the descriptor, same for examples from Cypress). Unfortunately I am not a programmer so I can only carry out minor modification of existing FW codes. |
I need to check but the following FX2LP FW seems to work, EP1 IN and EP1 OUT have wMacPacketSize = 64 bytes, but INPUT/OUTPUT report size are both 128 bytes.
fx2hid_128bytes_report.zip Similar thing for 512Bytes report.
|
I combined the codes from BulkLoop (change to Interrupt Endpoint) and FX2HID and create the new FX2HID FW using EP2 (OUT) and EP6 (IN) and it seems to work fine, with wMaxPacketSize = 512 Bytes and Report Size = 512 Bytes.
|
1024 bytes wMaxPacketSize and HID INPUT/OUTPUT report size.
|
BTW, I think the above implementation is not fully correct as I have not implemented getting the Input/Output report using Control Transfer. I will try that as well later. But I think it is good enough for Input/Output transfer using the Interrupt IN/OUT endpoint. I will also try to add Feature reports as well. |
For this purpose, I have the modified Generic HID Device Firmware example from Jan Axelson, using USB PIC (I have PIC18F87J50 USB PIM, other USB PICs should work).
|
Testing results of two examples from hidapitester. For Feature report, hidapitester needs to add first 0 in order to work with HID device without Feature report ID (tested under Windows). The zero will not appear on the wire and the device will not receive the firs zero.
Arduino serial monitor output.
There are four test FWs in hidapitester. I have only tested the first two examples: ProMicroRawHID and TeensyRawHid. I will try to get the other tinyusb based examples working later. |
Here are the test results for SAMD21 (using Arduino M0 clone) hidtest-tinyusb example.
|
Here are the test results for SAMD21 (using Arduino M0 clone) hidtest_tinyusb_static example. Mode: blink1 mode, echo ON.
teensy mode, echo ON.
|
BTW, Adafruit Arduino TinyUSB library has a generic hid example as well and it should work on many boards. The following test is using the Arduino M0 clone (Microchip/Atmel SAMD21).
The following result is from Raspberry Pi Pico.
|
I tend to think the two examples from hidapitester can be of good use to hidapi project testing.
Reference: the library is said to support USB AVR and SAMD21.
Reference:
|
"3" That would be great. |
For HID over I2C/SPI, I tend to think it is difficult to do under Windows as a driver may be needed. There are some examples of HID over I2C for Linux (using things as Raspberry Pi 4/400 as Linux host) For HID over SPI, it seems to me the support under Linux is quite new. |
Sorry to disturb you. I believe there is a stupid mistake here in Code.py is working fine for Generic USB HID device emulation.
But sending input report (looping back from output report) does not work.
hidapitester output
|
Hi @mcuee, As for why you need two descriptors in usb_hid.enable( (custom_device,) ) |
Yes you are right. The following works.
Relevant discussion here. |
I have had problems with 64-byte reports with report IDs. Not sure if this is a MCU buffer limitation (which is 64 bytes usually), an issue with hidapi, or something else. Here is a modified set of above code that does work, up to 63 byte reports: # rawhid_code.py
import time
import usb_hid
import adafruit_hid
custom_device = adafruit_hid.find_device(usb_hid.devices, usage_page=0xff00, usage=0x01)
print("custom_device: %04x %04x" % (custom_device.usage_page, custom_device.usage) )
while True:
out_report = custom_device.get_last_received_report(2) # out from computer
if out_report:
print("len:",len(out_report),["%02x" % x for x in out_report])
time.sleep(0.5)
print("sending copy on reportid 1")
in_report = bytearray(out_report) # copy in case we want to modify
custom_device.send_report(in_report, 1); # in to computer # rawhid_boot.py --
# any changes here only reflected after board reset
import usb_hid
REPORT_COUNT = 63 # size of report in bytes
CUSTOM_REPORT_DESCRIPTOR = bytes((
0x06, 0x00, 0xff, # Usage page (Vendor Defined Page1)
0x09, 0x01, # Usage (Vendor Page 1)
0xA1, 0x01, # Collection (Application)
0x85, 0x01, # Report ID (1)
0x09, 0x00, # Usage Page (Undefined)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8 bits)
0x95, REPORT_COUNT, # Report Count (64 fields)
0x82, 0x02, 0x01, # Input (Data,Var,Abs,Buf)
0x85, 0x02, # Report ID (2)
0x09, 0x00, # Usage (Undefined)
0x09, 0x00, # Usage Page (Undefined)
0x15, 0x00, # Logical Minimum (0)
0x26, 0xFF, 0x00, # Logical Maximum (255)
0x75, 0x08, # Report Size (8 bits)
0x95, REPORT_COUNT, # Report Count (64 fields)
0x92, 0x02, 0x01, # Output (Data,Var,Abs,Buf)
0xC0, # End Collection
))
custom_device = usb_hid.Device(
report_descriptor=CUSTOM_REPORT_DESCRIPTOR,
usage_page=0xff00, # Vendor defined
usage=0x01, # Vendor page 1
report_ids=(1, 2),
in_report_lengths=(REPORT_COUNT,0),
out_report_lengths=(0, REPORT_COUNT),
)
usb_hid.enable( (custom_device,) ) And running hidapitester: ./hidapitester --usagePage 0xff00 --usage 1 --open -l 64 --send-output 2,3,4,5 --timeout 1000 --read-input 1
Opening device, vid/pid:0x0000/0x0000, usagePage/usage: FF00/1
Device opened
Writing output report of 64-bytes...wrote 64 bytes:
02 03 04 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Reading 64-byte input report 0, 1000 msec timeout...read 64 bytes:
01 03 04 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Closing device Note that hidapitester is given When run, the CircuitPython device outputs this on its REPL:
|
Thanks a lot for the help. Interesting and this is exactly the same problem I have with my USB PIC using Jan Axelson's generic HID example as well. 63 bytes works but not 64 bytes. I think there are a few potential reasons.
This is one potential issue of hidapitester I would like to check with you and @Youw. I am thinking this should be worked-around inside hidapitest for Windows (report ID 0 needs to be in the buffer but not really appear in the USB BUS. That is probably why we need one more bytes of bufer than the length of report size. I believe this is not necessary for Linux and Windows. I could be wrong though. |
This reflects how |
Please take a look when you got the time. Thanks. |
@Youw and @todbot and @JoergAtGithub I think we have gone through this report length previously. Maybe we have to revisit them. I think the following PR fixes the issue for reading back the input report and it is correct. I think we need to revisit for Feature report. I think the following commit is kind of correct if we look at from Windows driver point of view. But from a cross-platform API point of view, we may need to revist to align with Linux and macOS, which means we need to focus on the data on the USB bus and we need to drop the extra 0 in front when the report ID is 0 for Windows. Same for Output report. Right now we may report one more byte than real data on the bus due to Windows driver behavior, when the report ID is 0. All in all, we may need to align Windows HIDAPI behavior along with Linux and macOS. Need to check with the libusb backend as well. Another related old PR for macOS. |
There are many confusions under libusb Windows HID backend as well. I think there are more problems with libusb Windows HID backend (libusb project recommends people to use HIDAPI and not libusb, so it is a legacy thingy).
There is another interesting issue there as well (hopefully not affecting HIDAPI). |
FYI as well. I believe libusb/libusb#1217 is incorrect. |
Unfortunately I've never had good test device(s) to check all: input/output/feature/interrupt, with and w/o report ID and with different lengths. All being said, I think we need to focus to make the behavior (e.g. in terms of the return length, etc.) be consistent on all platforms, specifically to match the documentation.
I'm a little lost in the context and worst of all - cannot properly check it locally... |
I will recommend the following devices which will work with the examples here. They are of relative low cost from online stores like AliExpress.
Yes I agree.
I understand. I will try to summarize and create another issue. And hopefully you can get one or two of the test devices without too much difficulties. |
Hm, I actually have an Arduino somewhere. Haven't used it for years. Maybe I could use it. |
No problem, take your time. The Arduino Uno and Maga 2560 (official version and some clones) come with ATmega16U2. It is a bit tricky to get the rawhid example working. Arduino Leonardo or Arduino Micro or Pro Micro or clones come with ATmega32U4 and then you should have no issues to get rawhid example working. |
I am going to move this to discussion and create a new issue to make this one clean. Sorry I have put too much info here and people may get confused. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
There is an example device for hidraw from umockdev project. Maybe we can integrate it for CI under Linux.
https://github.com/martinpitt/umockdev/tree/main/devices/hidraw
The text was updated successfully, but these errors were encountered: