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

Peer Manager fails to save bond

I am working on a BLE peripheral (nRF52832 & SDK 15) which uses the Peer Manager to handle encryption and bonding to a previously existing central device.  Sometimes bonding works, but often I am seeing a failure mode where the encryption and bonding process succeeds (the connection completes and data flows from central to peripheral and vice versa) but the Peer Manager doesn't save the bond.  I discover this when I disconnect and reconnect, and I get PM_EVT_CONN_SEC_FAILED with PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING.  

So far I have attempted to verify that the bond data isn't being stored by looking at what happens after I get PM_EVT_CONN_SEC_SUCCEEDED during bonding.  I went into peer_database.c and added some NRF_LOG()s in write_buf_store().  I see the write happen and no error is reported.  However I never get either PM_EVT_PEER_DATA_UPDATE_SUCCEEDED or PM_EVT_PEER_DATA_UPDATE_FAILED.  I put log msgs into pdb_pds_evt_handler() in peer_database.c, and in my own pm_evt_handler.  It appears that the bond save is failing silently.  This is very frustrating.

Sometimes the bond *is* successfully saved, and I'm able to reconnect to the central indefinitely.  I can't yet figure out why it sometimes succeeds.

I discovered this issue when starting to write code to handle a possible failure which could be caused by the central losing its bond data... the idea being that if the connection fails, both sides will the delete their bonds automatically and can then be manually rebonded by the user.  I test this scenario by manually deleting the bond in the central... on the next connection attempt, reestablishing the link fails and the peripheral deletes its bonds.  This all seems to be working as expected.  But when I manually rebond, I'm stuck... the nRF52 usually isn't saving the new bond.

This current project is to replace a remote control based on another vendor's BLE chip.  Encryption and bonding have worked for years with the central so I have no reason to distrust it.

Any advice on how to debug this further would be much appreciated.

Darren

  • OK I finally figured out the problem, and realize now that I should have started with this approach.  I went back in the git history to the very first version of my app that claimed to be able to bond with the central and found that it still worked.  So I tried different commits binary search style until I found the one that broke fds.  It turns out to be makefile related.  About a month ago, to try to reduce the makefile size and complexity (and the code size), I went through and removed everything that didn't break the build.  It turns out that the application needs

      $(SDK_ROOT)/components/softdevice/common/nrf_sdh_soc.c \

    even though the app will compile and run without it and generates no errors or warnings.

    When I put that file back in the build, all of my fds problems went away.

    If this code is required for proper functioning, it seems like there should be some warning generated if you remove it.

  • Apparently there is more to this, because when I init fds in my own code, it prevents fds from working.  If I don't init, it works fine.  

    /**@brief   Wait for fds to initialize. */
    static void wait_for_fds_ready(void)
    {
        while (!m_fds_initialized)
        {
            sd_app_evt_wait();
        }
    }
    
        err_code = fds_init();/    APP_ERROR_CHECK(err_code);
    
        /* Wait for fds to initialize. */
        wait_for_fds_ready();
    

    I took this directly from fds SDK example.

    Seems like still there is something wrong if fds can't properly handle double-init and fails silently.

  • One can use the same construct to wait for the peer manager to init fds, and then init locally.  This seems... awkward.  Is the best practice to assume fds has been initialized by the peer manager and just not do it if the app is going to make fds calls itself? 

        peer_manager_init();
    
        wait_for_fds_ready();
    
        NRF_LOG_INFO("App Initializing fds...");
        m_fds_initialized = false;
    
        err_code = fds_init();
        APP_ERROR_CHECK(err_code);
    
        wait_for_fds_ready();
    

Related