Skip to content

Commit

Permalink
Detect remote flag for commands (#564)
Browse files Browse the repository at this point in the history
* Detect remote flag for commands

* Fix tests

* Handle remote trigger flag for BolusNormal on x22 pumps
  • Loading branch information
ps2 authored Nov 26, 2019
1 parent 8c12092 commit 26931d3
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github "LoopKit/LoopKit" "a08405ec7a4e38fa96e39ae079114db30f393a2a"
github "LoopKit/LoopKit" "a931da1ca106697b791d1508bad357c47f73dec0"
github "LoopKit/MKRingProgressView" "f548a5c64832be2d37d7c91b5800e284887a2a0a"
39 changes: 17 additions & 22 deletions MinimedKit/PumpEvents/BolusNormalPumpEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ public struct BolusNormalPumpEvent: TimestampedPumpEvent {
public let unabsorbedInsulinTotal: Double
public let type: BolusType
public let duration: TimeInterval
public let wasRemotelyTriggered: Bool

public init(length: Int, rawData: Data, timestamp: DateComponents, unabsorbedInsulinRecord: UnabsorbedInsulinPumpEvent?, amount: Double, programmed: Double, unabsorbedInsulinTotal: Double, type: BolusType, duration: TimeInterval, wasRemotelyTriggered: Bool) {
self.length = length
self.rawData = rawData
self.timestamp = timestamp
self.unabsorbedInsulinRecord = unabsorbedInsulinRecord
self.amount = amount
self.programmed = programmed
self.unabsorbedInsulinTotal = unabsorbedInsulinTotal
self.type = type
self.duration = duration
self.wasRemotelyTriggered = wasRemotelyTriggered
}

/*
It takes a MM pump about 40s to deliver 1 Unit while bolusing
Expand All @@ -40,28 +54,7 @@ public struct BolusNormalPumpEvent: TimestampedPumpEvent {
}
}

public init(length: Int, rawData: Data, timestamp: DateComponents, unabsorbedInsulinRecord: UnabsorbedInsulinPumpEvent?, amount: Double, programmed: Double, unabsorbedInsulinTotal: Double, type: BolusType, duration: TimeInterval) {
self.length = length
self.rawData = rawData
self.timestamp = timestamp
self.unabsorbedInsulinRecord = unabsorbedInsulinRecord
self.amount = amount
self.programmed = programmed
self.unabsorbedInsulinTotal = unabsorbedInsulinTotal
self.type = type
self.duration = duration
}

public init?(availableData: Data, pumpModel: PumpModel) {
let length: Int
let rawData: Data
let timestamp: DateComponents
var unabsorbedInsulinRecord: UnabsorbedInsulinPumpEvent?
let amount: Double
let programmed: Double
let unabsorbedInsulinTotal: Double
let type: BolusType
let duration: TimeInterval

func doubleValueFromData(at index: Int) -> Double {
return Double(availableData[index])
Expand All @@ -81,20 +74,21 @@ public struct BolusNormalPumpEvent: TimestampedPumpEvent {

if pumpModel.larger {
timestamp = DateComponents(pumpEventData: availableData, offset: 8)
wasRemotelyTriggered = availableData[11] & 0b01000000 != 0
programmed = decodeInsulin(from: availableData.subdata(in: 1..<3))
amount = decodeInsulin(from: availableData.subdata(in: 3..<5))
unabsorbedInsulinTotal = decodeInsulin(from: availableData.subdata(in: 5..<7))
duration = TimeInterval(minutes: 30 * doubleValueFromData(at: 7))
} else {
timestamp = DateComponents(pumpEventData: availableData, offset: 4)
wasRemotelyTriggered = availableData[7] & 0b01000000 != 0
programmed = decodeInsulin(from: availableData.subdata(in: 1..<2))
amount = decodeInsulin(from: availableData.subdata(in: 2..<3))
duration = TimeInterval(minutes: 30 * doubleValueFromData(at: 3))
unabsorbedInsulinTotal = 0
}
type = duration > 0 ? .square : .normal

self.init(length: length, rawData: rawData, timestamp: timestamp, unabsorbedInsulinRecord: unabsorbedInsulinRecord, amount:amount, programmed: programmed, unabsorbedInsulinTotal: unabsorbedInsulinTotal, type: type, duration: duration)
}

public var dictionaryRepresentation: [String: Any] {
Expand All @@ -103,6 +97,7 @@ public struct BolusNormalPumpEvent: TimestampedPumpEvent {
"amount": amount,
"programmed": programmed,
"type": type.rawValue,
"wasRemotelyTriggered": wasRemotelyTriggered,
]

if let unabsorbedInsulinRecord = unabsorbedInsulinRecord {
Expand Down
4 changes: 4 additions & 0 deletions MinimedKit/PumpEvents/ResumePumpEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public struct ResumePumpEvent: TimestampedPumpEvent {
public let length: Int
public let rawData: Data
public let timestamp: DateComponents
public let wasRemotelyTriggered: Bool

public init?(availableData: Data, pumpModel: PumpModel) {
length = 7
Expand All @@ -23,11 +24,14 @@ public struct ResumePumpEvent: TimestampedPumpEvent {
rawData = availableData.subdata(in: 0..<length)

timestamp = DateComponents(pumpEventData: availableData, offset: 2)

wasRemotelyTriggered = availableData[5] & 0b01000000 != 0
}

public var dictionaryRepresentation: [String: Any] {
return [
"_type": "Resume",
"wasRemotelyTriggered": wasRemotelyTriggered,
]
}
}
6 changes: 5 additions & 1 deletion MinimedKit/PumpEvents/SuspendPumpEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public struct SuspendPumpEvent: TimestampedPumpEvent {
public let length: Int
public let rawData: Data
public let timestamp: DateComponents

public let wasRemotelyTriggered: Bool

public init?(availableData: Data, pumpModel: PumpModel) {
length = 7

Expand All @@ -23,11 +24,14 @@ public struct SuspendPumpEvent: TimestampedPumpEvent {
rawData = availableData.subdata(in: 0..<length)

timestamp = DateComponents(pumpEventData: availableData, offset: 2)

wasRemotelyTriggered = availableData[5] & 0b01000000 != 0
}

public var dictionaryRepresentation: [String: Any] {
return [
"_type": "Suspend",
"wasRemotelyTriggered": wasRemotelyTriggered,
]
}
}
4 changes: 4 additions & 0 deletions MinimedKit/PumpEvents/TempBasalPumpEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public struct TempBasalPumpEvent: TimestampedPumpEvent {
public let rateType: RateType
public let rate: Double
public let timestamp: DateComponents
public let wasRemotelyTriggered: Bool

public init?(availableData: Data, pumpModel: PumpModel) {
length = 8
Expand All @@ -43,13 +44,16 @@ public struct TempBasalPumpEvent: TimestampedPumpEvent {
}

timestamp = DateComponents(pumpEventData: availableData, offset: 2)

wasRemotelyTriggered = availableData[5] & 0b01000000 != 0
}

public var dictionaryRepresentation: [String: Any] {
return [
"_type": "TempBasal",
"rate": rate,
"temp": rateType.rawValue,
"wasRemotelyTriggered": wasRemotelyTriggered,
]
}

Expand Down
5 changes: 5 additions & 0 deletions MinimedKit/PumpManager/MinimedPumpManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,11 @@ extension MinimedPumpManager {
// Include events up to a minute before startDate, since pump event time and pending event time might be off
let (historyEvents, model) = try session.getHistoryEvents(since: startDate.addingTimeInterval(.minutes(-1)))

// if let lastEvent = historyEvents.last, let _ = lastEvent.pumpEvent as? ResumePumpEvent {
// self.log.default("Failing read when last event is resume.")
// throw PumpOpsError.rfCommsFailure("made up error")
// }

// Reconcile history with pending doses
let newPumpEvents = historyEvents.pumpEvents(from: model)
let reconciledEvents = self.reconcilePendingDosesWith(newPumpEvents)
Expand Down
24 changes: 24 additions & 0 deletions MinimedKitTests/PumpEvents/ResumePumpEventTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ResumePumpEventTests.swift
// MinimedKitTests
//
// Created by Pete Schwamb on 11/10/19.
// Copyright © 2019 Pete Schwamb. All rights reserved.
//

import XCTest

@testable import MinimedKit

class ResumePumpEventTests: XCTestCase {

func testRemotelyTriggeredFlag() {

let localResume = ResumePumpEvent(availableData: Data(hexadecimalString: "1f20a4e30e0a13")!, pumpModel: .model523)!
XCTAssert(!localResume.wasRemotelyTriggered)

let remoteResume = ResumePumpEvent(availableData: Data(hexadecimalString: "1f209de40e4a13")!, pumpModel: .model523)!
XCTAssert(remoteResume.wasRemotelyTriggered)
}
}

17 changes: 5 additions & 12 deletions MinimedKitTests/PumpOpsSynchronousTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,30 +258,23 @@ class PumpOpsSynchronousTests: XCTestCase {
return batteryPumpEvent
}

func createSquareBolusEvent2016() -> BolusNormalPumpEvent {
//2016-08-01 05:00:16 +000
let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2016, month: 8, day: 1, hour: 5, minute: 0, second: 16)
let data = Data(hexadecimalString: "01009009600058008a344b1010")!
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(minutes: 120))
}

func createSquareBolusEvent2010() -> BolusNormalPumpEvent {
//2010-08-01 05:00:16 +000
let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2010, month: 8, day: 1, hour: 5, minute: 0, second: 16)
let data = Data(hexadecimalString: "01009000900058008a344b1010")!
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(minutes: 120))
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(minutes: 120), wasRemotelyTriggered: false)
}

func createSquareBolusEvent(dateComponents: DateComponents) -> BolusNormalPumpEvent {
let data = Data(hexadecimalString: randomDataString(length: squareBolusDataLength))!
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(hours: 8))
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .square, duration: TimeInterval(hours: 8), wasRemotelyTriggered: false)
}

func createBolusEvent2011() -> BolusNormalPumpEvent {
//2010-08-01 05:00:11 +000
let dateComponents = DateComponents(calendar: Calendar.current, timeZone: pumpState.timeZone, year: 2011, month: 8, day: 1, hour: 5, minute: 0, second: 16)
let data = Data(hexadecimalString: "01009000900058008a344b10FF")!
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: TimeInterval(minutes: 120))
return BolusNormalPumpEvent(length: BolusNormalPumpEvent.calculateLength(pumpModel.larger), rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 0.0, programmed: 0.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: TimeInterval(minutes: 120), wasRemotelyTriggered: false)
}

func createTempEventBasal2016() -> TempBasalPumpEvent {
Expand All @@ -296,7 +289,7 @@ class PumpOpsSynchronousTests: XCTestCase {
let timeInterval: TimeInterval = TimeInterval(minutes: 2)
let data = Data(hexadecimalString:"338c4055145d2000")!

return BolusNormalPumpEvent(length: 13, rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 2.0, programmed: 1.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: timeInterval)
return BolusNormalPumpEvent(length: 13, rawData: data, timestamp: dateComponents, unabsorbedInsulinRecord: nil, amount: 2.0, programmed: 1.0, unabsorbedInsulinTotal: 0.0, type: .normal, duration: timeInterval, wasRemotelyTriggered: false)
}

func createNonDelayedEvent2009() -> BolusReminderPumpEvent {
Expand All @@ -311,7 +304,7 @@ class PumpOpsSynchronousTests: XCTestCase {
// from comment at https://gist.github.com/szhernovoy/276e69eb90a0de84dd90
func randomDataString(length:Int) -> String {
let charSet = "abcdef0123456789"
var c = charSet.map { String($0) }
let c = charSet.map { String($0) }
var s:String = ""
for _ in 0..<length {
s.append(c[Int(arc4random()) % c.count])
Expand Down
4 changes: 4 additions & 0 deletions RileyLink.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@
C12572922121EEEE0061BA2F /* SettingsImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12572912121EEEE0061BA2F /* SettingsImageTableViewCell.swift */; };
C125729421220FEC0061BA2F /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C125729321220FEC0061BA2F /* MainStoryboard.storyboard */; };
C12572982125FA390061BA2F /* RileyLinkConnectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12572972125FA390061BA2F /* RileyLinkConnectionManager.swift */; };
C127160A2378C2270093DAB7 /* ResumePumpEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12716092378C2270093DAB7 /* ResumePumpEventTests.swift */; };
C1271B071A9A34E900B7C949 /* Log.m in Sources */ = {isa = PBXBuildFile; fileRef = C1271B061A9A34E900B7C949 /* Log.m */; };
C1274F771D8232580002912B /* DailyTotal515PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1274F761D8232580002912B /* DailyTotal515PumpEvent.swift */; };
C1274F791D823A550002912B /* ChangeMeterIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1274F781D823A550002912B /* ChangeMeterIDPumpEvent.swift */; };
Expand Down Expand Up @@ -1261,6 +1262,7 @@
C125729321220FEC0061BA2F /* MainStoryboard.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainStoryboard.storyboard; sourceTree = "<group>"; };
C12572972125FA390061BA2F /* RileyLinkConnectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkConnectionManager.swift; sourceTree = "<group>"; };
C12616431B685F0A001FAD87 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
C12716092378C2270093DAB7 /* ResumePumpEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResumePumpEventTests.swift; sourceTree = "<group>"; };
C1271B061A9A34E900B7C949 /* Log.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Log.m; sourceTree = "<group>"; };
C1271B081A9A350400B7C949 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = "<group>"; };
C1274F761D8232580002912B /* DailyTotal515PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DailyTotal515PumpEvent.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1739,6 +1741,7 @@
isa = PBXGroup;
children = (
2F962EC71E7074E60070EFBD /* BolusNormalPumpEventTests.swift */,
C12716092378C2270093DAB7 /* ResumePumpEventTests.swift */,
);
path = PumpEvents;
sourceTree = "<group>";
Expand Down Expand Up @@ -3866,6 +3869,7 @@
54BC44A31DB7021B00340EED /* SensorStatusGlucoseEventTests.swift in Sources */,
C1EAD6E41C82BA87006DBA60 /* CRC16Tests.swift in Sources */,
2F962ECA1E70831F0070EFBD /* PumpModelTests.swift in Sources */,
C127160A2378C2270093DAB7 /* ResumePumpEventTests.swift in Sources */,
546A85CE1DF7B99D00733213 /* SensorPacketGlucoseEventTests.swift in Sources */,
43CA93311CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */,
54BC44A91DB704A600340EED /* CalBGForGHGlucoseEventTests.swift in Sources */,
Expand Down

0 comments on commit 26931d3

Please sign in to comment.