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

Invalid HID report

Hello all!

We have custom HID with multitouch BLE device. We took HID descriptor from USB where this works pretty good, ported it to BLE and it seems not working as expected.

Can someone please point us what we doing wrong?

/**@brief Function for initializing HID Service.
 */
static void hids_init(void)
{
    ret_code_t                err_code;
    ble_hids_init_t           hids_init_obj;

    static ble_hids_inp_rep_init_t inp_rep_array;
    static uint8_t rep_map_data[] =
    {
          0x05, 0x0d,                         // USAGE_PAGE (Digitizers)
          0x09, 0x04,                         // USAGE (Touch Screen)
          0xa1, 0x01,                         // COLLECTION (Application)
          0x85, 0x01,                         //   REPORT_ID (Touch)
          0x09, 0x22,                         //   USAGE (Finger)
          0xa1, 0x02,                         //     COLLECTION (Logical)
          0x05, 0x0d,                         //       USAGE_PAGE (Digitizers)
          0x09, 0x42,                         //         USAGE (Tip Switch)
          0x09, 0x32,                         //         USAGE (In Range)
          0x15, 0x00,                         //         LOGICAL_MINIMUM (0)
          0x25, 0x01,                         //         LOGICAL_MAXIMUM (1)
          0x75, 0x01,                         //         REPORT_SIZE (1)
          0x95, 0x02,                         //         REPORT_COUNT (2)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x95, 0x06,                         //         REPORT_COUNT (6)
          0x81, 0x03,                         //         INPUT (Cnst,Ary,Abs)
          0x75, 0x10,                         //         REPORT_SIZE (16)
          0x09, 0x51,                         //         USAGE (Contact Identifier)
          0x95, 0x01,                         //         REPORT_COUNT (1)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x05, 0x01,                         //         USAGE_PAGE (Generic Desktop)
          0x26, 0xff, 0x0f,                   //         LOGICAL_MAXIMUM (4095)
          0x55, 0x00,                         //         UNIT_EXPONENT (0)
          0x65, 0x00,                         //         UNIT (None)
          0x09, 0x30,                         //         USAGE (X)
          0x35, 0x00,                         //         PHYSICAL_MINIMUM (0)
          0x46, 0x00, 0x05,                   //         PHYSICAL_MAXIMUM (1280)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x09, 0x31,                         //         USAGE (Y)
          0x46, 0xd0, 0x02,                   //         PHYSICAL_MAXIMUM (720)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0xc0,                               //     END_COLLECTION
          0xa1, 0x02,                         //     COLLECTION (Logical)
          0x05, 0x0d,                         //       USAGE_PAGE (Digitizers)
          0x09, 0x42,                         //         USAGE (Tip Switch)
          0x09, 0x32,                         //         USAGE (In Range)
          0x15, 0x00,                         //         LOGICAL_MINIMUM (0)
          0x25, 0x01,                         //         LOGICAL_MAXIMUM (1)
          0x75, 0x01,                         //         REPORT_SIZE (1)
          0x95, 0x02,                         //         REPORT_COUNT (2)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x95, 0x06,                         //         REPORT_COUNT (6)
          0x81, 0x03,                         //         INPUT (Cnst,Ary,Abs)
          0x75, 0x10,                         //         REPORT_SIZE (16)
          0x09, 0x51,                         //         USAGE (Contact Identifier)
          0x95, 0x01,                         //         REPORT_COUNT (1)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x05, 0x01,                         //         USAGE_PAGE (Generic Desktop)
          0x26, 0xff, 0x0f,                   //         LOGICAL_MAXIMUM (4095)
          0x55, 0x00,                         //         UNIT_EXPONENT (0)
          0x65, 0x00,                         //         UNIT (None)
          0x09, 0x30,                         //         USAGE (X)
          0x35, 0x00,                         //         PHYSICAL_MINIMUM (0)
          0x46, 0x00, 0x05,                   //         PHYSICAL_MAXIMUM (1280)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0x09, 0x31,                         //         USAGE (Y)
          0x46, 0xd0, 0x02,                   //         PHYSICAL_MAXIMUM (720)
          0x81, 0x02,                         //         INPUT (Data,Var,Abs)
          0xc0,                               //     END_COLLECTION
          0x05, 0x0d,                         //    USAGE_PAGE (Digitizers)
          0x09, 0x54,                         //    USAGE (Contact Count)
          0x95, 0x01,                         //    REPORT_COUNT (1)
          0x75, 0x08,                         //    REPORT_SIZE (8)
          0x15, 0x00,                         //    LOGICAL_MINIMUM (0)
          0x25, 0x0a,                         //    LOGICAL_MAXIMUM (10)
          0x81, 0x02,                         //    INPUT (Data,Var,Abs)
          0x09, 0x55,                         //    USAGE(Contact Count Maximum)
          0xb1, 0x02,                         //    FEATURE (Data,Var,Abs)
          0xc0,                               // END_COLLECTION

    };

    memset(&inp_rep_array, 0, sizeof(inp_rep_array));

    // Initialize HID Service.
    {
      ble_hids_inp_rep_init_t * p_input_report;
      p_input_report = &inp_rep_array;
      p_input_report->max_len = INPUT_REP_TOUCH_LEN;
      p_input_report->rep_ref.report_id = INPUT_REP_REF_TOUCH_ID;
      p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;

      p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
      p_input_report->sec.wr = SEC_JUST_WORKS;
      p_input_report->sec.rd = SEC_JUST_WORKS;
    }

    memset(&hids_init_obj, 0, sizeof(hids_init_obj));

    hids_init_obj.evt_handler                    = on_hids_evt;
    hids_init_obj.error_handler                  = service_error_handler;
    hids_init_obj.is_kb                          = false;
    hids_init_obj.is_mouse                       = false;

    hids_init_obj.inp_rep_count                  = 1;
    hids_init_obj.p_inp_rep_array                = &inp_rep_array;

    hids_init_obj.outp_rep_count                 = 0;
    hids_init_obj.p_outp_rep_array               = NULL;

    hids_init_obj.feature_rep_count              = 0;
    hids_init_obj.p_feature_rep_array            = NULL;

    hids_init_obj.rep_map.data_len               = sizeof(rep_map_data);
    hids_init_obj.rep_map.p_data                 = rep_map_data;

    hids_init_obj.hid_information.bcd_hid        = BASE_USB_HID_SPEC_VERSION;
    hids_init_obj.hid_information.b_country_code = 0;
    hids_init_obj.hid_information.flags          = (HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK);

    hids_init_obj.included_services_count        = 0;
    hids_init_obj.p_included_services_array      = NULL;

    hids_init_obj.rep_map.rd_sec         = SEC_JUST_WORKS;
    hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;

    hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
    hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
    hids_init_obj.ctrl_point_wr_sec    = SEC_JUST_WORKS;

    err_code = ble_hids_init(&m_hids, &hids_init_obj);
    APP_ERROR_CHECK(err_code);
}

//--------------------------------------------------------------------------------
// Digitizer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct __packed
  {
    uint8_t DIG_TouchScreenFingerTipSwitch :1;        // Usage 0x000D0042: Tip Switch, Value = 0 to 1
    uint8_t DIG_TouchScreenFingerInRange :1;          // Usage 0x000D0032: In Range, Value = 0 to 1
    uint8_t :6;                                       // Pad
    uint16_t DIG_TouchScreenFingerContactIdentifier;  // Usage 0x000D0051: Contact Identifier, Value = 0 to 1
    uint16_t GD_TouchScreenFingerX;                   // Usage 0x00010030: X, Value = 0 to 4095, Physical = Value x 256 / 819
    uint16_t GD_TouchScreenFingerY;                   // Usage 0x00010031: Y, Value = 0 to 4095, Physical = Value x 16 / 91
                                                      // Collection: CA:TouchScreen CL:
                                          
    uint8_t DIG_TouchScreenTipSwitch :1;              // Usage 0x000D0042: Tip Switch, Value = 0 to 1, Physical = Value x 720
    uint8_t DIG_TouchScreenInRange :1;                // Usage 0x000D0032: In Range, Value = 0 to 1, Physical = Value x 720
    uint8_t :6;                                       // Pad
    uint16_t DIG_TouchScreenContactIdentifier;        // Usage 0x000D0051: Contact Identifier, Value = 0 to 1, Physical = Value x 720
    uint16_t GD_TouchScreenX;                         // Usage 0x00010030: X, Value = 0 to 4095, Physical = Value x 256 / 819
    uint16_t GD_TouchScreenY;                         // Usage 0x00010031: Y, Value = 0 to 4095, Physical = Value x 16 / 91
                                                      // Collection: CA:TouchScreen
                                                                   
    uint8_t DIG_TouchScreenContactCount;              // Usage 0x000D0054: Contact Count, Value = 0 to 10, Physical = Value x 72

  } CT_HID_Input_t;


   // Somewhere in code.
   // Create HID report.
   CT_HID_Input_t report = { 0 };
   
   // Populate...
   
   /* Send report. */
   ret_code_t err_code = ble_hids_inp_rep_send(&m_hids, INPUT_REP_TOUCH_INDEX, sizeof(report), (uint8_t *) &report, m_conn_handle);


Parents Reply Children
  • It would be interesting to see a bluetooth sniffer trace of the communication to see if there's anything that can be spotted there.

    You can use the nRF sniffer (in combination with wireshark) to see the on-air communication. Note that you have to delete the bonding information prior to starting the sniffer trace, so that wireshark is able to decrypt the communication.

    Could you provide a sniffer trace of a working and non-working scenario?

     

    Kind regards,

    Håkon

  • Hakon, thank for reply. I'm not sure that it helps us. I would like to know:

    1. Does HID over BLE supports Digitizer class, I see for most examples only mouse, keyboard and joystick, maybe each class use own characteristic to get reports?
    2. As I see now, in SDK we have weak definition of report ID in compare to USB HID, report ID not transmitted over the BLE characteristic, only report content, is that correct?
    3. Is features report required and should I send this before sending digitizer report?
  • Hi,

     

    BrainIOStream said:
    Does HID over BLE supports Digitizer class, I see for most examples only mouse, keyboard and joystick, maybe each class use own characteristic to get reports?

     Yes, that shall be supported. There's several other cases where people are using digitizers, for instance in this thread (with example):

    https://devzone.nordicsemi.com/f/nordic-q-a/38587/is-multi-touch-hid-possible-with-nrf51822-chip/155050#155050

    BrainIOStream said:
    As I see now, in SDK we have weak definition of report ID in compare to USB HID, report ID not transmitted over the BLE characteristic, only report content, is that correct?

    the "report index" is related to the input report array you initialized in hids_init(). Based on the index, it will send the data on the correct value handle for the BLE link.

    Bluetooth is a pure transport layer when looking at the on-air data. BLE doesn't really care about the USB ReportID (or USB at all for that matter), it just cares about its own GATT database, which again is parsed and mapped over to USB data when processed by the central stack.

    BrainIOStream said:
    Is features report required and should I send this before sending digitizer report?

    I haven't heard that this is a requirement. Could you look at the example linked further up and see if this one works better?

     

    Kind regards,

    Håkon

Related