Skip to content

Commit fc7e0fb

Browse files
authored
Merge pull request #378 from NordicSemiconductor/develop
Version 4.8.0
2 parents b0a042a + 710d9d9 commit fc7e0fb

File tree

14 files changed

+153
-50
lines changed

14 files changed

+153
-50
lines changed

Example/Pods/Pods.xcodeproj/project.pbxproj

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/Pods/Target Support Files/iOSDFULibrary-iOS/iOSDFULibrary-iOS-Info.plist

+20-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/Pods/Target Support Files/iOSDFULibrary-macOS/iOSDFULibrary-macOS-Info.plist

+20-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/iOSDFULibrary/View Controllers/DFUViewController.swift

+9
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,15 @@ class DFUViewController: UIViewController, CBCentralManagerDelegate, DFUServiceD
191191
dfuInitiator.delegate = self
192192
dfuInitiator.progressDelegate = self
193193
dfuInitiator.logger = self
194+
dfuInitiator.dataObjectPreparationDelay = 0.4 // sec
195+
196+
// Uncomment if you don't want resume feature in Secure DFU.
197+
// See: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library/pull/264
198+
// dfuInitiator.disableResume = true
199+
200+
// Uncomment only if Legacy DFU is us using address+1 in bootloader mode.
201+
// See: https://github.com/NordicSemiconductor/Android-DFU-Library/issues/262#issuecomment-665493850
202+
// dfuInitiator.forceScanningForNewAddressInLegacyDfu = true
194203

