Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

fatal error in the BLE observers

Hello, new-to-this platform dev here!

I am implementing BLE bonding on my nRF52840 DK, which uses the S140 Softdevice. The DK is a peripheral and I'm using version 17.1 of the SDK. I adapted most of the peer_manager/whitelist code from the ble_peripheral hci keyboard sample. However, I'd like to implement some special logic to allow only the first device to be bonded with my nRF52840 to talk to it, and to reject pairing/bonding attempts from other devices. 

I implemented this logic in the ble_evt_handler, where I intercept LE_GAP_EVT_CONNECTED events and apply my go/no go logic. If the connection request falls into the "no go" category, I call sd_ble_gap_disconnect function. This returns an err_code of 0x0. But the next thing that happens is nrf_sdh_ble_evts_poll tries to forward  the event to BLE observers (line 300 of nrf_sdh_ble.c), and that's where I hit the fatal error. In the debugger, it looks like the sdh_ble_observer items point to valid addresses, but that's about as far as I can get on this.

Can anyone see where I am going wrong? Or know a better way to accomplish my goal?

Code from my BLE event handler:

    case BLE_GAP_EVT_CONNECTED:
            NRF_LOG_INFO("ble_evt_handler: connected event ");

            pm_peer_id_t peer_id;
            err_code = pm_peer_id_get(p_ble_evt->evt.gattc_evt.conn_handle,&peer_id);
            APP_ERROR_CHECK(err_code);
            NRF_LOG_INFO("ble_evt_handler: conn handle 0x%x peer lookup returns %d", p_ble_evt->evt.gattc_evt.conn_handle,peer_id);
            NRF_LOG_INFO("current peer_cnt %d", pm_peer_count());

            // if this connection isn't already a peer and we already have a peer, reject it
            if ( peer_id == PM_PEER_ID_INVALID && pm_peer_count() > 0 )
            {
              NRF_LOG_INFO("ble_evt_handler: going to reject this");
              // according to message sequence charts at https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s140.api.v7.3.0/group___b_l_e___g_a_p___m_s_c.html,
               // I should send an sd_ble_gap_disconnect message here.
              // according to function docs at https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.s140.api.v6.0.0%2Fgroup___b_l_e___g_a_p___f_u_n_c_t_i_o_n_s.html,
              // BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and BLE_HCI_CONN_INTERVAL_UNACCEPTABLE are the only valid reason codes to use.
              // both return 0x0 in the err_code, but lead to a fatal error on line 300 of nrf_sdh_ble.c.
              //err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
              err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
              NRF_LOG_INFO("ble_evt_handler: disc error code %d",err_code)
              APP_ERROR_CHECK(err_code);
            }
            else
            {
              NRF_LOG_INFO("ble_evt_handler: going to set up connection");
              err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
              APP_ERROR_CHECK(err_code);
              m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
              err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
              APP_ERROR_CHECK(err_code);
              err_code = pm_conn_secure(p_ble_evt->evt.gap_evt.conn_handle, false);
              if (err_code != NRF_ERROR_BUSY)
              {
                APP_ERROR_CHECK(err_code);
              }
            }
            break;

    case BLE_GAP_EVT_DISCONNECTED:
            NRF_LOG_INFO("Disconnected, reason %d.", p_ble_evt->evt.gap_evt.params.disconnected.reason);
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            break;

  • I seem to have gotten rid of my APP_ERROR. But I am still having problems detecting when I've already entered a central device to the whitelist at the BLE connected event message level.

    I take the address in p_ble_evt->evt.gap_evt.params.connected.peer_addr and check it against the contents of the whitelist_addrs returned by pm_whitelist_get(). My central device sends the same peer_addr every time, but that's not what I see in the whitelist.

    I set the whitelist with the results of a call to pm_peer_id_list()  in the PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event. The peer_id is a unsigned 16-bit number.

    How can I take a ble_gap_add_t and map it to whatever is in the whitelist?

  • I am implementing BLE bonding on my nRF52840 DK, which uses the S140 Softdevice. The DK is a peripheral and I'm using version 17.1 of the SDK. I adapted most of the peer_manager/whitelist code from the ble_peripheral hci keyboard sample. However, I'd like to implement some special logic to allow only the first device to be bonded with my nRF52840 to talk to it, and to reject pairing/bonding attempts from other devices. 

    So I made this waaaaay more complicated than it needed to be. I would up implementing this feature by:

    • In my advertising_init, setting init.config.ble_adv_whitelist_enabled to true
    • In my peer_manager event handler, I handled the PM_EVT_PEER_DATA_UPDATE_SUCCEEDED event to add the new peer to my whitelist.
    • In my advertising event handler, handled the BLE_ADV_EVT_WHITELIST_REQUEST event to send a ble_advertising_whitelist_reply().

    This works because the advertising module disregards the whitelist when the whitelist is empty. This allows the first central device to make the connection, pair/bond, and get added to the peer list. This trips PM_EVT_PEER_DATA_UPDATE_SUCCEEDED and gets the new peer added to the whitelist. Now that the whitelist is nonempty, when advertising resumes it will get used, preventing other central devices from connecting. Using my reset button will clear my bond and whitelist data and put advertising back into its initial state.

    I found this discussion useful: devzone.nordicsemi.com/.../whitelist-set-but-not-automatically-restarted

  • Hello null handle,

    I am glad to hear that you were able to resolve the issue yourself so quickly. Thank you for sharing your solution here with us along with the discussion you found useful, so that other forum goers may see it in the future! :) 

    For the record, it is very helpful to make sure that you have DEBUG defined in your preprocessor defines, like shown in the included image, in order to have the logger output a detailed error message whenever a non-NRF_SUCCESS error is passed to an APP_ERROR_CHECK. This makes the debugging of failed sd_ and nrfx_ function calls much easier.


    Please do not hesitate to open another ticket if you should encounter any issues or questions in the future.

    Good luck with your development!

    Best regards,
    Karl

Related