Skip to content

Commit

Permalink
Update DIY PumpManagers to new PumpManager protocol changes (#24)
Browse files Browse the repository at this point in the history
* Update DIY PumpManagers to new PumpManager protocol changes

* Update RileyLink app to protocol changes
  • Loading branch information
ps2 authored Sep 1, 2020
1 parent 1042f10 commit f1e1592
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 230 deletions.
97 changes: 34 additions & 63 deletions MinimedKit/PumpManager/MinimedPumpManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ extension MinimedPumpManager {
}
}

/// - Throws: `PumpCommandError` specifying the failure sequence
private func runSuspendResumeOnSession(suspendResumeState: SuspendResumeMessageBody.SuspendResumeState, session: PumpOpsSession) throws {
defer { self.recents.suspendEngageState = .stable }
self.recents.suspendEngageState = suspendResumeState == .suspend ? .engaging : .disengaging
Expand Down Expand Up @@ -291,10 +292,10 @@ extension MinimedPumpManager {
}
}

private func setSuspendResumeState(state: SuspendResumeMessageBody.SuspendResumeState, completion: @escaping (Error?) -> Void) {
private func setSuspendResumeState(state: SuspendResumeMessageBody.SuspendResumeState, completion: @escaping (MinimedPumpManagerError?) -> Void) {
rileyLinkDeviceProvider.getDevices { (devices) in
guard let device = devices.firstConnected else {
completion(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink))
completion(MinimedPumpManagerError.noRileyLink)
return
}

Expand All @@ -315,7 +316,7 @@ extension MinimedPumpManager {
})
} catch let error {
self.troubleshootPumpComms(using: device)
completion(PumpManagerError.communication(error as? LocalizedError))
completion(MinimedPumpManagerError.commsError(error as! PumpCommandError))
}
}
}
Expand Down Expand Up @@ -417,7 +418,7 @@ extension MinimedPumpManager {
}

