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

ble central and peripheral + hid ble problem

Hello Nordic Team,

Currently i'm trying to join my custom HID (a joystick) with the ble_app_hrs_rscs_relay example  (SDK 16) for a personal project which consist in: a nrf52832 working as slave and another working as “my custom relay”. In the slave device I’m using the ble_app_hrs example code without any modifications. While my second nrf52832 is in central role, the relay scan’s (filter by name and UUID are set) and can connect to slave device. Instead, in peripheral mode that device is working as HID Joystick and can connect to a PC and smartphones… but the data it’s not sent. In debug mode I can see the ble_hids_inp_rep_send return a failure message.  I think the problem is relate to enable notifications, but I’m not sure…  

This are the main changes in the ble_app_hrs_rscs_relay.

/**@brief Function for initializing the advertising functionality.
 */
static void advertising_init(void)
{
    ret_code_t             err_code;
    ble_advertising_init_t init;

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

    init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;
    init.advdata.include_appearance      = true;
    init.advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    init.advdata.uuids_complete.p_uuids  = m_adv_uuids;

    int8_t tx_power                   = -20;// Set Power Level
    init.advdata.p_tx_power_level = &tx_power;

    init.config.ble_adv_whitelist_enabled          = true;
    init.config.ble_adv_directed_high_duty_enabled = true;
    init.config.ble_adv_directed_enabled           = false;
    init.config.ble_adv_directed_interval          = 0;
    init.config.ble_adv_directed_timeout           = 0;
    init.config.ble_adv_fast_enabled               = true;
    init.config.ble_adv_fast_interval              = APP_ADV_FAST_INTERVAL;
    init.config.ble_adv_fast_timeout               = APP_ADV_FAST_DURATION;
    init.config.ble_adv_slow_enabled               = true;
    init.config.ble_adv_slow_interval              = APP_ADV_SLOW_INTERVAL;
    init.config.ble_adv_slow_timeout               = APP_ADV_SLOW_DURATION;

    init.evt_handler = on_adv_evt;
    init.error_handler = ble_advertising_error_handler;

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);
    if (err_code== NRF_SUCCESS){
    NRF_LOG_INFO("ADV INIT SUCCESFULL")
    }

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}



/**@brief Function for handling BLE events.
 *
 * @param[in]   p_ble_evt   Bluetooth stack event.
 * @param[in]   p_context   Unused.
 */
static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    uint16_t conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
    uint16_t role        = ble_conn_state_role(conn_handle);

    // Based on the role this device plays in the connection, dispatch to the right handler.
    if (role == BLE_GAP_ROLE_PERIPH || ble_evt_is_advertising_timeout(p_ble_evt))
    {
       //ble_hids_on_ble_evt(p_ble_evt, &m_hids);
        on_ble_peripheral_evt(p_ble_evt);
    }
    else if ((role == BLE_GAP_ROLE_CENTRAL) || (p_ble_evt->header.evt_id == BLE_GAP_EVT_ADV_REPORT))
    {
        on_ble_central_evt(p_ble_evt);
    }
}


static ble_gap_scan_params_t m_scan_param =                 /**< Scan parameters requested for scanning and connection. */
{
    .active        = 0x01,
    .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,
    .window        = NRF_BLE_SCAN_SCAN_WINDOW,
    .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
    .timeout       = NRF_BLE_SCAN_SCAN_DURATION,
    .scan_phys     = BLE_GAP_PHY_1MBPS,
    .extended      = true,
    
};

static void scan_init(void)
{
    ret_code_t          err_code;
    nrf_ble_scan_init_t init_scan;

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

    init_scan.p_scan_param = &m_scan_param;

    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);
    APP_ERROR_CHECK(err_code);

    if (err_code== NRF_SUCCESS){
    NRF_LOG_INFO("Scan init success")
    }

    if (strlen(m_target_periph_name) != 0)
    {
        err_code = nrf_ble_scan_filter_set(&m_scan, 
                                           SCAN_NAME_FILTER, 
                                           m_target_periph_name);
        APP_ERROR_CHECK(err_code);

           if (err_code== NRF_SUCCESS){
            NRF_LOG_INFO("filter set by name set success")
           }
    }

    err_code = nrf_ble_scan_filter_set(&m_scan, 
                                       SCAN_UUID_FILTER, 
                                       &m_adv_slave_uuids[HART_RATE_SERVICE_UUID_IDX]);
    APP_ERROR_CHECK(err_code);

   if (err_code== NRF_SUCCESS){
            NRF_LOG_INFO("filter set by uuid success")
      }

    err_code = nrf_ble_scan_filters_enable(&m_scan, 
                                           NRF_BLE_SCAN_NAME_FILTER| NRF_BLE_SCAN_UUID_FILTER, 
                                           false);
    APP_ERROR_CHECK(err_code);

    if (err_code== NRF_SUCCESS){
    NRF_LOG_INFO("scan filter enable success")
    }

}

/**@brief Function for initializing the GAP.
 *
 * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
 *          device, including the device name, appearance, and the preferred connection parameters.
 */
static void gap_params_init(void)
{
    ret_code_t              err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *)DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HID_JOYSTICK);
    APP_ERROR_CHECK(err_code);

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

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}


/**@brief Function for initializing the Connection Parameters module.
 */
