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

Questions regarding DFU, Bonding and iOS (caching)

Hi,

I have some questions regarding DFU, Bonding and iOS (caching). In my current project I have a DFU bootloader which does not use bonds, however the application uses bonds.

The current setup is that the DFU bootloader uses a different MAC-address than the application, this way iOS will treat the DFU bootloader and the application as two different devices and caching is not an issue. Is this an okay solution or would it be preferable to use bonds in the DFU FW since the application uses it?

If using bonds with the DFU and adding the Services Changed characteristic and the application is it possible to share the bonding information between Application and DFU FWs? Is there any example that uses bonds for both DFU and application? From what I've read the DFU FW does not know where the App stores the bonding information and vice versa.

I've have tried changing the DFU FW to also use bonds, however I run into issues when I try to mergehex the settings file for the application with the hex for SD + APP + Bootloader, I'm assuming this is because there are overlapping memory addresses.

HW: nRF52832

SDK: 15.0

Softdevice: 6.0

Br,
Anton

Parents
  • The current setup is that the DFU bootloader uses a different MAC-address than the application, this way iOS will treat the DFU bootloader and the application as two different devices and caching is not an issue. Is this an okay solution or would it be preferable to use bonds in the DFU FW since the application uses it?

    The Secure bootloader in our SDK is considered production code so we do consider it a 'OK' solution for our customers. 

    If you configure the bootloader to use bonds, then the bootloader will only allow bonded devices to write to the DFU Control Point and DFU Packet characteristics. The same thing applies to the Buttonless DFU service characteritics in the application, only bonded peers will able to put the nRF device in bootloader mode. The BLE link that the DFU is performed over will also be encrypted. 

    If the bootloader and the Buttonless DFU service does not require bonds, then any central device can put the nRF in bootloader mode and write to the DFU Control Point and DFU Packet characteristics. The BLE link that the DFU is performed over will in this case not be encrypted. 

    Note that a DFU package will only be accepted if BLE central has an DFU image that has been signed with the private key that the public key was derived from in the bootloader on the nRF Device. Any other image will be rejected. 

     

    If using bonds with the DFU and adding the Services Changed characteristic and the application is it possible to share the bonding information between Application and DFU FWs? Is there any example that uses bonds for both DFU and application? From what I've read the DFU FW does not know where the App stores the bonding information and vice versa.

     Yes, it is possible for the application to share the bonding information with the bootloader. This is done when you definine NRF_DFU_BLE_REQUIRES_BONDS in the sdk_config.h file in the bootloader and defining NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS  in the sdk_config.h file of the application.

    The application will then use the function nrf_dfu_set_peer_data(), which is defined in the bootloader through a async SVC interface, to share the bonding data with the peer. When the device restes to bootloader mode, it will then use that bonding information to re-establish and re-encrypt the connection 

    I've have tried changing the DFU FW to also use bonds, however I run into issues when I try to mergehex the settings file for the application with the hex for SD + APP + Bootloader, I'm assuming this is because there are overlapping memory addresses.

     It should only be a matter of defining NRF_DFU_BLE_REQUIRES_BONDS in the sdk_config.h file in the bootloader and defining NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS  in the sdk_config.h file of the application.  The settings hex should only contain data on the bootloader settings page. You can also write it to the nRF device with nrfjprog using the --sectorerase option after flashing the bootloader. 

    Best regards

    Bjørn

  • The application will then use the function nrf_dfu_set_peer_data(), which is defined in the bootloader through a async SVC interface, to share the bonding data with the peer. When the device restes to bootloader mode, it will then use that bonding information to re-establish and re-encrypt the connection

    Where can I read more about nrf_dfu_set_peer_data()? I've tried looking through the Infocenter but the closest relevant information I can find is this.

    It should only be a matter of defining NRF_DFU_BLE_REQUIRES_BONDS in the sdk_config.h file in the bootloader and defining NRF_DFU_BLE_BUTTONLESS_SUPPORTS_BONDS  in the sdk_config.h file of the application.  The settings hex should only contain data on the bootloader settings page. You can also write it to the nRF device with nrfjprog using the --sectorerase option after flashing the bootloader. 

    I'm no quite sure how to ensure that the settings hex only contains data on the bootloader settings page. I've followed the steps that you provided in an answer to another user here on the dev zone. It fails on step 8 when I try to merge the settings file.

    Note: Im also getting NRF_ERROR_INTERNAL if I just try to flash the bootloader.

  • Updated my answer with the error code it's giving me, I missed the APP_ERROR_CHECK.

  • Ok so It's not the async SVC interface that's giving me NRF_INVALID_STATE, it's when I try to initialize the service.

  • So its not nrf_dfu_svci_vector_table_unset() that returns NRF_INVALID_STATE? Is a function that is called after ble_dfu_buttonless_async_svci_init() then?

  • I was a bit quick there.

    It is actually the function ble_dfu_buttonless_init() that returns NRF_INVALID_STATE.

    Edit: I've been going through that function and the only call that I can see which can possibly return NRF_INVALID_STATE is sd_ble_gatts_characteristic_add() which seems really strange.

    Edit:
    I have tried to incrementing the UUID count in sdk_config by one. Still gives NRF_INVALID_STATE.

  • If it was the UUID count then you should have gotten the NRF_ERROR_NO_MEM return value. 

    If you are getting NRF_ERROR_INVALID_STATE, then this suggests that there is some wrong with the service context passed to sd_ble_gatts_characteristic_add()

    NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required.

    What service handle is returned by sd_ble_gatts_service_add(), which is called prior to sd_ble_uuid_vs_add() and ble_dfu_buttonless_char_add()?

