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 

    It took me some time to figure out how to get the second endpoints running properly, but my modified example seems to enumerate properly now. 

    Please note that I only define a simple custom HID descriptor that allows you to send 64 bytes in each direction, and I configure EPIN2 and EPOUT2 for this report. 

    It should be possible to modify the report descriptor if you want to integrate the Battery System device instead. 

    Please note that you need to manually change the USBD_CUSTOM_REPORT_DESCRIPTOR_SIZE define based on the length of the USBD_CUSTOM_REPORT_DESCRIPTOR definition. 

    You can find my modified example here:
    https://github.com/too1/nrf52-usbd-custom-hid-ep

    If you have any problems getting it to work just let me know. 

    Best regards
    Torbjørn

  • Hi,

    thank you very much for the example. Is helping me a lot.
    Could you edit the example and make it also for the keyboard?
    Best regards,
    Alberto

  • 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

Reply
  • 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

Children
Related