Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Peer manager and FDS, new records at each connection.

Hi,

I am working with a NRF52840 with the SDK16 and I am facing field issues with the peer manager flash usage. At each connection the app subscribes to characteristic and the local data base of the MCU is updated (write to the flash). The main problem is since the app subscribe to multiple services at connection, MCU peer data are updated multiple time (644bytes) at each connection.

[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Peer rank, action: Update, no change
[00000015] <info> BLEDriver: Connected to a previously bonded device.
[00000015] <info> SecurityService: Bonded, not yet secured.
[00000015] <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
[00000015] <info> BLEDriver: Connected.
[00000015] <info> SecurityService: Bonded, not yet secured.
[00000015] <info> BLEDriver: Encryption started.
[00000015] <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Encryption
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Peer rank, action: Update, no change
[00000015] <info> BLEDriver: Connection secured: role: peripheral, conn_handle: 0x0, procedure: 0.
[00000015] <info> SecurityService: Secured.
[00000015] <debug> nrf_ble_gatt: ATT MTU updated to 185 bytes on connection 0x0 (response).
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000015] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update
[00000016] <info> peer_manager_handler: Peer data updated in flash: peer_id: 1, data_id: Local database, action: Update

Since our device could be used multiple time per day (connection in background when in range) and support multiple peers, the flash memory is really stressed and do a lot of Garbage collection and lead to various issue.

We found a workaround on Android where the phone first check their local data base at connection and subscribe only if the characteristic descriptor is not up to date. It works well and we don't experience issue. 

However, on iOS, it seems that the OS clears its cached value of the Client Characteristic Configuration descriptor (0x2902) after each disconnection. I checked in the iOS NRF connect app and after a reconnection, the previous characteristic state is overwritten to false. I already look at other post without having a clear solution eg : https://devzone.nordicsemi.com/f/nordic-q-a/59866/new-fds-record-on-each-connection.

What could be a short term solution on iOS or in the device firmware ? 

Thanks,

Florian

Parents
  • Hello Vidar,

    Thank you for this patch, it works well. 


    However I had to remove the ASSERT check because at the first connection on iOS, the ATT MTU negociation returns NRF_ERROR_NOT_SUPPORTED.

    [00000003] <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
    [00000003] <info> BLEDriver: Connected.
    [00000003] <info> SecurityService: Not bonded.
    [00000003] <debug> nrf_ble_gatt: ATT MTU updated to 185 bytes on connection 0x0 (response).
    [00000004] <error> app: ASSERTION FAILED at ../nordic_sdk/nRF5_SDK/components/ble/peer_manager/gatt_cache_manager.c:315

    It could be my configuration, but because since there was no ASSERT before it was not detected. 

    Anyway thank you very much for the great support.

    Florian

Reply
  • Hello Vidar,

    Thank you for this patch, it works well. 


    However I had to remove the ASSERT check because at the first connection on iOS, the ATT MTU negociation returns NRF_ERROR_NOT_SUPPORTED.

    [00000003] <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0.
    [00000003] <info> BLEDriver: Connected.
    [00000003] <info> SecurityService: Not bonded.
    [00000003] <debug> nrf_ble_gatt: ATT MTU updated to 185 bytes on connection 0x0 (response).
    [00000004] <error> app: ASSERTION FAILED at ../nordic_sdk/nRF5_SDK/components/ble/peer_manager/gatt_cache_manager.c:315

    It could be my configuration, but because since there was no ASSERT before it was not detected. 

    Anyway thank you very much for the great support.

    Florian

Children
  • Hello Florian,

    Thanks for reporting back. I assume you meant to say it returned NRF_ERROR_NOT_FOUND? The initial "local database" record was always written prior to the client CCCD write in my tests, but it seems now like that might not always be the case.

    Instead of removing the ASSERT line, you may consider implementing a check for this error as shown below.

    --- a/gatt_cache_manager.c
    +++ b/gatt_cache_manager.c
    @@ -302,6 +302,12 @@ static bool local_db_needs_update(uint16_t conn_handle)
         err_code = pdb_peer_data_ptr_get(im_peer_id_get_by_conn_handle(conn_handle),
                                       PM_PEER_DATA_ID_GATT_LOCAL,
                                       &peer_data);
    +    
    +    if (err_code == NRF_ERROR_NOT_FOUND)
    +    {
    +        return needs_update;
    +    }
    +
         ASSERT(err_code == NRF_SUCCESS);
     
         len = peer_data.p_local_gatt_db->len;
    

    Edit: Added missing parenthesis. Thanks

  • I got an NRF_ERROR_INVALID_PARAM. 

    It seems to happen when the NRF local peer data are deleted but not on iOS side. At the next connection, the phone tries to secure, fail but try to update the MTU. 

    I tried to trace the operation but i did not manage to find where the write event comes from.

    Here some log : 

    [00000043] <info> BLEDriver: Connected.
    [00000043] <info> SecurityService: Not bonded.
    [00000043] <info> BLEDriver: Encryption started.
    [00000043] <info> peer_manager_handler: Connection security failed: role: Peripheral, conn_handle: 0x0, procedure: Encryption, error: 4102
    [00000043] <info> BLEDriver: Failed to secure connection!
    [00000043] <info> SecurityService: Securing failed.
    [00000043] <debug> BLEDriver: handleBLEEvent: evt_id = 0x14 : BLE_GAP_EVT_SEC_INFO_REQUEST
    [00000043] <info> app: ATT MTU updated to 185 bytes on connection 0x0 (response).
    [00000043] <debug> BLEDriver: handleBLEEvent: evt_id = 0x3A : BLE_GATTC_EVT_EXCHANGE_MTU_RSP
    [00000043] <info> in local_db_needs_update -> error_id = 0x07 : NRF_ERROR_INVALID_PARAM , at pdb_peer_data_ptr_get
    [00000048] <error> app: SOFTDEVICE: ASSERTION FAILED

    It is probably my application or the phone that try to set some value even if it is not authorized. 

    I added a condition to handle this fault to avoid triggering the ASSERT : 

    --- a/gatt_cache_manager.c
    +++ b/gatt_cache_manager.c
    
    static bool local_db_needs_update(uint16_t conn_handle)
         err_code = pdb_peer_data_ptr_get(im_peer_id_get_by_conn_handle(conn_handle),
                                       PM_PEER_DATA_ID_GATT_LOCAL,
                                       &peer_data);
         
         if (err_code == NRF_ERROR_NOT_FOUND)
         {
             return needs_update;
         }
         
         if (err_code == NRF_ERROR_INVALID_PARAM)
         {
             return false;
         }
         
         ASSERT(err_code == NRF_SUCCESS);
     
         len = peer_data.p_local_gatt_db->len;
    

Related