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

HID endpoint clarification (feature reports)

I'm trying to wrap my head around the APP_USBD driver, but I'm running into a mental block.  I am implementing a report descriptor for the Battery System usage page, and all of the characteristics are features.  So would I use an in or out endpoint? or both?  I'm in the middle of trying this now and I'm not getting an error, but I'm not seeing the endpoint on the host either - so I'm not sure if this is caused by the endpoint definition or the report.

It has also lead me down a bit of a rabbit hole.  I actually have a composite device with two endpoints working nicely (joystick and keyboard).  When I was adding on this third piece, I remembered that the default keyboard descriptor from the example has an output in it, but there is only an in endpoint.  So this has me feeling like I don't understand what's going on.  Shouldn't there also have to be an out endpoint for the keyboard to get the output from the host?  I thought I would try it, but when I added an out endpoint, the GLOBAL_DEF macro didn't like it and I'm not sure why:

#define HID_KEYBOARD_EPIN       NRF_DRV_USBD_EPIN(2)
#define HID_KEYBOARD_EPOUT       NRF_DRV_USBD_EPOUT(1)

#define ENDPOINT_LIST_KEYBOARD() \
(                           \
        HID_KEYBOARD_EPIN,  \
        HID_KEYBOARD_EPOUT  \
)

APP_USBD_HID_KBD_GLOBAL_DEF(m_app_hid_keyboard,
                            HID_KEYBOARD_INTERFACE,
                            ENDPOINT_LIST_KEYBOARD(),
                            hid_kbd_user_ev_handler,
                            APP_USBD_HID_SUBCLASS_NONE);

gives an "initializer element is not constant" error:

7> Compiling ‘main.c’
7> In file included from ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd.h:58,
7>                  from C:\some_path\main.c:96:
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:116:1: error: initializer element is not constant
7> ../../../../../../components/libraries/util/app_util.h:712:37: note: in expansion of macro 'APP_USBD_HID_KBD_INTERVAL'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_1'
7> ../../../../../../components/libraries/util/app_util.h:700:29: note: in expansion of macro 'MACRO_MAP_N_'
7> ../../../../../../components/libraries/util/app_util.h:679:25: note: in expansion of macro 'MACRO_MAP_N'
7> ../../../../../../components/libraries/util/app_util.h:678:24: note: in expansion of macro 'MACRO_MAP_'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:167:52: note: in expansion of macro 'MACRO_MAP'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd.h:233:9: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL'
7> C:\some_path\main.c:619:1: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:116:1: note: (near initialization for 'm_app_hid_keyboard_ep')
7> ../../../../../../components/libraries/util/app_util.h:712:37: note: in expansion of macro 'APP_USBD_HID_KBD_INTERVAL'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_1'
7> ../../../../../../components/libraries/util/app_util.h:700:29: note: in expansion of macro 'MACRO_MAP_N_'
7> ../../../../../../components/libraries/util/app_util.h:679:25: note: in expansion of macro 'MACRO_MAP_N'
7> ../../../../../../components/libraries/util/app_util.h:678:24: note: in expansion of macro 'MACRO_MAP_'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:167:52: note: in expansion of macro 'MACRO_MAP'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd.h:233:9: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL'
7> C:\some_path\main.c:619:1: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF'
7> In file included from ../../../../../../components/libraries/usbd/app_usbd.h:46,
7>                  from C:\some_path\main.c:92:
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:463:18: error: initializer element is not constant
7> ../../../../../../components/libraries/util/app_util.h:747:41: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1__'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_REC_1'
7> ../../../../../../components/libraries/util/app_util.h:708:33: note: in expansion of macro 'MACRO_MAP_REC_N_'
7> ../../../../../../components/libraries/util/app_util.h:687:29: note: in expansion of macro 'MACRO_MAP_REC_N'
7> ../../../../../../components/libraries/util/app_util.h:686:28: note: in expansion of macro 'MACRO_MAP_REC_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:460:17: note: in expansion of macro 'MACRO_MAP_REC'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:457:17: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1_'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1'
7> ../../../../../../components/libraries/util/nordic_common.h:116:31: note: in expansion of macro 'CONCAT_2_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:440:9: note: in expansion of macro 'CONCAT_2'
7> ../../../../../../components/libraries/util/app_util.h:712:37: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_1'
7> ../../../../../../components/libraries/util/app_util.h:700:29: note: in expansion of macro 'MACRO_MAP_N_'
7> ../../../../../../components/libraries/util/app_util.h:679:25: note: in expansion of macro 'MACRO_MAP_N'
7> ../../../../../../components/libraries/util/app_util.h:678:24: note: in expansion of macro 'MACRO_MAP_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:583:5: note: in expansion of macro 'MACRO_MAP'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:811:29: note: in expansion of macro 'APP_USBD_CLASS_IFACES_EP_EXTRACT'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:946:9: note: in expansion of macro 'APP_USBD_CLASS_INSTANCE_INITVAL'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:169:5: note: in expansion of macro 'APP_USBD_CLASS_INST_GLOBAL_DEF'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd.h:233:9: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL'
7> C:\some_path\main.c:619:1: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:463:18: note: (near initialization for 'm_app_hid_keyboard.specific.iface.ep[0].address')
7> ../../../../../../components/libraries/util/app_util.h:747:41: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1__'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_REC_1'
7> ../../../../../../components/libraries/util/app_util.h:708:33: note: in expansion of macro 'MACRO_MAP_REC_N_'
7> ../../../../../../components/libraries/util/app_util.h:687:29: note: in expansion of macro 'MACRO_MAP_REC_N'
7> ../../../../../../components/libraries/util/app_util.h:686:28: note: in expansion of macro 'MACRO_MAP_REC_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:460:17: note: in expansion of macro 'MACRO_MAP_REC'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:457:17: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1_'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_1'
7> ../../../../../../components/libraries/util/nordic_common.h:116:31: note: in expansion of macro 'CONCAT_2_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:440:9: note: in expansion of macro 'CONCAT_2'
7> ../../../../../../components/libraries/util/app_util.h:712:37: note: in expansion of macro 'APP_USBD_CLASS_IFACE_EP_EXTRACT_'
7> ../../../../../../components/libraries/util/nordic_common.h:118:31: note: in expansion of macro 'MACRO_MAP_1'
7> ../../../../../../components/libraries/util/app_util.h:700:29: note: in expansion of macro 'MACRO_MAP_N_'
7> ../../../../../../components/libraries/util/app_util.h:679:25: note: in expansion of macro 'MACRO_MAP_N'
7> ../../../../../../components/libraries/util/app_util.h:678:24: note: in expansion of macro 'MACRO_MAP_'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:583:5: note: in expansion of macro 'MACRO_MAP'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:811:29: note: in expansion of macro 'APP_USBD_CLASS_IFACES_EP_EXTRACT'
7> ../../../../../../components/libraries/usbd/app_usbd_class_base.h:946:9: note: in expansion of macro 'APP_USBD_CLASS_INSTANCE_INITVAL'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd_internal.h:169:5: note: in expansion of macro 'APP_USBD_CLASS_INST_GLOBAL_DEF'
7> ../../../../../../components/libraries/usbd/class/hid/kbd/app_usbd_hid_kbd.h:233:9: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL'
7> C:\some_path\main.c:619:1: note: in expansion of macro 'APP_USBD_HID_KBD_GLOBAL_DEF'
Build failed

