NordicSemiconductor / IOS-nRF-Connect-Device-Manager

A mobile management library for devices supporting nRF Connect Device Manager.
https://www.nordicsemi.com/Software-and-tools/Software/nRF-Connect-SDK
Apache License 2.0
88 stars 40 forks source link

How to generate imageData? #121

Closed oswalde-p closed 11 months ago

oswalde-p commented 1 year ago

I can't find any documentation or examples on how the imageData object should be created. I'm fairly new to Swift so any help or resources would be greatly appreciated. I'm working on a capacitor plugin to implement device firmware updates using Nordic's native device manager libraries.

Essentially the plugin receives the image data as an array of integers along with a device ID. I get an invalidHeaderMagic error on FirmwareUpgradeManager.start(), so I'm guessing I've done something wrong when creating the Data object. The Android implementation is working with the same integer array and device, so I'm quite confident the data being sent from the plugin is valid.

Here's how I convert the [Int] to Data:

let firmware = call.getArray("firmware")!.capacitor.replacingNullValues() as? [Int]
// firmware: [61, 184, 243, 150, 0, 0, 0, 0, 0, 2, 0, ...]
// firmware.count: 170644
let firmwareData = Data(bytes: firmware!, count: firmware!.count)

And here's where I try to initiate the DFU process:

  public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
      print("DFU: \(peripheral)")
      if (peripheral.identifier.uuidString == self.deviceUuid) {
          print("DFU: found device with uuid \(self.deviceUuid)")
          self.peripheral = peripheral

          let bleTransport = McuMgrBleTransport(peripheral)
          bleTransport.logDelegate = UIApplication.shared.delegate as? McuMgrLogDelegate
          let delegate = UpgradeDelegate()
          let dfuManager = FirmwareUpgradeManager(transporter: bleTransport, delegate: delegate)
          dfuManager.logDelegate = UIApplication.shared.delegate as? McuMgrLogDelegate

          print("DFU: firmwareData.count: \(self.firmwareData.count)") // 170644
          do {
              try dfuManager.start(data: self.firmwareData)
          } catch {
              print("DFU: Unexpected error: \(error)")
          }
      }
  }

For reference, this is the byte array processing in the Android implementation (which works):

  final List<Object> list = firmware.toList();
  byte[] bytes = new byte[list.size()];
  for (int i = 0; i < list.size(); i++) {
      int val = (int) list.get(i);
      bytes[i] = (byte) val;
  }

Thanks :)

philips77 commented 11 months ago

Hello,

// firmware: [61, 184, 243, 150, 0, 0, 0, 0, 0, 2, 0, ...]

Your byte array seems OK. It starts with the correct magic value (4 first bytes, little endian) (Android, iOS).

The only place from where you may be getting .invalidHeaderMagic is here: https://github.com/NordicSemiconductor/IOS-nRF-Connect-Device-Manager/blob/2501419594e53c8ef5a688dfc57fefe76d4bf1ab/Source/McuMgrImage.swift#L55-L57

Check what is the lowerBound of your firmware array. Perhaps it's not 0, where the library is expecting the magic to be. For example, methods like .prefix(..) or .suffix(..) in Data return a part of the original array (also as Data type, but the indexes are different. Check explicitly if firmware[0] == 61, etc.

oswalde-p commented 11 months ago

Thanks, that was helpful! firmwareData[0] was correct, but the rest of the entries were all 0.

The problem was with the [Int] type of the initial firmware array. Changing it to Array<UInt8> worked:

 let firmware = call.getArray("firmware")!.capacitor.replacingNullValues() as? Array<UInt8>