fix: use dedicated retry counter for device info disconnect

The device info disconnect handler was sharing connectionRetryCount with
the initial connection retry logic. If earlier connection attempts burned
through retries, the device info handler had zero retries left and
immediately hit "retries exhausted" — causing the "Disconnected while
reading device information" error John reported.

Now uses a separate deviceInfoRetryCount (max 2) so device info retries
are independent of connection retries.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Schwifty 2026-03-21 23:35:15 +00:00
parent 3d56a1e31d
commit 64e3684209

View file

@ -178,7 +178,9 @@ class BeaconProvisioner: NSObject, ObservableObject {
// Connection retry state // Connection retry state
private var connectionRetryCount = 0 private var connectionRetryCount = 0
private var deviceInfoRetryCount = 0
private static let MAX_CONNECTION_RETRIES = 3 private static let MAX_CONNECTION_RETRIES = 3
private static let MAX_DEVICE_INFO_RETRIES = 2
private var currentBeacon: DiscoveredBeacon? private var currentBeacon: DiscoveredBeacon?
override init() { override init() {
@ -219,6 +221,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
self.skipDeviceInfoRead = false self.skipDeviceInfoRead = false
self.isTerminating = false self.isTerminating = false
self.connectionRetryCount = 0 self.connectionRetryCount = 0
self.deviceInfoRetryCount = 0
self.currentBeacon = beacon self.currentBeacon = beacon
state = .connecting state = .connecting
@ -266,6 +269,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
self.dxReadQueryIndex = 0 self.dxReadQueryIndex = 0
self.allDiscoveredServices.removeAll() self.allDiscoveredServices.removeAll()
self.connectionRetryCount = 0 self.connectionRetryCount = 0
self.deviceInfoRetryCount = 0
self.isTerminating = false self.isTerminating = false
self.currentBeacon = beacon self.currentBeacon = beacon
self.servicesToExplore.removeAll() self.servicesToExplore.removeAll()
@ -303,6 +307,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
skipDeviceInfoRead = false skipDeviceInfoRead = false
isTerminating = false isTerminating = false
connectionRetryCount = 0 connectionRetryCount = 0
deviceInfoRetryCount = 0
currentBeacon = nil currentBeacon = nil
state = .idle state = .idle
progress = "" progress = ""
@ -905,6 +910,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
configService = nil configService = nil
characteristics.removeAll() characteristics.removeAll()
connectionRetryCount = 0 connectionRetryCount = 0
deviceInfoRetryCount = 0
currentBeacon = nil currentBeacon = nil
operationMode = .provisioning operationMode = .provisioning
state = .idle state = .idle
@ -1030,11 +1036,11 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
awaitingDeviceInfoForProvisioning = false awaitingDeviceInfoForProvisioning = false
skipDeviceInfoRead = true // on reconnect, go straight to config write skipDeviceInfoRead = true // on reconnect, go straight to config write
if connectionRetryCount < BeaconProvisioner.MAX_CONNECTION_RETRIES { if deviceInfoRetryCount < BeaconProvisioner.MAX_DEVICE_INFO_RETRIES {
connectionRetryCount += 1 deviceInfoRetryCount += 1
let delay = Double(connectionRetryCount) let delay = Double(deviceInfoRetryCount)
progress = "Reconnecting (skip MAC read)..." progress = "Reconnecting (skip MAC read)..."
DebugLog.shared.log("BLE: Disconnect during device info read — reconnecting (\(connectionRetryCount)/\(BeaconProvisioner.MAX_CONNECTION_RETRIES)), will skip MAC read") DebugLog.shared.log("BLE: Disconnect during device info read — reconnecting (\(deviceInfoRetryCount)/\(BeaconProvisioner.MAX_DEVICE_INFO_RETRIES)), will skip MAC read")
// Reset BLE state for reconnect // Reset BLE state for reconnect
dxSmartAuthenticated = false dxSmartAuthenticated = false
@ -1056,7 +1062,7 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
} }
return return
} else { } else {
DebugLog.shared.log("BLE: Disconnect during device info read — max retries exhausted") DebugLog.shared.log("BLE: Disconnect during device info read — max device info retries exhausted (\(deviceInfoRetryCount)/\(BeaconProvisioner.MAX_DEVICE_INFO_RETRIES))")
fail("Disconnected while reading device information (retries exhausted)", code: .disconnected) fail("Disconnected while reading device information (retries exhausted)", code: .disconnected)
return return
} }