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

DFU Not switching to boot loader mode from iOS SDK


We are using the iOS DFU SDK https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library to update a device that is built against the nRF5 SDK 14.2.0. The problem is that from iOS we are unable to switch the device in to boot loader mode.

Using the Android nRF Connect app the DFU works except that after connecting to the device in app mode and initiating the DFU the device will disconnect and start advertising as a DfuTarg with the DFU service in its advertising packet. I need to go back in to the scanning screen of the nRF Connect app find the device, connect to it and initiate the DFU again. 

When I try on iOS, either with the nRF Toolbox app or using the SDK in my code to initiate the DFU. The device never starts advertising as a DfuTarg, instead it just restarts in app mode. I verified that the device does not advertise as a DfuTarg with the DFU service by using the android nRF Connect app and scanning while the iPhone initiates the DFU.

If I initiate the DFU from the android nRF Connect app, but then scan and connect to the DfuTarg on the iPhone so the device is already in boot loader mode when the iPhone connects to it I am able to complete the DFU on the iPhone without any more problems.

I tried implementing the peripheralSelector and don't see a device in DFU mode only our device in app mode.

func select(_ peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber, hint name: String?) -> Bool {

Here are the logs from the logger callbacks when using the iOS SDK

  DFU Accepted ZIP File

  DFU State = connecting

  DFU: [Callback] Central Manager did update state to: Powered ON

  DFU: Connecting to 574F48F5 KTV Front...

  DFU: centralManager.connect(peripheral, options: nil)

  DFU: [Callback] Central Manager did connect peripheral

  DFU: Connected to 574F48F5 KTV Front

  DFU: Discovering services...

  DFU: peripheral.discoverServices(nil)

  DFU: Services discovered

  DFU: Starting Secure DFU...

  DFU: Connected to 574F48F5 KTV Front

  DFU: Services discovered

  DFU: Secure DFU Service found

  DFU: Discovering characteristics in DFU Service...

  DFU: peripheral.discoverCharacteristics(nil, for: FE59)

  DFU: DFU characteristics discovered

  DFU State = starting

  DFU: Enabling indications for 8EC90003-F315-4F60-9FB8-838830DAEA50...

  DFU: peripheral.setNotifyValue(true, for: 8EC90003-F315-4F60-9FB8-838830DAEA50)

  DFU: Indications enabled for 8EC90003-F315-4F60-9FB8-838830DAEA50

  DFU: Buttonless DFU indications enabled

  DFU: Application with buttonless update found

  DFU State = enablingDfuMode

  DFU: Trying setting bootloader name to Dfu61636

  DFU: Writing to characteristic 8EC90003-F315-4F60-9FB8-838830DAEA50...

  DFU: peripheral.writeValue(0x02084466753631363336, for: 8EC90003-F315-4F60-9FB8-838830DAEA50, type: .withResponse)

  DFU: [Callback] Central Manager did disconnect peripheral

  DFU: Disconnected by the remote device

  DFU: Scanning for the DFU Bootloader...

 

If anyone has any suggestion as to what I need to do to successfully get the device to switch to the boot loader on the iPhone the help would be appreciated. 

Thanks

  • Hi ...

    Not sure if this is helpful. I have OTA DFU working (also using the Nordic DFU SDK). However, the target device is RF Digital's Simblee which uses Arduino IDE and RF's proprietary library for BLE. So not sure if this applies to applications developed using the Nordic SDK. My sense is it should be the same on the iOS side.

    When connected to the device via BLE, our iOS app executes (sorry, Objective C):

        DFUFirmware *dfuFirmware = [[DFUFirmware alloc] initWithUrlToZipFile:bundledFirmwareURL];

        DFUServiceInitiator *dfuInitiator = [[DFUServiceInitiator alloc] initWithCentralManager:self.centralManager target:myPeripheral];

        dfuInitiator.delegate = self;

        dfuInitiator.progressDelegate = self;

        dfuInitiator.logger = self;

       [dfuInitiator withFirmware:dfuFirmware];

        self.dfuController = [dfuInitiator start];

    bundledFirmwareURL is URL to zip file containing new app. myPeripheral is the connected BLE peripheral. This class implements CBCentralManagerDelegate and CBPeripheralDelegate methods as well as methods for DFUServiceDelegate, DFUProgressDelegate and LoggerDelegate.

    #pragma mark - DFUServiceDelegate methods

    - (void)dfuStateDidChangeTo:(enum DFUState)state

    {

        if (state == DFUStateConnecting) {

            NSLog(@"dfuStateDidChangeTo: DFUStateConnecting");

        } else if (state == DFUStateStarting) {

            NSLog(@"dfuStateDidChangeTo: DFUStateStarting");

        } else if (state == DFUStateEnablingDfuMode) {

            NSLog(@"dfuStateDidChangeTo: DFUStateEnablingDfuMode");

        } else if (state == DFUStateUploading) {

           // update UI ...

            NSLog(@"dfuStateDidChangeTo: DFUStateUploading");

        } else if (state == DFUStateValidating) {

            NSLog(@"dfuStateDidChangeTo: DFUStateValidating");

        } else if (state == DFUStateDisconnecting) {

            NSLog(@"dfuStateDidChangeTo: DFUStateDisconnecting");

        } else if (state == DFUStateCompleted) {

           // update UI ...

            NSLog(@"dfuStateDidChangeTo: DFUStateCompleted");

            self.centralManager.delegate = self;

        } else if (state == DFUStateAborted) {

            NSLog(@"dfuStateDidChangeTo: DFUStateAborted");

        }

        if (state == DFUStateCompleted || state == DFUStateAborted) {

            self.dfuController = nil;

        }

    }

    - (void)dfuError:(enum DFUError)error didOccurWithMessage:(NSString *)message

    {

        NSLog(@"dfuError: %@", message);

        self.dfuController = nil;

    }

    #pragma mark - DFUProgressDelegate methods

    - (void)dfuProgressDidChangeFor:(NSInteger)part outOf:(NSInteger)totalParts to:(NSInteger)progress currentSpeedBytesPerSecond:(double)currentSpeedBytesPerSecond avgSpeedBytesPerSecond:(double)avgSpeedBytesPerSecond

    {

        NSLog(@"dfuProgressDidChangeFor: %ld", (long)progress);

        // update UI ...

    }

    #pragma mark - LoggerDelegate

    methods

    - (void)logWith:(enum LogLevel)level message:(NSString *)message

    {

        NSLog(@"logWith: %@", message);

    }

  • The problem is that from iOS we are unable to switch the device in to boot loader mode.
    When I try on iOS, either with the nRF Toolbox app or using the SDK in my code to initiate the DFU. The device never starts advertising as a DfuTarg, instead it just restarts in app mode.

    Do you see the same issue when using nRF Connect app for iOS

  • Thanks for your suggestion.

    I tried with the iOS nRF Connect app and got similar results. When I initiate the DFU from the iPhone nRF Connect app and have the same app open on Android and scanning I see the device come back in app mode right away. If I switch to boot loader mode from the android app, then I am able to connect with the iPhone nRF Connect app and the DFU works. 

  • Could you flash the debug version of the bootloader, set a breakpoint at dfu_enter_check() in nrf_bootloader.c, and see if the function returns true or false.

  • We figured it out, the main difference from the Android version is that the iOS Connect app tries to set the DFU advertising name. Our implementation cannot support this and was causing a reset, instead we just return DFU_RSP_OP_CODE_NOT_SUPPORTED and it started working.

    Thanks,

    Terry

Related