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

[iOS] Reconnecting during full ota update, connect to wrong device

Hi,

we are developing and application on iOS which can among others, update our hardware over the air, and we found out that e.g. after bootloader update is done, then 'iOSDFULibrary' disconnect to the peripheral and connect again to update devices application in update part 2. We have a lot devices in DfuTarg mode, so sometimes it can connect to the wrong device and continue updating.

I saw a comment in your code '// Set the initial peripheral. It may be changed later (flashing App fw after first flashing SD/BL)' but my question is whether it can chagne even if device was paired with phone?

  • Hi,

    It depends on what SDK did you forked your project. The DFU differes a bit among them. Here's a short list:

    1. SDK 4.3 - 5.2 - Only the application can by updated. There is no Buttonless feature, so to update a device user must press a button. The bootloader uses the same device address (app and bootloader must have Service Changed characteristic to make update possible on iOS). Bond info is not shared between app and bootloader so for bonded devices update will fail (phone will fail to resume encryption when in bootloader mode).
    2. SDK 6.0 - SoftDevice and Bootloader update supported. Still no buttonless update.
    3. SDK 6.1 - Buttonless update supported. The address may or may not change, depending on the impl. The default SDK's bootloader will not change address but at least one implementation is known where it does. Still bond info is not shared.
    4. SDK 7.0 - Extended Init Packet required since now with some additional security checks (dev type & revision, app version, crc). No change regarding bonding.
    5. SDK 8.0 - Bonding is now fully supported. If the device in app mode was paired and had Service Changed characteristic indications enabled it pass this info to bootloader and the bootloader will keep the same address, will resume encryption and will notify the host using SC indication about service changed. If you want to preserve the bond info after the update you have to modify the DFU_APP_DATA_RESERVED constant in dfu_types.h to be at least 2 or 3 pages. Otherwise the update will be encrypted, but the new app will find the data cleared. The new app should also be able to read the old's app data.
    6. SDK 12.0 - Secure DFU introduced. Bonding is again not supported in bootloader mode, but the bootloader advertises with a different address so updating a bonded device is possible. If you have a lot of devices in bootloader mode at the time it is possible in the iOS DFULibrary to set a Device Selector object where you can for example rely on the RSSI to select the closest one... Unfortunately, on iOS we don't have access to device address, like we do on Android, so it is not easy to select a device we really wanted.
    7. SDK 14.0 - Bonding supported (there are two buttonless characteristics, one to be used for not bonded, one with bonded devices). Also, the non-bonded one has "set Boulder name" feature. Before jumping to the bl mode the iOS lib send unique random name to be later used be the bootloader. This name is then used by the peripheral selector.

    Also, I requested from the SDK team to implement a "mark" feature. When switching to DFU bootloader mode the service will accept number of random bytes that will be used in the adv packet, so the iOS lib will scan for those. Until then it may happen on iOS that a wrong device will be selected.

  • Thank for grat info! :) Do you know when mark feature will be available for developers?

    I have an idea to change this peace of code in DFUPeripheral.swift:

        override func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        // Is this a device we are looking for?
        if peripheralSelector.select(peripheral, advertisementData: advertisementData as [String : AnyObject], RSSI: RSSI) {
            // Hurray!
            central.stopScan()
            .
            .
            .
        }
    }
    

    to just use centralManager.retrievePeripherals(withIdentifiers: ) and connect to it, because if device was paired with phone it's identifier won't change in any time. Is it correct approach?

  • Right now the status of this feature is "hey, how about making something like this? ok, we'll think about it". So the SDK team acknowledged that there is a problem :)

    If I know that the bootloader keeps the same address then I'm just using the given CBPeripheral object. But in some cases the bootloader uses a different address so it's no longer seen as a paired device and in fact could have never been seen before. The code above I think is used when you update SD+BL before sending an App update. Then it's not that clear what will happen, as it may advertise with a new address if bond info was lost... or will always adv with new address, as bootloader gets this info in RAM and after an update it may be lost... I don't really know how have they solved it.

  • Ahh You right, in dfuTarg mode mac is +1 so there is no sense to bound it. Thanks for your time:) Pozdrawiam!

Related