host_cdc_msc_hid: incorrect len parameter in tuh_hid_report_received_cb
The len parameter is incorrect, it is 3 for many mice where it should be 4 or bigger. Essential data is then missing. For some mice, the len is correct, but that seems more like a coincidence.
Here is excerpt from hid_app.c with logging code to better see what is going on:
// Invoked when received report from device via interrupt endpoint
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len)
{
printf("len=%u;", (uint32_t)len);
for (int i = 0; i != len; ++i)
{
printf(" %x", (uint32_t)report[i]);
}
printf("\r\n");
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
switch (itf_protocol)
{
case HID_ITF_PROTOCOL_KEYBOARD:
TU_LOG2("HID receive boot keyboard report\r\n");
process_kbd_report( (hid_keyboard_report_t const*) report );
break;
case HID_ITF_PROTOCOL_MOUSE:
TU_LOG2("HID receive boot mouse report\r\n");
process_mouse_report( (hid_mouse_report_t const*) report );
break;
default:
// Generic report requires matching ReportID and contents with previous parsed report info
process_generic_report(dev_addr, instance, report, len);
break;
}
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
printf("Error: cannot request to receive report\r\n");
}
}
The length comes from tinyusb? I have seen a length > 3...
#0 process_mouse_report (report=0x20000fae <_hidh_dev+154>) at /home/peterh/source/pico/pico-examples/usb/host/host_cdc_msc_hid/hid_app.c:218 #1 0x100004fa in tuh_hid_report_received_cb (dev_addr=1 '\001', instance=1 '\001', report=0x20000fae <_hidh_dev+154> "", len=4) at /home/peterh/source/pico/pico-examples/usb/host/host_cdc_msc_hid/hid_app.c:113 #2 0x1000c808 in hidh_xfer_cb (dev_addr=1 '\001', ep_addr=130 '\202', result=XFER_RESULT_SUCCESS, xferred_bytes=4) at /home/peterh/source/pico/pico-sdk/lib/tinyusb/src/class/hid/hid_host.c:299 #3 0x10009720 in tuh_task_ext (timeout_ms=4294967295, in_isr=false) at /home/peterh/source/pico/pico-sdk/lib/tinyusb/src/host/usbh.c:456 #4 0x1000098a in tuh_task () at /home/peterh/source/pico/pico-sdk/lib/tinyusb/src/host/usbh.h:118 #5 main () at /home/peterh/source/pico/pico-examples/usb/host/host_cdc_msc_hid/main.c:54
This code is just an example. Feel free to fix your code. If you have a suggestion for a specific improvement we could consider it.
This example still does not work (see my original post). What HID devices was it tried with and what was the output? I suggest trying to turn the mouse wheel for example to see if it the value of the axis is output (hint: it is not), my snippet will be useful for that. After we gather some actual data on this, this issue can be closed. It can then turn into issue for both tinyusb and pico-sdk, because it is a problem with compatibility between those two.
pinging @hathach to see if he has any suggestions from the TinyUSB side.
I will add expected and actual data of my collection of USB mice in the following days. Some are rather esoteric, descriptor-wise (like 12-bit axis, or two-axis wheel). I managed to get quite a few working with older version of https://github.com/sekigon-gonnoc/Pico-PIO-USB , but the author switched from his own host stack to tinyusb and now it has the same issue.
This patch adds output of (potentially flawed) report data as provided by TinyUSB. I had to gzip it because it would not attach here in text format. print_report.tar.gz
First mouse to analyze is Logitech RX300 lsusb: "Logitech, Inc. Corded Tilt-Wheel Mouse" Example output after patched is: len=3; 0 ff 0
(-1 0 0)
Report data is 3 bytes: buttons, dx, dy This is obviously wrong. The mouse has scroll wheel for which the data is missing completely, so that means the report is truncated.
This alone is reproduction of the issue. However, I am going to provide more info such as report descriptor and actual report data, how they should look:
output of usbhid-dump
001:012:000:DESCRIPTOR 1742938398.348291 05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 08 15 00 25 01 95 08 75 01 81 02 95 00 81 03 05 01 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 05 0C 0A 38 02 95 01 81 06 C0 C0
Decoded by https://eleccelerator.com/usbdescreqparser/
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x08, // Usage Maximum (0x08) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x08, // Report Count (8) 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x95, 0x00, // Report Count (0) 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x09, 0x38, // Usage (Wheel) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x75, 0x08, // Report Size (8) 0x95, 0x03, // Report Count (3) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0x05, 0x0C, // Usage Page (Consumer) 0x0A, 0x38, 0x02, // Usage (AC Pan) 0x95, 0x01, // Report Count (1) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xC0, // End Collection
// 59 bytes
And now for some correct report data:
stdbuf -o0 xxd -p -l 100000 /dev/hidraw0 | stdbuf -o0 tr -d '\n' | fold -w 10
03ff000000 03ff000000 0100000000 01ff000000 01ff010000 01ff010000 01ff000000 00ff010000 00ff000000 0000010000 0000010000 0000010000
report is 5 bytes long and the bytes are as follows:
buttons dx dy wheel tilt
where wheel is standard wheel delta and tilt is wheel tilt function (it is possible to "click" the wheel left and right)
Again, where did the two last report bytes out of 5 go? Why parameter len of tuh_hid_report_received_cb is only 3 for this mouse?
Next one is this strange mouse: C-Tech Cronus Ultimate (GM-12)
lsusb: Bus 001 Device 017: ID 4321:6789 WingsChip Gaming Mouse
Our example's output is like this: len=3; 0 ff ff
(-1 -1 0)
len=3; 0 0 0
(0 0 0)
Report length is 3 again (too short), byte 0 is buttons, bytes 1 and 2 are related to mouse movement and show only 00 or ff.
usbhid-dump: 001:017:001:DESCRIPTOR 1742940892.974226 05 01 09 02 A1 01 09 01 A1 00 85 01 95 05 75 01 05 09 19 01 29 05 15 00 25 01 81 02 95 01 75 03 81 01 75 10 95 02 05 01 09 30 09 31 16 00 80 26 FF 7F 81 06 C0 A1 00 95 01 75 08 05 01 09 38 15 81 25 7F 81 06 C0 A1 00 95 01 75 08 05 0C 0A 38 02 15 81 25 7F 81 06 C0 C0 05 0C 09 01 A1 01 85 05 19 00 2A 3C 02 15 00 26 3C 02 95 01 75 10 81 00 C0 05 01 09 80 A1 01 85 03 19 81 29 83 15 00 25 01 75 01 95 03 81 02 95 05 81 01 C0
parsed:
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x85, 0x01, // Report ID (1) 0x95, 0x05, // Report Count (5) 0x75, 0x01, // Report Size (1) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x05, // Usage Maximum (0x05) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x95, 0x01, // Report Count (1) 0x75, 0x03, // Report Size (3) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x75, 0x10, // Report Size (16) 0x95, 0x02, // Report Count (2) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x16, 0x00, 0x80, // Logical Minimum (-32768) 0x26, 0xFF, 0x7F, // Logical Maximum (32767) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xA1, 0x00, // Collection (Physical) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x38, // Usage (Wheel) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xA1, 0x00, // Collection (Physical) 0x95, 0x01, // Report Count (1) 0x75, 0x08, // Report Size (8) 0x05, 0x0C, // Usage Page (Consumer) 0x0A, 0x38, 0x02, // Usage (AC Pan) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xC0, // End Collection 0x05, 0x0C, // Usage Page (Consumer) 0x09, 0x01, // Usage (Consumer Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x05, // Report ID (5) 0x19, 0x00, // Usage Minimum (Unassigned) 0x2A, 0x3C, 0x02, // Usage Maximum (AC Format) 0x15, 0x00, // Logical Minimum (0) 0x26, 0x3C, 0x02, // Logical Maximum (572) 0x95, 0x01, // Report Count (1) 0x75, 0x10, // Report Size (16) 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x80, // Usage (Sys Control) 0xA1, 0x01, // Collection (Application) 0x85, 0x03, // Report ID (3) 0x19, 0x81, // Usage Minimum (Sys Power Down) 0x29, 0x83, // Usage Maximum (Sys Wake Up) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x03, // Report Count (3) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x95, 0x05, // Report Count (5) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection
// 141 bytes
This mouse uses 16-bit deltas for mouse movement!
Example of report (8 bytes each):
01000000ffff0000
0100000001000000
0100010000000000
0100ffff00000000
01000000ffff0000
0100000001000000
0100ffff00000000
0100000001000000
0100000001000000
0100000001000000
01000000ffff0000
01000000ffff0000
0100ffffffff0000
01000000ffff0000
0100ffffffff0000
01000000ffff0000
0100feff00000000
0100ffff00000000
0100000001000000
0100fdff00000000
byte 0 is always 01, byte 1 is buttons, byte 2, 3 is dx, byte 4, 5 is dy, byte 6 is wheel, byte 7 I don't know
Logitech M-BT58 lsusb: Bus 001 Device 019: ID 046d:c03e Logitech, Inc. Premium Optical Wheel Mouse (M-BT58) Similar to RX300, but it is even simpler (simple wheel, no tilt) RPI output: len=3; 0 0 1
(0 1 0)
usbhid-dump: 001:019:000:DESCRIPTOR 1742941718.359465 05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 05 81 03 05 01 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 C0 C0
parsed: 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x02, // Usage (Mouse) 0xA1, 0x01, // Collection (Application) 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (0x01) 0x29, 0x03, // Usage Maximum (0x03) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x95, 0x03, // Report Count (3) 0x75, 0x01, // Report Size (1) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x95, 0x05, // Report Count (5) 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x09, 0x30, // Usage (X) 0x09, 0x31, // Usage (Y) 0x09, 0x38, // Usage (Wheel) 0x15, 0x81, // Logical Minimum (-127) 0x25, 0x7F, // Logical Maximum (127) 0x75, 0x08, // Report Size (8) 0x95, 0x03, // Report Count (3) 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) 0xC0, // End Collection 0xC0, // End Collection
// 50 bytes
Quite straightforward:
00fe0200 00fe0200 00fe0300 00fe0300 00ff0200 00ff0300 00000200 00000300 00010100 00000200 00010200 00010000 00000100 00010100 00010000 00010000 0000ff00 0000ff00 0000ff00 000000ff 0000ff00 0001ff00 0001ff00 0000ff00 00010000 0001ff00 0001ff00 01010000 0100ff00 0101ff00 0100ff00 0100ff00 0100ff00 0100ff00 00000000 00000100 00ff0000 00ff0000 00ff0100 00ff0000 00fe0200 00ff0000 00ff0000 00fe0100 00ff0100 00ff0000
4 bytes: buttons, dx, dy, wheel
Still, one more byte compared to RPI example output.
Please let me know if adding data for more USB mouse models would help.
The key to solving problems with host_hid_to_device_cdc is using the following as part of TinyUSB initialization: tuh_hid_set_default_protocol(HID_PROTOCOL_REPORT);
Then the report data must be interpreted according to the descriptor.
The default HID_PROTOCOL_BOOT does not work very well with many USB mice that I have tested so far.