Compare commits
2 commits
e9b668cb20
...
34e8ea0bab
| Author | SHA1 | Date | |
|---|---|---|---|
| 34e8ea0bab | |||
| df6601c50b |
1 changed files with 37 additions and 2 deletions
|
|
@ -179,8 +179,10 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
// Connection retry state
|
// Connection retry state
|
||||||
private var connectionRetryCount = 0
|
private var connectionRetryCount = 0
|
||||||
private var deviceInfoRetryCount = 0
|
private var deviceInfoRetryCount = 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 var currentBeacon: DiscoveredBeacon?
|
private var currentBeacon: DiscoveredBeacon?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
|
|
@ -222,6 +224,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
self.isTerminating = false
|
self.isTerminating = false
|
||||||
self.connectionRetryCount = 0
|
self.connectionRetryCount = 0
|
||||||
self.deviceInfoRetryCount = 0
|
self.deviceInfoRetryCount = 0
|
||||||
|
self.disconnectRetryCount = 0
|
||||||
self.currentBeacon = beacon
|
self.currentBeacon = beacon
|
||||||
|
|
||||||
state = .connecting
|
state = .connecting
|
||||||
|
|
@ -270,6 +273,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
self.allDiscoveredServices.removeAll()
|
self.allDiscoveredServices.removeAll()
|
||||||
self.connectionRetryCount = 0
|
self.connectionRetryCount = 0
|
||||||
self.deviceInfoRetryCount = 0
|
self.deviceInfoRetryCount = 0
|
||||||
|
self.disconnectRetryCount = 0
|
||||||
self.isTerminating = false
|
self.isTerminating = false
|
||||||
self.currentBeacon = beacon
|
self.currentBeacon = beacon
|
||||||
self.servicesToExplore.removeAll()
|
self.servicesToExplore.removeAll()
|
||||||
|
|
@ -308,6 +312,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
isTerminating = false
|
isTerminating = false
|
||||||
connectionRetryCount = 0
|
connectionRetryCount = 0
|
||||||
deviceInfoRetryCount = 0
|
deviceInfoRetryCount = 0
|
||||||
|
disconnectRetryCount = 0
|
||||||
currentBeacon = nil
|
currentBeacon = nil
|
||||||
state = .idle
|
state = .idle
|
||||||
progress = ""
|
progress = ""
|
||||||
|
|
@ -888,6 +893,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
characteristics.removeAll()
|
characteristics.removeAll()
|
||||||
connectionRetryCount = 0
|
connectionRetryCount = 0
|
||||||
deviceInfoRetryCount = 0
|
deviceInfoRetryCount = 0
|
||||||
|
disconnectRetryCount = 0
|
||||||
currentBeacon = nil
|
currentBeacon = nil
|
||||||
operationMode = .provisioning
|
operationMode = .provisioning
|
||||||
state = .idle
|
state = .idle
|
||||||
|
|
@ -1019,6 +1025,7 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
|
||||||
dxSmartNotifySubscribed = false
|
dxSmartNotifySubscribed = false
|
||||||
dxSmartCommandQueue.removeAll()
|
dxSmartCommandQueue.removeAll()
|
||||||
dxSmartWriteIndex = 0
|
dxSmartWriteIndex = 0
|
||||||
|
passwordIndex = 0
|
||||||
characteristics.removeAll()
|
characteristics.removeAll()
|
||||||
responseBuffer.removeAll()
|
responseBuffer.removeAll()
|
||||||
state = .connecting
|
state = .connecting
|
||||||
|
|
@ -1034,8 +1041,36 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// All other disconnects are unexpected
|
// Unexpected disconnect during auth or writing — retry with full reconnect
|
||||||
DebugLog.shared.log("BLE: UNEXPECTED disconnect — state=\(state) writeIdx=\(dxSmartWriteIndex) queueCount=\(dxSmartCommandQueue.count) authenticated=\(dxSmartAuthenticated)")
|
if (state == .authenticating || state == .writing) && disconnectRetryCount < BeaconProvisioner.MAX_DISCONNECT_RETRIES {
|
||||||
|
disconnectRetryCount += 1
|
||||||
|
DebugLog.shared.log("BLE: Disconnect during \(state) — reconnecting (attempt \(disconnectRetryCount)/\(BeaconProvisioner.MAX_DISCONNECT_RETRIES))")
|
||||||
|
progress = "Beacon disconnected, reconnecting (\(disconnectRetryCount)/\(BeaconProvisioner.MAX_DISCONNECT_RETRIES))..."
|
||||||
|
|
||||||
|
// Reset connection state for clean reconnect
|
||||||
|
dxSmartAuthenticated = false
|
||||||
|
dxSmartNotifySubscribed = false
|
||||||
|
dxSmartCommandQueue.removeAll()
|
||||||
|
dxSmartWriteIndex = 0
|
||||||
|
passwordIndex = 0
|
||||||
|
characteristics.removeAll()
|
||||||
|
responseBuffer.removeAll()
|
||||||
|
state = .connecting
|
||||||
|
|
||||||
|
let delay = Double(disconnectRetryCount) + 1.0 // 2s, 3s backoff
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
|
||||||
|
guard let self = self, let beacon = self.currentBeacon else { return }
|
||||||
|
guard self.state == .connecting else { return }
|
||||||
|
let resolvedPeripheral = self.resolvePeripheral(beacon)
|
||||||
|
self.peripheral = resolvedPeripheral
|
||||||
|
resolvedPeripheral.delegate = self
|
||||||
|
self.centralManager.connect(resolvedPeripheral, options: nil)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)")
|
||||||
fail("Unexpected disconnect (state: \(state))", code: .disconnected)
|
fail("Unexpected disconnect (state: \(state))", code: .disconnected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue