From da8408c19e0a289bb9cb4eb155669b6898fc0ae0 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 28 May 2018 14:25:00 -0500 Subject: [PATCH 1/6] Declare PumpState as equatable --- RileyLinkKit/PumpSettings.swift | 2 +- RileyLinkKit/PumpState.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/RileyLinkKit/PumpSettings.swift b/RileyLinkKit/PumpSettings.swift index 024cef51e..e36e90fc2 100644 --- a/RileyLinkKit/PumpSettings.swift +++ b/RileyLinkKit/PumpSettings.swift @@ -51,7 +51,7 @@ extension PumpSettings: CustomDebugStringConvertible { "## PumpSettings", "pumpID: ✔︎", "pumpRegion: \(pumpRegion)", - ].joined(separator: "\n") + ].joined(separator: "\n") } } diff --git a/RileyLinkKit/PumpState.swift b/RileyLinkKit/PumpState.swift index b2ca14269..18f6aaf97 100644 --- a/RileyLinkKit/PumpState.swift +++ b/RileyLinkKit/PumpState.swift @@ -10,7 +10,7 @@ import Foundation import MinimedKit -public struct PumpState: RawRepresentable { +public struct PumpState: RawRepresentable, Equatable { public typealias RawValue = [String: Any] public var timeZone: TimeZone From 635e63fd8d59443fdfd172b0707bf83d49738402 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 28 May 2018 14:26:04 -0500 Subject: [PATCH 2/6] Bump minVoltage on alkaline down to 1.18 --- MinimedKit/BatteryChemistryType.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MinimedKit/BatteryChemistryType.swift b/MinimedKit/BatteryChemistryType.swift index 30a047835..a797e7571 100644 --- a/MinimedKit/BatteryChemistryType.swift +++ b/MinimedKit/BatteryChemistryType.swift @@ -33,7 +33,7 @@ public enum BatteryChemistryType: Int, CustomStringConvertible { public var minVoltage: Double { switch self { case .alkaline: - return 1.20 + return 1.18 case .lithium: return 1.32 } From 52fa35ff2ffadd4f1508e659f18cfc38b5695e29 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Mon, 28 May 2018 19:55:52 -0500 Subject: [PATCH 3/6] Upload forecast error to NS, and add place to record other testing details --- .../DeviceStatus/ForecastError.swift | 32 +++++++++++++++++++ .../DeviceStatus/LoopStatus.swift | 16 ++++++++-- RileyLink.xcodeproj/project.pbxproj | 4 +++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 NightscoutUploadKit/DeviceStatus/ForecastError.swift diff --git a/NightscoutUploadKit/DeviceStatus/ForecastError.swift b/NightscoutUploadKit/DeviceStatus/ForecastError.swift new file mode 100644 index 000000000..105517165 --- /dev/null +++ b/NightscoutUploadKit/DeviceStatus/ForecastError.swift @@ -0,0 +1,32 @@ +// +// ForecastError.swift +// NightscoutUploadKit +// +// Created by Pete Schwamb on 5/28/18. +// Copyright © 2018 Pete Schwamb. All rights reserved. +// + +import Foundation +import HealthKit + +public struct ForecastError { + let velocity: Double + let measurementDuration: Double + + public init(velocity: HKQuantity, measurementDuration: TimeInterval) { + + let glucoseUnit = HKUnit.milligramsPerDeciliterUnit() + let velocityUnit = glucoseUnit.unitDivided(by: HKUnit.second()) + + self.velocity = velocity.doubleValue(for: velocityUnit) + self.measurementDuration = measurementDuration + } + + public var dictionaryRepresentation: [String: Any] { + var rval = [String: Any]() + rval["velocity"] = velocity + rval["measurementDuration"] = measurementDuration + //rval["velocityUnits"] = "mg/dL/s" + return rval + } +} diff --git a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift index 15cb6332c..73a414edb 100644 --- a/NightscoutUploadKit/DeviceStatus/LoopStatus.swift +++ b/NightscoutUploadKit/DeviceStatus/LoopStatus.swift @@ -7,6 +7,7 @@ // import Foundation +import HealthKit public struct LoopStatus { let name: String @@ -22,9 +23,10 @@ public struct LoopStatus { let rileylinks: [RileyLinkStatus]? let failureReason: Error? let currentCorrectionRange: CorrectionRange? + let forecastError: ForecastError? + let testingDetails: [String: Any]? - - public init(name: String, version: String, timestamp: Date, iob: IOBStatus? = nil, cob: COBStatus? = nil, predicted: PredictedBG? = nil, recommendedTempBasal:RecommendedTempBasal? = nil, recommendedBolus: Double? = nil, enacted: LoopEnacted? = nil, rileylinks: [RileyLinkStatus]? = nil, failureReason: Error? = nil, currentCorrectionRange: CorrectionRange? = nil) { + public init(name: String, version: String, timestamp: Date, iob: IOBStatus? = nil, cob: COBStatus? = nil, predicted: PredictedBG? = nil, recommendedTempBasal:RecommendedTempBasal? = nil, recommendedBolus: Double? = nil, enacted: LoopEnacted? = nil, rileylinks: [RileyLinkStatus]? = nil, failureReason: Error? = nil, currentCorrectionRange: CorrectionRange? = nil, forecastError: ForecastError? = nil, testingDetails: [String: Any]? = nil) { self.name = name self.version = version self.timestamp = timestamp @@ -37,6 +39,8 @@ public struct LoopStatus { self.rileylinks = rileylinks self.failureReason = failureReason self.currentCorrectionRange = currentCorrectionRange + self.forecastError = forecastError + self.testingDetails = testingDetails } public var dictionaryRepresentation: [String: Any] { @@ -81,6 +85,14 @@ public struct LoopStatus { if let currentCorrectionRange = currentCorrectionRange { rval["currentCorrectionRange"] = currentCorrectionRange.dictionaryRepresentation } + + if let forecastError = forecastError { + rval["forecastError"] = forecastError + } + + if let testingDetails = testingDetails { + rval["testingDetails"] = testingDetails + } return rval } diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 99ee088d3..98dff3792 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -305,6 +305,7 @@ C1842C241C8FA45100DB42AC /* BatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFA1C8FA45100DB42AC /* BatteryPumpEvent.swift */; }; C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */; }; C184875C20BC232F00ABE9E7 /* CorrectionRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = C184875B20BC232F00ABE9E7 /* CorrectionRange.swift */; }; + C184875E20BCDB0000ABE9E7 /* ForecastError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C184875D20BCDB0000ABE9E7 /* ForecastError.swift */; }; C18C8C531D64123400E043FB /* EnableBolusWizardPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18C8C521D64123400E043FB /* EnableBolusWizardPumpEvent.swift */; }; C18EB742207EE20100EA002B /* NightscoutProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18EB741207EE20100EA002B /* NightscoutProfile.swift */; }; C1A492631D4A5A19008964FF /* IOBStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A492621D4A5A19008964FF /* IOBStatus.swift */; }; @@ -797,6 +798,7 @@ C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutUploader.swift; sourceTree = ""; }; C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutPumpEvents.swift; sourceTree = ""; }; C184875B20BC232F00ABE9E7 /* CorrectionRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRange.swift; sourceTree = ""; }; + C184875D20BCDB0000ABE9E7 /* ForecastError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastError.swift; sourceTree = ""; }; C18C8C521D64123400E043FB /* EnableBolusWizardPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableBolusWizardPumpEvent.swift; sourceTree = ""; }; C18EB741207EE20100EA002B /* NightscoutProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutProfile.swift; sourceTree = ""; }; C1A492621D4A5A19008964FF /* IOBStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOBStatus.swift; sourceTree = ""; }; @@ -1501,6 +1503,7 @@ C1E5BEAC1D5E26F200BD4390 /* RileyLinkStatus.swift */, C1BAD1171E63984C009BA1C6 /* RadioAdapter.swift */, C184875B20BC232F00ABE9E7 /* CorrectionRange.swift */, + C184875D20BCDB0000ABE9E7 /* ForecastError.swift */, ); path = DeviceStatus; sourceTree = ""; @@ -2451,6 +2454,7 @@ C1A492691D4A66C0008964FF /* LoopEnacted.swift in Sources */, C1A492651D4A5DEB008964FF /* BatteryStatus.swift in Sources */, C1A492631D4A5A19008964FF /* IOBStatus.swift in Sources */, + C184875E20BCDB0000ABE9E7 /* ForecastError.swift in Sources */, 431CE7991F9B0F0200255374 /* OSLog.swift in Sources */, 43F348061D596270009933DC /* HKUnit.swift in Sources */, C133CF931D5943780034B82D /* PredictedBG.swift in Sources */, From 7cbe76333c7c282ff189f0f1715532d387f1425b Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Thu, 14 Jun 2018 23:48:37 -0500 Subject: [PATCH 4/6] Adding new commands for remote control of pump --- MinimedKit/BasalSchedule.swift | 8 +- MinimedKit/MessageType.swift | 41 +++++--- .../ChangeMaxBasalRateMessageBody.swift | 27 ++++++ .../Messages/ChangeMaxBolusMessageBody.swift | 27 ++++++ .../ChangeRemoteControlIDMessageBody.swift | 30 ++++++ .../ReadOtherDevicesIDsMessageBody.swift | 2 +- .../ReadRemoteControlIDsMessageBody.swift | 44 +++++++++ .../SetRemoteControlEnabledMessageBody.swift | 15 +++ MinimedKitTests/BasalScheduleTests.swift | 9 ++ .../ChangeMaxBasalRateMessageBodyTests.swift | 36 +++++++ .../ChangeMaxBolusMessageBodyTests.swift | 30 ++++++ ...hangeRemoteControlIDMessageBodyTests.swift | 28 ++++++ ...ReadRemoteControlIDsMessageBodyTests.swift | 42 +++++++++ RileyLink.xcodeproj/project.pbxproj | 46 +++++++-- .../xcshareddata/xcschemes/Crypto.xcscheme | 2 +- .../xcschemes/MinimedKit.xcscheme | 2 +- .../xcschemes/NightscoutUploadKit.xcscheme | 2 +- .../xcshareddata/xcschemes/RileyLink.xcscheme | 2 +- .../xcschemes/RileyLinkBLEKit.xcscheme | 2 +- .../xcschemes/RileyLinkKit.xcscheme | 2 +- .../xcschemes/RileyLinkKitUI.xcscheme | 2 +- RileyLinkBLEKit/RileyLinkDeviceError.swift | 2 +- RileyLinkKit/PumpOps.swift | 8 +- RileyLinkKit/PumpOpsSession.swift | 93 +++++++++++++++++-- ...sponseViewController+RileyLinkDevice.swift | 6 +- 25 files changed, 464 insertions(+), 44 deletions(-) create mode 100644 MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift create mode 100644 MinimedKit/Messages/ChangeMaxBolusMessageBody.swift create mode 100644 MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift create mode 100644 MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift create mode 100644 MinimedKit/Messages/SetRemoteControlEnabledMessageBody.swift create mode 100644 MinimedKitTests/Messages/ChangeMaxBasalRateMessageBodyTests.swift create mode 100644 MinimedKitTests/Messages/ChangeMaxBolusMessageBodyTests.swift create mode 100644 MinimedKitTests/Messages/ChangeRemoteControlIDMessageBodyTests.swift create mode 100644 MinimedKitTests/Messages/ReadRemoteControlIDsMessageBodyTests.swift diff --git a/MinimedKit/BasalSchedule.swift b/MinimedKit/BasalSchedule.swift index 28ad48219..4af810e65 100644 --- a/MinimedKit/BasalSchedule.swift +++ b/MinimedKit/BasalSchedule.swift @@ -48,7 +48,7 @@ extension BasalSchedule { if let entry = BasalScheduleEntry( index: tuple.index, rawValue: rawValue[beginOfRange..= entry.timeOffset { // Stop if the new timeOffset isn't greater than the last one break @@ -77,6 +77,11 @@ extension BasalSchedule { byteIndex += rawEntry.count } + // Send the special "empty" code to clear a schedule + if entries.count == 0 { + buffer[2] = 0x3f + } + return buffer } } @@ -97,6 +102,7 @@ private extension BasalScheduleEntry { let offsetMinutes = Double(rawValue.last!) * 30 let timeOffset = TimeInterval(minutes: offsetMinutes) + // 0x3f *30*60 denotes a stop value guard timeOffset < .hours(24) else { return nil } diff --git a/MinimedKit/MessageType.swift b/MinimedKit/MessageType.swift index df3580e03..95b186b8a 100644 --- a/MinimedKit/MessageType.swift +++ b/MinimedKit/MessageType.swift @@ -18,28 +18,30 @@ public enum MessageType: UInt8 { case errorResponse = 0x15 case writeGlucoseHistoryTimestamp = 0x28 - case readRemoteControlID = 0x2e // Refused by x23 pumps + case setBasalProfileA = 0x30 // CMD_SET_A_PROFILE + case setBasalProfileB = 0x31 // CMD_SET_B_PROFILE case changeTime = 0x40 + case setMaxBolus = 0x41 // CMD_SET_MAX_BOLUS case bolus = 0x42 case PumpExperiment_OP67 = 0x43 case PumpExperiment_OP68 = 0x44 - case PumpExperiment_OP69 = 0x45 + case PumpExperiment_OP69 = 0x45 // CMD_SET_VAR_BOLUS_ENABLE case selectBasalProfile = 0x4a case changeTempBasal = 0x4c case PumpExperiment_OP80 = 0x50 - case PumpExperiment_OP81 = 0x51 - case PumpExperiment_OP82 = 0x52 - case PumpExperiment_OP83 = 0x53 - case PumpExperiment_OP84 = 0x54 - case PumpExperiment_OP85 = 0x55 + case setRemoteControlID = 0x51 // CMD_SET_RF_REMOTE_ID + case PumpExperiment_OP82 = 0x52 // CMD_SET_BLOCK_ENABLE + case setLanguage = 0x53 + case PumpExperiment_OP84 = 0x54 // CMD_SET_ALERT_TYPE + case PumpExperiment_OP85 = 0x55 // CMD_SET_PATTERNS_ENABLE case PumpExperiment_OP86 = 0x56 - case PumpExperiment_OP87 = 0x57 - case PumpExperiment_OP88 = 0x58 + case setRemoteControlEnabled = 0x57 // CMD_SET_RF_ENABLE + case PumpExperiment_OP88 = 0x58 // CMD_SET_INSULIN_ACTION_TYPE case PumpExperiment_OP89 = 0x59 case PumpExperiment_OP90 = 0x5a @@ -49,16 +51,23 @@ public enum MessageType: UInt8 { case powerOn = 0x5d - case PumpExperiment_OP97 = 0x61 - case PumpExperiment_OP98 = 0x62 - case PumpExperiment_OP99 = 0x63 - case PumpExperiment_O100 = 0x64 - case PumpExperiment_O101 = 0x65 - case PumpExperiment_O103 = 0x67 + case setBolusWizardEnabled1 = 0x61 + case setBolusWizardEnabled2 = 0x62 + case setBolusWizardEnabled3 = 0x63 + case setBolusWizardEnabled4 = 0x64 + case setBolusWizardEnabled5 = 0x65 + case setAlarmClockEnable = 0x67 + + case setMaxBasalRate = 0x6e // CMD_SET_MAX_BASAL + case setBasalProfileStandard = 0x6f // CMD_SET_STD_PROFILE case readTime = 0x70 case getBattery = 0x72 case readRemainingInsulin = 0x73 + case readFirmwareVersion = 0x74 + case readErrorStatus = 0x75 + case readRemoteControlIDs = 0x76 // CMD_READ_REMOTE_CTRL_IDS + case getHistoryPage = 0x80 case getPumpModel = 0x8d case readProfileSTD512 = 0x92 @@ -130,6 +139,8 @@ public enum MessageType: UInt8 { return ReadOtherDevicesIDsMessageBody.self case .readOtherDevicesStatus: return ReadOtherDevicesStatusMessageBody.self + case .readRemoteControlIDs: + return ReadRemoteControlIDsMessageBody.self default: return UnknownMessageBody.self } diff --git a/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift b/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift new file mode 100644 index 000000000..108b074d1 --- /dev/null +++ b/MinimedKit/Messages/ChangeMaxBasalRateMessageBody.swift @@ -0,0 +1,27 @@ +// +// ChangeMaxBasalRateMessageBody.swift +// MinimedKit +// +// Copyright © 2018 Pete Schwamb. All rights reserved. +// + +import Foundation + + +public class ChangeMaxBasalRateMessageBody: CarelinkLongMessageBody { + + static let multiplier: Double = 40 + + public convenience init?(maxBasalUnitsPerHour: Double) { + guard maxBasalUnitsPerHour >= 0 && maxBasalUnitsPerHour <= 35 else { + return nil + } + + let ticks = UInt16(maxBasalUnitsPerHour * type(of: self).multiplier) + var data = Data(bytes: [UInt8(clamping: ticks.bitWidth / 8)]) + data.appendBigEndian(ticks) + + self.init(rxData: data) + } + +} diff --git a/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift b/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift new file mode 100644 index 000000000..ebb0ae4ce --- /dev/null +++ b/MinimedKit/Messages/ChangeMaxBolusMessageBody.swift @@ -0,0 +1,27 @@ +// +// ChangeMaxBolusMessageBody.swift +// MinimedKit +// +// Copyright © 2018 Pete Schwamb. All rights reserved. +// + +import Foundation + + +public class ChangeMaxBolusMessageBody: CarelinkLongMessageBody { + + static let multiplier: Double = 10 + + public convenience init?(maxBolusUnits: Double) { + guard maxBolusUnits >= 0 && maxBolusUnits <= 25 else { + return nil + } + + let ticks = UInt8(maxBolusUnits * type(of: self).multiplier) + var data = Data(bytes: [UInt8(clamping: ticks.bitWidth / 8)]) + data.appendBigEndian(ticks) + + self.init(rxData: data) + } + +} diff --git a/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift b/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift new file mode 100644 index 000000000..3de363c6a --- /dev/null +++ b/MinimedKit/Messages/ChangeRemoteControlIDMessageBody.swift @@ -0,0 +1,30 @@ +// +// ChangeRemoteControlIDMessageBody.swift +// MinimedKit +// +// Copyright © 2018 Pete Schwamb. All rights reserved. +// + +import Foundation + + +public class ChangeRemoteControlIDMessageBody: CarelinkLongMessageBody { + public convenience init?(id: Data? = nil, index: Int) { + guard index < 3 else { + return nil + } + + var rxData = Data(repeating: 0x2d, count: 8) // 2d signifies a deletion + rxData[0] = 0x07 // length + rxData[1] = UInt8(clamping: index) + + if let id = id { + for (index, byte) in id.enumerated() { + rxData[2 + index] = 0b00110000 + byte + } + } + + self.init(rxData: rxData) + } + +} diff --git a/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift b/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift index 9e266628b..57ccb1501 100644 --- a/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift +++ b/MinimedKit/Messages/ReadOtherDevicesIDsMessageBody.swift @@ -10,7 +10,7 @@ import Foundation public class ReadOtherDevicesIDsMessageBody: CarelinkLongMessageBody { - let ids: [Data] + public let ids: [Data] public required init?(rxData: Data) { guard rxData.count == type(of: self).length else { diff --git a/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift b/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift new file mode 100644 index 000000000..370009cdc --- /dev/null +++ b/MinimedKit/Messages/ReadRemoteControlIDsMessageBody.swift @@ -0,0 +1,44 @@ +// +// ReadRemoteControlIDsMessageBody.swift +// MinimedKit +// +// Copyright © 2018 Pete Schwamb. All rights reserved. +// + +import Foundation + +private let idSize = 6 + +public class ReadRemoteControlIDsMessageBody: CarelinkLongMessageBody { + public let ids: [Data] + + public required init?(rxData: Data) { + guard rxData.count == type(of: self).length else { + return nil + } + + var ids: [Data] = [] + + remotes: for index in stride(from: 0, to: 3, by: 1) { + let start = (index * idSize + 1) + let end = start + idSize + + var remoteID = Data(capacity: idSize) + + for byte in rxData[start.. BasalSchedule { + public func getBasalSchedule(for profile: BasalProfile = .standard) throws -> BasalSchedule? { try wakeup() var isFinished = false @@ -243,21 +243,45 @@ extension PumpOpsSession { message = PumpMessage(settings: settings, type: .pumpAck) } - return BasalSchedule(rawValue: scheduleData)! + return BasalSchedule(rawValue: scheduleData) } + /// - Throws: + /// - PumpOpsError.crosstalk + /// - PumpOpsError.deviceError + /// - PumpOpsError.noResponse + /// - PumpOpsError.unexpectedResponse + /// - PumpOpsError.unknownResponse public func getOtherDevicesIDs() throws -> ReadOtherDevicesIDsMessageBody { try wakeup() return try session.getResponse(to: PumpMessage(settings: settings, type: .readOtherDevicesIDs), responseType: .readOtherDevicesIDs) } + /// - Throws: + /// - PumpOpsError.crosstalk + /// - PumpOpsError.deviceError + /// - PumpOpsError.noResponse + /// - PumpOpsError.unexpectedResponse + /// - PumpOpsError.unknownResponse public func getOtherDevicesEnabled() throws -> Bool { try wakeup() let response: ReadOtherDevicesStatusMessageBody = try session.getResponse(to: PumpMessage(settings: settings, type: .readOtherDevicesStatus), responseType: .readOtherDevicesStatus) return response.isEnabled } + + /// - Throws: + /// - PumpOpsError.crosstalk + /// - PumpOpsError.deviceError + /// - PumpOpsError.noResponse + /// - PumpOpsError.unexpectedResponse + /// - PumpOpsError.unknownResponse + public func getRemoteControlIDs() throws -> ReadRemoteControlIDsMessageBody { + try wakeup() + + return try session.getResponse(to: PumpMessage(settings: settings, type: .readRemoteControlIDs), responseType: .readRemoteControlIDs) + } } @@ -364,6 +388,28 @@ extension PumpOpsSession { let _: PumpAckMessageBody = try runCommandWithArguments(message) } + /// - Throws: PumpCommandError + public func setMaxBasalRate(unitsPerHour: Double) throws { + guard let body = ChangeMaxBasalRateMessageBody(maxBasalUnitsPerHour: unitsPerHour) else { + throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) + } + + let message = PumpMessage(settings: settings, type: .setMaxBasalRate, body: body) + + let _: PumpAckMessageBody = try runCommandWithArguments(message) + } + + /// - Throws: PumpCommandError + public func setMaxBolus(units: Double) throws { + guard let body = ChangeMaxBolusMessageBody(maxBolusUnits: units) else { + throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) + } + + let message = PumpMessage(settings: settings, type: .setMaxBolus, body: body) + + let _: PumpAckMessageBody = try runCommandWithArguments(message) + } + /// Changes the current temporary basal rate /// /// - Parameters: @@ -512,9 +558,37 @@ extension PumpOpsSession { return } - /// - Throws: `PumpCommandError` specifying the failure sequence - public func setBasalSchedule(_ basalSchedule: BasalSchedule, for profile: BasalProfile, type: MessageType) throws { + /// - Throws: PumpCommandError + public func setRemoteControlEnabled(_ enabled: Bool) throws { + let message = PumpMessage(settings: settings, type: .setRemoteControlEnabled, body: SetRemoteControlEnabledMessageBody(enabled: enabled)) + + let _: PumpAckMessageBody = try runCommandWithArguments(message) + } + + /// - Throws: PumpCommandError + public func setRemoteControlID(_ id: Data, atIndex index: Int) throws { + guard let body = ChangeRemoteControlIDMessageBody(id: id, index: index) else { + throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) + } + + let message = PumpMessage(settings: settings, type: .setRemoteControlID, body: body) + + let _: PumpAckMessageBody = try runCommandWithArguments(message) + } + + /// - Throws: PumpCommandError + public func removeRemoteControlID(atIndex index: Int) throws { + guard let body = ChangeRemoteControlIDMessageBody(id: nil, index: index) else { + throw PumpCommandError.command(PumpOpsError.pumpError(PumpErrorCode.maxSettingExceeded)) + } + + let message = PumpMessage(settings: settings, type: .setRemoteControlID, body: body) + let _: PumpAckMessageBody = try runCommandWithArguments(message) + } + + /// - Throws: `PumpCommandError` specifying the failure sequence + public func setBasalSchedule(_ basalSchedule: BasalSchedule, for profile: BasalProfile) throws { let frames = DataFrameMessageBody.dataFramesFromContents(basalSchedule.rawValue) @@ -522,14 +596,21 @@ extension PumpOpsSession { return } - NSLog(firstFrame.txData.hexadecimalString) + let type: MessageType + switch profile { + case .standard: + type = .setBasalProfileStandard + case .profileA: + type = .setBasalProfileA + case .profileB: + type = .setBasalProfileB + } let message = PumpMessage(settings: settings, type: type, body: firstFrame) let _: PumpAckMessageBody = try runCommandWithArguments(message) for nextFrame in frames.dropFirst() { let message = PumpMessage(settings: settings, type: type, body: nextFrame) - NSLog(nextFrame.txData.hexadecimalString) do { let _: PumpAckMessageBody = try session.getResponse(to: message) } catch let error as PumpOpsError { diff --git a/RileyLinkKitUI/CommandResponseViewController+RileyLinkDevice.swift b/RileyLinkKitUI/CommandResponseViewController+RileyLinkDevice.swift index 8b06de238..8eade33ae 100644 --- a/RileyLinkKitUI/CommandResponseViewController+RileyLinkDevice.swift +++ b/RileyLinkKitUI/CommandResponseViewController+RileyLinkDevice.swift @@ -188,9 +188,9 @@ extension CommandResponseViewController { ops?.runSession(withName: "Get Basal Settings", using: device) { (session) in let response: String do { - let schedule = try session.getBasalSchedule(for: .standard) - var str = String(format: NSLocalizedString("%1$@ basal schedule entries\n", comment: "The format string describing number of basal schedule entries: (1: number of entries)"), integerFormatter.string(from: NSNumber(value: schedule.entries.count))!) - for entry in schedule.entries { + let schedule = try session.getBasalSchedule(for: .profileB) + var str = String(format: NSLocalizedString("%1$@ basal schedule entries\n", comment: "The format string describing number of basal schedule entries: (1: number of entries)"), integerFormatter.string(from: NSNumber(value: schedule?.entries.count ?? 0))!) + for entry in schedule?.entries ?? [] { str += "\(String(describing: entry))\n" } response = str From 3b71629d220bc2f95e12dd937cf22a0090d2c1ab Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Sat, 16 Jun 2018 22:56:30 -0500 Subject: [PATCH 5/6] Ensure RileyLink is configured after disconnection --- RileyLinkKit/PumpOps.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift index 12d3a5181..bea775877 100644 --- a/RileyLinkKit/PumpOps.swift +++ b/RileyLinkKit/PumpOps.swift @@ -98,6 +98,7 @@ public class PumpOps { NotificationCenter.default.post(name: .DeviceRadioConfigDidChange, object: device) NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceRadioConfigDidChange, object: device) + NotificationCenter.default.addObserver(self, selector: #selector(deviceRadioConfigDidChange(_:)), name: .DeviceConnectionStateDidChange, object: device) configuredDevices.insert(device) } @@ -107,6 +108,7 @@ public class PumpOps { } NotificationCenter.default.removeObserver(self, name: .DeviceRadioConfigDidChange, object: device) + NotificationCenter.default.removeObserver(self, name: .DeviceConnectionStateDidChange, object: device) configuredDevices.remove(device) } } From dca51a8e9b643a7e923b05f2e4f90a948c6c8026 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Sun, 17 Jun 2018 08:26:49 -0500 Subject: [PATCH 6/6] Bump version --- Crypto/Info.plist | 2 +- MinimedKit/Info.plist | 2 +- MinimedKitTests/Info.plist | 2 +- NightscoutUploadKit/Info.plist | 2 +- NightscoutUploadKitTests/Info.plist | 2 +- RileyLink.xcodeproj/project.pbxproj | 48 ++++++++++++------------ RileyLink/RileyLink-Info.plist | 2 +- RileyLinkBLEKit/Info.plist | 2 +- RileyLinkBLEKitTests/Info.plist | 2 +- RileyLinkKit/Info.plist | 2 +- RileyLinkKitTests/Info.plist | 2 +- RileyLinkKitUI/Info.plist | 2 +- RileyLinkTests/RileyLinkTests-Info.plist | 2 +- 13 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Crypto/Info.plist b/Crypto/Info.plist index 0e27f5f6d..e13d2efa7 100644 --- a/Crypto/Info.plist +++ b/Crypto/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/MinimedKit/Info.plist b/MinimedKit/Info.plist index 783e22ec8..a16c895d4 100644 --- a/MinimedKit/Info.plist +++ b/MinimedKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/MinimedKitTests/Info.plist b/MinimedKitTests/Info.plist index b7683fde8..9798c2ab8 100644 --- a/MinimedKitTests/Info.plist +++ b/MinimedKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/NightscoutUploadKit/Info.plist b/NightscoutUploadKit/Info.plist index 783e22ec8..a16c895d4 100644 --- a/NightscoutUploadKit/Info.plist +++ b/NightscoutUploadKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/NightscoutUploadKitTests/Info.plist b/NightscoutUploadKitTests/Info.plist index 840b2c791..6f3a2eb14 100644 --- a/NightscoutUploadKitTests/Info.plist +++ b/NightscoutUploadKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index a30ebbcd7..47c880b9a 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -2713,7 +2713,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; @@ -2749,7 +2749,7 @@ DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; @@ -2825,11 +2825,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2856,11 +2856,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -2923,12 +2923,12 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Crypto/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -2951,12 +2951,12 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Crypto/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -2981,12 +2981,12 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = RileyLinkKitUI/Info.plist; @@ -3017,12 +3017,12 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = RileyLinkKitUI/Info.plist; @@ -3046,12 +3046,12 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -3077,11 +3077,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -3164,7 +3164,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -3223,7 +3223,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -3335,11 +3335,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -3365,11 +3365,11 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 37; + CURRENT_PROJECT_VERSION = 38; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 37; + DYLIB_CURRENT_VERSION = 38; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; diff --git a/RileyLink/RileyLink-Info.plist b/RileyLink/RileyLink-Info.plist index 9611a7aa7..b3db443e0 100644 --- a/RileyLink/RileyLink-Info.plist +++ b/RileyLink/RileyLink-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkBLEKit/Info.plist b/RileyLinkBLEKit/Info.plist index 12c94a4e8..0e8b81880 100644 --- a/RileyLinkBLEKit/Info.plist +++ b/RileyLinkBLEKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/RileyLinkBLEKitTests/Info.plist b/RileyLinkBLEKitTests/Info.plist index 40302d5d0..83957c236 100644 --- a/RileyLinkBLEKitTests/Info.plist +++ b/RileyLinkBLEKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleVersion 1 diff --git a/RileyLinkKit/Info.plist b/RileyLinkKit/Info.plist index 783e22ec8..a16c895d4 100644 --- a/RileyLinkKit/Info.plist +++ b/RileyLinkKit/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkKitTests/Info.plist b/RileyLinkKitTests/Info.plist index b7683fde8..9798c2ab8 100644 --- a/RileyLinkKitTests/Info.plist +++ b/RileyLinkKitTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion diff --git a/RileyLinkKitUI/Info.plist b/RileyLinkKitUI/Info.plist index 12c94a4e8..0e8b81880 100644 --- a/RileyLinkKitUI/Info.plist +++ b/RileyLinkKitUI/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/RileyLinkTests/RileyLinkTests-Info.plist b/RileyLinkTests/RileyLinkTests-Info.plist index 5422a5804..8e3ad2ab9 100644 --- a/RileyLinkTests/RileyLinkTests-Info.plist +++ b/RileyLinkTests/RileyLinkTests-Info.plist @@ -13,7 +13,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.0.1 + 2.0.2 CFBundleSignature ???? CFBundleVersion