195204
// Here would be a good chance to change the UUIDs to your custom UUIDs
196205

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ let package = Package(
5656
dependencies: [
5757
.package(
5858
url: "https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library",
59-
.upToNextMajor(from: "<Desired Version, e.g. 4.7.2>")
59+
.upToNextMajor(from: "<Desired Version, e.g. 4.8.0>")
6060
)
6161
],
6262
targets: [.target(name: "<Your Target Name>", dependencies: ["NordicDFU"])]

changelog.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
### Changelog
2+
- **4.8.0**
3+
- Feature: Option to force scanning for Legacy DFU bootloader after jumping using Buttonless Service (#374).
4+
- Feature: Option to set connection timeout (#369).
5+
- Feature: Option to set data object preparation delay (#377).
6+
27
- **4.7.2**
38
- Improvement: Report error when bluetooth is turned off (#371).
49
- Bugfix: Fixed Carthage configuration (shared schemes) (#370).

iOSDFULibrary.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "iOSDFULibrary"
3-
s.version = "4.7.2"
3+
s.version = "4.8.0"
44
s.summary = "This repository contains a tested library for iOS 9+ devices to perform Device Firmware Update on the nRF5x devices"
55
s.description = <<-DESC
66
The nRF5x Series chips are flash-based SoCs, and as such they represent the most flexible solution available. A key feature of the nRF5x Series and their associated software architecture and S-Series SoftDevices is the possibility for Over-The-Air Device Firmware Upgrade (OTA-DFU). See Figure 1. OTA-DFU allows firmware upgrades to be issued and downloaded to products in the field via the cloud and so enables OEMs to fix bugs and introduce new features to products that are already out on the market. This brings added security and flexibility to product development when using the nRF5x Series SoCs.

iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift

+59
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,63 @@ import CoreBluetooth
168168
*/
169169
@objc public var forceDfu = false
170170

171+
/**
172+
By default, the Legacy DFU bootloader starting from SDK 7.1, when enabled using
173+
buttonless service, advertises with the same Bluetooth address as the application
174+
using direct advertisement. This complies with the Bluetooth specification.
175+
However, starting from iOS 13.x, iPhones and iPads use random addresses on each
176+
connection and do not expect direct advertising unless bonded. This causes thiose
177+
packets being missed and not reported to the library, making reconnection to the
178+
bootloader and proceeding with DFU impossible.
179+
A solution requires modifying either the bootloader not to use the direct advertising,
180+
or the application not to share the peer data with bootloader, in which case it will
181+
advertise undirectly using address +1, like it does when the switch to bootloader mode
182+
is initiated with a button. After such modification, setting this flag to true will make the
183+
library scan for the bootloader using `DFUPeripheralSelector`.
184+
185+
Setting this flag to true without modifying the booloader behavior will break the DFU,
186+
as the direct advertising packets are empty and will not pass the default
187+
`DFUPeripheralSelector`.
188+
189+
- since: 4.8.0
190+
*/
191+
@objc public var forceScanningForNewAddressInLegacyDfu = false
192+
193+
/**
194+
Connection timeout.
195+
196+
When the DFU target does not connect before the time runs out, a timeout error
197+
is reported.
198+
199+
- since: 4.8.0
200+
*/
201+
@objc public var connectionTimeout: TimeInterval = 10.0
202+
203+
/**
204+
Duration of a delay, that the service will wait before sending each data object in
205+
Secure DFU. The delay will be done after a data object is created, and before
206+
any data byte is sent. The default value is 0, which disables this feature for the
207+
second and following data objects, but the first one will be delayed by 0.4 sec.
208+
209+
It has been found, that a delay of at least 0.3 sec reduces the risk of packet lose
210+
(the bootloader needs some time to prepare flash memory) on DFU bootloader from
211+
SDK 15, 16 and 17. The delay does not have to be longer than 0.4 sec, as according to
212+
performed tests, such delay is sufficient.
213+
214+
The longer the delay, the more time DFU will take to complete (delay will be repeated for
215+
each data object (4096 bytes)). However, with too small delay a packet lose may occur,
216+
causing the service to enable PRN and set them to 1 making DFU process very, very slow
217+
(but reliable).
218+
219+
The recommended delay is from 0.3 to 0.4 second if your DFU bootloader is from
220+
SDK 15, 16 or 17. Older bootloaders do not need this delay.
221+
222+
This variable is ignored in Legacy DFU.
223+
224+
- since: 4.8.0
225+
*/
226+
@objc public var dataObjectPreparationDelay: TimeInterval = 0.0
227+
171228
/**
172229
In SDK 14.0.0 a new feature was added to the Buttonless DFU for non-bonded
173230
devices which allows to send a unique name to the device before it is switched
@@ -243,6 +300,8 @@ import CoreBluetooth
243300

244301
/**
245302
Disable the ability for the DFU process to resume from where it was.
303+
304+
- since: 4.3.0
246305
*/
247306
@objc public var disableResume: Bool = false
248307

iOSDFULibrary/Classes/Implementation/GenericDFU/DFUPeripheral.swift

+7-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,11 @@ internal class BaseDFUPeripheral<TD : BasePeripheralDelegate> : NSObject, BaseDF
112112
/// A flag set when upload has been aborted.
113113
fileprivate var aborted: Bool = false
114114
/// Connection timer cancels connection attempt if the device doesn't
115-
/// connect within 10 seconds.
115+
/// connect before the time runs out.
116116
private var connectionTimer: DispatchSourceTimer?
117+
/// Connection timeout.
118+
/// - since: 4.8.0
119+
private let connectionTimeout: TimeInterval
117120

118121
init(_ initiator: DFUServiceInitiator, _ logger: LoggerHelper) {
119122
self.centralManager = initiator.centralManager
@@ -122,6 +125,7 @@ internal class BaseDFUPeripheral<TD : BasePeripheralDelegate> : NSObject, BaseDF
122125
self.logger = logger
123126
self.experimentalButtonlessServiceInSecureDfuEnabled = initiator.enableUnsafeExperimentalButtonlessServiceInSecureDfu
124127
self.uuidHelper = initiator.uuidHelper
128+
self.connectionTimeout = initiator.connectionTimeout
125129

126130
super.init()
127131
}
@@ -470,11 +474,12 @@ internal class BaseDFUPeripheral<TD : BasePeripheralDelegate> : NSObject, BaseDF
470474
connectionTimer?.setEventHandler {
471475
if let peripheral = self.peripheral {
472476
self.connectionTimer?.cancel()
477+
self.logger.w("Connection timeout!")
473478
self.logger.d("centralManager.cancelPeripheralConnection(peripheral)")
474479
self.centralManager.cancelPeripheralConnection(peripheral)
475480
}
476481
}
477-
connectionTimer?.schedule(deadline: .now() + 10.0)
482+
connectionTimer?.schedule(deadline: .now() + connectionTimeout)
478483
connectionTimer?.resume()
479484
logger.d("centralManager.connect(peripheral, options: nil)")
480485
centralManager.connect(peripheral!, options: nil)

iOSDFULibrary/Classes/Implementation/LegacyDFU/DFU/LegacyDFUExecutor.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ internal class LegacyDFUExecutor : DFUExecutor, LegacyDFUPeripheralDelegate {
8181
delegate {
8282
$0.dfuStateDidChange(to: .enablingDfuMode)
8383
}
84-
peripheral.jumpToBootloader()
84+
peripheral.jumpToBootloader(
85+
forceNewAddress: initiator.forceScanningForNewAddressInLegacyDfu
86+
)
8587
} else {
8688
// The device is ready to proceed with DFU.
8789
peripheral.sendStartDfu(withFirmwareType: firmware.currentPartType,

iOSDFULibrary/Classes/Implementation/LegacyDFU/Peripherals/LegacyDFUPeripheral.swift

+5-2
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,13 @@ internal class LegacyDFUPeripheral : BaseCommonDFUPeripheral<LegacyDFUExecutor,
7777

7878
/**
7979
Switches target device to the DFU Bootloader mode.
80+
81+
- parameter forceNewAddress: Set to true if the bootloader is expected to adveritse
82+
with a different address than when in app mode.
8083
*/
81-
func jumpToBootloader() {
84+
func jumpToBootloader(forceNewAddress: Bool) {
8285
jumpingToBootloader = true
83-
newAddressExpected = dfuService!.newAddressExpected
86+
newAddressExpected = dfuService!.newAddressExpected || forceNewAddress
8487
dfuService!.jumpToBootloaderMode(
8588
// On success, the device gets disconnected and
8689
// `centralManager(_:didDisconnectPeripheral:error)` will be called.

iOSDFULibrary/Classes/Implementation/SecureDFU/DFU/SecureDFUExecutor.swift

+4-3
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,10 @@ internal class SecureDFUExecutor : DFUExecutor, SecureDFUPeripheralDelegate {
317317
logger.i("Data object \(currentRangeIdx + 1)/\(firmwareRanges!.count) created")
318318
// For SDK 15.x and 16 the bootloader needs some time before it's ready to receive data.
319319
// Otherwise, some packets may be discarded and the received checksum will not match.
320-
if currentRangeIdx == 0 {
321-
logger.d("wait(400)")
322-
initiator.queue.asyncAfter(deadline: .now() + .milliseconds(400)) {
320+
if currentRangeIdx == 0 || initiator.dataObjectPreparationDelay > 0 {
321+
let delay = initiator.dataObjectPreparationDelay > 0 ? initiator.dataObjectPreparationDelay : 0.4
322+
logger.d("wait(\(Int(delay * 1000))")
323+
initiator.queue.asyncAfter(deadline: .now() + delay) {
323324
self.sendDataObject(self.currentRangeIdx) // -> peripheralDidReceiveObject() will be called.
324325
}
325326
} else {

0 commit comments

Comments
 (0)