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

Bonding lost on Android 8.1 when reconnecting from the central

Hi,

I'm developping an application for nRF52840 as a BLE central. It is supposed to connect to an Android device (BLE peripheral) using a bond (encrypted connection with keys stored on both sides). The Android device implements a GATT service with readable and writable characteristics. The board has no IO capability so that it uses the Just Works pairing method.

When debugging, I'm continuously checking what method BluetoothAdapter.getBondedDevices() returns.

The first time the board connects to the Android device, everything goes well: it generates a pop up asking for user confirmation on the Android device, and once it is confirmed, the event BluetoothDevice.BOND_BONDED is received from the Android BLE stack and method BluetoothAdapter.getBondedDevices() starts returning the central is bonded. The central can write on the GATT server characteristics and be notified of any changes.

To simulate a second connection, I turn the BT off on the Android device, wait for a few seconds (until the timeout expires and the board notices the peripheral has been disconnected), and turn BT on again. Here, method BluetoothAdapter.getBondedDevices() still returns the central is bonded.

The board receives the peripheral's advertising packets, connects to the device, and an event BluetoothDevice.BOND_NONE is triggered by Android. At that moment, the central has been removed from the list of bonded devices (returned by method BluetoothAdapter.getBondedDevices()). The central can still be notified of any changes on read-permissions characteristics but cannot write on the GATT server characteristics.

So I suppose I'm using the SoftDevice API wrongly but I cannot find how to fix that.

Here is how I connect to the peripheral:

I define the pairing parameters:

ble_gap_sec_params_t sec_param;
ret_code_t err_code; 

memset(&sec_param, 0, sizeof(ble_gap_sec_params_t)); 
sec_param.bond           = true;                 // need to bond (encrypt the connexion and keep the device's key to direcly encrypt the next connexion)
sec_param.mitm           = false;                // no man-in-the-middle protection
sec_param.lesc           = 0;                    // LE secure connection disabled
sec_param.keypress       = 0;                    // no keypress notifications
sec_param.io_caps        = BLE_GAP_IO_CAPS_NONE; // the central has no keyboard/display capability
sec_param.oob            = false;                // no OOB
sec_param.min_key_size   = 7; 
sec_param.max_key_size   = 16; 
sec_param.kdist_own.enc  = 1; 
sec_param.kdist_own.id   = 1; 
sec_param.kdist_peer.enc = 1; 
sec_param.kdist_peer.id  = 1; 

err_code = pm_sec_params_set(&sec_param); 
APP_ERROR_CHECK(err_code);

When receiving an advertising report from the peripheral, I connect to it:

static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
{
   ret_code_t err_code;
   err_code = sd_ble_gap_connect(&p_adv_report->peer_addr, &m_scan_param, &m_connection_param, APP_BLE_CONN_CFG_TAG);
   APP_ERROR_CHECK(err_code);     
}

My BLE events handler receives a CONNECTED event and starts discovering the services:


static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
{
    ret_code_t err_code;
    ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
        // launch the service discovery process
        err_code = ble_db_discovery_start(&m_db_disc, p_gap_evt->conn_handle);
        APP_ERROR_CHECK(err_code);
        break;
    }
}

My service events handler receives an event after the service discovery has been completed and connect to the peripheral:

static void service_c_evt_handler(service_c_t* p_service_c, service_c_evt_t * p_service_c_evt)
{
     switch (p_service_c_evt->evt_type)
     {
           case SERVICE_C_EVT_DISCOVERY_COMPLETE:
           {
                ret_code_t err_code;
                // last parameter false means there is no need to force repairing if the bond with the device already exists
                err_code = pm_conn_secure(p_service_c_evt->conn_handle, false);
                APP_ERROR_CHECK(err_code);
           } break;
     }
}

My peer events handler:

static void pm_evt_handler(pm_evt_t const * p_evt)
{
     ret_code_t err_code; 
     switch (p_evt->evt_id) 
     { 
          case PM_EVT_BONDED_PEER_CONNECTED: 
          { 
               // connected to an already paired device 
          } break; 

          case PM_EVT_CONN_SEC_SUCCEEDED: 
          { 
               // connected to an newly paired device 
          } break; 
     }
}


The first time the central connects and pairs with the Android device, event PM_EVT_CONN_SEC_SUCCEEDED is triggered.
The next times, event PM_EVT_BONDED_PEER_CONNECTED is received, so that the bonding procedure has no been reinitialized.
Parameter force_repairing when calling function pm_conn_secure is false.

Thank you in advance for your help!

Let me know if something is unclear.

Cécile

Parents Reply Children
No Data
Related