Using ble_conn_state_conn_idx() to get separate central/peripheral indexes

I would like to store context information for each connection, but with central and peripheral connections storing different information.  Ideally, this is done in two separate arrays.

I see that ble_conn_state_conn_idx() gives an array index in the range 0 to BLE_CONN_STATE_MAX_CONNECTIONS - 1, as long as the connection state is valid.

Experimentally, the central connections' indexes are always in the lower segment of these index values.  For example, with 10 central and 1 peripheral, the connection handles are always [0-9] central and [10] peripheral.  I tested on nRF52840 with SDK 17.1.0 and SD s140 7.2.0, repeatedly connecting and disconnecting in different combinations.

From this, it looks like I can get separate central/peripheral indexes simply by subtracting.  Something like the following is consistently working for us:

uint16_t get_central_array_index(uint16_t conn_handle)
{
    uint16_t conn_index = ble_conn_state_conn_idx(conn_handle);
     
    if (conn_index >= NRF_SDH_BLE_CENTRAL_LINK_COUNT)
    {
        // not central, handle error
        return UINT16_MAX;  // or some other terrible thing
    }
    
    return conn_index;
}

uint16_t get_peripheral_array_index(uint16_t conn_handle)
{
    uint16_t conn_index = ble_conn_state_conn_idx(conn_handle);
    
    if ((conn_index < NRF_SDH_BLE_CENTRAL_LINK_COUNT) || (conn_index >= NRF_SDH_BLE_TOTAL_LINK_COUNT))
    {
        // not peripheral, handle error
        return UINT16_MAX;  // or some other terrible thing
    }
    
    return conn_index - NRF_SDH_BLE_CENTRAL_LINK_COUNT;
}

Can I rely on this index segmentation?  There are of course other more complex approaches with looped lookups, but this seems really clean if the index segmentation is guaranteed.

Thanks for the help!

Parents
  • Hi Jeff,

    Experimentally, the central connections' indexes are always in the lower segment of these index values.  For example, with 10 central and 1 peripheral, the connection handles are always [0-9] central and [10] peripheral.  I tested on nRF52840 with SDK 17.1.0 and SD s140 7.2.0, repeatedly connecting and disconnecting in different combinations.

    Are you certain? Looking at the implementation of ble_conn_state_conn_idx(), it simply returns the connection handle itself after a basic validity check.

    I expect that the connection handle is given in order from 0 to maximum, with recycling when disconnection happens.

    I run a quick test with the LE Secure Connections Multirole Example and the Heart Rate Application, and see that when the Multirole Example connects to the Heart Rate board, the Heart Rate board is given connection handle 0. This experiment alone shows that we cannot assume that Peripheral connection handles all start after a certain threshold.

    Hieu

  • Hi Hieu,

    Thank you for the response.  Your example does not appear to contradict what I'm asking.  The line you've highlighted in your screen capture shows a central connection taking a low connection handle (in this case zero).  This aligns with the experiments I've done.

    I think the confusion here is how we're using the terms "central" and "peripheral" to describe connections.  I'm using the terms to refer to the local role, the same way you see in your screen capture.

    • "Central" = a connection in which my firmware is the central.  These appear to take the lower connection handles.
    • "Peripheral" = a connection in which my firmware is peripheral.  These appear to take the upper connection handles.

    In the LE Secure Connection Multirole Example code, you can see that your highlighted log message comes from on_ble_central_evt, which is called when the local role is central (by way of the check on BLE_GAP_ROLE_CENTRAL in ble_evt_handler).

    Does that clarify what I'm asking?  And is there a way to confirm this in the actual SoftDevice code, so we're not relying on experimentation?

    Thanks

    Jeff

Reply
  • Hi Hieu,

    Thank you for the response.  Your example does not appear to contradict what I'm asking.  The line you've highlighted in your screen capture shows a central connection taking a low connection handle (in this case zero).  This aligns with the experiments I've done.

    I think the confusion here is how we're using the terms "central" and "peripheral" to describe connections.  I'm using the terms to refer to the local role, the same way you see in your screen capture.

    • "Central" = a connection in which my firmware is the central.  These appear to take the lower connection handles.
    • "Peripheral" = a connection in which my firmware is peripheral.  These appear to take the upper connection handles.

    In the LE Secure Connection Multirole Example code, you can see that your highlighted log message comes from on_ble_central_evt, which is called when the local role is central (by way of the check on BLE_GAP_ROLE_CENTRAL in ble_evt_handler).

    Does that clarify what I'm asking?  And is there a way to confirm this in the actual SoftDevice code, so we're not relying on experimentation?

    Thanks

    Jeff

Children
Related