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

Questions about implementing BLE bonding with NUS

Hi

This is Joe.
I would like to ask questions about implementing BLE bonding.

SDK:
16.0.0 (nRF5SDK160098a08e2)

Projects:
The base project I start with is NUS example (both Peripheral and Central)
example/ble_peripheral/ble_app_uart
example/ble_central/ble_app_uart_c

What I have done / tried:
1. First of all I just build both projects and run on 2 devices. Make sure the NUS example is working correctly.

2. Then, by referencing the code from another example (ble_app_hrs and ble_app_hrs_c), I added peer manager and bonding related code, such as pm_evt_handler, peer_manager_init, delete_bonds, etc to both projects (ble_app_uart & ble_app_uart_c).

3. And also according to this forum post (https://devzone.nordicsemi.com/f/nordic-q-a/43400/peer_manager_sm-could-not-perform-security-procedure-smd_params_reply-or-smd_link_secure-returned-nrf_error_invalid_addr), cc310 is also added to the project.

The project structure looks like this:


What is the current status:
1. The Peripheral (ble_app_uart) is able to connect to the iOS app "nRF Connect".
When connected to iOS app "nRF Connect", I can see the device advertising, connect to the device, notify from the device, disconnect from the device. Everything working correctly.

2. The Peripheral (ble_app_uart) is not able to connect to Central (ble_app_uart_c).
When try to connect to the Central device (ble_app_uart_c), it shows connected (green rectangle in below image) at first but then disconnected (red rectangle in below image) after 1 second.
(P.S. To minimize unknown problem, I execute delete_bonds everytime when the Peripheral or Central is power on)

This is the RTT output of Central device.


The error message shows that connection failed due to connection security failed (error 4352).
In this forum post (https://devzone.nordicsemi.com/f/nordic-q-a/49894/peermanager-error-error-4352), 4352 is PM_CONN_SEC_ERROR_DISCONNECT.

What my question is:
1. I cannot figure out what caused the problem and now I have no idea how to fix this. Could anyone give me some help or some hints to guide me to the correct way?
2. Actually what I would like to archive is that I want the previously paired devices remember each other. Just like our earphone always connect to our smartphone when both power on. Therefore even if there are multiple peripherals and centrals are power on, the devices will not paired to a device that is not paired before.
As far as my understanding, the original example of NUS, Central will search for any Peripheral device with NUS UUID. So I cannot guarantee which device connect to which if I have multiple Peripheral advertising and Central scanning at the same time. So I googled and found bonding seems to be the solution. Is my understanding correct? Please correct me if I am wrong.

Thank you very much.

Best Regards
Joe

  • Hello Edvin,

    Just like some additional observation.

    Instead of deleting bond by pressing button to call delete_bond from the problem, I tried Target > Erase All to remove the whole device memory by J-Link.

    (The observed result is same as previous.)
    Scenario 1:
    If I perform remove all to the Peripheral, the Central can no longer connect due to PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING.
    Scenario 2:
    On the otherhand, if I perform remove all to the Central, the Peripheral still can connect again.

    According to the observation, I understand the situation as follow:
    Scenario 1 proved that the Central is actually remembering the Peripheral, because when the Peripheral device is cleared the key is also lost, therefore, the "old" Central rejects the connection of the "new" Peripheral?
    Scenario 2 proved that the Peripheral is not remembering the Central, because the Peripheral can connect to a "new" Central, even it has been bonded with the "old" Central.

    So I guess the problem is due to some security or bonding setting?
    I think should look for the problem from the code on Peripheral side rather than on Central side.

    Best Regards,
    Joe

  • I don't think I follow what you are doing anymore. If one of the devices still has bonding information and the other one doesn't, I believe you should get an event to which you should call a reply with .allow_repairing = true or false. I believe this event is the PM_EVT_CONN_SEC_CONFIG_REQ event.

    If you are not sure how whether your bonds are deleted, I suggest you work with manually erasing the chip for now, until you figure out how to handle the different setups (one device having the bonding information, while the other doesn't).

    Best regards,

    Edvin

  • Hi Edvin,

    Thank you for your reply.
    May be I have do something wrong when integrating my project code from the sample code.
    Let me try to figure it out why PM_EVT_CONN_SEC_CONFIG_REQ does not appear first.
    And I will use manually erasing as you suggested for testing.

    Best Regards,

    Joe

  • Hi Edvin,

    I have solved the problem finally. It is because I missed the whitelist in the Peripheral side.
    After integrating the whitelist by referencing example ble_app_hids_keyboard, the Problem #2 is fixed.
    After some simple tests, bonded device will only connect to each other correctly.

    And I found a new problem about advertising on Peripheral.

    Background:
    There is a button on Peripheral, the button will erase the the saved bonding information on Peripheral. And the same for Central.
    After erasing, I want the device to restart scan for Central and advertising for Peripheral.

    Scenario:
    (Code sample are below)
    1. Peripheral and Central are bonded and connected.
    2. On Peripheral, press on the button to call advertising_start(true), which will call delete_bond().
    3. pm_peers_delete() will trigger event PM_EVT_PEERS_DELETE_SUCCEEDED in pm_evt_handler.
    4. PM_EVT_PEERS_DELETE_SUCCEEDED event will call advertising_start(false)
    5. When ble_advertising_start is called, the error NRF_ERROR_CONN_COUNT is returned.

    static void advertising_start(bool erase_bonds)
    {
        NRF_LOG_INFO("advertising_start(%d)", erase_bonds);
        if (erase_bonds == true)
        {
            delete_bonds();
            // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
        }
        else
        {
            whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
    
            ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
            APP_ERROR_CHECK(err_code);	// Line 1180
    
            m_is_advertising = true;
            NRF_LOG_INFO("Advertising start");
        }
    }

    static void delete_bonds(void)
    {
        ret_code_t err_code;
    
        NRF_LOG_INFO("Erase bonds");
    
        err_code = pm_peers_delete();
        APP_ERROR_CHECK(err_code);
    }

    static void pm_evt_handler(pm_evt_t const * p_evt)
    {
        pm_handler_on_pm_evt(p_evt);
        pm_handler_flash_clean(p_evt);
    
        switch (p_evt->evt_id)
        {
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
                NRF_LOG_INFO("PM_EVT_PEERS_DELETE_SUCCEEDED");
                advertising_start(false);
                break;
    		//...
    }

    I found that the error is from sd_ble_gap_adv_start(...), line 653 of ble_advertising.c

    if (p_advertising->adv_mode_current != BLE_ADV_MODE_IDLE)
    {
    
    	ret = sd_ble_gap_adv_set_configure(&p_advertising->adv_handle, p_advertising->p_adv_data, &p_advertising->adv_params);
    	if (ret != NRF_SUCCESS)
    	{
    		return ret;
    	}
    	ret = sd_ble_gap_adv_start(p_advertising->adv_handle, p_advertising->conn_cfg_tag);		// Line 653
    
    	if (ret != NRF_SUCCESS)
    	{
    		return ret;
    	}
    }

    According to nrf_error.h:

    #define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded.

    Does it mean that I cannot advertise when there is an active connection?
    If so, does it mean that I have to disconnect from Central before start to advertise?

    Best Regards,
    Joe

  • Hello,

    Thanks for sharing your progress. It is very useful for other users who encounter similar problems.

    The softdevice can only have a certain number of connections (declared in the application). If you are in a connection, and you have set the maximum number of connections to 1, then sd_ble_gap_adv_start() will return NRF_ERROR_CONN_COUNT. So in your case, you are probably still connected, and you start advertising again. 

    If you only intend to support one connection at the time, you need to disconnect before you start advertising. Deleting the bonds will not disconnect your current connections, so you need to do this "manually". 

    Perhaps your button handler can disconnect from the central before it deletes the bonds. Remember that disconnecting can take some time, especially if you have a long connection interval. If so, perhaps you should set a flag (a local variable), and disconnect. When you get the disconnected event, you can check this flag, and call advertising_start(true) if the flag is set, and advertising_start(false) if the flag is not set (just a normal disconnect). 

    If you intend to support more than one connection, you need to increase the connection count. Please refer to the multilink examples. ble_app_multilink_central for multilink central, and ble_app_multiperipheral for multiperipheral.

    Best regards,

    Edvin

Related