/// Called on an unknown queue by the delegate
private func pumpManagerDelegateDidProcessReservoirValue(_ result: PumpManagerResult<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool)>) {
private func pumpManagerDelegateDidProcessReservoirValue(_ result: Result<(newValue: ReservoirValue, lastValue: ReservoirValue?, areStoredValuesContinuous: Bool), Error>) {
switch result {
case .failure:
break
Expand Down Expand Up @@ -574,7 +575,7 @@ extension MinimedPumpManager {
}
}

private func storePendingPumpEvents(_ completion: @escaping (_ error: Error?) -> Void) {
private func storePendingPumpEvents(_ completion: @escaping (_ error: MinimedPumpManagerError?) -> Void) {
// Must be called from the sessionQueue
let events = (self.state.pendingDoses + [self.state.unfinalizedBolus, self.state.unfinalizedTempBasal]).compactMap({ $0?.newPumpEvent })

Expand All @@ -587,7 +588,8 @@ extension MinimedPumpManager {

delegate.pumpManager(self, hasNewPumpEvents: events, lastReconciliation: self.lastReconciliation, completion: { (error) in
// Called on an unknown queue by the delegate
completion(error)
self.log.error("Pump event storage failed: %{public}@", String(describing: error))
completion(MinimedPumpManagerError.storageFailure)
})

})
Expand Down Expand Up @@ -869,8 +871,8 @@ extension MinimedPumpManager: PumpManager {
}
}
}

public func enactBolus(units: Double, at startDate: Date, willRequest: @escaping (_ dose: DoseEntry) -> Void, completion: @escaping (PumpManagerResult<DoseEntry>) -> Void) {
public func enactBolus(units: Double, at startDate: Date, completion: @escaping (PumpManagerResult<DoseEntry>) -> Void) {
let enactUnits = roundToSupportedBolusVolume(units: units)

guard enactUnits > 0 else {
Expand All @@ -882,13 +884,13 @@ extension MinimedPumpManager: PumpManager {
pumpOps.runSession(withName: "Bolus", using: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in

guard let session = session else {
completion(.failure(SetBolusError.certain(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink))))
completion(.failure(PumpManagerError.connection(MinimedPumpManagerError.noRileyLink)))
return
}

if let unfinalizedBolus = self.state.unfinalizedBolus {
guard unfinalizedBolus.isFinished else {
completion(.failure(SetBolusError.certain(PumpManagerError.deviceState(MinimedPumpManagerError.bolusInProgress))))
completion(.failure(PumpManagerError.deviceState(MinimedPumpManagerError.bolusInProgress)))
return
}

Expand All @@ -910,55 +912,28 @@ extension MinimedPumpManager: PumpManager {
// Ignore result
}
})
} catch let error as PumpOpsError {
self.log.error("Failed to fetch pump status: %{public}@", String(describing: error))
completion(.failure(SetBolusError.certain(error)))
return
} catch let error as PumpCommandError {
self.log.error("Failed to fetch pump status: %{public}@", String(describing: error))
switch error {
case .arguments(let error):
completion(.failure(SetBolusError.certain(error)))
case .command(let error):
completion(.failure(SetBolusError.certain(error)))
}
return
} catch let error {
self.recents.bolusEngageState = .stable
completion(.failure(error))
self.log.error("Failed to fetch pump status: %{public}@", String(describing: error))
completion(.failure(PumpManagerError.communication(error as? LocalizedError)))
return
}
}

do {
if case .suspended = self.state.suspendState {
do {
try self.runSuspendResumeOnSession(suspendResumeState: .resume, session: session)
} catch let error as PumpOpsError {
self.log.error("Failed to resume pump for bolus: %{public}@", String(describing: error))
completion(.failure(SetBolusError.certain(error)))
return
} catch let error as PumpCommandError {
self.log.error("Failed to resume pump for bolus: %{public}@", String(describing: error))
switch error {
case .arguments(let error):
completion(.failure(SetBolusError.certain(error)))
case .command(let error):
completion(.failure(SetBolusError.certain(error)))
}
return
} catch let error {
self.recents.bolusEngageState = .stable
completion(.failure(error))
return
}
if case .suspended = self.state.suspendState {
do {
try self.runSuspendResumeOnSession(suspendResumeState: .resume, session: session)
} catch let error {
self.recents.bolusEngageState = .stable
self.log.error("Failed to resume pump for bolus: %{public}@", String(describing: error))
completion(.failure(PumpManagerError.communication(error as? LocalizedError)))
return
}
}

let date = Date()
let deliveryTime = self.state.pumpModel.bolusDeliveryTime(units: enactUnits)
let requestedDose = UnfinalizedDose(bolusAmount: enactUnits, startTime: date, duration: deliveryTime)
willRequest(DoseEntry(requestedDose))
let deliveryTime = self.state.pumpModel.bolusDeliveryTime(units: enactUnits)

do {
try session.setNormalBolus(units: enactUnits)

// Between bluetooth and the radio and firmware, about 2s on average passes before we start tracking
Expand All @@ -977,7 +952,7 @@ extension MinimedPumpManager: PumpManager {
} catch let error {
self.log.error("Failed to bolus: %{public}@", String(describing: error))
self.recents.bolusEngageState = .stable
completion(.failure(error))
completion(.failure(PumpManagerError.communication(error as? LocalizedError)))
}
}
}
Expand All @@ -987,14 +962,13 @@ extension MinimedPumpManager: PumpManager {
setSuspendResumeState(state: .suspend) { (error) in
self.recents.bolusEngageState = .stable
if let error = error {
completion(.failure(error))
completion(.failure(PumpManagerError.communication(error)))
} else {
completion(.success(nil))
}
}
}



public func enactTempBasal(unitsPerHour: Double, for duration: TimeInterval, completion: @escaping (PumpManagerResult<DoseEntry>) -> Void) {
pumpOps.runSession(withName: "Set Temp Basal", using: rileyLinkDeviceProvider.firstConnectedDevice) { (session) in
guard let session = session else {
Expand All @@ -1004,9 +978,10 @@ extension MinimedPumpManager: PumpManager {

self.recents.tempBasalEngageState = .engaging

do {
let response = try session.setTempBasal(unitsPerHour, duration: duration)

let result = session.setTempBasal(unitsPerHour, duration: duration)

switch result {
case .success(let response):
let now = Date()
let endDate = now.addingTimeInterval(response.timeRemaining)
let startDate = endDate.addingTimeInterval(-duration)
Expand Down Expand Up @@ -1044,8 +1019,8 @@ extension MinimedPumpManager: PumpManager {
})

// Continue below
} catch let error as PumpCommandError {
completion(.failure(error))
case .failure(let error):
completion(.failure(PumpManagerError.communication(error)))

// If we got a command-refused error, we might be suspended or bolusing, so update the state accordingly
if case .arguments(.pumpError(.commandRefused)) = error {
Expand All @@ -1063,10 +1038,6 @@ extension MinimedPumpManager: PumpManager {
}
self.recents.tempBasalEngageState = .stable
return
} catch {
self.recents.tempBasalEngageState = .stable
completion(.failure(error))
return
}

do {
Expand Down
26 changes: 13 additions & 13 deletions MinimedKit/PumpManager/MinimedPumpManagerError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,46 @@ public enum MinimedPumpManagerError: Error {
case bolusInProgress
case noDate // TODO: This is less of an error and more of a precondition/assertion state
case tuneFailed(LocalizedError)
case commsError(LocalizedError)
case storageFailure
}


extension MinimedPumpManagerError: LocalizedError {
public var errorDescription: String? {
switch self {
case .noRileyLink:
return nil
return LocalizedString("No RileyLink Connected", comment: "Error description when no rileylink connected")
case .bolusInProgress:
return nil
return LocalizedString("Bolus in Progress", comment: "Error description when failure due to bolus in progress")
case .noDate:
return nil
case .tuneFailed(let error):
return [LocalizedString("RileyLink radio tune failed", comment: "Error description"), error.errorDescription].compactMap({ $0 }).joined(separator: ": ")
return [LocalizedString("RileyLink radio tune failed", comment: "Error description for tune failure"), error.errorDescription].compactMap({ $0 }).joined(separator: ": ")
case .commsError(let error):
return error.errorDescription
case .storageFailure:
return LocalizedString("Unable to store pump data", comment: "Error description when storage fails")
}
}

public var failureReason: String? {
switch self {
case .noRileyLink:
return nil
case .bolusInProgress:
return nil
case .noDate:
return nil
case .tuneFailed(let error):
return error.failureReason
default:
return nil
}
}

public var recoverySuggestion: String? {
switch self {
case .noRileyLink:
return LocalizedString("Make sure your RileyLink is nearby and powered on", comment: "Recovery suggestion")
case .bolusInProgress:
return nil
case .noDate:
return nil
case .tuneFailed(let error):
return error.recoverySuggestion
default:
return nil
}
}
}
9 changes: 8 additions & 1 deletion MinimedKitUI/MinimedPumpManager+UI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ extension MinimedPumpManager: PumpManagerUI {
let nav = SettingsNavigationViewController(rootViewController: settings)
return nav
}


public func deliveryUncertaintyRecoveryViewController(insulinTintColor: Color, guidanceColors: GuidanceColors) -> (UIViewController & CompletionNotifying) {
// Return settings for now. No uncertainty handling atm.
let settings = MinimedPumpSettingsViewController(pumpManager: self)
let nav = SettingsNavigationViewController(rootViewController: settings)
return nav
}

public var smallImage: UIImage? {
return state.smallPumpImage
}
Expand Down
Loading

0 comments on commit f1e1592

Please sign in to comment.