diff --git a/Cartfile b/Cartfile
new file mode 100644
index 00000000..7e96d16f
--- /dev/null
+++ b/Cartfile
@@ -0,0 +1 @@
+github "weichsel/ZIPFoundation" ~> 0.9
\ No newline at end of file
diff --git a/iOSDFULibrary/Classes/Implementation/DFUSelector/DFUServiceSelector.swift b/iOSDFULibrary/Classes/Implementation/DFUSelector/DFUServiceSelector.swift
index ee102b60..8b314f5a 100644
--- a/iOSDFULibrary/Classes/Implementation/DFUSelector/DFUServiceSelector.swift
+++ b/iOSDFULibrary/Classes/Implementation/DFUSelector/DFUServiceSelector.swift
@@ -44,22 +44,24 @@ internal class DFUServiceSelector : BaseDFUExecutor, DFUStarterPeripheralDelegat
typealias DFUPeripheralType = DFUStarterPeripheral
internal let initiator: DFUServiceInitiator
+ internal let logger: LoggerHelper
internal let controller: DFUServiceController
internal let peripheral: DFUStarterPeripheral
internal var error: (error: DFUError, message: String)?
init(initiator: DFUServiceInitiator, controller: DFUServiceController) {
self.initiator = initiator
+ self.logger = LoggerHelper(initiator.logger, initiator.loggerQueue)
self.controller = controller
- self.peripheral = DFUStarterPeripheral(initiator)
+ self.peripheral = DFUStarterPeripheral(initiator, logger)
self.peripheral.delegate = self
}
func start() {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .connecting)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .connecting)
+ }
peripheral.start()
}
@@ -67,7 +69,7 @@ internal class DFUServiceSelector : BaseDFUExecutor, DFUStarterPeripheralDelegat
// Release the cyclic reference
peripheral.destroy()
- let executor = ExecutorType.init(initiator)
+ let executor = ExecutorType.init(initiator, logger)
controller.executor = executor
executor.start()
}
diff --git a/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift b/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift
index 0e809af3..42cccf3f 100644
--- a/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift
+++ b/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift
@@ -35,6 +35,11 @@ import CoreBluetooth
internal var target : CBPeripheral!
internal var file : DFUFirmware?
+ internal var queue : DispatchQueue
+ internal var delegateQueue : DispatchQueue
+ internal var progressDelegateQueue : DispatchQueue
+ internal var loggerQueue : DispatchQueue
+
//MARK: - Public variables
/**
@@ -239,6 +244,10 @@ import CoreBluetooth
// Default UUID helper with standard set of UUIDs
self.uuidHelper = DFUUuidHelper()
+ self.queue = DispatchQueue.main
+ self.delegateQueue = DispatchQueue.main
+ self.progressDelegateQueue = DispatchQueue.main
+ self.loggerQueue = DispatchQueue.main
super.init()
}
@@ -246,14 +255,20 @@ import CoreBluetooth
Creates the DFUServiceInitializer that will allow to send an update to peripherals.
- parameter queue: The dispatch queue to run BLE operations on.
+ - parameter callbackQueue: The dispatch queue to invoke all delegate callbacks on.
+ - parameter progressQueue: The dispatch queue to invoke all progress delegate callbacks on.
+ - parameter loggerQueue: The dispatch queue to invoke all logger events on.
- returns: The initiator instance.
- - version: Added in version 4.2 of the iOS DFU Library.
+ - version: Added in version 4.2 of the iOS DFU Library. Extended in 4.3 to allow setting delegate queues.
- seeAlso: peripheralSelector property - a selector used when scanning for a device in DFU Bootloader mode
in case you want to update a Softdevice and Application from a single ZIP Distribution Packet.
*/
- @objc public init(queue: DispatchQueue? = nil) {
+ @objc public init(queue: DispatchQueue? = nil,
+ delegateQueue: DispatchQueue = DispatchQueue.main,
+ progressQueue: DispatchQueue = DispatchQueue.main,
+ loggerQueue: DispatchQueue = DispatchQueue.main) {
// Create a new instance of CBCentralManager
self.centralManager = CBCentralManager(delegate: nil, queue: queue)
// Default peripheral selector will choose the service UUID as a filter
@@ -261,6 +276,10 @@ import CoreBluetooth
// Default UUID helper with standard set of UUIDs
self.uuidHelper = DFUUuidHelper()
+ self.queue = queue ?? DispatchQueue.main
+ self.delegateQueue = delegateQueue
+ self.progressDelegateQueue = progressQueue
+ self.loggerQueue = loggerQueue
super.init()
}
diff --git a/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUExecutor.swift b/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUExecutor.swift
index 305ebdee..69e23fbe 100644
--- a/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUExecutor.swift
+++ b/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUExecutor.swift
@@ -22,6 +22,8 @@
import CoreBluetooth
+typealias DelegateCallback = (DFUServiceDelegate) -> Void
+
internal protocol BaseExecutorAPI : class, DFUController {
/**
@@ -33,28 +35,18 @@ internal protocol BaseExecutorAPI : class, DFUController {
internal protocol BaseDFUExecutor : BaseExecutorAPI, BasePeripheralDelegate {
associatedtype DFUPeripheralType : BaseDFUPeripheralAPI
- /// Target peripheral object
+ /// Target peripheral object.
var peripheral: DFUPeripheralType { get }
/// The DFU Service Initiator instance that was used to start the service.
var initiator: DFUServiceInitiator { get }
+ /// The optional logger delegate.
+ var logger: LoggerHelper { get }
/// If an error occurred it is set as this variable. It will be reported to the user when the device gets disconnected.
var error: (error: DFUError, message: String)? { set get }
}
extension BaseDFUExecutor {
- /// The service delegate will be informed about status changes and errors.
- internal var delegate: DFUServiceDelegate? {
- // The delegate may change during DFU operation (by setting a new one in the initiator). Let's always use the current one.
- return initiator.delegate
- }
-
- /// The progress delegate will be informed about current upload progress.
- internal var progressDelegate: DFUProgressDelegate? {
- // The delegate may change during DFU operation (by setting a new one in the initiator). Let's always use the current one.
- return initiator.progressDelegate
- }
-
// MARK: - DFU Controller API
func pause() -> Bool {
@@ -72,38 +64,38 @@ extension BaseDFUExecutor {
// MARK: - BasePeripheralDelegate API
func peripheralDidFailToConnect() {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuError(.failedToConnect, didOccurWithMessage: "Device failed to connect")
- })
+ delegate {
+ $0.dfuError(.failedToConnect, didOccurWithMessage: "Device failed to connect")
+ }
// Release the cyclic reference
peripheral.destroy()
}
func peripheralDidDisconnect() {
// The device is now disconnected. Check if there was an error that needs to be reported now
- DispatchQueue.main.async(execute: {
+ delegate {
if let error = self.error {
- self.delegate?.dfuError(error.error, didOccurWithMessage: error.message)
+ $0.dfuError(error.error, didOccurWithMessage: error.message)
} else {
- self.delegate?.dfuError(.deviceDisconnected, didOccurWithMessage: "Device disconnected unexpectedly")
+ $0.dfuError(.deviceDisconnected, didOccurWithMessage: "Device disconnected unexpectedly")
}
- })
+ }
// Release the cyclic reference
peripheral.destroy()
}
func peripheralDidDisconnect(withError error: Error) {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuError(.deviceDisconnected, didOccurWithMessage: "\(error.localizedDescription) (code: \((error as NSError).code))")
- })
+ delegate {
+ $0.dfuError(.deviceDisconnected, didOccurWithMessage: "\(error.localizedDescription) (code: \((error as NSError).code))")
+ }
// Release the cyclic reference
peripheral.destroy()
}
func peripheralDidDisconnectAfterAborting() {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .aborted)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .aborted)
+ }
// Release the cyclic reference
peripheral.destroy()
}
@@ -118,21 +110,27 @@ extension BaseDFUExecutor {
// MARK: - Helper functions
- func logWith(_ level: LogLevel, message: String) {
- initiator.logger?.logWith(level, message: message)
+ /// Calls the delegate method on the delegate queue given in the initiator.
+ func delegate(callback: @escaping DelegateCallback) {
+ if let delegate = initiator.delegate {
+ initiator.delegateQueue.async {
+ callback(delegate)
+ }
+ }
}
}
// MARK: -
internal protocol DFUExecutorAPI : BaseExecutorAPI {
- /// Required constructor
- init(_ initiator: DFUServiceInitiator)
+
+ /// Required constructor.
+ init(_ initiator: DFUServiceInitiator, _ logger: LoggerHelper)
}
internal protocol DFUExecutor : DFUExecutorAPI, BaseDFUExecutor, DFUPeripheralDelegate where DFUPeripheralType: DFUPeripheralAPI {
- /// The firmware to be sent over-the-air
+ /// The firmware to be sent over-the-air.
var firmware: DFUFirmware { get }
}
@@ -144,16 +142,15 @@ extension DFUExecutor {
// Check if there is another part of the firmware that has to be sent
if firmware.hasNextPart() {
firmware.switchToNextPart()
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .connecting)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .connecting)
+ }
return true
}
// If not, we are done here. Congratulations!
- DispatchQueue.main.async(execute: {
- // If no, the DFU operation is complete
- self.delegate?.dfuStateDidChange(to: .completed)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .completed)
+ }
// Release the cyclic reference
peripheral.destroy()
diff --git a/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUPeripheral.swift b/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUPeripheral.swift
index 9f1edb4b..1cebd345 100644
--- a/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUPeripheral.swift
+++ b/iOSDFULibrary/Classes/Implementation/GenericDFU/DFUPeripheral.swift
@@ -50,6 +50,7 @@ internal protocol BaseDFUPeripheralAPI : class, DFUController {
internal class BaseDFUPeripheral
: NSObject, BaseDFUPeripheralAPI, CBPeripheralDelegate, CBCentralManagerDelegate {
/// Bluetooth Central Manager used to scan for the peripheral.
internal let centralManager: CBCentralManager
+ internal let queue: DispatchQueue
/// The DFU Target peripheral.
internal var peripheral: CBPeripheral?
/// The peripheral delegate.
@@ -86,9 +87,10 @@ internal class BaseDFUPeripheral | : NSObject, BaseDF
/// A flag set when upload has been aborted.
fileprivate var aborted: Bool = false
- init(_ initiator: DFUServiceInitiator) {
+ init(_ initiator: DFUServiceInitiator, _ logger: LoggerHelper) {
self.centralManager = initiator.centralManager
- self.logger = LoggerHelper(initiator.logger)
+ self.queue = initiator.queue
+ self.logger = logger
self.experimentalButtonlessServiceInSecureDfuEnabled = initiator.enableUnsafeExperimentalButtonlessServiceInSecureDfu
self.uuidHelper = initiator.uuidHelper
@@ -487,15 +489,15 @@ internal class BaseCommonDFUPeripheral | 0 {
- logWith(.warning, message: "Retrying...")
+ logger.w("Retrying...")
invalidStateRetryCount -= 1
peripheral.start()
} else {
@@ -133,14 +135,14 @@ internal class LegacyDFUExecutor : DFUExecutor, LegacyDFUPeripheralDelegate {
Sends the current part of the firmware to the target DFU device.
*/
private func sendFirmware() {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .uploading)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .uploading)
+ }
// First the service will send the number of packets of firmware data to be received
// by the DFU target before sending a new Packet Receipt Notification.
// After receiving status Success it will send the firmware.
peripheral.sendFirmware(firmware,
withPacketReceiptNotificationNumber: initiator.packetReceiptNotificationParameter,
- andReportProgressTo: progressDelegate)
+ andReportProgressTo: initiator.progressDelegate, on: initiator.progressDelegateQueue)
}
}
diff --git a/iOSDFULibrary/Classes/Implementation/LegacyDFU/DFU/LegacyDFUServiceInitiator.swift b/iOSDFULibrary/Classes/Implementation/LegacyDFU/DFU/LegacyDFUServiceInitiator.swift
index e0fdd4c7..076921fd 100644
--- a/iOSDFULibrary/Classes/Implementation/LegacyDFU/DFU/LegacyDFUServiceInitiator.swift
+++ b/iOSDFULibrary/Classes/Implementation/LegacyDFU/DFU/LegacyDFUServiceInitiator.swift
@@ -31,7 +31,8 @@ import CoreBluetooth
return nil
}
- let executor = LegacyDFUExecutor(self)
+ let logger = LoggerHelper(self.logger, loggerQueue)
+ let executor = LegacyDFUExecutor(self, logger)
let controller = DFUServiceController()
controller.executor = executor
executor.start()
diff --git a/iOSDFULibrary/Classes/Implementation/LegacyDFU/Peripherals/LegacyDFUPeripheral.swift b/iOSDFULibrary/Classes/Implementation/LegacyDFU/Peripherals/LegacyDFUPeripheral.swift
index 5a57e970..ed6ed4c9 100644
--- a/iOSDFULibrary/Classes/Implementation/LegacyDFU/Peripherals/LegacyDFUPeripheral.swift
+++ b/iOSDFULibrary/Classes/Implementation/LegacyDFU/Peripherals/LegacyDFUPeripheral.swift
@@ -149,8 +149,10 @@ internal class LegacyDFUPeripheral : BaseCommonDFUPeripheral 2) {
prn = 2
@@ -158,7 +160,8 @@ internal class LegacyDFUPeripheral : BaseCommonDFUPeripheral 0 it will receive Packet Receit Notifications
@@ -419,6 +427,7 @@ import CoreBluetooth
self.firmware = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
success()
},
onPacketReceiptNofitication: {
@@ -436,7 +445,8 @@ import CoreBluetooth
let bytesSent = self.dfuPacketCharacteristic!.bytesSent
// Due to https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library/issues/54 only 16 least significant bits are verified
if peripheralIsReadyToSendWriteWithoutRequest || (bytesSent & 0xFFFF) == (bytesReceived! & 0xFFFF) {
- self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber, packetsOf: firmware, andReportProgressTo: progress)
+ self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber, packetsOf: firmware,
+ andReportProgressTo: progress, on: queue)
} else {
// Target device deported invalid number of bytes received
report(.bytesLost, "\(bytesSent) bytes were sent while \(bytesReceived!) bytes were reported as received")
@@ -446,6 +456,7 @@ import CoreBluetooth
self.firmware = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
self.sendReset(onError: report)
}
},
@@ -455,6 +466,7 @@ import CoreBluetooth
self.firmware = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
report(error, message)
}
)
@@ -463,12 +475,13 @@ import CoreBluetooth
let start = {
self.logger.a("Uploading firmware...")
self.logger.v("Sending firmware to DFU Packet characteristic...")
- self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber, packetsOf: firmware, andReportProgressTo: progress)
+ self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber, packetsOf: firmware,
+ andReportProgressTo: progress, on: queue)
}
// On devices running SDK 6.0 or older a delay is required before the device is ready to receive data
if delay {
self.logger.d("wait(1000)")
- DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000), execute: start)
+ queue.asyncAfter(deadline: .now() + .milliseconds(1000), execute: start)
} else {
start()
}
@@ -477,6 +490,7 @@ import CoreBluetooth
self.firmware = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
self.sendReset(onError: report)
}
},
diff --git a/iOSDFULibrary/Classes/Implementation/SecureDFU/Characteristics/SecureDFUPacket.swift b/iOSDFULibrary/Classes/Implementation/SecureDFU/Characteristics/SecureDFUPacket.swift
index 8a5ed641..e88b0676 100644
--- a/iOSDFULibrary/Classes/Implementation/SecureDFU/Characteristics/SecureDFUPacket.swift
+++ b/iOSDFULibrary/Classes/Implementation/SecureDFU/Characteristics/SecureDFUPacket.swift
@@ -96,10 +96,12 @@ internal class SecureDFUPacket: DFUCharacteristic {
- range: The range of the firmware that is to be sent in this object.
- firmware: The whole firmware to be sent in this part.
- progress: An optional progress delegate.
+ - queue: The queue to dispatch progress events on.
- complete: The completon callback.
*/
func sendNext(_ prnValue: UInt16, packetsFrom range: Range, of firmware: DFUFirmware,
- andReportProgressTo progress: DFUProgressDelegate?, andCompletionTo complete: @escaping Callback) {
+ andReportProgressTo progress: DFUProgressDelegate?, on queue: DispatchQueue,
+ andCompletionTo complete: @escaping Callback) {
let peripheral = characteristic.service.peripheral
let objectData = firmware.data.subdata(in: range)
let objectSizeInBytes = UInt32(objectData.count)
@@ -129,7 +131,7 @@ internal class SecureDFUPacket: DFUCharacteristic {
totalBytesSentSinceProgessNotification = totalBytesSentWhenDfuStarted
// Notify progress delegate that upload has started (0%)
- DispatchQueue.main.async(execute: {
+ queue.async(execute: {
progress?.dfuProgressDidChange(
for: firmware.currentPart,
outOf: firmware.parts,
@@ -174,7 +176,7 @@ internal class SecureDFUPacket: DFUCharacteristic {
totalBytesSentSinceProgessNotification = totalBytesSent
// Notify progress delegate of overall progress
- DispatchQueue.main.async(execute: {
+ queue.async(execute: {
progress?.dfuProgressDidChange(
for: firmware.currentPart,
outOf: firmware.parts,
diff --git a/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUExecutor.swift b/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUExecutor.swift
index 1cb9c708..2c763800 100644
--- a/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUExecutor.swift
+++ b/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUExecutor.swift
@@ -25,6 +25,7 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
typealias DFUPeripheralType = SecureDFUPeripheral
internal let initiator : DFUServiceInitiator
+ internal let logger : LoggerHelper
internal let peripheral : SecureDFUPeripheral
internal var firmware : DFUFirmware
internal var error : (error: DFUError, message: String)?
@@ -45,10 +46,11 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
private var retryCount: Int
// MARK: - Initialization
- required init(_ initiator: DFUServiceInitiator) {
+ required init(_ initiator: DFUServiceInitiator, _ logger: LoggerHelper) {
self.initiator = initiator
+ self.logger = logger
self.firmware = initiator.file!
- self.peripheral = SecureDFUPeripheral(initiator)
+ self.peripheral = SecureDFUPeripheral(initiator, logger)
self.retryCount = MaxRetryCount
}
@@ -68,18 +70,18 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
}
resetFirmwareRanges()
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .starting)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .starting)
+ }
peripheral.enableControlPoint() // -> peripheralDidEnableControlPoint() will be called when done
}
func peripheralDidEnableControlPoint() {
// Check whether the target is in application or bootloader mode
if peripheral.isInApplicationMode(initiator.forceDfu) {
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .enablingDfuMode)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .enablingDfuMode)
+ }
peripheral.jumpToBootloader() // -> peripheralDidBecomeReady() will be called again, when connected to the Bootloader
} else {
// The device is ready to proceed with DFU
@@ -100,13 +102,13 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
if !initiator.disableResume && verifyCRC(for: firmware.initPacket!, andPacketOffset: offset, matches: crc) {
// Resume sending Init Packet
if offset < UInt32(firmware.initPacket!.count) {
- logWith(.application, message: "Resuming sending Init packet...")
+ logger.a("Resuming sending Init packet...")
// We need to send rest of the Init packet, but before that let's make sure the PRNs are disabled
peripheral.setPRNValue(0) // -> peripheralDidSetPRNValue() will be called
} else {
// The same Init Packet was already sent. We must execute it, as it may have not been executed before.
- logWith(.application, message: "Received CRC match Init packet")
+ logger.a("Received CRC match Init packet")
peripheral.sendExecuteCommand(forCommandObject: true) // -> peripheralDidExecuteObject() or peripheralRejectedCommandObject(...) will be called
}
} else {
@@ -138,7 +140,7 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
}
func peripheralDidReceiveInitPacket() {
- logWith(.application, message: String(format: "Command object sent (CRC = %08X)", CRC32(data: firmware.initPacket!).crc))
+ logger.a(String(format: "Command object sent (CRC = %08X)", CRC32(data: firmware.initPacket!).crc))
// Init Packet sent. Let's check the CRC before executing it.
peripheral.sendCalculateChecksumCommand() // -> peripheralDidSendChecksum(...) will be called
@@ -189,7 +191,7 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
if firmware.hasNextPart() {
firmware.switchToNextPart()
- logWith(.warning, message: "Invalid system components. Trying to send application")
+ logger.w("Invalid system components. Trying to send application")
// New Init Packet has to be sent. Create the Command object.
offset = 0
@@ -202,14 +204,14 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
func peripheralDidExecuteObject() {
if initPacketSent == false {
- logWith(.application, message: "Command object executed")
+ logger.a("Command object executed")
initPacketSent = true
// Set the correct PRN value. If initiator.packetReceiptNotificationParameter is 0
// and PRNs were already disabled to send the Init packet, this method will immediately
// call peripheralDidSetPRNValue() callback.
peripheral.setPRNValue(initiator.packetReceiptNotificationParameter) // -> peripheralDidSetPRNValue() will be called
} else {
- logWith(.application, message: "Data object executed")
+ logger.a("Data object executed")
if firmwareSent == false {
currentRangeIdx += 1
@@ -218,11 +220,11 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
// The last data object was sent
// Now the device will reset itself and onTransferCompleted() method will ba called (from the extension)
let interval = CFAbsoluteTimeGetCurrent() - uploadStartTime! as CFTimeInterval
- logWith(.application, message: "Upload completed in \(interval.format(".2")) seconds")
+ logger.a("Upload completed in \(interval.format(".2")) seconds")
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .disconnecting)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .disconnecting)
+ }
}
}
}
@@ -240,9 +242,9 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
currentRangeIdx = 0
}
- DispatchQueue.main.async(execute: {
- self.delegate?.dfuStateDidChange(to: .uploading)
- })
+ delegate {
+ $0.dfuStateDidChange(to: .uploading)
+ }
if offset > 0 {
// Find the current range index.
@@ -255,13 +257,13 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
}
if verifyCRC(for: firmware.data, andPacketOffset: offset, matches: crc) {
- logWith(.info, message: "\(offset) bytes of data sent before, CRC match")
+ logger.i("\(offset) bytes of data sent before, CRC match")
// Did we sent the whole firmware?
if offset == UInt32(firmware.data.count) {
firmwareSent = true
peripheral.sendExecuteCommand(andActivateIf: firmwareSent) // -> peripheralDidExecuteObject() will be called
} else {
- logWith(.info, message: "Resuming uploading firmware...")
+ logger.i("Resuming uploading firmware...")
// If the whole object was sent before, make sure it's executed
if (offset % maxLen) == 0 {
@@ -290,7 +292,7 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
}
func peripheralDidCreateDataObject() {
- logWith(.info, message: "Data object \(currentRangeIdx + 1)/\(firmwareRanges!.count) created")
+ logger.i("Data object \(currentRangeIdx + 1)/\(firmwareRanges!.count) created")
sendDataObject(currentRangeIdx) // -> peripheralDidReceiveObject() will be called
}
@@ -303,10 +305,10 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
private func retryOrReportCrcError(_ operation:()->()) {
retryCount -= 1
if retryCount > 0 {
- logWith(.warning, message: "CRC does not match! Retrying...")
+ logger.w("CRC does not match! Retrying...")
operation()
} else {
- logWith(.error, message: "CRC does not match!")
+ logger.e("CRC does not match!")
error(.crcError, didOccurWithMessage: "Sending firmware failed")
}
}
@@ -427,7 +429,8 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
aRange = Int(resumeOffset) ..< newLength + Int(resumeOffset)
}
- peripheral.sendNextObject(from: aRange, of: firmware, andReportProgressTo: progressDelegate)
+ peripheral.sendNextObject(from: aRange, of: firmware,
+ andReportProgressTo: initiator.progressDelegate, on: initiator.progressDelegateQueue)
// -> peripheralDidReceiveObject() will be called
}
}
diff --git a/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUServiceInitiator.swift b/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUServiceInitiator.swift
index 65496cee..a9763d1c 100644
--- a/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUServiceInitiator.swift
+++ b/iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUServiceInitiator.swift
@@ -31,7 +31,8 @@ import CoreBluetooth
return nil
}
- let executor = SecureDFUExecutor(self)
+ let logger = LoggerHelper(self.logger, loggerQueue)
+ let executor = SecureDFUExecutor(self, logger)
let controller = DFUServiceController()
controller.executor = executor
executor.start()
diff --git a/iOSDFULibrary/Classes/Implementation/SecureDFU/Peripheral/SecureDFUPeripheral.swift b/iOSDFULibrary/Classes/Implementation/SecureDFU/Peripheral/SecureDFUPeripheral.swift
index 1f0b061f..504050b4 100644
--- a/iOSDFULibrary/Classes/Implementation/SecureDFU/Peripheral/SecureDFUPeripheral.swift
+++ b/iOSDFULibrary/Classes/Implementation/SecureDFU/Peripheral/SecureDFUPeripheral.swift
@@ -40,9 +40,9 @@ internal class SecureDFUPeripheral : BaseCommonDFUPeripheral, of firmware: DFUFirmware, andReportProgressTo progress: DFUProgressDelegate?) {
- dfuService!.sendNextObject(from: range, of: firmware, andReportProgressTo: progress,
+ func sendNextObject(from range: Range, of firmware: DFUFirmware,
+ andReportProgressTo progress: DFUProgressDelegate?, on queue: DispatchQueue) {
+ dfuService!.sendNextObject(from: range, of: firmware,
+ andReportProgressTo: progress, on: queue,
onSuccess: { self.delegate?.peripheralDidReceiveObject() },
onError: defaultErrorCallback
)
diff --git a/iOSDFULibrary/Classes/Implementation/SecureDFU/Services/SecureDFUService.swift b/iOSDFULibrary/Classes/Implementation/SecureDFU/Services/SecureDFUService.swift
index ad6d920b..6c75d845 100644
--- a/iOSDFULibrary/Classes/Implementation/SecureDFU/Services/SecureDFUService.swift
+++ b/iOSDFULibrary/Classes/Implementation/SecureDFU/Services/SecureDFUService.swift
@@ -24,6 +24,7 @@ import CoreBluetooth
@objc internal class SecureDFUService : NSObject, CBPeripheralDelegate, DFUService {
+ internal let queue: DispatchQueue
internal var targetPeripheral: DFUPeripheralAPI?
internal var uuidHelper: DFUUuidHelper
@@ -47,6 +48,7 @@ import CoreBluetooth
private var report : ErrorCallback?
/// A temporaty callback used to report progress status.
private var progressDelegate : DFUProgressDelegate?
+ private var progressQueue : DispatchQueue?
// -- Properties stored when upload started in order to resume it --
private var firmware: DFUFirmware?
@@ -56,10 +58,11 @@ import CoreBluetooth
// MARK: - Initialization
- required init(_ service: CBService, _ logger: LoggerHelper, _ uuidHelper: DFUUuidHelper) {
+ required init(_ service: CBService, _ logger: LoggerHelper, _ uuidHelper: DFUUuidHelper, _ queue: DispatchQueue) {
self.service = service
self.logger = logger
self.uuidHelper = uuidHelper
+ self.queue = queue
super.init()
self.logger.v("Secure DFU Service found")
@@ -84,7 +87,8 @@ import CoreBluetooth
if !aborted && paused && firmware != nil {
paused = false
dfuPacketCharacteristic!.sendNext(packetReceiptNotificationNumber ?? 0, packetsFrom: range!, of: firmware!,
- andReportProgressTo: progressDelegate, andCompletionTo: success!)
+ andReportProgressTo: progressDelegate, on: progressQueue!,
+ andCompletionTo: success!)
return paused
}
paused = false
@@ -102,6 +106,7 @@ import CoreBluetooth
success = nil
report = nil
progressDelegate = nil
+ progressQueue = nil
// Upload has been aborted. Reset the target device. It will disconnect automatically
sendReset(onError: _report)
}
@@ -294,13 +299,15 @@ import CoreBluetooth
/**
Sends the next object of firmware. Result it reported using callbacks.
- - parameter aRange: Given range of the firmware will be sent.
- - parameter aFirmware: The firmware from with part is to be sent.
+ - parameter range: Given range of the firmware will be sent.
+ - parameter firmware: The firmware from with part is to be sent.
- parameter progressDelegate: An optional progress delegate.
+ - parameter queue: The queue to dispatch progress events on.
- parameter success: Method called when the object was sent.
- parameter report: Method called when an error occurred.
*/
- func sendNextObject(from aRange: Range, of aFirmware: DFUFirmware, andReportProgressTo progressDelegate: DFUProgressDelegate?,
+ func sendNextObject(from range: Range, of firmware: DFUFirmware,
+ andReportProgressTo progressDelegate: DFUProgressDelegate?, on queue: DispatchQueue,
onSuccess success: @escaping Callback, onError report: @escaping ErrorCallback) {
guard !aborted else {
sendReset(onError: report)
@@ -308,9 +315,10 @@ import CoreBluetooth
}
// Those will be stored here in case of pause/resume
- self.firmware = aFirmware
- self.range = aRange
+ self.firmware = firmware
+ self.range = range
self.progressDelegate = progressDelegate
+ self.progressQueue = queue
self.report = {
error, message in
@@ -319,6 +327,7 @@ import CoreBluetooth
self.success = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
report(error, message)
}
self.success = {
@@ -327,6 +336,7 @@ import CoreBluetooth
self.success = nil
self.report = nil
self.progressDelegate = nil
+ self.progressQueue = nil
self.dfuControlPointCharacteristic!.peripheralDidReceiveObject()
success()
} as Callback
@@ -341,10 +351,11 @@ import CoreBluetooth
}
if !self.paused && !self.aborted {
- let bytesSent = self.dfuPacketCharacteristic!.bytesSent + UInt32(aRange.lowerBound)
+ let bytesSent = self.dfuPacketCharacteristic!.bytesSent + UInt32(range.lowerBound)
if peripheralIsReadyToSendWriteWithoutRequest || bytesSent == bytesReceived! {
- self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber ?? 0, packetsFrom: aRange, of: aFirmware,
- andReportProgressTo: progressDelegate, andCompletionTo: self.success!)
+ self.dfuPacketCharacteristic!.sendNext(self.packetReceiptNotificationNumber ?? 0, packetsFrom: range, of: firmware,
+ andReportProgressTo: progressDelegate, on: queue,
+ andCompletionTo: self.success!)
} else {
// Target device deported invalid number of bytes received
report(.bytesLost, "\(bytesSent) bytes were sent while \(bytesReceived!) bytes were reported as received")
@@ -365,8 +376,9 @@ import CoreBluetooth
if !paused && !aborted {
// ...and start sending firmware if
- dfuPacketCharacteristic!.sendNext(packetReceiptNotificationNumber ?? 0, packetsFrom: aRange, of: aFirmware,
- andReportProgressTo: progressDelegate, andCompletionTo: self.success!)
+ dfuPacketCharacteristic!.sendNext(packetReceiptNotificationNumber ?? 0, packetsFrom: range, of: firmware,
+ andReportProgressTo: progressDelegate, on: queue,
+ andCompletionTo: self.success!)
} else if aborted {
self.firmware = nil
self.range = nil
diff --git a/iOSDFULibrary/Classes/Utilities/Logging/LoggerHelper.swift b/iOSDFULibrary/Classes/Utilities/Logging/LoggerHelper.swift
index 9a11b027..5b99e8b8 100644
--- a/iOSDFULibrary/Classes/Utilities/Logging/LoggerHelper.swift
+++ b/iOSDFULibrary/Classes/Utilities/Logging/LoggerHelper.swift
@@ -23,40 +23,50 @@ import Foundation
class LoggerHelper {
private weak var logger: LoggerDelegate?
+ private var queue: DispatchQueue
- init(_ logger: LoggerDelegate?) {
+ init(_ logger: LoggerDelegate?, _ queue: DispatchQueue) {
self.logger = logger
+ self.queue = queue
}
func d(_ message: String) {
- logger?.logWith(.debug, message: message)
+ log(with: .debug, message: message)
}
func v(_ message: String) {
- logger?.logWith(.verbose, message: message)
+ log(with: .verbose, message: message)
}
func i(_ message: String) {
- logger?.logWith(.info, message: message)
+ log(with: .info, message: message)
}
func a(_ message: String) {
- logger?.logWith(.application, message: message)
+ log(with: .application, message: message)
}
func w(_ message: String) {
- logger?.logWith(.warning, message: message)
+ log(with: .warning, message: message)
}
func e(_ message: String) {
- logger?.logWith(.error, message: message)
+ log(with: .error, message: message)
}
func w(_ error: Error) {
- logger?.logWith(.warning, message: "Error \((error as NSError).code): \(error.localizedDescription)")
+ log(with: .warning, message: "Error \((error as NSError).code): \(error.localizedDescription)")
}
func e(_ error: Error) {
- logger?.logWith(.error, message: "Error \((error as NSError).code): \(error.localizedDescription)")
+ log(with: .error, message: "Error \((error as NSError).code): \(error.localizedDescription)")
+ }
+
+ private func log(with level: LogLevel, message: String) {
+ if let logger = logger {
+ queue.async {
+ logger.logWith(level, message: message)
+ }
+ }
}
}
|