Reply
  • If it was the UUID count then you should have gotten the NRF_ERROR_NO_MEM return value. 

    If you are getting NRF_ERROR_INVALID_STATE, then this suggests that there is some wrong with the service context passed to sd_ble_gatts_characteristic_add()

    NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required.

    What service handle is returned by sd_ble_gatts_service_add(), which is called prior to sd_ble_uuid_vs_add() and ble_dfu_buttonless_char_add()?

Children
  • Right.

    I've added some debug logs to ble_dfu, and its seems to be the function ble_dfu_buttonless_backend_init which returns NRF_ERROR_INVALID_STATE.

  • I found the issue, I was looking in the wrong file (ble_dfu_unbonded.c, my ctags took me there instead of ble_dfu_bonded). All that was needed was to move the Peer Manager initialization to before init of ble dfu buttonless service.

    I'm now struggling with entering the bootloader. After I have bonded and try to write to the DFU characteristic I receive this in the logs:

    app: Read/Write Authorization request.
    <info> app: Writing peer data to the bootloader...
    <error> app: Request to enter bootloader mode failed asynchroneously.
    <info> app: Handle Value Confirmation
    

    the issue seems to be that ble_dfu_bonded.c cannot find the bonding information, retrieve_peer_data() returns NRF_ERROR_NOT_FOUND. Not really sure where to go from here.

  • Hi again Björn,

    I've managed to get it all working. I was missing some necessary things such as Service Changed Characterstic in the application and so on. After adding them I can enter the DFU bootloader using the shared bond.

    One thing I've noticed is that when the DFU is complete and I reconnect the DFU services are still there and I have to refresh the services on my Android device. I'm guessing I should call sd_ble_gatts_service_changed() to notify the Central that the services has changed in the application, is there in any specific event that you recommend that I call this function? Like BLE_GAP_EVT_CONNECTED?

    Edit:

    I've found another question here on Devzone where the call to sd_ble_gatts_service_changed() is placed in BLE_GAP_EVT_CONN_SEC_UPDATE. I placed it there and notifications are sent when i disconnect / reconnect. But after DFU I get BLE_ERROR_INVALID_ATTR_HANDLE, I have pretty much copied how I send notifications from nrf_dfu_ble.c

    err_code = sd_ble_gatts_sys_attr_set(
                p_ble_evt->evt.gap_evt.conn_handle,
                sys_serv_attr,
                len,                               
                BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS
            );
    
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_INFO("Error setting system attributes!");
            }
    
    
            err_code = sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gap_evt.conn_handle,
                                             NULL,
                                             0,
                                             BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_INFO("Failed to set system attributes!");
            }
    
            err_code = sd_ble_gatts_service_changed(p_ble_evt->evt.gap_evt.conn_handle, system_service_get_service_handle(), 0xFFFF);
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_INFO("Failed to send service changed indication!, err_code: %d", err_code);
            }
            else
            {
                NRF_LOG_INFO("Service changed indication sent!");
            }

  • Hi Anton, 

    I apologize for the late reply, I have been on vacation the past week.  

    What start handle are you passing to sd_ble_gatts_service_changed(), i.e. which handle value is system_service_get_service_handle() returning? Can you post the code for system_service_get_service_handle()?

    Best regards

    Bjørn

  • Hi Björn,

    So for the late reply here aswell.

    Everything works now, I moved over to letting the Peer Manager send out the notifications. After resolving a bug in SDK described here everything works as expected.

    Br,
    Anton

Related