From 9b038ddf32da89dcf90c44995169910a9069ed55 Mon Sep 17 00:00:00 2001 From: Joe Moran Date: Tue, 7 Jul 2026 17:29:56 -0700 Subject: [PATCH] Add post runSession onFault handler to store reconciled doses immediately --- OmnipodKit/Bluetooth/BlePodComms.swift | 12 ++++++++++- OmnipodKit/Eros/ErosPodComms.swift | 14 +++++++++++-- OmnipodKit/PumpManager/OmniPumpManager.swift | 22 ++++++++++++++++++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/OmnipodKit/Bluetooth/BlePodComms.swift b/OmnipodKit/Bluetooth/BlePodComms.swift index 2df476e..20b90d3 100644 --- a/OmnipodKit/Bluetooth/BlePodComms.swift +++ b/OmnipodKit/Bluetooth/BlePodComms.swift @@ -629,7 +629,11 @@ class BlePodComms: PodComms { } } - func bleRunSession(withName name: String, _ block: @escaping (_ result: SessionRunResult) -> Void) { + func bleRunSession( + withName name: String, + onFault: @escaping (_ session: PodCommsSession) -> Void, + _ block: @escaping (_ result: SessionRunResult) -> Void + ) { guard let manager = manager, manager.peripheral.state == .connected else { block(.failure(PodCommsError.podNotConnected)) @@ -654,6 +658,12 @@ class BlePodComms: PodComms { let podSession = PodCommsSession(podState: self.podState!, transport: transport, delegate: self) block(.success(session: podSession)) + + // If the pod is faulted, call the onFault + // handler to save any updated dose info. + if self.podState?.isFaulted == true { + onFault(podSession) + } } } diff --git a/OmnipodKit/Eros/ErosPodComms.swift b/OmnipodKit/Eros/ErosPodComms.swift index bf40304..d908cd7 100644 --- a/OmnipodKit/Eros/ErosPodComms.swift +++ b/OmnipodKit/Eros/ErosPodComms.swift @@ -326,8 +326,12 @@ class ErosPodComms: PodComms { } } - func erosRunSession(withName name: String, using deviceSelector: @escaping (_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) -> Void, _ block: @escaping (_ result: SessionRunResult) -> Void) - { + func erosRunSession( + withName name: String, + using deviceSelector: @escaping (_ completion: @escaping (_ device: RileyLinkDevice?) -> Void) -> Void, + onFault: @escaping (_ session: PodCommsSession) -> Void, + _ block: @escaping (_ result: SessionRunResult) -> Void + ) { deviceSelector { (device) in guard let device = device else { block(.failure(PodCommsError.noRileyLinkAvailable)) @@ -352,6 +356,12 @@ class ErosPodComms: PodComms { erosPodMessageTransport.messageLogger = self.messageLogger let podSession = PodCommsSession(podState: self.podState!, transport: erosPodMessageTransport, delegate: self) block(.success(session: podSession)) + + // If the pod is faulted, call the onFault + // handler to save any updated dose info. + if self.podState?.isFaulted == true { + onFault(podSession) + } } } } diff --git a/OmnipodKit/PumpManager/OmniPumpManager.swift b/OmnipodKit/PumpManager/OmniPumpManager.swift index 42d846f..98f34ef 100644 --- a/OmnipodKit/PumpManager/OmniPumpManager.swift +++ b/OmnipodKit/PumpManager/OmniPumpManager.swift @@ -1513,15 +1513,33 @@ extension OmniPumpManager { // Used to serialize a set of Pod Commands for a given session - vectors to correct version private func runSession(withName name: String, _ block: @escaping (_ result: PodComms.SessionRunResult) -> Void) { if let blePodComms = self.podComms as? BlePodComms { - blePodComms.bleRunSession(withName: name, block) + blePodComms.bleRunSession(withName: name, onFault: onFault, block) } else if let erosPodComms = self.podComms as? ErosPodComms { let device = self.rileyLinkDeviceProvider.firstConnectedDevice - erosPodComms.erosRunSession(withName: name, using: device, block) + erosPodComms.erosRunSession(withName: name, using: device, onFault: onFault, block) } else { block(.failure(.diagnosticMessage(str: OmniPumpManagerError.podTypeNotConfigured.localizedDescription))) } } + /// Called at the end of the PodComms RunSession manager sequence if a pod fault has been + /// detected to ensure the any updated dose information is saved immediately after the pod fault + /// is detected reported to the app as doses may contained interrupted doses. This will better + /// handle various cases where a pod fault has have detected during some operation, but the + /// calling flow has to rely on some later flow (e.g., in forgetPod() or handlePodUpdatesAsNeeded()) + /// to actually handle getting the interrupted doses saved after the pod fault has occurred. + func onFault(session: PodCommsSession) { + if state.podState?.isFaulted == true, + let dosesToStore = state.podState?.dosesToStore, + dosesToStore.count > 0 + { + self.log.default("@@@ onFault storing doses: %{public}@", String(describing: dosesToStore)) + session.dosesForStorage() { (doses) -> Bool in + return store(doses: doses, in: session) + } + } + } + // Shared handler for getPodStatus() and post-connnect() that does a getStatus() // (unless canOptimize is true and a StatusResponse had been recently received) // and other associated actions that need to be regularly performed.