diff --git a/sources/iOS/ios-communications/Sources/PolarBleSdk/sdk/impl/PolarBleApiImpl.swift b/sources/iOS/ios-communications/Sources/PolarBleSdk/sdk/impl/PolarBleApiImpl.swift index dd7fbd0b..9670f083 100644 --- a/sources/iOS/ios-communications/Sources/PolarBleSdk/sdk/impl/PolarBleApiImpl.swift +++ b/sources/iOS/ios-communications/Sources/PolarBleSdk/sdk/impl/PolarBleApiImpl.swift @@ -2313,20 +2313,36 @@ extension PolarBleApiImpl: PolarBleApi { let sortedFirmwarePackage = unzippedFirmwarePackage.sorted { (file1, file2) -> Bool in return PolarFirmwareUpdateUtils.FwFileComparator.compare(file1.key, file2.key) == .orderedAscending } - - return Observable.from(sortedFirmwarePackage) - .flatMap { fileEntry -> Observable in - let fileName = fileEntry.key - let firmwareBytes = fileEntry.value - let filePath = "/\(fileName)" - - return self.writeFirmwareToDevice(deviceId: identifier, firmwareFilePath: filePath, firmwareBytes: firmwareBytes) - .map { bytesWritten -> FirmwareUpdateStatus in - BleLogger.trace("Writing firmware update file \(fileName), bytes written: \(bytesWritten)/\(firmwareBytes.count) bytes") - return FirmwareUpdateStatus.writingFwUpdatePackage(details: "Writing firmware update file \(fileName), bytes written: \(bytesWritten)/\(firmwareBytes.count) bytes") + + return Completable.deferred { + BleLogger.trace("Performing factory reset while preserving pairing information") + return self.doFactoryReset(identifier, preservePairingInformation: true) + } + .andThen(Completable.deferred { + BleLogger.trace("Waiting for device session to open after factory reset") + return self.waitDeviceSessionWithPftpToOpen(deviceId: identifier, timeoutSeconds: Int(factoryResetMaxWaitTimeSeconds), waitForDeviceDownSeconds: 10) + }) + .andThen(Observable.deferred { + BleLogger.trace("Writing firmware update files: \(sortedFirmwarePackage.count)") + return Observable.from(sortedFirmwarePackage) + .concatMap { fileEntry -> Observable in + let fileName = fileEntry.key + let firmwareBytes = fileEntry.value + let filePath = "/\(fileName)" + + BleLogger.trace("Writing firmware update file \(fileName), size: \(firmwareBytes.count) bytes") + + return self.writeFirmwareToDevice(deviceId: identifier, firmwareFilePath: filePath, firmwareBytes: firmwareBytes) + .map { bytesWritten -> FirmwareUpdateStatus in + BleLogger.trace("writeFirmwareToDevice(): Writing firmware update file \(fileName), bytes written: \(bytesWritten)/\(firmwareBytes.count) bytes") + return FirmwareUpdateStatus.writingFwUpdatePackage(details: "Writing firmware update file \(fileName), bytes written: \(bytesWritten)/\(firmwareBytes.count) bytes") + } } - } - .concat(Observable.just(FirmwareUpdateStatus.finalizingFwUpdate(details: "Finalizing firmware update..."))) + .concat(Observable.deferred { + BleLogger.trace("Firmware update files written, finalizing firmware update") + return Observable.just(FirmwareUpdateStatus.finalizingFwUpdate(details: "Finalizing firmware update...")) + }) + }) } } .flatMap { status -> Observable in @@ -3057,56 +3073,54 @@ extension PolarBleApiImpl: PolarBleApi { } private func writeFirmwareToDevice(deviceId: String, firmwareFilePath: String, firmwareBytes: Data) -> Observable { - let factoryResetMaxWaitTimeSeconds: TimeInterval = 6 * 60 - BleLogger.trace("Write FW to device") - return doFactoryReset(deviceId, preservePairingInformation: true) - .andThen(waitDeviceSessionToOpen(deviceId: deviceId, timeoutSeconds: Int(factoryResetMaxWaitTimeSeconds), waitForDeviceDownSeconds: 10)) - .andThen(Observable.create { observer in - do { - let session = try self.sessionFtpClientReady(deviceId) - guard let client = session.fetchGattClient(BlePsFtpClient.PSFTP_SERVICE) as? BlePsFtpClient else { - throw PolarErrors.serviceNotFound - } + BleLogger.trace("writeFirmwareToDevice(): deviceId: \(deviceId), firmwareFilePath: \(firmwareFilePath)") + return Observable.create { observer in + do { + let session = try self.sessionFtpClientReady(deviceId) + guard let client = session.fetchGattClient(BlePsFtpClient.PSFTP_SERVICE) as? BlePsFtpClient else { + throw PolarErrors.serviceNotFound + } - BleLogger.trace("Initialize session") - self.sendInitializationAndStartSyncNotifications(client: client) - sleep(1) // Some race condition here? - BleLogger.trace("Start \(firmwareFilePath) write") - - var builder = Protocol_PbPFtpOperation() - builder.command = Protocol_PbPFtpOperation.Command.put - builder.path = firmwareFilePath - let proto = try builder.serializedData() - return client.write( - proto as NSData, - data: InputStream(data: firmwareBytes) - ) - .throttle(.seconds(5), scheduler: MainScheduler.instance) - .do(onNext: { bytesWritten in - BleLogger.trace("Writing firmware update file, bytes written: \(bytesWritten)/\(firmwareBytes.count)") - observer.onNext(UInt(bytesWritten)) - }) - .ignoreElements() - .asCompletable() - .subscribe(onCompleted: { - if firmwareFilePath.contains("SYSUPDAT.IMG") { - BleLogger.trace("Firmware file is SYSUPDAT.IMG, waiting for reboot") - } - observer.onCompleted() - }, onError: { error in - BleLogger.trace("ERROR: \(error.localizedDescription)") - if (error.localizedDescription.contains("ResponseError error 1")) { - observer.onCompleted() - } else { - BleLogger.trace("Error in writeFirmwareToDevice(): \(error.localizedDescription)") - observer.onError(error) - } - }) - } catch { + BleLogger.trace("writeFirmwareToDevice(): Initialize session") + self.sendInitializationAndStartSyncNotifications(client: client) + sleep(1) // Some race condition here? + BleLogger.trace("writeFirmwareToDevice(): Start \(firmwareFilePath) write") + + var builder = Protocol_PbPFtpOperation() + builder.command = Protocol_PbPFtpOperation.Command.put + builder.path = firmwareFilePath + let proto = try builder.serializedData() + return client.write( + proto as NSData, + data: InputStream(data: firmwareBytes) + ) + .throttle(.seconds(5), scheduler: MainScheduler.instance) + .do(onNext: { bytesWritten in + BleLogger.trace("Writing firmware update file, bytes written: \(bytesWritten)/\(firmwareBytes.count)") + observer.onNext(UInt(bytesWritten)) + }) + .ignoreElements() + .asCompletable() + .subscribe(onCompleted: { + if firmwareFilePath.contains("SYSUPDAT.IMG") { + BleLogger.trace("writeFirmwareToDevice(): Firmware file is SYSUPDAT.IMG, waiting for reboot") + } + observer.onCompleted() + }, onError: { error in + BleLogger.trace("writeFirmwareToDevice(): ERROR: \(error.localizedDescription)") + if (error.localizedDescription.contains("ResponseError error 1")) { + observer.onCompleted() + } else { + BleLogger.trace("writeFirmwareToDevice(): Error in writeFirmwareToDevice(): \(error.localizedDescription)") observer.onError(error) } - return Disposables.create() }) + } catch { + observer.onError(error) + } + + return Disposables.create() + } }