which I don't understand.  How could it not be constant?  I got the endpoints the same way I did when there was only one of them.

Anyway, I think maybe I have asked too many questions here, but I'm not 100% if I'm asking the right things so I'm hoping that there is an answer that kind of gets everything since they are related.  If this is wrong, I can always break this into different questions.  Then I can also make another one for my confusion about what the interface parameter does... :-P

Parents
  • Hi

    What does your report descriptor look like?

    Is it based on the one in the USB HID Usage Table document?

    Feature and out reports can use either an output interrupt endpoint or the control endpoint. The control endpoint is always present, so technically no OUT endpoint is needed, which is why the keyboard descriptor can support output reports without configuring an OUT endpoint. 

    Best regards
    Torbjørn

  • The report is based on the usage table doc for HID power devices (cf. the chapter on Battery System and the example in Appendix A here, especially section A.6.9).  Generally, I am doing okay with creating descriptors I think.  I'm just a little fuzzy on getting and setting them using the app_usbd driver, and what the interplay is between endpoints, interfaces, and descriptors in the actual implementation.  Here is the descriptor, I can either use it at its own endpoint, or include it as a on the joystick or keyboard descriptor (I think, no?):

    #define HID_BATT_REPORT_DESC() {  \
        0x05, 0x85,                    /* USAGE_PAGE (Battery System) */ \
     \
        0x09, 0x18,                    /* USAGE (BatteryInsertion) */ \
        0x75, 0x01,                    /* REPORT_SIZE (1) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0x15, 0x00,                    /* LOGICAL_MINIMUM (0) */ \
        0x25, 0x01,                    /* LOGICAL_MAXIMUM (1) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs) */ \
     \
        0x09, 0x2c,                    /* USAGE (CapacityMode) */ \
        0x75, 0x01,                    /* REPORT_SIZE (1) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs) */ \
     \
        0x75, 0x06,                    /* REPORT_SIZE (6) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs)  ; end byte 1 */ \
     \
        0x09, 0x83,                    /* USAGE (DesignCapacity) */ \
        0x75, 0x18,                    /* REPORT_SIZE (24) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0x67, 0x01, 0x10, 0x10, 0x00,  /* UNIT (SI Lin:Battery Capacity) */ \
        0x55, 0x00,                    /* UNIT_EXPONENT (0) */ \
        0x15, 0x00,                    /* LOGICAL_MINIMUM (0) */ \
        0x27, 0xfe, 0xff, 0xff, 0x00,  /* LOGICAL_MAXIMUM (16777214) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs)  ; end byte 1 + 3 = 4 */ \
     \
        0x09, 0x66,                    /* USAGE (RemainingCapacity) */ \
        0x75, 0x24,                    /* REPORT_SIZE (36) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0x67, 0x01, 0x10, 0x10, 0x00,  /* UNIT (SI Lin:Battery Capacity) */ \
        0x55, 0x00,                    /* UNIT_EXPONENT (0) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs)  ; end byte 4 + 4 = 8, start byte 9 with 4 bits */ \
     \
        0x75, 0x04,                    /* REPORT_SIZE (4) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs)  ; end byte 9 */ \
     \
        0x09, 0x42,                    /* USAGE (BelowRemainingCapacityLimit) */ \
        0x09, 0x44,                    /* USAGE (Charging) */ \
        0x09, 0x45,                    /* USAGE (Discharging) */ \
        0x75, 0x01,                    /* REPORT_SIZE (1) */ \
        0x95, 0x03,                    /* REPORT_COUNT (3) */ \
        0x15, 0x00,                    /* LOGICAL_MINIMUM (0) */ \
        0x25, 0x01,                    /* LOGICAL_MAXIMUM (1) */ \
        0x65, 0x00,                    /* UNIT (None) */ \
        0xb1, 0x03,                    /* FEATURE (Cnst,Var,Abs)  ; start byte 10 with 3 bits */ \
     \
        0x75, 0x05,                    /* REPORT_SIZE (5) */ \
        0x95, 0x01,                    /* REPORT_COUNT (1) */ \
        0xb1, 0x03                     /* FEATURE (Cnst,Var,Abs)  ; +5bits = end byte 10 */ \
    }

    As I said before, I try to give it it's own endpoint, but I get an error using the macro APP_USBD_HID_KBD_GLOBAL_DEF.  The most important information first is to know what is the preferred way to set up a report descriptor like this one?

    Then, once I get it setup without throwing errors, I have no idea how to set the feature reports (I found this for BLE HID, but nothing for USBD) so some information about that would be appreciated.  Finally, if you are feeling particularly generous, maybe you could also clear up for me why I might use a separate endpoint for a new report descriptor vs just trying to append it to an existing descriptor?  Is it just if I plan on updating the data separately?

    Thanks for your help!

  • Hi Alberto

    Sorry for the slow response, I have been out in leave for the last couple of months. 

    The usbd_hid_composite example in the SDK supports mouse and keyboard. Wouldn't this example be sufficient?

    Best regards
    Torbjørn

  • Hi Torbjørn,

    i figure out how to change the USB descriptor and use the keyboard.

    Do you know any information about to do that also in the BLE HID keyboard?

    I mean, make a custom End-point with the HID over BLE? Any example?

    Best regards,

    Alberto

  • Hi Alberto

    No, we don't have any examples showing how to do a custom HID report over BLE unfortunately.  

    If you need to send custom data over a BLE connection it is usually much easier just to use a proprietary BLE service, you don't really need to package all the custom data in HID reports. 

    Would this be an option for you?

    What platform are you planning to use on the BLE host side?

    Best regards
    Torbjørn

  • Hi,

    we are going to connect the system to Windows 10 OS.

    We have develop the usb over hid with the end-point and to keep everything driverless and we would like also to keep the same communication over BLE.

    Is it really difficult add another end-point over BLE HID?

    Thank you a lot.

    Alberto

  • Hi Alberto

    It should be possible to configure multiple endpoints with the ble_hids.c module, since this module is 'instanced'. 

    What this means is that you pass a pointer to an instance struct to all the function calls, which contains all relevant information for that HID instance, such as which endpoint is used, what the report descriptor is etc. 

    Essentially all you have to do is create another instance using the BLE_HIDS_DEF(..) macro, and add a second hids_init() function where you set up your second instance. 

    I haven't tested this myself, but I will check with the developers that this is supported just to be sure. 

    Best regards
    Torbjørn

Reply
  • Hi Alberto

    It should be possible to configure multiple endpoints with the ble_hids.c module, since this module is 'instanced'. 

    What this means is that you pass a pointer to an instance struct to all the function calls, which contains all relevant information for that HID instance, such as which endpoint is used, what the report descriptor is etc. 

    Essentially all you have to do is create another instance using the BLE_HIDS_DEF(..) macro, and add a second hids_init() function where you set up your second instance. 

    I haven't tested this myself, but I will check with the developers that this is supported just to be sure. 

    Best regards
    Torbjørn

Children
Related