diff --git a/cue-ios/CueIOS/AppState.swift b/cue-ios/CueIOS/AppState.swift index 7dfd29d..630d395 100644 --- a/cue-ios/CueIOS/AppState.swift +++ b/cue-ios/CueIOS/AppState.swift @@ -223,6 +223,7 @@ final class AppState { status = "Chlorine complete: \(clPoints.count) points" case .phResult(let r): + transport.measuring = false if collectingRefs { phRef = r } else { @@ -256,6 +257,7 @@ final class AppState { break case .refsDone: + transport.measuring = false collectingRefs = false hasDeviceRefs = true refMode = nil @@ -364,6 +366,7 @@ final class AppState { func startPh() { phResult = nil + transport.measuring = true let stab = Float(phStabilize) ?? 30 send(buildSysexGetTemp()) send(buildSysexStartPh(stabilizeS: stab)) @@ -408,6 +411,7 @@ final class AppState { func collectRefs() { collectingRefs = true + transport.measuring = true eisRefs.removeAll() status = "Starting reference collection..." send(buildSysexStartRefs()) @@ -415,6 +419,7 @@ final class AppState { func getRefs() { collectingRefs = true + transport.measuring = true eisRefs.removeAll() send(buildSysexGetRefs()) } @@ -432,8 +437,12 @@ final class AppState { func startClean() { let v = Float(cleanV) ?? 1200 let d = Float(cleanDur) ?? 30 + transport.measuring = true send(buildSysexStartClean(vMv: v, durationS: d)) status = String(format: "Cleaning: %.0f mV for %.0fs", v, d) + DispatchQueue.main.asyncAfter(deadline: .now() + Double(d) + 2) { [weak self] in + self?.transport.measuring = false + } } var hasCurrentRef: Bool { diff --git a/cue-ios/CueIOS/Transport/UDPManager.swift b/cue-ios/CueIOS/Transport/UDPManager.swift index a228c02..351aa91 100644 --- a/cue-ios/CueIOS/Transport/UDPManager.swift +++ b/cue-ios/CueIOS/Transport/UDPManager.swift @@ -23,6 +23,9 @@ final class UDPManager: @unchecked Sendable { var address: String var port: UInt16 + /// Suppress keepalive timeout during blocking firmware operations (pH, clean, refs) + var measuring: Bool = false + private var connection: NWConnection? private let queue = DispatchQueue(label: "udp.eis4", qos: .userInitiated) private var onMessage: ((EisMessage) -> Void)? @@ -76,6 +79,7 @@ final class UDPManager: @unchecked Sendable { stopTimers() connection?.cancel() connection = nil + measuring = false state = .disconnected } @@ -178,7 +182,7 @@ final class UDPManager: @unchecked Sendable { } timeoutTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] _ in - guard let self, self.state == .connected else { return } + guard let self, self.state == .connected, !self.measuring else { return } if Date().timeIntervalSince(self.lastReceived) > Self.timeout { self.state = .disconnected self.stopTimers()