This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

HID output report size and count

Hello,

I am developing a simple HID device with output report to receive data from PC. I took keyboard example as base project and I want to increase output report size (count) up to 64 bytes. 

I can successfully send data from PC to device when output report is not larger than 1 byte. If I change size or count in descriptor, data transmission is not working.

I use c# code to connect to device and send byte buffer. It does not show any errors, I have just "success" or "fail".

Device is recognized by the PC correctly.

Here is my descriptor

#define HID_CONTROL_REPORT_DESCRIPTOR() {                \
    0x05, 0x01,                    /* USAGE_PAGE (Generic Desktop)*/	\
    0x09, 0x00,                    /* USAGE (Undefined)*/	\
    0xa1, 0x01,                    /* COLLECTION (Application)*/	\
    0x75, 0x08,                    /*   REPORT_SIZE (1)*/	\
    0x95, 0x01,                    /*   REPORT_COUNT (1)*/	\
    0x15, 0x00,                    /*   LOGICAL_MINIMUM (0)*/	\
    0x25, 0x7F,                    /*   LOGICAL_MAXIMUM (127)*/	\
    0x09, 0x01,                    /*   USAGE (Consumer Control)*/	\
    0x91, 0x02,                    /*   OUTPUT (Data,Ary,Abs)*/	\
    0xc0                           /* END_COLLECTION*/	\
}

It works perfectly. But if I increase REPORT_COUNT, or REPORT_SIZE, it stops receiving data from PC

  • What should I do to be able to receive reports from PC with size more than 1 byte?

  • Have you tried report length lower than 64 bytes? Length of the report cannot be longer than length of a BLE packet (20 bytes by default, and we had no success to send larger reports even with increased packet length). Also note that HID report packet that comes from PC should have a length exactly as report count in your descriptor, first byte is a report ID that is 0x00 by default, so your report  will start from byte 0x00 and take (REPORT_COUNT-1) bytes of your data. Though I am not sure whether it is correct in case with c#, I use hidapi library that handles all this magic for me.

    Here is my working in-out HID descriptor:

    	0x06, 0x00, 0xff,  // USAGE_PAGE (Vendor Defined)
    	0x09, 0x01,        // USAGE (1)
    	0xa1, 0x01,        // COLLECTION (Application)
    	0x09, 0x20,        // USAGE (Input Report Data)
    	0x15, 0x00,        // LOGICAL_MINIMUM (0)
    	0x26, 0xff, 0x00,  // LOGICAL_MAXIMUM (255)
    	0x75, 0x08,        // REPORT_SIZE (8)
    	0x95, 0x14,        // REPORT_COUNT (20)
    	0x81, 0x02,        // INPUT (Data,Var,Abs)
    	0x09, 0x21,        // USAGE (Output Report Data)
    	0x15, 0x00,        // LOGICAL_MINIMUM (0)
    	0x26, 0xff, 0x00,  // LOGICAL_MAXIMUM (255)
    	0x75, 0x08,        // REPORT_SIZE (8)
    	0x95, 0x14,        // REPORT_COUNT (20)
    	0x91, 0x02,        // OUTPUT (Data,Var,Abs)
    	0xc0               // END_COLLECTION
    

  • Hi. Yes, I tried different report length. I use HID over USB, not over BLE. I tried to use your descriptor, but I got the same failed result. When I changed report count to 1, data was sent successfully. I tried to use hidapi from c, and I got the same results. 

    Maybe I need to make some additional configuration in firmware on the device?

  • Ok, I found what causes such behavior.

    Apparently, changing REPORT_COUNT in HID descriptor is not enough. For example, there is a app_usbd_hid_kbd_internal.h file for keyboard descriptor. In this file there is global definition of app_usbd_hid_kbd_t class:

    #define APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL(instance_name,                                        \
                                                 interface_number,                                     \
                                                 endpoint,                                             \
                                                 user_ev_handler,                                      \
                                                 subclass_boot)                                        \
        static app_usbd_hid_report_buffer_t CONCAT_2(instance_name, _in)[1];                           \
        static uint8_t CONCAT_2(instance_name, _ep) = {MACRO_MAP(APP_USBD_HID_KBD_INTERVAL,endpoint)}; \
        APP_USBD_HID_GENERIC_GLOBAL_OUT_REP_DEF(CONCAT_2(instance_name, _out), 1 + 1);                 \
        APP_USBD_CLASS_INST_GLOBAL_DEF(                                                                \
            instance_name,                                                                             \
            app_usbd_hid_kbd,                                                                          \
            &app_usbd_hid_kbd_class_methods,                                                           \
            APP_USBD_HID_KBD_CONFIG(interface_number, endpoint),                                       \
            (APP_USBD_HID_KBD_INST_CONFIG(CONCAT_2(instance_name, _in),                                \
                                          &CONCAT_2(instance_name, _out),                              \
                                          user_ev_handler,                                             \
                                          subclass_boot,                                               \
                                          &CONCAT_2(instance_name, _ep)))                              \
        )

    The following line looks like definition of the output report:

    APP_USBD_HID_GENERIC_GLOBAL_OUT_REP_DEF(CONCAT_2(instance_name, _out), 1 + 1); 

    That "1 + 1" looks like size of this output report: 1 byte for Report_ID + 1 byte for data that was defined in descriptor.

    Thus, when I change Report_Count in descriptor, I can't receive more data because I specified here only 2 byte buffer. And I also can't receive same 1 byte data because my descriptor requires larger byte count.

    So, in the global definition for my custom hid class I changed that "1 + 1" to "1 + 64" and updated my descriptor with 64 bytes output report count. And it works.

Related