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

NUS Server does not restore notification state

Enabling or disabling notification on Client does always lead to an update of local database of Server by writing to its flash memory. Particularly NUS requires enabling of notification on each reconnection. Up to me flash memory of NUS Server's IC will fully degrade after about a dozen thousand of reconnections following this way. If I don't enable notification on NUS Client by skipping a call of ble_nus_c_tx_notif_enable() relying on everything was previously restored from database cache, NUS Server isn't able to send data. What is the reason to store anything on flash while it'll not be used (restored) when required?

Parents
  • Hello,

    By default, enabling a notification doesn't write anything to flash. The examples ble_app_uart and ble_app_uart_c doesn't use flash at all (other than storing the application and softdevice in flash). It doesn't update anything in the flash during runtime, unless you have changed it to do so.

    So have you modified them to store something in flash during runtime?

    Best regards,

    Edvin

  • Dear Edvin, I've included NUS sources ble_nus.c and ble_nus_c.c into my own application which uses bonding and MITM so the only modification I've made is an increase of characteristic's security level to MITM.

  • I see. Then I agree that it uses flash to store data.

    The peer manager uses the FDS (flash data storage) module to store peer data (encryption keys, BLE addresses and so on). Eventually the flash will fill up. If any of your peer manager or fds calls returns an error indicating that the flash is full, you should run fds_gc(). By default, I believe that the peer manager already did this, but maybe it isn't done correctly if you are missing some parts in the implementation. 

    If I understand your question correctly, you ask why the peer manager stores the notification state? This is because when the devices are bonded, the notification state needs to be stored for the next time they connect, so that they do not have to turn on the notification the next time they connect. It is part of the BLE spec.

    But it isn't much data that is stored each time, and the peer manager should clean the flash if it is full. Do you run into an issue with the full flash?

    Best regards,

    Edvin

  • Dear Edvin, I know that PM uses FDS including fds_gc(). But I don't receive any errors from FDS, flash isn't full for sure because I work with two fresh (erased) ICs. So each peer stores on flash the only data of one bond which is less than 100 bytes.

    It's great that PM stores notification state (I assumed the same in my original post) but I observe this state isn't restored on next connect - that's my question - see the log on Server:

    peer_manager_handler: Event PM_EVT_BONDED_PEER_CONNECTED
    peer_manager_handler: Previously bonded peer connected: role: Peripheral, conn_handle: 0, peer_id: 0
    peer_manager_handler: Event PM_EVT_LOCAL_DB_CACHE_APPLIED
    peer_manager_handler: Previously stored local DB applied: conn_handle: 0, peer_id: 0
    app: Connected to 0xXXXXXXXXXXXX
    peer_manager_handler: Event PM_EVT_CONN_SEC_START
    peer_manager_handler: Connection security procedure started: role: Peripheral, conn_handle: 0, procedure: Encryption
    peer_manager_handler: Event PM_EVT_CONN_SEC_SUCCEEDED
    peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Encryption
    <here Client calls ble_nus_c_tx_notif_enable() even it was called on last connection>
    app: BLE_NUS_EVT_COMM_STARTED
    peer_manager_handler: Event PM_EVT_PEER_DATA_UPDATE_SUCCEEDED
    peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update

    Once again: if Client will not call ble_nus_c_tx_notif_enable() then Server will not be able to send data, ble_nus_data_send() will return NRF_ERROR_INVALID_STATE.

    Is there any alternative way for the Server to check a state of notification in local database? What type of data should be passed to pm_peer_data_load(PM_PEER_DATA_ID_GATT_LOCAL)?

  • Ok. So your issue is that the notification state is not stored, correct?

    What SDK version are you using?

  • Dear Edvin, if you (and spec) say that Server should store notification state then correct, I observe it's not (re)stored. I'm using SDK 15.2.0 and SD 6.1.0.

  • Hello, 

    Can you please check my colleagues reply in this ticket, and see if you can use any of those functions to restore the value of the notification/cccd?

    Best regards,

    Edvin

Reply Children
  • Dear Edvin, what reply/ticket do you mean? I don't see any replies here other than yours.

  • Dear Edvin, could you kindly be more precise on answers? The ticket you referred to doesn't mention exact instructions, just a couple of ways (functions) which mean about nothing for me.

    sd_ble_gatts_sys_attr_get(SYS_ATTR_FLAG_SYS_SRVCS | SYS_ATTR_FLAG_USR_SRVCS) returns following array of data: 0xCACD000100020010. How should I interpret it?

  • Hello,

    Sorry. I didn't mean to be imprecise. I am still trying to clarify whether you want the notification status to be stored but it is not being stored, or if the issue is something else?

    If that is the issue:

    When you are connected to the already bonded device. Can you then try to call sd_ble_gatts_sys_attr_get() with the current connection?

    The reason that I can't tell you exactly how to use it is because I haven't tested this functionality before. Is it possible to share your project, and I can give it a go.

    In your peripheral project:

    Do you call sd_ble_gatts_sys_attr_set in the BLE_GATTS_EVT_SYS_ATTR_MISSING event?

    Can you try to add the following in your ble_evt_handler():

    // near top of main.c:
    static volatile uint8_t * my_p_sus_attr_data;
    
    
    
    static void ble_evt_handler(...)
    {
        ret_code_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_DISCONNECTED:
            {
                uint16_t * my_p_len;
                uint32_t flags = BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS | BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS;
                
                err_code = sd_ble_gatts_sys_attr_get(conn_handle, my_p_sus_attr_data, my_p_len, flags);
                APP_ERROR_CHECK(err_code);
                
                // Somehow, you need to store this data. my_p_sus_attr_data. 
                // For testing purposes  before you start doing this, you can just 
                // disconnect and reconnect, so that you don't have to store the data in flash.
            }break;
            
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            {
                err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, my_p_sys_attr_data, len, flags);
                APP_ERROR_CHECK(err_code);
            }break;
        }    
    }   

    Best regards,

    Edvin

  • Dear Edvin, everything was much easier than we thought. After reading Automatically start notification upon connection event and How to know if the Notification/Indication of a Characteristic is enabled I've got a look into on_connect() handler in ble_nus.c, there's a call of sd_ble_gatts_value_get(), and the great mistake was in the name of the handle which we need to get a value of: rx_handles. Once I've changed it to tx_handles, the log on Server became as expected. Please report this bug to SDK team.

    peer_manager_handler: Event PM_EVT_BONDED_PEER_CONNECTED
    peer_manager_handler: Previously bonded peer connected: role: Peripheral, conn_handle: 0, peer_id: 0
    peer_manager_handler: Event PM_EVT_LOCAL_DB_CACHE_APPLIED
    peer_manager_handler: Previously stored local DB applied: conn_handle: 0, peer_id: 0
    app: BLE_NUS_EVT_COMM_STARTED <Server restored a notification state of just connected bonded Client>
    app: Connected to 0xXXXXXXXXXXXX
    peer_manager_handler: Event PM_EVT_CONN_SEC_START
    peer_manager_handler: Connection security procedure started: role: Peripheral, conn_handle: 0, procedure: Encryption
    peer_manager_handler: Event PM_EVT_CONN_SEC_SUCCEEDED
    peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Encryption

Related