static void conn_params_init(void)
{
    ret_code_t             err_code;
    ble_conn_params_init_t cp_init;

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

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle    = BLE_CONN_HANDLE_INVALID; // Start upon connection.
    cp_init.disconnect_on_fail             = true;
    cp_init.evt_handler                    = NULL;  // Ignore events.
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing HID Service.
 */
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 inp_rep_array[INPUT_REPORT_COUNT];
    static uint8_t rep_map_data[] =
    {       
    0x05, 0x01,  /* USAGE_PAGE (Generic Desktop)       */
    0x09, 0x04,  /* USAGE (Joystick)                   */
    0xa1, 0x01,  /* COLLECTION (Application)           */
    0xa1, 0x03,  /*   COLLECTION (Report)              */
    0x85, 0x01,  /*     REPORT_ID (1)                  */
    0x05, 0x09,  /*     USAGE_PAGE (Button)            */
    0x19, 0x01,  /*     USAGE_MINIMUM (Button 1)       */
    0x29, 0x10,  /*     USAGE_MAXIMUM (Button 16)      */
    0x15, 0x00,  /*     LOGICAL_MINIMUM (0)            */
    0x25, 0x01,  /*     LOGICAL_MAXIMUM (1)            */
    0x95, 0x10,  /*     REPORT_COUNT (16)              */
    0x75, 0x01,  /*     REPORT_SIZE (1)                */
    0x81, 0x02,  /*     INPUT (Data,Var,Abs)           */
    0xa1, 0x00,  /*     COLLECTION (Physical)          */
    0x05, 0x01,  /*       USAGE_PAGE (Generic Desktop) */
    0x09, 0x30,  /*       USAGE (X)                    */
    0x09, 0x31,  /*       USAGE (Y)                    */
    0x15, 0x81,  /*       LOGICAL_MINIMUM (-127)       */
    0x25, 0x7f,  /*       LOGICAL_MAXIMUM (127)        */
    0x75, 0x08,  /*       REPORT_SIZE (8)              */
    0x95, 0x02,  /*       REPORT_COUNT (2)             */
    0x81, 0x02,  /*       INPUT (Data,Var,Abs)         */
    0xc0,        /*     END_COLLECTION                 */
    0xc0,        /*   END_COLLECTION                   */
    0xc0         /* END_COLLECTION                     */
    };

    memset(inp_rep_array, 0, sizeof(inp_rep_array));
    // Initialize HID Service.

    p_input_report                      = &inp_rep_array[INPUT_REP_INDEX];
    p_input_report->max_len             = INPUT_REP_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_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                  = INPUT_REPORT_COUNT;
    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_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_mouse_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
    hids_init_obj.boot_mouse_inp_rep_sec.wr      = SEC_JUST_WORKS;
    hids_init_obj.boot_mouse_inp_rep_sec.rd      = 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);
    
    if(err_code==NRF_SUCCESS){
    
    NRF_LOG_INFO("HID init");
    }
}


static void joystickMovementSendData( uint8_t buttonsOneToEight, uint8_t buttonsNineToSixteen, uint8_t inputX, uint8_t inputY)
{
    ret_code_t err_code;   
    uint8_t buffer[INPUT_REP_LEN];

    if (m_in_boot_mode)
      return; 

    APP_ERROR_CHECK_BOOL(INPUT_REP_LEN == 4);

    buffer[0] = buttonsOneToEight;
    buffer[1] = buttonsNineToSixteen;
    buffer[2] = inputX;
    buffer[3] = inputY;

    err_code = ble_hids_inp_rep_send(&m_hids,
                                         INPUT_REP_INDEX,
                                         INPUT_REP_LEN,                             
                                         buffer,
                                         m_conn_handle);
  
    if ((err_code != NRF_SUCCESS) &&
        (err_code != NRF_ERROR_INVALID_STATE) &&
        (err_code != NRF_ERROR_RESOURCES) &&
        (err_code != NRF_ERROR_BUSY) &&
        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
       )
    {
        APP_ERROR_HANDLER(err_code);
    }

    if (err_code== NRF_SUCCESS){
     NRF_LOG_INFO("Send!");
    }else {
    NRF_LOG_INFO("NOT SENT...FAILED");

    }
}

 

Your help will be greatly appreciable.

Thanks in advance for your support.

Regards,

Parents
  • Hello,

    The client needs to enable notifications first, so that may a possible explanation as to why the data is not being sent.  Have you checked what the returned error code from ble_hids_inp_rep_send()->sd_ble_gatts_hvx() is?

    Regards,

    Vidar

  • Hello Vidar,

    TodaThe ble_hids_inp_rep_send is returning ERROR 8 [NRF_ERROR_INVALID_STATE], maybe i configuring something wrong. In debug mode, i can see the notification are enable before calling ble_hids_inp_rep_send  (SS attached)… if  notificaction are truly enabled, what else may cause this error?

    Also:

    • Im using the battery service in this project, and his notification are working fine.
    • In other project im implement the same HID profile and i don’t have any problema with ble_hids_inp_rep_send and the nrf52832 work as joystick.
    • Maybe the “Relay example” aren´t compatible with BLE HID in peripheral mode?

           

    Your help will be greatly appreciable.

    Thanks in advance for your support.

    Regards,

    ***I apologize for my delayed reply, i was busy with pcb design in this last week.

Reply
  • Hello Vidar,

    TodaThe ble_hids_inp_rep_send is returning ERROR 8 [NRF_ERROR_INVALID_STATE], maybe i configuring something wrong. In debug mode, i can see the notification are enable before calling ble_hids_inp_rep_send  (SS attached)… if  notificaction are truly enabled, what else may cause this error?

    Also:

    • Im using the battery service in this project, and his notification are working fine.
    • In other project im implement the same HID profile and i don’t have any problema with ble_hids_inp_rep_send and the nrf52832 work as joystick.
    • Maybe the “Relay example” aren´t compatible with BLE HID in peripheral mode?

           

    Your help will be greatly appreciable.

    Thanks in advance for your support.

    Regards,

    ***I apologize for my delayed reply, i was busy with pcb design in this last week.

Children
Related