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

what can I do ,if I want to send left or right button data with ble_hids_inp_rep_send()

I what to send button data , how to construct button data array : uint8_t buffer[INPUT_REP_BUTTONS_LEN]; in function ble_hids_inp_rep_send() ?

In SDK mouse demo I can see that, if I want to send mouse move data I can do like this :

    APP_ERROR_CHECK_BOOL(INPUT_REP_MOVEMENT_LEN == 3);
    
    x_delta = MIN(x_delta, 0x0fff);
    y_delta = MIN(y_delta, 0x0fff);

    buffer[0] = x_delta & 0x00ff;
    buffer[1] = ((y_delta & 0x000f) << 4) | ((x_delta & 0x0f00) >> 8);
    buffer[2] = (y_delta & 0x0ff0) >> 4;
    
    err_code = ble_hids_inp_rep_send(&m_hids,
                                     INPUT_REP_MOVEMENT_INDEX, 
                                     INPUT_REP_MOVEMENT_LEN, 
                                     buffer);

but I don't know why buffer[] construct like this and how can I construct it in button data array.

  • Hi gootoomoon,

    the HID over GATT service is a straight mapping from USB HID in case you are familiar with that. When the service is initialized (hids_init()) you configure a Report Map (called HID Report descriptor in USB HID) and set up a bunch of characteristics (Input/Output/Feature Reports). These characteristics must match the contents of the Report Map. The Report Map describes the number and type of Reports that exists in this Service, and also describes the data format for each report. Thus, the data format in buffer[] is found in the Report Map.

    If you are not familiar with USB HID or HID over GATT, the Report Map looks like black magic. If you cannot use any of the Report Maps in our examples, I suggest reading up a bit on HIDPage. There's also a [HID Descriptor tool](www.usb.org/.../hidpage Descriptor Tool) available.

    Now, with that information in mind, let's look at the ble_hids_mouse example. The mouse movement data you refer to has a format specified by the Report Map:

    
    (...)
    // Report ID 2: Mouse motion
    0x85, 0x02, //     Report Id 2 
    0x09, 0x01, //     Usage (Pointer)
    0xA1, 0x00, //     Collection (Physical)
    0x75, 0x0C, //         Report Size (12)
    0x95, 0x02, //         Report Count (2)
    0x05, 0x01, //         Usage Page (Generic Desktop)
    0x09, 0x30, //             Usage (X)
    0x09, 0x31, //             Usage (Y)
    0x16, 0x01, 0xF8, //             Logical maximum (2047)
    0x26, 0xFF, 0x07, //             Logical minimum (-2047)
    0x81, 0x06, //             Input (Data, Variable, Relative)
    0xC0, //     End Collection (Physical)
    0xC0, // End Collection (Application)
    (...)
    
    

    This piece of code describes Input Report #2, with two 12-bit values: Mouse X and mouse Y. These are part of the Generic Desktop Usage page (see HID Usage Tables page 26).

    Similarly, the button Input Report is described by the following part of the Report Map:

    
    (...)
    // Report ID 1: Mouse buttons + scroll/pan
    0x85, 0x01, //     Report Id 1 
    0x09, 0x01, //     Usage (Pointer)
    0xA1, 0x00, //     Collection (Physical)
    0x95, 0x05, //         Report Count (3)
    0x75, 0x01, //         Report Size (1)
    0x05, 0x09, //         Usage Page (Buttons)
    0x19, 0x01, //             Usage Minimum (01)
    0x29, 0x05, //             Usage Maximum (05)
    0x15, 0x00, //             Logical Minimum (0)
    0x25, 0x01, //             Logical Maximum (1)
    0x81, 0x02, //             Input (Data, Variable, Absolute)
    0x95, 0x01, //             Report Count (1)
    0x75, 0x03, //             Report Size (3)
    0x81, 0x01, //             Input (Constant) for padding
    0x75, 0x08, //             Report Size (8)
    0x95, 0x01, //             Report Count (1)
    0x05, 0x01, //         Usage Page (Generic Desktop)
    0x09, 0x38, //             Usage (Wheel)
    0x15, 0x81, //             Logical Minimum (-127)
    0x25, 0x7F, //             Logical Maximum (127)
    0x81, 0x06, //             Input (Data, Variable, Relative) 
    0x05, 0x0C, //         Usage Page (Consumer)
    0x0A, 0x38, 0x02, //             Usage (AC Pan) 
    0x95, 0x01, //             Report Count (1)
    0x81, 0x06, //             Input (Data,Value,Relative,Bit Field)
    0xC0,       //     End Collection (Physical)
    (...)
    
    

    This code describes the format of a combined button + scroll wheel packet. The first byte is a button bitmask: Bit 0 = button0 (left), bit 1 = button1 (right), bit 2 = button2 (middle), bits 3-7 are not used. The second byte is a normal scroll, while the third byte is sideways scroll.

    During the HoG Service initialization, it is important to know the relationship between Report Map and characteristics. When you want to send a button press, you need to use the characteristic which represents the Input Report with ID 1 (notice there are several Report ID fields in the Report Map). In the example, For example, INPUT_REP_MOVEMENT_INDEX is a reference to the movement Input Report characteristic (Report ID #2 in the Report Map).

    If you want to send a "hold down left mouse button" report, you'll want to do something like this:

    
    buffer[0] = 0x01; // Left button (bit 0) pressed
    buffer[1] = 0; // Scroll value (-127, 128)
    buffer[2] = 0; // Sideways scroll value (-127, 128)
    
    err_code = ble_hids_inp_rep_send(&m_hids,
    INPUT_REP_BUTTONS_INDEX, 
    INPUT_REP_BUTTONS_LEN, 
    buffer);
    
    

    It's important to note that INPUT_REP_BUTTONS_INDEX is a reference to the HID Service, and not directly related to the Report Map. INPUT_REP_REF_BUTTONS_ID is on the other hand directly related to the Report Map. The ID must match what is written in the Report Map. If the Reports (characteristics) doesnt match the Report Map, the Host will give you an error.

    This is a lot of information, but I hope it helps! In short: you need to know both BLE and USB HID to fully comprehend the HoG Service.

    Audun

  • when I initialize button

    static void buttons_init(void) { static app_button_cfg_t buttons[] = { {LEFT_BUTTON_PIN_NO, false, NRF_GPIO_PIN_NOPULL, button_event_handler}, {RIGHT_BUTTON_PIN_NO, false, NRF_GPIO_PIN_NOPULL, button_event_handler}, // Note: This pin is also BONDMNGR_DELETE_BUTTON_PIN_NO {UP_BUTTON_PIN_NO, false, NRF_GPIO_PIN_NOPULL, button_event_handler}, {DOWN_BUTTON_PIN_NO, false, NRF_GPIO_PIN_NOPULL, button_event_handler} };

    APP_BUTTON_INIT(buttons, sizeof(buttons) / sizeof(buttons[0]), BUTTON_DETECTION_DELAY, true);
    

    }

    I can send data when button is pressed,but how can I send button release event when button is release?

    One click event is constructed of a press and a release event.

  • Yeah, it doesn't look like the app_button library handles press and release for a single button.. app_gpiote does however. You can either start a timer when the button is pressed, and then at regular intervals use app_button_is_pushed(). Or you can use app_gpiote to set up your button interrupt instead.

    Using a timer is probably the best solution, as that gives you button debounce as well.

  • In the demo // Report ID 1: Mouse buttons + scroll/pan 0x85, 0x01, // Report Id 1 0x09, 0x01, // Usage (Pointer) 0xA1, 0x00, // Collection (Physical) 0x95, 0x05, // Report Count (3)

    at the lase line the value of Report Count is 0x05 ,it that mean it descriptions five button or just as comment described count val is only 3?

    and in 0x05, 0x0C, // Usage Page (消费类 Consumer) 0x0A, 0x38, 0x02, // Usage (AC Pan) 0x95, 0x01, // Report Count (1) 0x81, 0x06, // Input (Data,Value,Relative,Bit Field)

    there is no Report Size, should I add 0x75, 0x08,?

    or just delete it because Consumer button is described at Report ID 3 :

        // Report ID 3: Advanced buttons  
        0x05, 0x0C,                     // Usage Page (Consumer)
        0x09, 0x01,                     // Usage (Consumer Control) 
        0xA1, 0x01,                     // Collection (Application)
        0x85, 0x03,                     //     Report Id (3)
    
Related