Merge pull request 'fix: retry char discovery when FFE2 missing after disconnect' (#14) from schwifty/fix-ffe2-missing-after-disconnect into main
This commit is contained in:
commit
057a215a50
1 changed files with 30 additions and 1 deletions
|
|
@ -190,6 +190,8 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
// If a write callback doesn't come back in time, we retry or fail gracefully
|
// If a write callback doesn't come back in time, we retry or fail gracefully
|
||||||
// instead of hanging until the 30s global timeout
|
// instead of hanging until the 30s global timeout
|
||||||
private var writeTimeoutTimer: DispatchWorkItem?
|
private var writeTimeoutTimer: DispatchWorkItem?
|
||||||
|
private var charRediscoveryCount = 0
|
||||||
|
private static let MAX_CHAR_REDISCOVERY = 2
|
||||||
private static let WRITE_TIMEOUT_SECONDS: Double = 5.0
|
private static let WRITE_TIMEOUT_SECONDS: Double = 5.0
|
||||||
private var writeRetryCount = 0
|
private var writeRetryCount = 0
|
||||||
private static let MAX_WRITE_RETRIES = 1 // Retry once per command before failing
|
private static let MAX_WRITE_RETRIES = 1 // Retry once per command before failing
|
||||||
|
|
@ -336,6 +338,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
deviceInfoRetryCount = 0
|
deviceInfoRetryCount = 0
|
||||||
disconnectRetryCount = 0
|
disconnectRetryCount = 0
|
||||||
writeRetryCount = 0
|
writeRetryCount = 0
|
||||||
|
charRediscoveryCount = 0
|
||||||
currentBeacon = nil
|
currentBeacon = nil
|
||||||
state = .idle
|
state = .idle
|
||||||
progress = ""
|
progress = ""
|
||||||
|
|
@ -571,10 +574,29 @@ class BeaconProvisioner: NSObject, ObservableObject {
|
||||||
progress = "Writing config (\(current)/\(total))..."
|
progress = "Writing config (\(current)/\(total))..."
|
||||||
|
|
||||||
guard let commandChar = characteristics[BeaconProvisioner.DXSMART_COMMAND_CHAR] else {
|
guard let commandChar = characteristics[BeaconProvisioner.DXSMART_COMMAND_CHAR] else {
|
||||||
fail("DX-Smart command characteristic (FFE2) not found", code: .serviceNotFound)
|
// After disconnect+reconnect, characteristic discovery may return incomplete results.
|
||||||
|
// Re-discover characteristics instead of hard-failing.
|
||||||
|
if charRediscoveryCount < BeaconProvisioner.MAX_CHAR_REDISCOVERY, let service = configService {
|
||||||
|
charRediscoveryCount += 1
|
||||||
|
DebugLog.shared.log("BLE: FFE2 missing — re-discovering characteristics (attempt \(charRediscoveryCount)/\(BeaconProvisioner.MAX_CHAR_REDISCOVERY))")
|
||||||
|
progress = "Re-discovering characteristics..."
|
||||||
|
state = .discoveringServices
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
|
||||||
|
self?.peripheral?.discoverCharacteristics([
|
||||||
|
BeaconProvisioner.DXSMART_NOTIFY_CHAR,
|
||||||
|
BeaconProvisioner.DXSMART_COMMAND_CHAR,
|
||||||
|
BeaconProvisioner.DXSMART_PASSWORD_CHAR
|
||||||
|
], for: service)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail("DX-Smart command characteristic (FFE2) not found after \(charRediscoveryCount) rediscovery attempts", code: .serviceNotFound)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset rediscovery counter on successful characteristic access
|
||||||
|
charRediscoveryCount = 0
|
||||||
|
|
||||||
DebugLog.shared.log("BLE: Writing command \(current)/\(total): \(packet.map { String(format: "%02X", $0) }.joined(separator: " "))")
|
DebugLog.shared.log("BLE: Writing command \(current)/\(total): \(packet.map { String(format: "%02X", $0) }.joined(separator: " "))")
|
||||||
writeRetryCount = 0
|
writeRetryCount = 0
|
||||||
scheduleWriteTimeout()
|
scheduleWriteTimeout()
|
||||||
|
|
@ -1294,6 +1316,13 @@ extension BeaconProvisioner: CBPeripheralDelegate {
|
||||||
if operationMode == .readingConfig {
|
if operationMode == .readingConfig {
|
||||||
// Continue exploring next service
|
// Continue exploring next service
|
||||||
exploreNextService()
|
exploreNextService()
|
||||||
|
} else if charRediscoveryCount > 0 && dxSmartAuthenticated && !dxSmartCommandQueue.isEmpty {
|
||||||
|
// Rediscovery during active write — resume writing directly (already authenticated)
|
||||||
|
DebugLog.shared.log("BLE: Characteristics re-discovered after FFE2 miss — resuming write")
|
||||||
|
state = .writing
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
|
self?.dxSmartSendNextCommand()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Provisioning: DX-Smart auth flow
|
// Provisioning: DX-Smart auth flow
|
||||||
dxSmartStartAuth()
|
dxSmartStartAuth()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue