HID output reports

91 views
Skip to first unread message

fullmetalfelix

unread,
Nov 23, 2023, 8:45:53 AM11/23/23
to btstack-dev
Hi,

I have been working on a custom bluetooth (classic) controller (joystick) and now I'm stuck on the force feedback. The device is a BTStack based program running on a PiZero.

Does anyone have an example of HID device that can get output reports from the host?

Best,
Filippo

Matthias Ringwald

unread,
Nov 24, 2023, 4:07:01 AM11/24/23
to btsta...@googlegroups.com
Hi Filippo

I don't think I've ever tried Output Reports, but there's a hid_device_register_set_report_callback which suggests you should get a callback if the HID Host sends an output report.
You could start with hid_keyboard_demo.c, and try to send the caps lock or num lock key as that should trigger the Host to update the keyboard LEDs with a Output Report.

Best
Matthias
> --
> You received this message because you are subscribed to the Google Groups "btstack-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to btstack-dev...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/btstack-dev/070f72a8-3f45-4e06-818e-839810e4f27dn%40googlegroups.com.

fullmetalfelix

unread,
Nov 24, 2023, 8:00:19 AM11/24/23
to btstack-dev
Hi,

it appears that the keyboard demo in master branch does not use the hid_device_register_set_report_callback, and seems there is no handling of keyboard LEDs.

Best,
Filippo

Matthias Ringwald

unread,
Nov 24, 2023, 10:43:23 AM11/24/23
to btsta...@googlegroups.com
Hi Fllippo

Well, no, it doesn't, but it's not much work to add a function and call hid_device_register_set_report_callback. The other thing to do is to figure out how to send the CAPS LOCK key event.

Cheers
Matthias
> To view this discussion on the web visit https://groups.google.com/d/msgid/btstack-dev/e4a84843-6851-4f52-bafe-bb1c47d93245n%40googlegroups.com.

fullmetalfelix

unread,
Nov 24, 2023, 11:46:14 AM11/24/23
to btstack-dev
So, I have managed to make a report descriptor that the computer interprets correctly as a joystick, and it also has a custom (vendor defined) output report of one byte.
I added the function in the code as such:

void set_report(uint16_t hid_cid, hid_report_type_t report_type, int report_size, uint8_t *report){

    printf("Host HID output report:\n");
    printf("\tHID CID: %i\n", hid_cid);
    printf("\tReport Type: %i\n", report_type);
    printf("\tReport Size: %i\n", report_size);
    printf("\tReport Data: ");
    for (int i=0; i<report_size; i++) printf("%#02X ",report[i]);
    printf("\n");
}
...
    // HID Device
    hid_device_init(hid_boot_device, sizeof(hid_descriptor_joystick_mode), hid_descriptor_joystick_mode);
   
    // register for HCI events
    hci_event_callback_registration.callback = &packet_handler;
    hci_add_event_handler(&hci_event_callback_registration);

    // register for HID events
    hid_device_register_packet_handler(&packet_handler);

    // sign up for host output reports?
    hid_device_register_set_report_callback(&set_report); // <--

    // turn on!
    hci_power_control(HCI_POWER_ON);

The callback should just print the report info in the console.
The thing compiles and runs, pairs with computer and sends the HID input reports. Then I tried to send some bare bytes using HIDPyToy, but nothing happens: the set_report callback is never called.
Is there some other step that I am missing?

Matthias Ringwald

unread,
Nov 27, 2023, 8:39:43 AM11/27/23
to btsta...@googlegroups.com
Hi Filippo

It's possible that the HIDPyToy doesn't work as expected.

I've just run the hid_keyboard_demo on my mac and paired it via Bluetooth as well. I've then started HIDPyToy and try to send various reports as well as tried reading them.
However, in the HCI packet log, there have been no HID messages, so BTstack had no chance to forward output reports as it didn't receive any.
Please enable HCI logging (see documentation), it's easiest on a desktop system with a USB Bluetooth dongle and try to figure out how you can send Output reports.
You can open the HCI log in Wireshark. Once that is working, you can check if you also get the report via the callback, or not.

Cheers
Matthias
> To view this discussion on the web visit https://groups.google.com/d/msgid/btstack-dev/1e89c1b5-10b3-4099-82b9-c7f30db37cedn%40googlegroups.com.

fullmetalfelix

unread,
Nov 30, 2023, 3:04:20 PM11/30/23
to btstack-dev

Hi,

thanks for the suggestion. I sniffed the packets from my device, and the input reports look like this:

bytes (sent by my btstack program): a1 03 00 00 00 00 00
bytes (sniffed): 02 47 20 0b 00 07 00 41 00 a1 03 00 00 00 00 00
info: Rcvd DATA - Input - unknown type

Bluetooth HCI H4
    [Direction: Rcvd (0x01)]
    HCI Packet Type: ACL Data (0x02)
Bluetooth HCI ACL Packet
    .... 0000 0100 0111 = Connection Handle: 0x047
    ..10 .... .... .... = PB Flag: First Automatically Flushable Packet (2)
    00.. .... .... .... = BC Flag: Point-To-Point (0)
    Data Total Length: 11
    Data
    [Connect in frame: 7]
    [Source BD_ADDR: RaspberryPiF_XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    [Source Device Name: ]
    [Source Role: Slave (2)]
    [Destination BD_ADDR: Xerox_00:00:00 (00:00:00:00:00:00)]
    [Destination Device Name: ]
    [Destination Role: Master (1)]
    [Last Role Change in Frame: 6]
    [Current Mode: Active Mode (0)]
    [Last Mode Change in Frame: 7]
Bluetooth L2CAP Protocol
    Length: 7
    CID: Dynamically Allocated Channel (0x0041)
    [Connect in frame: 63]
    [PSM: HID-Interrupt (0x0013)]
Bluetooth HID Profile
    1010 .... = Transaction Type: DATA (0xa)
    .... 00.. = Parameter reserved: 0x0
    .... ..01 = Report Type: Input (0x1)
    Protocol Code: Unknown (0x03)

The GUI in wireshark does not give any more details after this last byte 0x03.
Wireshark seem to think that the last byte 0x03 is the protocol code, but it really is the report ID which I sent, and the last 5 bytes all set to 0, are the report data: joystick axes and buttons.
I am not sure if they are supposed to look like this, but when I sniff USB packets (non-bluetooth) from other devices, they look significatly different, and I can recognize the fields described in the HID documentation (bmRequestType, bRequest,wValue,...)
Another difference is that this packet info is "Rcvd DATA - Input - unknown type", while packets from a USB device are labelled "URB_CONTROL in" or "URB_INTERRUPT in".
Regardless, this does work, it is treated as the joystick input.

Then I made a C# app using HIDAPI.NET. This also reads the input reports just fine, but then sends an output report using the Device.Write() function.
I sent 0x03 0x01, which should be the report ID (same as input report) and just one test byte as expected by the descriptor.
This is how it is logged in wireshark:

bytes (sent by my C# program): 03 01
bytes (sniffed): 02 47 00 07 00 03 00 42 00 a2 03 01
info: Sent DATA - Output - unknown type

Bluetooth HCI H4
    [Direction: Sent (0x00)]
    HCI Packet Type: ACL Data (0x02)
Bluetooth HCI ACL Packet
    .... 0000 0100 0111 = Connection Handle: 0x047
    ..00 .... .... .... = PB Flag: First Non-automatically Flushable Packet (0)
    00.. .... .... .... = BC Flag: Point-To-Point (0)
    Data Total Length: 7
    Data
    [Connect in frame: 7]
    [Source BD_ADDR: Xerox_00:00:00 (00:00:00:00:00:00)]
    [Source Device Name: ]
    [Source Role: Master (1)]
    [Destination BD_ADDR: RaspberryPiF_XX:XX:XX (XX:XX:XX:XX:XX:XX)]
    [Destination Device Name: ]
    [Destination Role: Slave (2)]
    [Last Role Change in Frame: 6]
    [Current Mode: Active Mode (0)]
    [Last Mode Change in Frame: 7]
Bluetooth L2CAP Protocol
    Length: 3
    CID: Dynamically Allocated Channel (0x0042)
    [Connect in frame: 63]
    [PSM: HID-Interrupt (0x0013)]
Bluetooth HID Profile
    1010 .... = Transaction Type: DATA (0xa)
    .... 00.. = Parameter reserved: 0x0
    .... ..10 = Report Type: Output (0x2)
    Protocol Code: Unknown (0x03)

On the device nothing happens, the set_report callback is never called.


fullmetalfelix

unread,
Nov 30, 2023, 4:30:07 PM11/30/23
to btstack-dev
I think I understand what is going on a bit better.
btstack expect an L2CAP_DATA_PACKET, with message type HID_MESSAGE_TYPE_SET_REPORT (=0x5). But HIDAPI.NET sends a message of type 0xA which is of type DATA.
The set_report call back should not be called at all.

Thanks for pointing me in the right direction.

fullmetalfelix

unread,
Dec 1, 2023, 4:49:06 AM12/1/23
to btstack-dev
Hi again,

I managed to kinda fix it last night but something else happened in the process. Initially the reports sent by my HIDAPI.NET program were ignored and I started adding debug printf all over the btstack source.

Turns out btstack thought my report ID (3) was invalid, as determined by hid_report_id_status in hid_device.c
The device seemed to be in boot protocol mode, and so btstack expects the report ID to be that of a keyboard (1) or mouse (2).

So I changed my device report ID to 1 and tried again, and it failed because hid_report_size_valid returns invalid size. Report size should be at least 8 for keyboard report ID and 1 for mouse report ID.
Finally I changed the report ID to 2 and it all worked.

The question is now why is my device in boot protocol mode? I tried initialising it with hid_boot_device set to either 0 and 1 (this goes in both the hid_create_sdp_record and hid_device_init), but regardless of the value the device ends up in boot protocol mode. I even added a printf to check if the host is sending a SET_PROTOCOL message, but that never happens. Looks like the device is in boot protocol mode from the very start.
Is this intended and I am missing something again?

Best,
Filippo

Matthias Ringwald

unread,
Dec 1, 2023, 5:05:03 AM12/1/23
to btsta...@googlegroups.com
Hi Filippo

Glad you got (at least a POC) to work. Please switch to BTstack's develop branch. I think there was an issue with HID Device being in Boot Protocol Mode by default which has been fixed recently.

Cheers
Matthias
> To view this discussion on the web visit https://groups.google.com/d/msgid/btstack-dev/c238aa61-2087-4711-aa95-b22f98abb464n%40googlegroups.com.

fullmetalfelix

unread,
Dec 1, 2023, 10:47:58 AM12/1/23
to btstack-dev
Thanks again. I am using a fork of  btstack master as submodule in my repo because I had to a few issues like #include <printf.h> not existing. I found the commit in develop about the report mode decoming default and copied that code into my fork. It all seems to work fine for now.

Thank you for your continued support!

Best,
Filippo

Matthias Ringwald

unread,
Dec 1, 2023, 11:11:26 AM12/1/23
to btsta...@googlegroups.com
Hi Filippo

Glad you got it working. We've also fixed the accidental #include <printf.h> -- interestingly, this file exists on my mac.
If you have other issues just compiling the stack (develop branch), please file an issue on GitHub.

Best
Matthias
> To view this discussion on the web visit https://groups.google.com/d/msgid/btstack-dev/be69b948-4a2a-4727-9d41-cd48cc4dc1edn%40googlegroups.com.

Reply all
Reply to author
Forward
0 new messages