Compare commits

..

No commits in common. "720c560760f5fcd76b85cc254c7597f7262b7a71" and "a1d3b0f4577bbc23ba0edb53b05452e4355e1052" have entirely different histories.

View file

@ -157,7 +157,6 @@ class BeaconProvisioner: NSObject, ObservableObject {
private var dxSmartWriteIndex = 0
private var provisioningMacAddress: String?
private var awaitingDeviceInfoForProvisioning = false
private var skipDeviceInfoRead = false // set after disconnect during device info skip MAC read on reconnect
private var isTerminating = false // guards against re-entrant disconnect handling
// Read config mode
@ -178,9 +177,7 @@ class BeaconProvisioner: NSObject, ObservableObject {
// Connection retry state
private var connectionRetryCount = 0
private var deviceInfoRetryCount = 0
private static let MAX_CONNECTION_RETRIES = 3
private static let MAX_DEVICE_INFO_RETRIES = 2
private var currentBeacon: DiscoveredBeacon?
override init() {
@ -218,10 +215,8 @@ class BeaconProvisioner: NSObject, ObservableObject {
self.dxSmartWriteIndex = 0
self.provisioningMacAddress = nil
self.awaitingDeviceInfoForProvisioning = false
self.skipDeviceInfoRead = false
self.isTerminating = false
self.connectionRetryCount = 0
self.deviceInfoRetryCount = 0
self.currentBeacon = beacon
state = .connecting
@ -269,7 +264,6 @@ class BeaconProvisioner: NSObject, ObservableObject {
self.dxReadQueryIndex = 0
self.allDiscoveredServices.removeAll()
self.connectionRetryCount = 0
self.deviceInfoRetryCount = 0
self.isTerminating = false
self.currentBeacon = beacon
self.servicesToExplore.removeAll()
@ -304,10 +298,8 @@ class BeaconProvisioner: NSObject, ObservableObject {
dxSmartWriteIndex = 0
provisioningMacAddress = nil
awaitingDeviceInfoForProvisioning = false
skipDeviceInfoRead = false
isTerminating = false
connectionRetryCount = 0
deviceInfoRetryCount = 0
currentBeacon = nil
state = .idle
progress = ""
@ -414,14 +406,6 @@ class BeaconProvisioner: NSObject, ObservableObject {
/// Read device info (MAC address) before writing config
private func dxSmartReadDeviceInfoBeforeWrite() {
// If we previously disconnected during device info read, skip it entirely
if skipDeviceInfoRead {
DebugLog.shared.log("BLE: Skipping device info read (reconnect after previous disconnect)")
skipDeviceInfoRead = false
dxSmartWriteConfig()
return
}
guard let commandChar = characteristics[BeaconProvisioner.DXSMART_COMMAND_CHAR] else {
DebugLog.shared.log("BLE: FFE2 not found, proceeding without MAC")
dxSmartWriteConfig()
@ -910,7 +894,6 @@ class BeaconProvisioner: NSObject, ObservableObject {
configService = nil
characteristics.removeAll()
connectionRetryCount = 0
deviceInfoRetryCount = 0
currentBeacon = nil
operationMode = .provisioning
state = .idle
@ -1029,43 +1012,16 @@ extension BeaconProvisioner: CBCentralManagerDelegate {
return
}
// Disconnect during device info read (post-auth, pre-write) beacon dropped
// connection during the optional MAC address query. Instead of failing, reconnect
// and skip the device info step (MAC is nice-to-have, not required).
// Disconnect during device info read (post-auth, pre-write) beacon may have
// dropped the connection during the MAC address query. We authenticated but
// lost connection before writing config, so this is a failure but a known
// one with a clear retry path, not an unexplained "Unexpected disconnect".
if state == .authenticating && awaitingDeviceInfoForProvisioning && dxSmartAuthenticated {
DebugLog.shared.log("BLE: Disconnect during device info read (post-auth) — connection lost before config write, failing with retry prompt")
awaitingDeviceInfoForProvisioning = false
skipDeviceInfoRead = true // on reconnect, go straight to config write
if deviceInfoRetryCount < BeaconProvisioner.MAX_DEVICE_INFO_RETRIES {
deviceInfoRetryCount += 1
let delay = Double(deviceInfoRetryCount)
progress = "Reconnecting (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
dxSmartAuthenticated = false
dxSmartNotifySubscribed = false
dxSmartCommandQueue.removeAll()
dxSmartWriteIndex = 0
characteristics.removeAll()
responseBuffer.removeAll()
state = .connecting
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
} else {
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)
return
}
// Connection lost can't write config without it, fail with specific message
fail("Disconnected after auth during device info read — please retry", code: .disconnected)
return
}
// All other disconnects are unexpected