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

BLE HID parameter error

I'm sorry to ask a question that I'm sure has been answered before, but I can't find another post similar enough to be of help.  I have an HID application that bounces back and forth between USB and BLE, two endpoints, one a joystick, one a keyboard.  This works very nicely when I have only one endpoint (joystick), but now throws an invalid parameter error with two endpoints.  The issue is that it is very difficult to debug which parameter it doesn't like since I only get the error on BLE connection so it is coming as a callback (i.e. I can't see it happen realtime).  I should also mention that it works perfectly via USB - the error is only with BLE.

I changed my sdk_config to increase maximum NRF_SDH_BLE_TOTAL_LINK_COUNT to 2 (not sure if this was necessary), and here is some of the code that I added (all of this just adds the keyboard stuff, the joystick stuff was all present in the 1 endpoint scenario that works):

...

BLE_HIDS_DEF(m_hids_joystick,                                                /**< Structure used to identify the HID service. */
             NRF_SDH_BLE_TOTAL_LINK_COUNT,
             INPUT_REPORT_JOYSTICK_MAX_LEN);
BLE_HIDS_DEF(m_hids_keyboard,                                                /**< Structure used to identify the HID service. */
             NRF_SDH_BLE_TOTAL_LINK_COUNT,
             INPUT_REPORT_KEYS_MAX_LEN);

...

static void hids_init(void)
{
    ret_code_t                    err_code;
    ble_hids_init_t               hids_init_obj;
    ble_hids_inp_rep_init_t     * p_input_report;
    uint8_t                       hid_info_flags;

    static ble_hids_inp_rep_init_t     input_report_array[1];
    static uint8_t                     report_map_data[] = HID_JOYSTICK_REPORT_DESCRIPTOR;
    static uint8_t                     report_map_data_keyboard[] = APP_USBD_HID_KBD_REPORT_DSC();

    memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));

    // Initialize HID Service
    p_input_report                      = &input_report_array[INPUT_REPORT_KEYS_INDEX];
    p_input_report->max_len             = INPUT_REPORT_JOYSTICK_MAX_LEN;
    p_input_report->rep_ref.report_id   = INPUT_REP_REF_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;

    hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;

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

    hids_init_obj.evt_handler                    = on_hids_joy_evt;
    hids_init_obj.error_handler                  = service_error_handler_joy;
    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                = input_report_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(report_map_data);
    hids_init_obj.rep_map.p_data                 = report_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_flags;
    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_joystick, &hids_init_obj);
    APP_ERROR_CHECK(err_code);

    /* Now the keyboard */
    memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));

    // Initialize HID Service
    p_input_report                      = &input_report_array[INPUT_REPORT_KEYS_INDEX];
    p_input_report->max_len             = INPUT_REPORT_KEYS_MAX_LEN;
    p_input_report->rep_ref.report_id   = INPUT_REP_REF_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;

    hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;

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

    hids_init_obj.evt_handler                    = on_hids_key_evt;
    hids_init_obj.error_handler                  = service_error_handler_key;
    hids_init_obj.is_kb                          = true;
    hids_init_obj.is_mouse                       = false;
    hids_init_obj.inp_rep_count                  = 1;
    hids_init_obj.p_inp_rep_array                = input_report_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(report_map_data_keyboard);
    hids_init_obj.rep_map.p_data                 = report_map_data_keyboard;
    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_flags;
    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.boot_kb_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
    hids_init_obj.boot_kb_inp_rep_sec.rd      = SEC_JUST_WORKS;

    hids_init_obj.boot_kb_outp_rep_sec.rd = SEC_JUST_WORKS;
    hids_init_obj.boot_kb_outp_rep_sec.wr = 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_keyboard, &hids_init_obj);
    APP_ERROR_CHECK(err_code);
}

Now, like I said, there is no change in the joystick parts of this code between the two scenarios - so could it be an issue in reusing the initialization objects?  Are they used elsewhere on connecting?  If so, I guess they could still be filled with the keyboard parameters from the init process and that could throw the invalid param error on the joystick?  Also, is there anything else I need to change (in, say, the sdk_config) in order to add an endpoint for BLE HID devices?

Thanks for your help!

Parents
  • Don't ask why I didn't try just making new initialization objects (the answer is, I thought I was swamped when I wrote this) but I just got to it and now it looks like everything works.  This leaves me happy but with a question: where are these objects being used?  I really figured that once the ble_hids_init_t object was set up and ble_hids_init was run, that the object could safely be destroyed, but it appears that the system still uses this for something?  I have been searching the code to find why that data needs to remain untouched, but I'm not seeing it.

  • I managed to answer my own question.  After paying more attention, I realize that the real problem is that I wasn't creating a separate ble_hids_inp_rep_init_t array for each hid.  Once you walk through the code (ble_hids.c) you see that you need a unique such array for each HID.

Reply Children
Related