Merge pull request 'fix: live progress display + better disconnect resilience' (#11) from schwifty/fix-progress-and-reconnect into main
This commit is contained in:
commit
292821622e
2 changed files with 10 additions and 7 deletions
|
|
@ -182,7 +182,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
private var disconnectRetryCount = 0
|
private var disconnectRetryCount = 0
|
||||||
private static let MAX_CONNECTION_RETRIES = 3
|
private static let MAX_CONNECTION_RETRIES = 3
|
||||||
private static let MAX_DEVICE_INFO_RETRIES = 2
|
private static let MAX_DEVICE_INFO_RETRIES = 2
|
||||||
private static let MAX_DISCONNECT_RETRIES = 2
|
private static let MAX_DISCONNECT_RETRIES = 3
|
||||||
private var currentBeacon: DiscoveredBeacon?
|
private var currentBeacon: DiscoveredBeacon?
|
||||||
|
|
||||||
// Per-write timeout (matches Android's 5-second per-write timeout)
|
// Per-write timeout (matches Android's 5-second per-write timeout)
|
||||||
|
|
@ -241,8 +241,8 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
|
|
||||||
centralManager.connect(resolvedPeripheral, options: nil)
|
centralManager.connect(resolvedPeripheral, options: nil)
|
||||||
|
|
||||||
// Timeout after 30 seconds
|
// Timeout after 45 seconds (increased from 30s to accommodate 3 disconnect retries with backoff)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 30) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 45) { [weak self] in
|
||||||
if self?.state != .success && self?.state != .idle {
|
if self?.state != .success && self?.state != .idle {
|
||||||
self?.fail("Connection timeout", code: .connectionTimeout)
|
self?.fail("Connection timeout", code: .connectionTimeout)
|
||||||
}
|
}
|
||||||
|
|
@ -1114,6 +1114,9 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel any pending write timeout — disconnect supersedes it
|
||||||
|
cancelWriteTimeout()
|
||||||
|
|
||||||
// Unexpected disconnect during any active provisioning phase — retry with full reconnect
|
// Unexpected disconnect during any active provisioning phase — retry with full reconnect
|
||||||
let isActivePhase = (state == .discoveringServices || state == .authenticating || state == .writing || state == .verifying)
|
let isActivePhase = (state == .discoveringServices || state == .authenticating || state == .writing || state == .verifying)
|
||||||
if isActivePhase && disconnectRetryCount < BeaconProvisioner.MAX_DISCONNECT_RETRIES {
|
if isActivePhase && disconnectRetryCount < BeaconProvisioner.MAX_DISCONNECT_RETRIES {
|
||||||
|
|
@ -1131,7 +1134,7 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
|
||||||
responseBuffer.removeAll()
|
responseBuffer.removeAll()
|
||||||
state = .connecting
|
state = .connecting
|
||||||
|
|
||||||
let delay = Double(disconnectRetryCount) + 1.0 // 2s, 3s backoff
|
let delay = Double(disconnectRetryCount) + 2.0 // 3s, 4s, 5s backoff — give BLE time to settle
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
guard let self = self, let beacon = self.currentBeacon else { return }
|
guard let self = self, let beacon = self.currentBeacon else { return }
|
||||||
guard self.state == .connecting else { return }
|
guard self.state == .connecting else { return }
|
||||||
|
|
@ -1145,7 +1148,7 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
|
||||||
|
|
||||||
// All retries exhausted or disconnect in unexpected state — fail
|
// All retries exhausted or disconnect in unexpected state — fail
|
||||||
DebugLog.shared.log("BLE: UNEXPECTED disconnect — state=\(state) writeIdx=\(dxSmartWriteIndex) queueCount=\(dxSmartCommandQueue.count) authenticated=\(dxSmartAuthenticated) disconnectRetries=\(disconnectRetryCount)")
|
DebugLog.shared.log("BLE: UNEXPECTED disconnect — state=\(state) writeIdx=\(dxSmartWriteIndex) queueCount=\(dxSmartCommandQueue.count) authenticated=\(dxSmartAuthenticated) disconnectRetries=\(disconnectRetryCount)")
|
||||||
fail("Unexpected disconnect (state: \(state))", code: .disconnected)
|
fail("Beacon disconnected \(disconnectRetryCount + 1) times during \(state). Move closer to the beacon and try again.", code: .disconnected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -385,11 +385,11 @@ struct ScanView: View {
|
||||||
.font(.title3)
|
.font(.title3)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provisioning progress
|
// Provisioning progress — show live updates from provisioner
|
||||||
if isProvisioning {
|
if isProvisioning {
|
||||||
HStack {
|
HStack {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
Text(provisioningProgress)
|
Text(provisioner.progress.isEmpty ? provisioningProgress : provisioner.progress)
|
||||||
.font(.callout)
|
.font(.callout)
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue