diff --git a/Crypto/Info.plist b/Crypto/Info.plist
index a86af35aa..1903193db 100644
--- a/Crypto/Info.plist
+++ b/Crypto/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
diff --git a/MinimedKit/Extensions/NSData.swift b/MinimedKit/Extensions/NSData.swift
index 284a8a816..3699b4909 100644
--- a/MinimedKit/Extensions/NSData.swift
+++ b/MinimedKit/Extensions/NSData.swift
@@ -71,7 +71,6 @@ extension Data {
*/
}
-
extension Data {
init?(hexadecimalString: String) {
guard let chars = hexadecimalString.cString(using: String.Encoding.utf8) else {
diff --git a/MinimedKit/Extensions/NSDateComponents.swift b/MinimedKit/Extensions/NSDateComponents.swift
index 8f758190e..6fd023610 100644
--- a/MinimedKit/Extensions/NSDateComponents.swift
+++ b/MinimedKit/Extensions/NSDateComponents.swift
@@ -47,4 +47,17 @@ extension DateComponents {
calendar = Calendar(identifier: Calendar.Identifier.gregorian)
}
+
+ init(glucoseEventBytes: Data) {
+ self.init()
+
+ year = Int(glucoseEventBytes[3] & 0b01111111) + 2000
+ month = Int((glucoseEventBytes[0] & 0b11000000) >> 4 +
+ (glucoseEventBytes[1] & 0b11000000) >> 6)
+ day = Int(glucoseEventBytes[2] & 0b00011111)
+ hour = Int(glucoseEventBytes[0] & 0b00011111)
+ minute = Int(glucoseEventBytes[1] & 0b00111111)
+
+ calendar = Calendar(identifier: Calendar.Identifier.gregorian)
+ }
}
diff --git a/MinimedKit/GlucoseEventType.swift b/MinimedKit/GlucoseEventType.swift
new file mode 100644
index 000000000..e89d74335
--- /dev/null
+++ b/MinimedKit/GlucoseEventType.swift
@@ -0,0 +1,56 @@
+//
+// GlucoseEventType.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/16/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public enum GlucoseEventType: UInt8 {
+ case dataEnd = 0x01
+ case sensorWeakSignal = 0x02
+ case sensorCal = 0x03
+ case fokko7 = 0x07
+ case sensorTimestamp = 0x08
+ case batteryChange = 0x0a
+ case sensorStatus = 0x0b
+ case dateTimeChange = 0x0c
+ case sensorSync = 0x0d
+ case calBGForGH = 0x0e
+ case sensorCalFactor = 0x0f
+ case tenSomething = 0x10
+ case nineteenSomething = 0x13
+
+ public var eventType: GlucoseEvent.Type {
+ switch self {
+ case .dataEnd:
+ return DataEndGlucoseEvent.self
+ case .sensorWeakSignal:
+ return SensorWeakSignalGlucoseEvent.self
+ case .sensorCal:
+ return SensorCalGlucoseEvent.self
+ case .fokko7:
+ return Fokko7GlucoseEvent.self
+ case .sensorTimestamp:
+ return SensorTimestampGlucoseEvent.self
+ case .batteryChange:
+ return BatteryChangeGlucoseEvent.self
+ case .sensorStatus:
+ return SensorStatusGlucoseEvent.self
+ case .dateTimeChange:
+ return DateTimeChangeGlucoseEvent.self
+ case .sensorSync:
+ return SensorSyncGlucoseEvent.self
+ case .calBGForGH:
+ return CalBGForGHGlucoseEvent.self
+ case .sensorCalFactor:
+ return SensorCalFactorGlucoseEvent.self
+ case .tenSomething:
+ return TenSomethingGlucoseEvent.self
+ case .nineteenSomething:
+ return NineteenSomethingGlucoseEvent.self
+ }
+ }
+}
diff --git a/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift b/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift
new file mode 100644
index 000000000..22af2c62f
--- /dev/null
+++ b/MinimedKit/GlucoseEvents/BatteryChangeGlucoseEvent.swift
@@ -0,0 +1,32 @@
+//
+// BatteryChangeGlucoseEvent.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/16/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public struct BatteryChangeGlucoseEvent : GlucoseEvent {
+ public let length: Int
+ public let rawData: Data
+ public let timestamp: DateComponents
+
+ public init?(availableData: Data) {
+ length = 5
+
+ guard length <= availableData.count else {
+ return nil
+ }
+
+ rawData = availableData.subdata(in: 0.. Int {
+ return Int(availableData[idx] as UInt8)
+ }
+
+ rawData = availableData.subdata(in: 0.. Int {
+ return Int(availableData[idx] as UInt8)
+ }
+
+ rawData = availableData.subdata(in: 0.. Int {
+ return Int(availableData[idx] as UInt8)
+ }
+
+ rawData = availableData.subdata(in: 0.. GlucoseEvent {
+ let remainingData = pageData.subdata(in: offset..= 20 {
+ return GlucoseSensorDataGlucoseEvent(availableData: remainingData)!
+ }
+
+ return UnknownGlucoseEvent(availableData: remainingData)!
+ }
+
+ func addTimestampsToEvents(startTimestamp: DateComponents, eventsNeedingTimestamp: [RelativeTimestampedGlucoseEvent]) -> [GlucoseEvent] {
+ var eventsWithTimestamps = [GlucoseEvent]()
+ let calendar = Calendar.current
+ var date : Date = calendar.date(from: startTimestamp)!
+ for var event in eventsNeedingTimestamp {
+ if !(event is NineteenSomethingGlucoseEvent) {
+ date = calendar.date(byAdding: Calendar.Component.minute, value: 5, to: date)!
+ }
+ event.timestamp = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
+ event.timestamp.calendar = calendar
+ eventsWithTimestamps.append(event)
+ }
+ return eventsWithTimestamps
+ }
+
+ while offset < length {
+ // Slurp up 0's
+ if pageData[offset] as UInt8 == 0 {
+ offset += 1
+ continue
+ }
+
+ let event = matchEvent(offset)
+
+ if let event = event as? RelativeTimestampedGlucoseEvent {
+ eventsNeedingTimestamp.insert(event, at: 0)
+ } else if let event = event as? ReferenceTimestampedGlucoseEvent {
+ let eventsWithTimestamp = addTimestampsToEvents(startTimestamp: event.timestamp, eventsNeedingTimestamp: eventsNeedingTimestamp).reversed()
+ tempEvents.append(contentsOf: eventsWithTimestamp)
+ eventsNeedingTimestamp.removeAll()
+ tempEvents.append(event)
+ } else {
+ tempEvents.append(event)
+ }
+
+ offset += event.length
+ }
+ events = tempEvents.reversed()
+ }
+}
diff --git a/MinimedKit/HistoryPage.swift b/MinimedKit/HistoryPage.swift
index b7bb505c7..6442cdd38 100644
--- a/MinimedKit/HistoryPage.swift
+++ b/MinimedKit/HistoryPage.swift
@@ -6,6 +6,8 @@
// Copyright © 2016 Pete Schwamb. All rights reserved.
//
+import Foundation
+
public class HistoryPage {
public enum HistoryPageError: Error {
diff --git a/MinimedKit/Info.plist b/MinimedKit/Info.plist
index 2ed8188bd..c66882b70 100644
--- a/MinimedKit/Info.plist
+++ b/MinimedKit/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/MinimedKit/MessageType.swift b/MinimedKit/MessageType.swift
index e1b75bd32..45481924a 100644
--- a/MinimedKit/MessageType.swift
+++ b/MinimedKit/MessageType.swift
@@ -27,7 +27,9 @@ public enum MessageType: UInt8 {
case getHistoryPage = 0x80
case getPumpModel = 0x8d
case readTempBasal = 0x98
+ case getGlucosePage = 0x9A
case readSettings = 0xc0
+ case readCurrentGlucosePage = 0xcd
case readPumpStatus = 0xce
var bodyType: MessageBody.Type {
@@ -62,6 +64,10 @@ public enum MessageType: UInt8 {
return ReadRemainingInsulinMessageBody.self
case .readPumpStatus:
return ReadPumpStatusMessageBody.self
+ case .readCurrentGlucosePage:
+ return ReadCurrentGlucosePageMessageBody.self
+ case .getGlucosePage:
+ return GetGlucosePageMessageBody.self
default:
return UnknownMessageBody.self
}
diff --git a/MinimedKit/Messages/GetGlucosePageMessageBody.swift b/MinimedKit/Messages/GetGlucosePageMessageBody.swift
new file mode 100644
index 000000000..0f15b04ed
--- /dev/null
+++ b/MinimedKit/Messages/GetGlucosePageMessageBody.swift
@@ -0,0 +1,35 @@
+//
+// GetGlucosePageMessageBody.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/19/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public class GetGlucosePageMessageBody: CarelinkLongMessageBody {
+ public let lastFrame: Bool
+ public let frameNumber: Int
+ public let frame: Data
+
+ public required init?(rxData: Data) {
+ guard rxData.count == type(of: self).length else {
+ return nil
+ }
+ frameNumber = Int(rxData[0] as UInt8) & 0b1111111
+ lastFrame = (rxData[0] as UInt8) & 0b10000000 > 0
+ frame = rxData.subdata(in: 1..<65)
+ super.init(rxData: rxData)
+ }
+
+ public required init(pageNum: UInt32) {
+ let numArgs = 4
+ lastFrame = false
+ frame = Data()
+ frameNumber = 0
+ let data = Data(hexadecimalString: String(format: "%02x%08x", numArgs, pageNum))!
+ super.init(rxData: data)!
+ }
+
+}
diff --git a/MinimedKit/Messages/ReadCurrentGlucosePageMessageBody.swift b/MinimedKit/Messages/ReadCurrentGlucosePageMessageBody.swift
new file mode 100644
index 000000000..0d2f6274f
--- /dev/null
+++ b/MinimedKit/Messages/ReadCurrentGlucosePageMessageBody.swift
@@ -0,0 +1,30 @@
+//
+// ReadCurrentGlucosePageMessageBody.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/19/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public class ReadCurrentGlucosePageMessageBody: CarelinkLongMessageBody {
+
+ public let pageNum: UInt32
+ public let glucose: Int
+ public let isig: Int
+
+ public required init?(rxData: Data) {
+ guard rxData.count == type(of: self).length else {
+ return nil
+ }
+
+ self.pageNum = rxData.subdata(in: 1..<5).withUnsafeBytes({ (bytes: UnsafePointer) -> UInt32 in
+ return UInt32(bigEndian: bytes.pointee)
+ })
+ self.glucose = Int(rxData[6] as UInt8)
+ self.isig = Int(rxData[8] as UInt8)
+
+ super.init(rxData: rxData)
+ }
+}
diff --git a/MinimedKit/PumpModel.swift b/MinimedKit/PumpModel.swift
index 865bfc682..951073b27 100644
--- a/MinimedKit/PumpModel.swift
+++ b/MinimedKit/PumpModel.swift
@@ -12,8 +12,11 @@
public enum PumpModel: String {
case Model508 = "508"
case Model511 = "511"
+ case Model711 = "711"
case Model512 = "512"
+ case Model712 = "712"
case Model515 = "515"
+ case Model715 = "715"
case Model522 = "522"
case Model722 = "722"
case Model523 = "523"
diff --git a/MinimedKit/TimestampedGlucoseEvent.swift b/MinimedKit/TimestampedGlucoseEvent.swift
new file mode 100644
index 000000000..ca7cfd69e
--- /dev/null
+++ b/MinimedKit/TimestampedGlucoseEvent.swift
@@ -0,0 +1,34 @@
+//
+// TimestampedGlucoseEvent.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/19/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public struct TimestampedGlucoseEvent {
+ public let glucoseEvent: GlucoseEvent
+ public let date: Date
+
+ public func isMutable(atDate date: Date = Date()) -> Bool {
+ return false
+ }
+
+ public init(glucoseEvent: GlucoseEvent, date: Date) {
+ self.glucoseEvent = glucoseEvent
+ self.date = date
+ }
+}
+
+
+extension TimestampedGlucoseEvent: DictionaryRepresentable {
+ public var dictionaryRepresentation: [String : Any] {
+ var dict = glucoseEvent.dictionaryRepresentation
+
+ dict["timestamp"] = DateFormatter.ISO8601DateFormatter().string(from: date)
+
+ return dict
+ }
+}
diff --git a/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift
new file mode 100644
index 000000000..e7af514b8
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/BatteryChangeGlucoseEventTests.swift
@@ -0,0 +1,31 @@
+//
+// BatteryChangeGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class BatteryChangeGlucoseEventTests: XCTestCase {
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "0a0bae0a0e")!
+ let subject = BatteryChangeGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2014, month: 2, day: 10, hour: 11, minute: 46)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+}
diff --git a/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift
new file mode 100644
index 000000000..3301e3f75
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/CalBGForGHGlucoseEventTests.swift
@@ -0,0 +1,34 @@
+//
+// CalBGForGHGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class CalBGForGHGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "0e4f5b138fa0")!
+ let subject = CalBGForGHGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2015, month: 5, day: 19, hour: 15, minute: 27)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ XCTAssertEqual(subject.amount, 160)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift
new file mode 100644
index 000000000..ae3b72ea3
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/DateTimeChangeGlucoseEventTests.swift
@@ -0,0 +1,33 @@
+//
+// DateTimeChangeGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class DateTimeChangeGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "0c0ad23e0e")!
+ let subject = DateTimeChangeGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2014, month: 3, day: 30, hour: 10, minute: 18)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift
new file mode 100644
index 000000000..89654aa08
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/GlucoseSensorDataGlucoseEventTests.swift
@@ -0,0 +1,31 @@
+//
+// GlucoseSensorDataGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class GlucoseSensorDataGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "35")!
+ let subject = GlucoseSensorDataGlucoseEvent(availableData: rawData)!
+
+ XCTAssertEqual(subject.sgv, 106)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift
new file mode 100644
index 000000000..e5c45f70a
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/SensorCalFactorGlucoseEventTests.swift
@@ -0,0 +1,34 @@
+//
+// SensorCalFactorGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class SensorCalFactorGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "0f4f67130f128c")!
+ let subject = SensorCalFactorGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2015, month: 5, day: 19, hour: 15, minute: 39)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ XCTAssertEqual(subject.factor, 4.748)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift
new file mode 100644
index 000000000..2b14f66d1
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/SensorCalGlucoseEventTests.swift
@@ -0,0 +1,38 @@
+//
+// SensorCalGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class SensorCalGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecodingMeterBgNow() {
+ let rawData = Data(hexadecimalString: "0300")!
+ let subject = SensorCalGlucoseEvent(availableData: rawData)!
+
+ XCTAssertEqual(subject.waiting, "meter_bg_now")
+ }
+
+ func testDecodingWaiting() {
+ let rawData = Data(hexadecimalString: "0301")!
+ let subject = SensorCalGlucoseEvent(availableData: rawData)!
+
+ XCTAssertEqual(subject.waiting, "waiting")
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift
new file mode 100644
index 000000000..482863555
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/SensorStatusGlucoseEventTests.swift
@@ -0,0 +1,32 @@
+//
+// SensorStatusGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class SensorStatusGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "0b0baf0a0e")!
+ let subject = SensorStatusGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2014, month: 2, day: 10, hour: 11, minute: 47)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+}
diff --git a/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift
new file mode 100644
index 000000000..8d2a49f56
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/SensorSyncGlucoseEventTests.swift
@@ -0,0 +1,38 @@
+//
+// SensorSyncGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class SensorSyncGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testExample() {
+ // This is an example of a functional test case.
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ }
+
+ func testPerformanceExample() {
+ let rawData = Data(hexadecimalString: "0d4d44330f")!
+ let subject = SensorSyncGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2015, month: 5, day: 19, hour: 13, minute: 04)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift
new file mode 100644
index 000000000..e899bfb04
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift
@@ -0,0 +1,33 @@
+//
+// SensorTimestampGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class SensorTimestampGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "088d9b5d0c")!
+ let subject = SensorTimestampGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2012, month: 10, day: 29, hour: 13, minute: 27)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+
+}
diff --git a/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift
new file mode 100644
index 000000000..6a98b2dec
--- /dev/null
+++ b/MinimedKitTests/GlucoseEvents/TenSomethingGlucoseEventTests.swift
@@ -0,0 +1,33 @@
+//
+// TenSomethingGlucoseEventTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class TenSomethingGlucoseEventTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testDecoding() {
+ let rawData = Data(hexadecimalString: "100bb40a0e")!
+ let subject = TenSomethingGlucoseEvent(availableData: rawData)!
+
+ let expectedTimestamp = DateComponents(calendar: Calendar.current,
+ year: 2014, month: 2, day: 10, hour: 11, minute: 52)
+ XCTAssertEqual(subject.timestamp, expectedTimestamp)
+ }
+
+}
diff --git a/MinimedKitTests/GlucosePageTests.swift b/MinimedKitTests/GlucosePageTests.swift
new file mode 100644
index 000000000..5329e4f49
--- /dev/null
+++ b/MinimedKitTests/GlucosePageTests.swift
@@ -0,0 +1,122 @@
+//
+// GlucosePageTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/16/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class GlucosePageTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testGlucosePageCRC() {
+ do {
+ let _ = try GlucosePage(pageData: Data(hexadecimalString: "201E1D1C1A1817161718191B1D1B1C1F212527282A2E3235383C3FCD9086850E0E0000011006850E1043484857EB181006940E0F595E00000110069F0E106670757374767A7D7F8181817D7813726D6663605E5B554F4C4E4F4B484946423E3B38353234332D2B2B2B2C2E302F2F312F2D2D2E2D2C2D2D2A2B292700000110069F1310242323272B2C3235383C00000110069514103E3E3F404141444A4945413E3D3D3A35302C2823201D1B1C1D1A1A1B1C1E2123272B2F3231323235383B3F43484949474542779007A0000E41423D6C171007AD000F3C3D3D3B3C3E3F41474F545A626A6E700000011007860210717271727476797A7A7B7C7D7C7B777472706E6D6C6B6A6763605C5A6064636160605F5D5C5C5B5956545250555A585656555554565654504D4C4A484E515455555452504F4D4D504E4D4E505050504F4E4D4C4C4F50510000011007980910539290079C090E54554BC4141007A8090F4A4A49494C4C4D50515253524F53524F4D4C7590078E0B0E7590878E0B0E4A4947433BD0121007A30B0F373333312F2B26242423252526292A2A2A0000011007810D102A2A2828282B3337383A3F44474746484B4F52504B4846434343413D393500000110079F0F10312F2D2B27211E1D3F90078E100E1C1A191214100798100F181817181F20242A2E33383E41464B4B4F56595E000001100788121065686667660000011007A3121066686B6D6F727375777774707273706C6764615F5A575553453D39322C251F1A1C191614171D2124282C2E31353A3F4144484A4B4C4D50555B000001100790171061656A6665656768C99007B9170E0000011007B917106869659413100889000F625F5D5D5F5D5A56524B4E4E4C4B4847494B494A4D5051514F4E4C4E4E4D4B4A494A4B4B4B4B47474D4E4E4E4E4E4C4B4A46434B4D4C4B49490000011008B804104B4B4B4D515456565655545455595A5800000110088F0610595A5A595A595755555858575655545453525152534E4A474445484B4E4F13505251135113515051525154AF9088A6090E0000011008A6091052505594141008B3090F55565B5A58534F4B49134037132F28132320131A13181514151615171919191A1A1B1A1B1C1D202325242221225890088B0D0E00000110088C0D1023252AEC151008990D0F2B2B2E31393F3A3C41484E555D00000110089F0E1063696E73767A7C7D7F7E7F8085878689E59008B50F0E0000011008B50F10878979CD13100885100F76737272706D0000011008A71010696461605D5A57555352520000011008A11110504C4947484743434278900893120E0000011008941210423F3A3837D6131008A9120F33322F2E2F31322F2C2C2B2828292A2827243A90088E140E211C19181809141008A4140F191A19191028B6140813131313133C95")!)
+ } catch GlucosePage.GlucosePageError.invalidCRC {
+ XCTFail("page decoding threw invalid crc")
+ } catch GlucosePage.GlucosePageError.unknownEventType(let eventType) {
+ XCTFail("unknown event type" + String(eventType))
+ } catch {
+ XCTFail("Unexpected exception...")
+ }
+ }
+
+ func testGlucosePageInvalidCRC() {
+ do {
+ let _ = try GlucosePage(pageData: Data(hexadecimalString: "201E1D1C1A1817161718191B1D1B1C1F212527282A2E3235383C3FCD9086850E0E0000011006850E1043484857EB181006940E0F595E00000110069F0E106670757374767A7D7F8181817D7813726D6663605E5B554F4C4E4F4B484946423E3B38353234332D2B2B2B2C2E302F2F312F2D2D2E2D2C2D2D2A2B292700000110069F1310242323272B2C3235383C00000110069514103E3E3F404141444A4945413E3D3D3A35302C2823201D1B1C1D1A1A1B1C1E2123272B2F3231323235383B3F43484949474542779007A0000E41423D6C171007AD000F3C3D3D3B3C3E3F41474F545A626A6E700000011007860210717271727476797A7A7B7C7D7C7B777472706E6D6C6B6A6763605C5A6064636160605F5D5C5C5B5956545250555A585656555554565654504D4C4A484E515455555452504F4D4D504E4D4E505050504F4E4D4C4C4F50510000011007980910539290079C090E54554BC4141007A8090F4A4A49494C4C4D50515253524F53524F4D4C7590078E0B0E7590878E0B0E4A4947433BD0121007A30B0F373333312F2B26242423252526292A2A2A0000011007810D102A2A2828282B3337383A3F44474746484B4F52504B4846434343413D393500000110079F0F10312F2D2B27211E1D3F90078E100E1C1A191214100798100F181817181F20242A2E33383E41464B4B4F56595E000001100788121065686667660000011007A3121066686B6D6F727375777774707273706C6764615F5A575553453D39322C251F1A1C191614171D2124282C2E31353A3F4144484A4B4C4D50555B000001100790171061656A6665656768C99007B9170E0000011007B917106869659413100889000F625F5D5D5F5D5A56524B4E4E4C4B4847494B494A4D5051514F4E4C4E4E4D4B4A494A4B4B4B4B47474D4E4E4E4E4E4C4B4A46434B4D4C4B49490000011008B804104B4B4B4D515456565655545455595A5800000110088F0610595A5A595A595755555858575655545453525152534E4A474445484B4E4F13505251135113515051525154AF9088A6090E0000011008A6091052505594141008B3090F55565B5A58534F4B49134037132F28132320131A13181514151615171919191A1A1B1A1B1C1D202325242221225890088B0D0E00000110088C0D1023252AEC151008990D0F2B2B2E31393F3A3C41484E555D00000110089F0E1063696E73767A7C7D7F7E7F8085878689E59008B50F0E0000011008B50F10878979CD13100885100F76737272706D0000011008A71010696461605D5A57555352520000011008A11110504C4947484743434278900893120E0000011008941210423F3A3837D6131008A9120F33322F2E2F31322F2C2C2B2828292A2827243A90088E140E211C19181809141008A4140F191A19191028B6140813131313133C94")!)
+ XCTFail("Should have thrown InvalidCRC")
+ } catch GlucosePage.GlucosePageError.invalidCRC {
+ // Happy path
+ } catch GlucosePage.GlucosePageError.unknownEventType(let eventType) {
+ XCTFail("unknown event type" + String(eventType))
+ } catch {
+ XCTFail("Unexpected exception...")
+ }
+ }
+
+ func testUnknownRecords() {
+ do {
+ //05 is a currently unknown opcode
+ let pageData = Data(hexadecimalString: "051053b394081053b3940b014a60".leftPadding(toLength: 2048, withPad: "0"))!
+ let page = try GlucosePage(pageData: pageData)
+ let events = page.events
+
+ XCTAssertEqual(events.count, 4)
+ XCTAssertEqual((events.first as! UnknownGlucoseEvent).op, "05")
+
+ } catch GlucosePage.GlucosePageError.invalidCRC {
+ XCTFail("page decoding threw invalid crc")
+ } catch GlucosePage.GlucosePageError.unknownEventType(let eventType) {
+ XCTFail("unknown event type" + String(eventType))
+ } catch {
+ XCTFail("Unexpected exception...")
+ }
+ }
+
+ func testRelativeTimestamping() {
+ do {
+ let calendar = Calendar.current
+ // a sensor timestamp, then "19-Something" and glucose relative timestamp records
+ let pageData = Data(hexadecimalString: "1028B6140813306BFB".leftPadding(toLength: 2048, withPad: "0"))!
+ let page = try GlucosePage(pageData: pageData)
+ let events = page.events
+
+ XCTAssertEqual(events.count, 3)
+ //the initial timestamp comes from the sensor timestamp reference record
+ let expectedTimestamp = DateComponents(calendar: calendar,
+ year: 2016, month: 2, day: 8,
+ hour: 20, minute: 54)
+ XCTAssertEqual(events[0].timestamp, expectedTimestamp)
+
+ //The 19-Something needs a timestamp, but doesn't increment the relative counter
+ XCTAssertEqual(events[1].timestamp, expectedTimestamp)
+
+ //The GlucoseSensorData event needs a timestamp and does increment the relative counter by 5 minutes
+ let expectedGlucoseTimestamp = DateComponents(calendar: calendar,
+ year: 2016, month: 2, day: 8,
+ hour: 20, minute: 59)
+ XCTAssertEqual(events[2].timestamp, expectedGlucoseTimestamp)
+
+ } catch GlucosePage.GlucosePageError.invalidCRC {
+ XCTFail("page decoding threw invalid crc")
+ } catch GlucosePage.GlucosePageError.unknownEventType(let eventType) {
+ XCTFail("unknown event type" + String(eventType))
+ } catch {
+ XCTFail("Unexpected exception...")
+ }
+ }
+
+ func testGlucosePageEventDecoding() {
+ do {
+ let page = try GlucosePage(pageData: Data(hexadecimalString: "201E1D1C1A1817161718191B1D1B1C1F212527282A2E3235383C3FCD9086850E0E0000011006850E1043484857EB181006940E0F595E00000110069F0E106670757374767A7D7F8181817D7813726D6663605E5B554F4C4E4F4B484946423E3B38353234332D2B2B2B2C2E302F2F312F2D2D2E2D2C2D2D2A2B292700000110069F1310242323272B2C3235383C00000110069514103E3E3F404141444A4945413E3D3D3A35302C2823201D1B1C1D1A1A1B1C1E2123272B2F3231323235383B3F43484949474542779007A0000E41423D6C171007AD000F3C3D3D3B3C3E3F41474F545A626A6E700000011007860210717271727476797A7A7B7C7D7C7B777472706E6D6C6B6A6763605C5A6064636160605F5D5C5C5B5956545250555A585656555554565654504D4C4A484E515455555452504F4D4D504E4D4E505050504F4E4D4C4C4F50510000011007980910539290079C090E54554BC4141007A8090F4A4A49494C4C4D50515253524F53524F4D4C7590078E0B0E7590878E0B0E4A4947433BD0121007A30B0F373333312F2B26242423252526292A2A2A0000011007810D102A2A2828282B3337383A3F44474746484B4F52504B4846434343413D393500000110079F0F10312F2D2B27211E1D3F90078E100E1C1A191214100798100F181817181F20242A2E33383E41464B4B4F56595E000001100788121065686667660000011007A3121066686B6D6F727375777774707273706C6764615F5A575553453D39322C251F1A1C191614171D2124282C2E31353A3F4144484A4B4C4D50555B000001100790171061656A6665656768C99007B9170E0000011007B917106869659413100889000F625F5D5D5F5D5A56524B4E4E4C4B4847494B494A4D5051514F4E4C4E4E4D4B4A494A4B4B4B4B47474D4E4E4E4E4E4C4B4A46434B4D4C4B49490000011008B804104B4B4B4D515456565655545455595A5800000110088F0610595A5A595A595755555858575655545453525152534E4A474445484B4E4F13505251135113515051525154AF9088A6090E0000011008A6091052505594141008B3090F55565B5A58534F4B49134037132F28132320131A13181514151615171919191A1A1B1A1B1C1D202325242221225890088B0D0E00000110088C0D1023252AEC151008990D0F2B2B2E31393F3A3C41484E555D00000110089F0E1063696E73767A7C7D7F7E7F8085878689E59008B50F0E0000011008B50F10878979CD13100885100F76737272706D0000011008A71010696461605D5A57555352520000011008A11110504C4947484743434278900893120E0000011008941210423F3A3837D6131008A9120F33322F2E2F31322F2C2C2B2828292A2827243A90088E140E211C19181809141008A4140F191A19191028B6140813131313133C95")!)
+
+ let events = page.events
+
+ let expectedEventNames: [String] = ["CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "CalBGForGH", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "CalBGForGH", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "CalBGForGH", "CalBGForGH", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "CalBGForGH", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "19-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "DataEnd", "CalBGForGH", "10-Something", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "CalBGForGH", "SensorCalFactor", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "GlucoseSensorData", "SensorTimestamp", "19-Something", "19-Something", "19-Something", "19-Something", "19-Something"]
+
+ for (index, values) in zip(expectedEventNames, events).enumerated() {
+ let eventName = values.1.dictionaryRepresentation["name"] as! String
+ XCTAssertEqual(values.0, eventName, "Decoded events don't match at index: \(index). Event: \(values.1.dictionaryRepresentation)")
+ }
+
+ } catch GlucosePage.GlucosePageError.invalidCRC {
+ XCTFail("page decoding threw invalid crc")
+ } catch GlucosePage.GlucosePageError.unknownEventType(let eventType) {
+ XCTFail("unknown event type" + String(eventType))
+ } catch {
+ XCTFail("Unexpected exception...")
+ }
+ }
+}
diff --git a/MinimedKitTests/Info.plist b/MinimedKitTests/Info.plist
index c0a7b8da5..8e0afffd2 100644
--- a/MinimedKitTests/Info.plist
+++ b/MinimedKitTests/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift b/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift
new file mode 100644
index 000000000..b516004c3
--- /dev/null
+++ b/MinimedKitTests/Messages/GetGlucosePageMessageBodyTests.swift
@@ -0,0 +1,30 @@
+//
+// GetGlucosePageMessageBodyTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/19/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class GetGlucosePageMessageBodyTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testTxDataEncoding() {
+ let messageBody = GetGlucosePageMessageBody(pageNum: 13)
+
+ XCTAssertEqual(messageBody.txData.subdata(in: 0..<5).hexadecimalString, "040000000d")
+ }
+
+}
diff --git a/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift b/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift
new file mode 100644
index 000000000..99a655c7c
--- /dev/null
+++ b/MinimedKitTests/Messages/ReadCurrentGlucosePageMessageBodyTests.swift
@@ -0,0 +1,35 @@
+//
+// ReadCurrentGlucosePageMessageBodyTests.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/19/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import XCTest
+@testable import MinimedKit
+
+class ReadCurrentGlucosePageMessageBodyTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testResponseInitializer() {
+ var responseData = Data(hexadecimalString: "0000000D6100100020")!
+ responseData.append(contentsOf: [UInt8](repeating: 0, count: 65 - responseData.count))
+
+ let messageBody = ReadCurrentGlucosePageMessageBody(rxData: responseData)!
+
+ XCTAssertEqual(messageBody.pageNum, 3425)
+ XCTAssertEqual(messageBody.glucose, 16)
+ XCTAssertEqual(messageBody.isig, 32)
+ }
+
+}
diff --git a/MinimedKitTests/NSDateComponentsTests.swift b/MinimedKitTests/NSDateComponentsTests.swift
index c4a141cf5..b61ee07b1 100644
--- a/MinimedKitTests/NSDateComponentsTests.swift
+++ b/MinimedKitTests/NSDateComponentsTests.swift
@@ -30,4 +30,13 @@ class NSDateComponentsTests: XCTestCase {
XCTAssertEqual(2, comps.month)
}
+ func testInitWithGlucoseData() {
+ let input = Data(hexadecimalString: "0bae0a0e")!
+ let comps = DateComponents(glucoseEventBytes: input)
+ XCTAssertEqual(2014, comps.year)
+ XCTAssertEqual(2, comps.month)
+ XCTAssertEqual(10, comps.day)
+ XCTAssertEqual(11, comps.hour)
+ XCTAssertEqual(46, comps.minute)
+ }
}
diff --git a/MinimedKitTests/NSStringExtensions.swift b/MinimedKitTests/NSStringExtensions.swift
new file mode 100644
index 000000000..ad445a477
--- /dev/null
+++ b/MinimedKitTests/NSStringExtensions.swift
@@ -0,0 +1,20 @@
+//
+// NSStringExtensions.swift
+// RileyLink
+//
+// Created by Timothy Mecklem on 10/18/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+extension String {
+ func leftPadding(toLength: Int, withPad character: Character) -> String {
+ let newLength = self.characters.count
+ if newLength < toLength {
+ return String(repeatElement(character, count: toLength - newLength)) + self
+ } else {
+ return self.substring(from: index(self.startIndex, offsetBy: newLength - toLength))
+ }
+ }
+}
diff --git a/NightscoutUploadKit/Either.swift b/NightscoutUploadKit/Either.swift
new file mode 100644
index 000000000..16eb92c43
--- /dev/null
+++ b/NightscoutUploadKit/Either.swift
@@ -0,0 +1,14 @@
+//
+// Either.swift
+// RileyLink
+//
+// Created by Pete Schwamb on 10/9/16.
+// Copyright © 2016 Pete Schwamb. All rights reserved.
+//
+
+import Foundation
+
+public enum Either {
+ case success(T1)
+ case failure(T2)
+}
diff --git a/NightscoutUploadKit/Info.plist b/NightscoutUploadKit/Info.plist
index 2ed8188bd..c66882b70 100644
--- a/NightscoutUploadKit/Info.plist
+++ b/NightscoutUploadKit/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/NightscoutUploadKit/NightscoutUploader.swift b/NightscoutUploadKit/NightscoutUploader.swift
index a2bb6caa6..fda11ba07 100644
--- a/NightscoutUploadKit/NightscoutUploader.swift
+++ b/NightscoutUploadKit/NightscoutUploader.swift
@@ -13,12 +13,13 @@ import Crypto
public enum UploadError: Error {
case httpError(status: Int, body: String)
case missingTimezone
+ case invalidResponse(reason: String)
case unauthorized
}
-private let defaultNightscoutEntriesPath = "/api/v1/entries.json"
-private let defaultNightscoutTreatmentPath = "/api/v1/treatments.json"
-private let defaultNightscoutDeviceStatusPath = "/api/v1/devicestatus.json"
+private let defaultNightscoutEntriesPath = "/api/v1/entries"
+private let defaultNightscoutTreatmentPath = "/api/v1/treatments"
+private let defaultNightscoutDeviceStatusPath = "/api/v1/devicestatus"
private let defaultNightscoutAuthTestPath = "/api/v1/experiments/test"
public class NightscoutUploader {
@@ -51,6 +52,9 @@ public class NightscoutUploader {
public var errorHandler: ((_ error: Error, _ context: String) -> Void)?
+ private var dataAccessQueue: DispatchQueue = DispatchQueue(label: "com.rileylink.NightscoutUploadKit.dataAccessQueue", attributes: [])
+
+
public func reset() {
observingPumpEventsSince = Date(timeIntervalSinceNow: TimeInterval(hours: -24))
lastStoredTreatmentTimestamp = nil
@@ -119,7 +123,72 @@ public class NightscoutUploader {
public func upload(_ pumpEvents: [TimestampedHistoryEvent], forSource source: String, from pumpModel: PumpModel, completionHandler: @escaping (Error?) -> Void) {
let treatments = NightscoutPumpEvents.translate(pumpEvents, eventSource: source).map { $0.dictionaryRepresentation }
- uploadToNS(treatments, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler)
+ postToNS(treatments, endpoint: defaultNightscoutTreatmentPath) { (result) in
+ switch result {
+ case .success( _):
+ completionHandler(nil)
+ case .failure(let error):
+ completionHandler(error)
+ }
+ }
+ }
+
+ /// Attempts to upload nightscout treatment objects.
+ /// This method will not retry if the network task failed.
+ ///
+ /// - parameter treatments: An array of nightscout treatments.
+ /// - parameter completionHandler: A closure to execute when the task completes. It has a single argument for any error that might have occurred during the upload.
+ public func upload(_ treatments: [NightscoutTreatment], completionHandler: @escaping (Either<[String],Error>) -> Void) {
+ postToNS(treatments.map { $0.dictionaryRepresentation }, endpoint: defaultNightscoutTreatmentPath, completion: completionHandler)
+ }
+
+ /// Attempts to modify nightscout treatments. This method will not retry if the network task failed.
+ ///
+ /// - parameter treatments: An array of nightscout treatments. The id attribute must be set, identifying the treatment to update.
+ /// - parameter completionHandler: A closure to execute when the task completes. It has a single argument for any error that might have occurred during the modify.
+ public func modifyTreatments(_ treatments:[NightscoutTreatment], completionHandler: @escaping (Error?) -> Void) {
+ dataAccessQueue.async {
+ let modifyGroup = DispatchGroup()
+ var errors = [Error]()
+
+ for treatment in treatments {
+ modifyGroup.enter()
+ self.putToNS( treatment.dictionaryRepresentation, endpoint: defaultNightscoutTreatmentPath ) { (error) in
+ if let error = error {
+ errors.append(error)
+ }
+ modifyGroup.leave()
+ }
+ }
+
+ _ = modifyGroup.wait(timeout: DispatchTime.distantFuture)
+ completionHandler(errors.first)
+ }
+
+ }
+
+ /// Attempts to delete treatments from nightscout. This method will not retry if the network task failed.
+ ///
+ /// - parameter id: An array of nightscout treatment ids
+ /// - parameter completionHandler: A closure to execute when the task completes. It has a single argument for any error that might have occurred during the deletion.
+ public func deleteTreatmentsById(_ ids:[String], completionHandler: @escaping (Error?) -> Void) {
+ dataAccessQueue.async {
+ let deleteGroup = DispatchGroup()
+ var errors = [Error]()
+
+ for id in ids {
+ deleteGroup.enter()
+ self.deleteFromNS(id, endpoint: defaultNightscoutTreatmentPath) { (error) in
+ if let error = error {
+ errors.append(error)
+ }
+ deleteGroup.leave()
+ }
+ }
+
+ _ = deleteGroup.wait(timeout: DispatchTime.distantFuture)
+ completionHandler(errors.first)
+ }
}
public func uploadDeviceStatus(_ status: DeviceStatus) {
@@ -225,50 +294,158 @@ public class NightscoutUploader {
flushEntries()
flushTreatments()
}
-
- func uploadToNS(_ json: [Any], endpoint:String, completion: @escaping (Error?) -> Void) {
+
+ func deleteFromNS(_ id: String, endpoint:String, completion: @escaping (Error?) -> Void) {
+ let resource = "\(endpoint)/\(id)"
+ callNS(nil, endpoint: resource, method: "DELETE") { (result) in
+ switch result {
+ case .success( _):
+ completion(nil)
+ case .failure(let error):
+ completion(error)
+ }
+ }
+
+ }
+
+ func putToNS(_ json: Any, endpoint:String, completion: @escaping (Error?) -> Void) {
+ callNS(json, endpoint: endpoint, method: "PUT") { (result) in
+ switch result {
+ case .success( _):
+ completion(nil)
+ case .failure(let error):
+ completion(error)
+ }
+ }
+ }
+
+ func postToNS(_ json: [Any], endpoint:String, completion: @escaping (Either<[String],Error>) -> Void) {
if json.count == 0 {
- completion(nil)
+ completion(.success([]))
return
}
-
+
+ callNS(json, endpoint: endpoint, method: "POST") { (result) in
+ switch result {
+ case .success(let json):
+ guard let insertedEntries = json as? [[String: Any]] else {
+ completion(.failure(UploadError.invalidResponse(reason: "Expected array of objects in JSON response")))
+ return
+ }
+
+ let ids = insertedEntries.map({ (entry: [String: Any]) -> String in
+ if let id = entry["_id"] as? String {
+ return id
+ } else {
+ // Upload still succeeded; likely that this is an old version of NS
+ // Instead of failing (which would cause retries later, we just mark
+ // This entry has having an id of 'NA', which will let us consider it
+ // uploaded.
+ //throw UploadError.invalidResponse(reason: "Invalid/missing id in response.")
+ return "NA"
+ }
+ })
+ completion(.success(ids))
+ case .failure(let error):
+ completion(.failure(error))
+ }
+
+ }
+ }
+
+ func callNS(_ json: Any?, endpoint:String, method:String, completion: @escaping (Either) -> Void) {
let uploadURL = siteURL.appendingPathComponent(endpoint)
var request = URLRequest(url: uploadURL)
- request.httpMethod = "POST"
+ request.httpMethod = method
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue(apiSecret.sha1, forHTTPHeaderField: "api-secret")
do {
- let sendData = try JSONSerialization.data(withJSONObject: json, options: [])
- let task = URLSession.shared.uploadTask(with: request, from: sendData, completionHandler: { (data, response, error) in
- if let error = error {
- completion(error)
- return
- }
-
- if let httpResponse = response as? HTTPURLResponse ,
- httpResponse.statusCode != 200 {
- completion(UploadError.httpError(status: httpResponse.statusCode, body:String(data: data!, encoding: String.Encoding.utf8)!))
- } else {
- completion(nil)
- }
- })
- task.resume()
+ if let json = json {
+ let sendData = try JSONSerialization.data(withJSONObject: json, options: [])
+ let task = URLSession.shared.uploadTask(with: request, from: sendData, completionHandler: { (data, response, error) in
+ if let error = error {
+ completion(.failure(error))
+ return
+ }
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ completion(.failure(UploadError.invalidResponse(reason: "Response is not HTTPURLResponse")))
+ return
+ }
+
+ if httpResponse.statusCode != 200 {
+ let error = UploadError.httpError(status: httpResponse.statusCode, body:String(data: data!, encoding: String.Encoding.utf8)!)
+ completion(.failure(error))
+ return
+ }
+
+ guard let data = data else {
+ completion(.failure(UploadError.invalidResponse(reason: "No data in response")))
+ return
+ }
+
+ do {
+ let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
+ completion(.success(json))
+ } catch {
+ completion(.failure(error))
+ return
+ }
+ })
+ task.resume()
+ } else {
+ let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
+ if let error = error {
+ completion(.failure(error))
+ return
+ }
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ completion(.failure(UploadError.invalidResponse(reason: "Response is not HTTPURLResponse")))
+ return
+ }
+
+ if httpResponse.statusCode != 200 {
+ let error = UploadError.httpError(status: httpResponse.statusCode, body:String(data: data!, encoding: String.Encoding.utf8)!)
+ completion(.failure(error))
+ return
+ }
+
+ guard let data = data else {
+ completion(.failure(UploadError.invalidResponse(reason: "No data in response")))
+ return
+ }
+
+ do {
+ let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions())
+ completion(.success(json))
+ } catch {
+ completion(.failure(error))
+ return
+ }
+ })
+ task.resume()
+ }
+
} catch let error {
- completion(error)
+ completion(.failure(error))
}
}
func flushDeviceStatuses() {
let inFlight = deviceStatuses
deviceStatuses = []
- uploadToNS(inFlight as [Any], endpoint: defaultNightscoutDeviceStatusPath) { (error) in
- if let error = error {
+ postToNS(inFlight as [Any], endpoint: defaultNightscoutDeviceStatusPath) { (result) in
+ switch result {
+ case .failure(let error):
self.errorHandler?(error, "Uploading device status")
// Requeue
self.deviceStatuses.append(contentsOf: inFlight)
+ case .success(_):
+ break
}
}
}
@@ -276,11 +453,14 @@ public class NightscoutUploader {
func flushEntries() {
let inFlight = entries
entries = []
- uploadToNS(inFlight as [Any], endpoint: defaultNightscoutEntriesPath) { (error) in
- if let error = error {
+ postToNS(inFlight as [Any], endpoint: defaultNightscoutEntriesPath) { (result) in
+ switch result {
+ case .failure(let error):
self.errorHandler?(error, "Uploading nightscout entries")
// Requeue
self.entries.append(contentsOf: inFlight)
+ case .success(_):
+ break
}
}
}
@@ -288,12 +468,13 @@ public class NightscoutUploader {
func flushTreatments() {
let inFlight = treatmentsQueue
treatmentsQueue = []
- uploadToNS(inFlight.map({$0.dictionaryRepresentation}), endpoint: defaultNightscoutTreatmentPath) { (error) in
- if let error = error {
+ postToNS(inFlight.map({$0.dictionaryRepresentation}), endpoint: defaultNightscoutTreatmentPath) { (result) in
+ switch result {
+ case .failure(let error):
self.errorHandler?(error, "Uploading nightscout treatment records")
// Requeue
self.treatmentsQueue.append(contentsOf: inFlight)
- } else {
+ case .success(_):
if let last = inFlight.last {
self.lastStoredTreatmentTimestamp = last.timestamp
}
diff --git a/NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift b/NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift
index 3c88077be..3112adce4 100644
--- a/NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift
+++ b/NightscoutUploadKit/Treatments/MealBolusNightscoutTreatment.swift
@@ -10,28 +10,36 @@ import Foundation
public class MealBolusNightscoutTreatment: NightscoutTreatment {
- let glucose: Int
- let glucoseType: GlucoseType
- let units: Units
let carbs: Int
- let insulin: Double
-
- init(timestamp: Date, enteredBy: String, glucose: Int, glucoseType: GlucoseType, units: Units, carbs: Int, insulin: Double) {
+ let absorptionTime: TimeInterval?
+ let insulin: Double?
+ let glucose: Int?
+ let units: Units? // of glucose entry
+ let glucoseType: GlucoseType?
+
+ public init(timestamp: Date, enteredBy: String, id: String?, carbs: Int, absorptionTime: TimeInterval? = nil, insulin: Double? = nil, glucose: Int? = nil, glucoseType: GlucoseType? = nil, units: Units? = nil) {
+ self.carbs = carbs
+ self.absorptionTime = absorptionTime
self.glucose = glucose
self.glucoseType = glucoseType
self.units = units
self.insulin = insulin
- self.carbs = carbs
- super.init(timestamp: timestamp, enteredBy: enteredBy)
+ super.init(timestamp: timestamp, enteredBy: enteredBy, id: id)
}
override public var dictionaryRepresentation: [String: Any] {
var rval = super.dictionaryRepresentation
rval["eventType"] = "Meal Bolus"
- rval["glucose"] = glucose
- rval["glucoseType"] = glucoseType.rawValue
- rval["units"] = units.rawValue
+ rval["carbs"] = carbs
+ if let absorptionTime = absorptionTime {
+ rval["absorptionTime"] = absorptionTime.minutes
+ }
+ rval["insulin"] = insulin
+ if let glucose = glucose {
+ rval["glucose"] = glucose
+ rval["glucoseType"] = glucoseType?.rawValue
+ rval["units"] = units?.rawValue
+ }
return rval
}
-
}
diff --git a/NightscoutUploadKit/Treatments/NightscoutTreatment.swift b/NightscoutUploadKit/Treatments/NightscoutTreatment.swift
index 61f20866c..96afdad4b 100644
--- a/NightscoutUploadKit/Treatments/NightscoutTreatment.swift
+++ b/NightscoutUploadKit/Treatments/NightscoutTreatment.swift
@@ -10,7 +10,7 @@ import MinimedKit
public class NightscoutTreatment : DictionaryRepresentable {
- enum GlucoseType: String {
+ public enum GlucoseType: String {
case Meter
case Sensor
}
@@ -22,17 +22,23 @@ public class NightscoutTreatment : DictionaryRepresentable {
let timestamp: Date
let enteredBy: String
-
- init(timestamp: Date, enteredBy: String) {
+ let id: String?
+
+ init(timestamp: Date, enteredBy: String, id: String? = nil) {
self.timestamp = timestamp
self.enteredBy = enteredBy
+ self.id = id
}
public var dictionaryRepresentation: [String: Any] {
- return [
+ var rval = [
"created_at": TimeFormat.timestampStrFromDate(timestamp),
"timestamp": TimeFormat.timestampStrFromDate(timestamp),
"enteredBy": enteredBy,
]
+ if let id = id {
+ rval["_id"] = id
+ }
+ return rval
}
}
diff --git a/NightscoutUploadKitTests/Info.plist b/NightscoutUploadKitTests/Info.plist
index 8c56e9a00..d6de4eb78 100644
--- a/NightscoutUploadKitTests/Info.plist
+++ b/NightscoutUploadKitTests/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj
index 9d4a33765..2d02d956f 100644
--- a/RileyLink.xcodeproj/project.pbxproj
+++ b/RileyLink.xcodeproj/project.pbxproj
@@ -86,6 +86,43 @@
43EC9DCB1B786C6200DB0D18 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43EC9DCA1B786C6200DB0D18 /* LaunchScreen.xib */; };
43F348061D596270009933DC /* HKUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43F348051D596270009933DC /* HKUnit.swift */; };
43FF221C1CB9B9DE00024F30 /* NSDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */; };
+ 541688DB1DB820BF005B1891 /* ReadCurrentGlucosePageMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541688DA1DB820BF005B1891 /* ReadCurrentGlucosePageMessageBodyTests.swift */; };
+ 541688DD1DB82213005B1891 /* ReadCurrentGlucosePageMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541688DC1DB82213005B1891 /* ReadCurrentGlucosePageMessageBody.swift */; };
+ 541688DF1DB82E72005B1891 /* TimestampedGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 541688DE1DB82E72005B1891 /* TimestampedGlucoseEvent.swift */; };
+ 54A840D11DB85D0600B1F202 /* UnknownGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A840D01DB85D0600B1F202 /* UnknownGlucoseEvent.swift */; };
+ 54BC44731DB46A5200340EED /* GlucosePageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44721DB46A5200340EED /* GlucosePageTests.swift */; };
+ 54BC44751DB46B0A00340EED /* GlucosePage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44741DB46B0A00340EED /* GlucosePage.swift */; };
+ 54BC44781DB46C7D00340EED /* GlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44771DB46C7D00340EED /* GlucoseEvent.swift */; };
+ 54BC447C1DB4742F00340EED /* GlucoseEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC447B1DB4742F00340EED /* GlucoseEventType.swift */; };
+ 54BC447E1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC447D1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift */; };
+ 54BC44801DB4762200340EED /* TenSomethingGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC447F1DB4762200340EED /* TenSomethingGlucoseEvent.swift */; };
+ 54BC44821DB476BB00340EED /* CalBGForGHGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44811DB476BB00340EED /* CalBGForGHGlucoseEvent.swift */; };
+ 54BC44841DB476F600340EED /* SensorCalFactorGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44831DB476F600340EED /* SensorCalFactorGlucoseEvent.swift */; };
+ 54BC44881DB47B5F00340EED /* DataEndGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44871DB47B5F00340EED /* DataEndGlucoseEvent.swift */; };
+ 54BC448A1DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44891DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift */; };
+ 54BC448C1DB47BEA00340EED /* SensorCalGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC448B1DB47BEA00340EED /* SensorCalGlucoseEvent.swift */; };
+ 54BC448E1DB47C1E00340EED /* Fokko7GlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC448D1DB47C1E00340EED /* Fokko7GlucoseEvent.swift */; };
+ 54BC44901DB47C7400340EED /* SensorTimestampGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC448F1DB47C7400340EED /* SensorTimestampGlucoseEvent.swift */; };
+ 54BC44921DB47CBA00340EED /* BatteryChangeGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44911DB47CBA00340EED /* BatteryChangeGlucoseEvent.swift */; };
+ 54BC44941DB47CFB00340EED /* SensorStatusGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44931DB47CFB00340EED /* SensorStatusGlucoseEvent.swift */; };
+ 54BC44961DB47D2A00340EED /* DateTimeChangeGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44951DB47D2A00340EED /* DateTimeChangeGlucoseEvent.swift */; };
+ 54BC44981DB47D5300340EED /* SensorSyncGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44971DB47D5300340EED /* SensorSyncGlucoseEvent.swift */; };
+ 54BC449A1DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44991DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift */; };
+ 54BC449C1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC449B1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift */; };
+ 54BC449E1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC449D1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift */; };
+ 54BC44A11DB6F74300340EED /* BatteryChangeGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44A01DB6F74300340EED /* BatteryChangeGlucoseEventTests.swift */; };
+ 54BC44A31DB7021B00340EED /* SensorStatusGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44A21DB7021B00340EED /* SensorStatusGlucoseEventTests.swift */; };
+ 54BC44A51DB702C800340EED /* DateTimeChangeGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44A41DB702C800340EED /* DateTimeChangeGlucoseEventTests.swift */; };
+ 54BC44A71DB703E900340EED /* SensorSyncGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44A61DB703E900340EED /* SensorSyncGlucoseEventTests.swift */; };
+ 54BC44A91DB704A600340EED /* CalBGForGHGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44A81DB704A600340EED /* CalBGForGHGlucoseEventTests.swift */; };
+ 54BC44AB1DB7093700340EED /* SensorTimestampGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44AA1DB7093700340EED /* SensorTimestampGlucoseEventTests.swift */; };
+ 54BC44AD1DB70A5E00340EED /* SensorCalFactorGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44AC1DB70A5E00340EED /* SensorCalFactorGlucoseEventTests.swift */; };
+ 54BC44AF1DB70C3E00340EED /* TenSomethingGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44AE1DB70C3E00340EED /* TenSomethingGlucoseEventTests.swift */; };
+ 54BC44B11DB70F4A00340EED /* GlucoseSensorDataGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44B01DB70F4A00340EED /* GlucoseSensorDataGlucoseEventTests.swift */; };
+ 54BC44B31DB711BE00340EED /* SensorCalGlucoseEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44B21DB711BE00340EED /* SensorCalGlucoseEventTests.swift */; };
+ 54BC44B51DB7184D00340EED /* NSStringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44B41DB7184D00340EED /* NSStringExtensions.swift */; };
+ 54BC44B71DB81B5100340EED /* GetGlucosePageMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44B61DB81B5100340EED /* GetGlucosePageMessageBodyTests.swift */; };
+ 54BC44B91DB81D6100340EED /* GetGlucosePageMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54BC44B81DB81D6100340EED /* GetGlucosePageMessageBody.swift */; };
C10AB08D1C855613000F102E /* FindDeviceMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10AB08C1C855613000F102E /* FindDeviceMessageBody.swift */; };
C10AB08F1C855F34000F102E /* DeviceLinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10AB08E1C855F34000F102E /* DeviceLinkMessageBody.swift */; };
C10D9BC41C8269D500378342 /* MinimedKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C10D9BC31C8269D500378342 /* MinimedKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -130,6 +167,7 @@
C12EA26A198B442100309FA4 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C12EA269198B442100309FA4 /* Storyboard.storyboard */; };
C133CF931D5943780034B82D /* PredictedBG.swift in Sources */ = {isa = PBXBuildFile; fileRef = C133CF921D5943780034B82D /* PredictedBG.swift */; };
C139AC241BFD84B500B0518F /* RuntimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC231BFD84B500B0518F /* RuntimeUtils.m */; };
+ C13D155A1DAACE8400ADC044 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = C13D15591DAACE8400ADC044 /* Either.swift */; };
C14303161C97C98000A40450 /* PumpAckMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14303151C97C98000A40450 /* PumpAckMessageBody.swift */; };
C14303181C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14303171C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift */; };
C143031A1C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14303191C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift */; };
@@ -469,6 +507,43 @@
43EC9DCA1B786C6200DB0D18 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; };
43F348051D596270009933DC /* HKUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKUnit.swift; sourceTree = ""; };
43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponents.swift; sourceTree = ""; };
+ 541688DA1DB820BF005B1891 /* ReadCurrentGlucosePageMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadCurrentGlucosePageMessageBodyTests.swift; sourceTree = ""; };
+ 541688DC1DB82213005B1891 /* ReadCurrentGlucosePageMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadCurrentGlucosePageMessageBody.swift; sourceTree = ""; };
+ 541688DE1DB82E72005B1891 /* TimestampedGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedGlucoseEvent.swift; sourceTree = ""; };
+ 54A840D01DB85D0600B1F202 /* UnknownGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44721DB46A5200340EED /* GlucosePageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucosePageTests.swift; sourceTree = ""; };
+ 54BC44741DB46B0A00340EED /* GlucosePage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucosePage.swift; sourceTree = ""; };
+ 54BC44771DB46C7D00340EED /* GlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEvent.swift; sourceTree = ""; };
+ 54BC447B1DB4742F00340EED /* GlucoseEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseEventType.swift; sourceTree = ""; };
+ 54BC447D1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSensorDataGlucoseEvent.swift; sourceTree = ""; };
+ 54BC447F1DB4762200340EED /* TenSomethingGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TenSomethingGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44811DB476BB00340EED /* CalBGForGHGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForGHGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44831DB476F600340EED /* SensorCalFactorGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalFactorGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44871DB47B5F00340EED /* DataEndGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataEndGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44891DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorWeakSignalGlucoseEvent.swift; sourceTree = ""; };
+ 54BC448B1DB47BEA00340EED /* SensorCalGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalGlucoseEvent.swift; sourceTree = ""; };
+ 54BC448D1DB47C1E00340EED /* Fokko7GlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fokko7GlucoseEvent.swift; sourceTree = ""; };
+ 54BC448F1DB47C7400340EED /* SensorTimestampGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorTimestampGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44911DB47CBA00340EED /* BatteryChangeGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryChangeGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44931DB47CFB00340EED /* SensorStatusGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorStatusGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44951DB47D2A00340EED /* DateTimeChangeGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTimeChangeGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44971DB47D5300340EED /* SensorSyncGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorSyncGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44991DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NineteenSomethingGlucoseEvent.swift; sourceTree = ""; };
+ 54BC449B1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativeTimestampedGlucoseEvent.swift; sourceTree = ""; };
+ 54BC449D1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferenceTimestampedGlucoseEvent.swift; sourceTree = ""; };
+ 54BC44A01DB6F74300340EED /* BatteryChangeGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryChangeGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44A21DB7021B00340EED /* SensorStatusGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorStatusGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44A41DB702C800340EED /* DateTimeChangeGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateTimeChangeGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44A61DB703E900340EED /* SensorSyncGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorSyncGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44A81DB704A600340EED /* CalBGForGHGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForGHGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44AA1DB7093700340EED /* SensorTimestampGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorTimestampGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44AC1DB70A5E00340EED /* SensorCalFactorGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalFactorGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44AE1DB70C3E00340EED /* TenSomethingGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TenSomethingGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44B01DB70F4A00340EED /* GlucoseSensorDataGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlucoseSensorDataGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44B21DB711BE00340EED /* SensorCalGlucoseEventTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorCalGlucoseEventTests.swift; sourceTree = ""; };
+ 54BC44B41DB7184D00340EED /* NSStringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSStringExtensions.swift; sourceTree = ""; };
+ 54BC44B61DB81B5100340EED /* GetGlucosePageMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetGlucosePageMessageBodyTests.swift; sourceTree = ""; };
+ 54BC44B81DB81D6100340EED /* GetGlucosePageMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetGlucosePageMessageBody.swift; sourceTree = ""; };
C10AB08C1C855613000F102E /* FindDeviceMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindDeviceMessageBody.swift; sourceTree = ""; };
C10AB08E1C855F34000F102E /* DeviceLinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkMessageBody.swift; sourceTree = ""; };
C10D9BC11C8269D500378342 /* MinimedKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MinimedKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -524,6 +599,7 @@
C133CF921D5943780034B82D /* PredictedBG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PredictedBG.swift; sourceTree = ""; };
C139AC221BFD84B500B0518F /* RuntimeUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeUtils.h; sourceTree = ""; };
C139AC231BFD84B500B0518F /* RuntimeUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeUtils.m; sourceTree = ""; };
+ C13D15591DAACE8400ADC044 /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; };
C14303151C97C98000A40450 /* PumpAckMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpAckMessageBody.swift; sourceTree = ""; };
C14303171C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPumpModelCarelinkMessageBodyTests.swift; sourceTree = ""; };
C14303191C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBatteryCarelinkMessageBodyTests.swift; sourceTree = ""; };
@@ -862,15 +938,60 @@
path = Crypto;
sourceTree = "";
};
+ 54BC44761DB46C3100340EED /* GlucoseEvents */ = {
+ isa = PBXGroup;
+ children = (
+ 54BC44911DB47CBA00340EED /* BatteryChangeGlucoseEvent.swift */,
+ 54BC44811DB476BB00340EED /* CalBGForGHGlucoseEvent.swift */,
+ 54BC44871DB47B5F00340EED /* DataEndGlucoseEvent.swift */,
+ 54BC44951DB47D2A00340EED /* DateTimeChangeGlucoseEvent.swift */,
+ 54BC448D1DB47C1E00340EED /* Fokko7GlucoseEvent.swift */,
+ 54BC44771DB46C7D00340EED /* GlucoseEvent.swift */,
+ 54BC447D1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift */,
+ 54BC44991DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift */,
+ 54BC449D1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift */,
+ 54BC449B1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift */,
+ 54BC44831DB476F600340EED /* SensorCalFactorGlucoseEvent.swift */,
+ 54BC448B1DB47BEA00340EED /* SensorCalGlucoseEvent.swift */,
+ 54BC44931DB47CFB00340EED /* SensorStatusGlucoseEvent.swift */,
+ 54BC44971DB47D5300340EED /* SensorSyncGlucoseEvent.swift */,
+ 54BC448F1DB47C7400340EED /* SensorTimestampGlucoseEvent.swift */,
+ 54BC44891DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift */,
+ 54BC447F1DB4762200340EED /* TenSomethingGlucoseEvent.swift */,
+ 54A840D01DB85D0600B1F202 /* UnknownGlucoseEvent.swift */,
+ );
+ path = GlucoseEvents;
+ sourceTree = "";
+ };
+ 54BC449F1DB6F6C100340EED /* GlucoseEvents */ = {
+ isa = PBXGroup;
+ children = (
+ 54BC44A01DB6F74300340EED /* BatteryChangeGlucoseEventTests.swift */,
+ 54BC44A81DB704A600340EED /* CalBGForGHGlucoseEventTests.swift */,
+ 54BC44A41DB702C800340EED /* DateTimeChangeGlucoseEventTests.swift */,
+ 54BC44B01DB70F4A00340EED /* GlucoseSensorDataGlucoseEventTests.swift */,
+ 54BC44AC1DB70A5E00340EED /* SensorCalFactorGlucoseEventTests.swift */,
+ 54BC44B21DB711BE00340EED /* SensorCalGlucoseEventTests.swift */,
+ 54BC44A21DB7021B00340EED /* SensorStatusGlucoseEventTests.swift */,
+ 54BC44A61DB703E900340EED /* SensorSyncGlucoseEventTests.swift */,
+ 54BC44AA1DB7093700340EED /* SensorTimestampGlucoseEventTests.swift */,
+ 54BC44AE1DB70C3E00340EED /* TenSomethingGlucoseEventTests.swift */,
+ );
+ path = GlucoseEvents;
+ sourceTree = "";
+ };
C10D9BC21C8269D500378342 /* MinimedKit */ = {
isa = PBXGroup;
children = (
C1EAD6B81C826B92006DBA60 /* Extensions */,
C1EAD6BC1C826B92006DBA60 /* Messages */,
+ 54BC44761DB46C3100340EED /* GlucoseEvents */,
C1842BB91C8E15C600DB42AC /* PumpEvents */,
C1EAD6AE1C826B6D006DBA60 /* AlertType.swift */,
C1EAD6DD1C82B78C006DBA60 /* CRC8.swift */,
C1EAD6E11C82BA7A006DBA60 /* CRC16.swift */,
+ 54BC447B1DB4742F00340EED /* GlucoseEventType.swift */,
+ 54BC44741DB46B0A00340EED /* GlucosePage.swift */,
C1EB955C1C887FE5002517DF /* HistoryPage.swift */,
C10D9BC51C8269D500378342 /* Info.plist */,
C1EAD6AF1C826B6D006DBA60 /* MessageBody.swift */,
@@ -884,6 +1005,7 @@
C1274F851D8242BE0002912B /* PumpRegion.swift */,
C1EAD6D91C829104006DBA60 /* RFTools.swift */,
43B0ADC11D12454700AAD278 /* TimestampedHistoryEvent.swift */,
+ 541688DE1DB82E72005B1891 /* TimestampedGlucoseEvent.swift */,
);
path = MinimedKit;
sourceTree = "";
@@ -891,17 +1013,20 @@
C10D9BD01C8269D500378342 /* MinimedKitTests */ = {
isa = PBXGroup;
children = (
- C10D9BD31C8269D500378342 /* Info.plist */,
+ 54BC449F1DB6F6C100340EED /* GlucoseEvents */,
+ C121985D1C8DE72500BC374C /* Messages */,
C1EAD6DF1C82B910006DBA60 /* CRC8Tests.swift */,
C1EAD6E31C82BA87006DBA60 /* CRC16Tests.swift */,
+ 54BC44721DB46A5200340EED /* GlucosePageTests.swift */,
C12198621C8DF4C800BC374C /* HistoryPageTests.swift */,
+ C10D9BD31C8269D500378342 /* Info.plist */,
C1C357901C92733A009BDD4F /* MeterMessageTests.swift */,
C1EAD6D11C826C43006DBA60 /* MinimedKitTests.swift */,
C1EAD6D31C826C43006DBA60 /* NSDataTests.swift */,
43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */,
43B0ADBF1D0FC03200AAD278 /* NSDateComponentsTests.swift */,
C1EAD6DB1C82A4AB006DBA60 /* RFToolsTests.swift */,
- C121985D1C8DE72500BC374C /* Messages */,
+ 54BC44B41DB7184D00340EED /* NSStringExtensions.swift */,
);
path = MinimedKitTests;
sourceTree = "";
@@ -915,11 +1040,13 @@
C12198601C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift */,
C121985E1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift */,
C14303191C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift */,
+ 54BC44B61DB81B5100340EED /* GetGlucosePageMessageBodyTests.swift */,
C14303171C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift */,
C1EAD6D21C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift */,
+ 43A068EB1CF6BA6900F9EFE4 /* ReadRemainingInsulinMessageBodyTests.swift */,
C1EAD6D41C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift */,
43CA93301CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift */,
- 43A068EB1CF6BA6900F9EFE4 /* ReadRemainingInsulinMessageBodyTests.swift */,
+ 541688DA1DB820BF005B1891 /* ReadCurrentGlucosePageMessageBodyTests.swift */,
);
path = Messages;
sourceTree = "";
@@ -1227,6 +1354,7 @@
children = (
C1B3830D1CD0665D00CE7782 /* NightscoutUploadKit.h */,
C1B3830F1CD0665D00CE7782 /* Info.plist */,
+ C13D15591DAACE8400ADC044 /* Either.swift */,
43F348051D596270009933DC /* HKUnit.swift */,
C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */,
C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */,
@@ -1295,6 +1423,7 @@
C10AB08E1C855F34000F102E /* DeviceLinkMessageBody.swift */,
C10AB08C1C855613000F102E /* FindDeviceMessageBody.swift */,
C1711A5B1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift */,
+ 54BC44B81DB81D6100340EED /* GetGlucosePageMessageBody.swift */,
C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */,
C1711A591C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift */,
C1EAD6BE1C826B92006DBA60 /* MySentryAckMessageBody.swift */,
@@ -1303,12 +1432,13 @@
C1EAD6C11C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift */,
C1EAD6C21C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift */,
C14303151C97C98000A40450 /* PumpAckMessageBody.swift */,
+ C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */,
433568751CF67FA800FD9D54 /* ReadRemainingInsulinMessageBody.swift */,
C1EAD6C31C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift */,
43CA932C1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift */,
43CA932D1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift */,
C1EAD6C41C826B92006DBA60 /* UnknownMessageBody.swift */,
- C178845C1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift */,
+ 541688DC1DB82213005B1891 /* ReadCurrentGlucosePageMessageBody.swift */,
);
path = Messages;
sourceTree = "";
@@ -1819,6 +1949,7 @@
C1842BD11C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift in Sources */,
C1842C1B1C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift in Sources */,
C1842BC51C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift in Sources */,
+ 54BC448C1DB47BEA00340EED /* SensorCalGlucoseEvent.swift in Sources */,
C14FFC4A1D3AF1AC0049CF85 /* JournalEntryInsulinMarkerPumpEvent.swift in Sources */,
C1842C081C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift in Sources */,
C1842BFF1C8FA45100DB42AC /* DailyTotal522PumpEvent.swift in Sources */,
@@ -1828,9 +1959,12 @@
C1842BC11C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift in Sources */,
C1EAD6B51C826B6D006DBA60 /* MessageType.swift in Sources */,
C1842C111C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift in Sources */,
+ 54BC44981DB47D5300340EED /* SensorSyncGlucoseEvent.swift in Sources */,
+ 54BC448A1DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift in Sources */,
C1C3578F1C927303009BDD4F /* MeterMessage.swift in Sources */,
C1842BFC1C8FA45100DB42AC /* SuspendPumpEvent.swift in Sources */,
C1842C131C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift in Sources */,
+ 54BC44901DB47C7400340EED /* SensorTimestampGlucoseEvent.swift in Sources */,
C18C8C531D64123400E043FB /* EnableBolusWizardPumpEvent.swift in Sources */,
C1EAD6B61C826B6D006DBA60 /* PacketType.swift in Sources */,
C1842C041C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift in Sources */,
@@ -1838,24 +1972,31 @@
C1842C0B1C8FA45100DB42AC /* ChangeTimePumpEvent.swift in Sources */,
C1842C0D1C8FA45100DB42AC /* TempBasalPumpEvent.swift in Sources */,
C178845D1D4EF3D800405663 /* ReadPumpStatusMessageBody.swift in Sources */,
+ 54BC447C1DB4742F00340EED /* GlucoseEventType.swift in Sources */,
43B0ADCB1D126B1100AAD278 /* SelectBasalProfilePumpEvent.swift in Sources */,
C1842C0C1C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift in Sources */,
C1274F861D8242BE0002912B /* PumpRegion.swift in Sources */,
C15AF2AF1D7498930031FC9D /* RestoreMystery54PumpEvent.swift in Sources */,
C10AB08D1C855613000F102E /* FindDeviceMessageBody.swift in Sources */,
+ 54BC449E1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift in Sources */,
C1711A5A1C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift in Sources */,
C1EB955D1C887FE5002517DF /* HistoryPage.swift in Sources */,
+ 54BC44921DB47CBA00340EED /* BatteryChangeGlucoseEvent.swift in Sources */,
C1EAD6CA1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift in Sources */,
C1842C181C8FA45100DB42AC /* BolusWizardSetupPumpEvent.swift in Sources */,
C1274F791D823A550002912B /* ChangeMeterIDPumpEvent.swift in Sources */,
C1842C201C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift in Sources */,
+ 54BC44881DB47B5F00340EED /* DataEndGlucoseEvent.swift in Sources */,
C1EAD6B31C826B6D006DBA60 /* AlertType.swift in Sources */,
C1842C051C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift in Sources */,
C1711A5C1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift in Sources */,
C1842C1D1C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift in Sources */,
+ 54BC448E1DB47C1E00340EED /* Fokko7GlucoseEvent.swift in Sources */,
+ 54BC44961DB47D2A00340EED /* DateTimeChangeGlucoseEvent.swift in Sources */,
C1842C061C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift in Sources */,
C10AB08F1C855F34000F102E /* DeviceLinkMessageBody.swift in Sources */,
C15AF2B11D7498DD0031FC9D /* RestoreMystery55PumpEvent.swift in Sources */,
+ 54BC449C1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift in Sources */,
C1842C091C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift in Sources */,
C1842BC91C8F968B00DB42AC /* BGReceivedPumpEvent.swift in Sources */,
C1842C0F1C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift in Sources */,
@@ -1866,7 +2007,9 @@
C1EAD6C81C826B92006DBA60 /* CarelinkMessageBody.swift in Sources */,
C1842C121C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift in Sources */,
433568761CF67FA800FD9D54 /* ReadRemainingInsulinMessageBody.swift in Sources */,
+ 54BC44941DB47CFB00340EED /* SensorStatusGlucoseEvent.swift in Sources */,
C1842C231C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift in Sources */,
+ 54BC44821DB476BB00340EED /* CalBGForGHGlucoseEvent.swift in Sources */,
C1EAD6CF1C826B92006DBA60 /* UnknownMessageBody.swift in Sources */,
C1842C161C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift in Sources */,
C1842C241C8FA45100DB42AC /* BatteryPumpEvent.swift in Sources */,
@@ -1874,6 +2017,7 @@
C1711A561C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift in Sources */,
43D657451D0CF1D500216E20 /* NSTimeInterval.swift in Sources */,
C1842C011C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */,
+ 54BC447E1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift in Sources */,
C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */,
C1842BCB1C8F9A7200DB42AC /* RewindPumpEvent.swift in Sources */,
C1842BCD1C8F9BBD00DB42AC /* PrimePumpEvent.swift in Sources */,
@@ -1882,11 +2026,15 @@
C1EAD6C91C826B92006DBA60 /* MySentryAckMessageBody.swift in Sources */,
C1EAD6CE1C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift in Sources */,
C12198AD1C8F332500BC374C /* TimestampedPumpEvent.swift in Sources */,
+ 54BC44751DB46B0A00340EED /* GlucosePage.swift in Sources */,
C1EAD6DE1C82B78C006DBA60 /* CRC8.swift in Sources */,
C1EAD6C51C826B92006DBA60 /* Int.swift in Sources */,
C1842C021C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift in Sources */,
+ 541688DF1DB82E72005B1891 /* TimestampedGlucoseEvent.swift in Sources */,
C1EAD6CB1C826B92006DBA60 /* MySentryAlertMessageBody.swift in Sources */,
+ 54BC449A1DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift in Sources */,
C15AF2AD1D74929D0031FC9D /* ChangeBolusWizardSetupPumpEvent.swift in Sources */,
+ 54BC44801DB4762200340EED /* TenSomethingGlucoseEvent.swift in Sources */,
C1842BC71C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift in Sources */,
C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */,
C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */,
@@ -1897,11 +2045,14 @@
438D39221D19011700D40CA4 /* PlaceholderPumpEvent.swift in Sources */,
C1EAD6B41C826B6D006DBA60 /* MessageBody.swift in Sources */,
C1842C001C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift in Sources */,
+ 54A840D11DB85D0600B1F202 /* UnknownGlucoseEvent.swift in Sources */,
C1842BCF1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift in Sources */,
C1EAD6C61C826B92006DBA60 /* NSData.swift in Sources */,
C1842C211C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift in Sources */,
C1842BC31C8E931E00DB42AC /* BolusNormalPumpEvent.swift in Sources */,
+ 541688DD1DB82213005B1891 /* ReadCurrentGlucosePageMessageBody.swift in Sources */,
43CA932F1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift in Sources */,
+ 54BC44781DB46C7D00340EED /* GlucoseEvent.swift in Sources */,
C1842C221C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift in Sources */,
C1842BFD1C8FA45100DB42AC /* ResumePumpEvent.swift in Sources */,
C1EAD6CC1C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift in Sources */,
@@ -1917,6 +2068,7 @@
C1842C0A1C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift in Sources */,
C1842C191C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift in Sources */,
C1842C171C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift in Sources */,
+ 54BC44B91DB81D6100340EED /* GetGlucosePageMessageBody.swift in Sources */,
43B0ADC41D12506A00AAD278 /* NSDateFormatter.swift in Sources */,
C1EAD6DA1C829104006DBA60 /* RFTools.swift in Sources */,
43CA932B1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift in Sources */,
@@ -1924,6 +2076,7 @@
C1842C031C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift in Sources */,
C1EAD6B71C826B6D006DBA60 /* PumpMessage.swift in Sources */,
C12198A91C8F2AF200BC374C /* DailyTotal523PumpEvent.swift in Sources */,
+ 54BC44841DB476F600340EED /* SensorCalFactorGlucoseEvent.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1932,22 +2085,36 @@
buildActionMask = 2147483647;
files = (
C12198631C8DF4C800BC374C /* HistoryPageTests.swift in Sources */,
+ 54BC44A71DB703E900340EED /* SensorSyncGlucoseEventTests.swift in Sources */,
+ 54BC44A11DB6F74300340EED /* BatteryChangeGlucoseEventTests.swift in Sources */,
+ 54BC44A51DB702C800340EED /* DateTimeChangeGlucoseEventTests.swift in Sources */,
+ 54BC44B31DB711BE00340EED /* SensorCalGlucoseEventTests.swift in Sources */,
+ 54BC44B11DB70F4A00340EED /* GlucoseSensorDataGlucoseEventTests.swift in Sources */,
43A068EC1CF6BA6900F9EFE4 /* ReadRemainingInsulinMessageBodyTests.swift in Sources */,
C1EAD6D61C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift in Sources */,
C1EAD6D81C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift in Sources */,
43B0ADC01D0FC03200AAD278 /* NSDateComponentsTests.swift in Sources */,
C1C357911C92733A009BDD4F /* MeterMessageTests.swift in Sources */,
+ 54BC44AD1DB70A5E00340EED /* SensorCalFactorGlucoseEventTests.swift in Sources */,
C12198611C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift in Sources */,
C14303181C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift in Sources */,
+ 54BC44A31DB7021B00340EED /* SensorStatusGlucoseEventTests.swift in Sources */,
C1EAD6E41C82BA87006DBA60 /* CRC16Tests.swift in Sources */,
43CA93311CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */,
+ 54BC44A91DB704A600340EED /* CalBGForGHGlucoseEventTests.swift in Sources */,
43FF221C1CB9B9DE00024F30 /* NSDateComponents.swift in Sources */,
C12198A31C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift in Sources */,
C121985F1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift in Sources */,
+ 541688DB1DB820BF005B1891 /* ReadCurrentGlucosePageMessageBodyTests.swift in Sources */,
C1EAD6D71C826C43006DBA60 /* NSDataTests.swift in Sources */,
+ 54BC44731DB46A5200340EED /* GlucosePageTests.swift in Sources */,
+ 54BC44AF1DB70C3E00340EED /* TenSomethingGlucoseEventTests.swift in Sources */,
C143031A1C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift in Sources */,
43CA93351CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift in Sources */,
+ 54BC44B71DB81B5100340EED /* GetGlucosePageMessageBodyTests.swift in Sources */,
C1EAD6E01C82B910006DBA60 /* CRC8Tests.swift in Sources */,
+ 54BC44B51DB7184D00340EED /* NSStringExtensions.swift in Sources */,
+ 54BC44AB1DB7093700340EED /* SensorTimestampGlucoseEventTests.swift in Sources */,
43CA93331CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift in Sources */,
C1EAD6DC1C82A4AB006DBA60 /* RFToolsTests.swift in Sources */,
C1EAD6D51C826C43006DBA60 /* MinimedKitTests.swift in Sources */,
@@ -2025,6 +2192,7 @@
43D657461D0CF38F00216E20 /* NSTimeInterval.swift in Sources */,
C133CF931D5943780034B82D /* PredictedBG.swift in Sources */,
C1AF21E41D4865320088C41D /* LoopStatus.swift in Sources */,
+ C13D155A1DAACE8400ADC044 /* Either.swift in Sources */,
C1AF21F11D4901220088C41D /* NightscoutTreatment.swift in Sources */,
C1A492671D4A65D9008964FF /* RecommendedTempBasal.swift in Sources */,
C178845F1D5166BE00405663 /* COBStatus.swift in Sources */,
@@ -2136,11 +2304,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2164,11 +2332,11 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2227,11 +2395,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2258,11 +2426,11 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2325,12 +2493,12 @@
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Crypto/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -2353,12 +2521,12 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Crypto/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -2379,11 +2547,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2409,11 +2577,11 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2488,7 +2656,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -2535,7 +2703,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@@ -2639,11 +2807,11 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2669,11 +2837,11 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 22;
+ CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 22;
+ DYLIB_CURRENT_VERSION = 23;
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 0312a807b..63e3011c7 100644
--- a/RileyLink/RileyLink-Info.plist
+++ b/RileyLink/RileyLink-Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLinkBLEKit/Info.plist b/RileyLinkBLEKit/Info.plist
index 2ed8188bd..c66882b70 100644
--- a/RileyLinkBLEKit/Info.plist
+++ b/RileyLinkBLEKit/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLinkBLEKitTests/Info.plist b/RileyLinkBLEKitTests/Info.plist
index c0a7b8da5..8e0afffd2 100644
--- a/RileyLinkBLEKitTests/Info.plist
+++ b/RileyLinkBLEKitTests/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLinkKit/Info.plist b/RileyLinkKit/Info.plist
index 2ed8188bd..c66882b70 100644
--- a/RileyLinkKit/Info.plist
+++ b/RileyLinkKit/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift
index 929f71e09..9510dac8c 100644
--- a/RileyLinkKit/PumpOps.swift
+++ b/RileyLinkKit/PumpOps.swift
@@ -143,6 +143,34 @@ public class PumpOps {
}
}
+ /**
+ Fetches glucose history entries which occurred on or after the specified date.
+
+ History timestamps are reconciled with UTC based on the `timeZone` property of PumpState, as well as recorded clock change events.
+
+ - parameter startDate: The earliest date of events to retrieve
+ - parameter completion: A closure called after the command is complete. This closure takes a single Result argument:
+ - success(events): An array of fetched history entries, in ascending order of insertion
+ - failure(error): An error describing why the command failed
+
+ */
+ public func getGlucoseHistoryEvents(since startDate: Date, completion: @escaping (Either<[TimestampedGlucoseEvent], Error>) -> Void) {
+ device.runSession(withName: "Get glucose history events") { (session) -> Void in
+ NSLog("Glucose history fetching task started.")
+ let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session)
+ do {
+ let events = try ops.getGlucoseHistoryEvents(since: startDate)
+ DispatchQueue.main.async { () -> Void in
+ completion(.success(events))
+ }
+ } catch let error {
+ DispatchQueue.main.async { () -> Void in
+ completion(.failure(error))
+ }
+ }
+ }
+ }
+
/**
Reads the pump's clock
diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift
index 588add72c..370ba537f 100644
--- a/RileyLinkKit/PumpOpsSynchronous.swift
+++ b/RileyLinkKit/PumpOpsSynchronous.swift
@@ -432,7 +432,7 @@ class PumpOpsSynchronous {
try wakeup()
let pumpModel = try getPumpModel()
-
+
var events = [TimestampedHistoryEvent]()
var timeAdjustmentInterval: TimeInterval = 0
@@ -544,6 +544,104 @@ class PumpOpsSynchronous {
}
return frameData as Data
}
+
+ internal func getGlucoseHistoryEvents(since startDate: Date) throws -> [TimestampedGlucoseEvent] {
+ try wakeup()
+
+ var events = [TimestampedGlucoseEvent]()
+
+ let currentGlucosePage = try readCurrentGlucosePage()
+ let startPage = Int(currentGlucosePage.pageNum)
+ //max lookback of 15 pages or when page is 0
+ let endPage = max(startPage - 15, 0)
+
+ pages: for pageNum in stride(from: startPage, to: endPage - 1, by: -1) {
+ NSLog("Fetching page %d", pageNum)
+ let pageData: Data
+
+ do {
+ pageData = try getGlucosePage(UInt32(pageNum))
+ } catch let error as PumpCommsError {
+ if case .unexpectedResponse(let response, from: _) = error, response.messageType == .emptyHistoryPage {
+ break pages
+ } else {
+ throw error
+ }
+ }
+
+ var idx = 0
+ let chunkSize = 256;
+ while idx < pageData.count {
+ let top = min(idx + chunkSize, pageData.count)
+ let range = Range(uncheckedBounds: (lower: idx, upper: top))
+ NSLog(String(format: "GlucosePage %02d - (bytes %03d-%03d): ", pageNum, idx, top-1) + pageData.subdata(in: range).hexadecimalString)
+ idx = top
+ }
+
+ let page = try GlucosePage(pageData: pageData)
+
+ for event in page.events.reversed() {
+ var timestamp = event.timestamp
+ timestamp.timeZone = pump.timeZone
+
+ if event is UnknownGlucoseEvent {
+ continue pages
+ }
+
+ if let date = timestamp.date {
+ if date < startDate && event is ReferenceTimestampedGlucoseEvent {
+ NSLog("Found reference event at (%@) to be before startDate(%@)", date as NSDate, startDate as NSDate);
+ break pages
+ } else {
+ events.insert(TimestampedGlucoseEvent(glucoseEvent: event, date: date), at: 0)
+ }
+ }
+ }
+ }
+ return events
+ }
+
+ private func readCurrentGlucosePage() throws -> ReadCurrentGlucosePageMessageBody {
+ let readCurrentGlucosePageResponse: ReadCurrentGlucosePageMessageBody = try messageBody(to: .readCurrentGlucosePage)
+
+ return readCurrentGlucosePageResponse
+ }
+
+ private func getGlucosePage(_ pageNum: UInt32) throws -> Data {
+ var frameData = Data()
+
+ let msg = makePumpMessage(to: .getGlucosePage, using: GetGlucosePageMessageBody(pageNum: pageNum))
+
+ let firstResponse = try runCommandWithArguments(msg, responseMessageType: .getGlucosePage)
+
+ var expectedFrameNum = 1
+ var curResp = firstResponse.messageBody as! GetGlucosePageMessageBody
+
+ while(expectedFrameNum == curResp.frameNumber) {
+ frameData.append(curResp.frame)
+ expectedFrameNum += 1
+ let msg = makePumpMessage(to: .pumpAck)
+ if !curResp.lastFrame {
+ guard let resp = try? sendAndListen(msg) else {
+ throw PumpCommsError.rfCommsFailure("Did not receive frame data from pump")
+ }
+ guard resp.packetType == .carelink && resp.messageType == .getGlucosePage else {
+ throw PumpCommsError.rfCommsFailure("Bad packet type or message type. Possible interference.")
+ }
+ curResp = resp.messageBody as! GetGlucosePageMessageBody
+ } else {
+ let cmd = SendPacketCmd()
+ cmd.packet = RFPacket(data: msg.txData)
+ session.doCmd(cmd, withTimeoutMs: expectedMaxBLELatencyMS)
+ break
+ }
+ }
+
+ guard frameData.count == 1024 else {
+ throw PumpCommsError.rfCommsFailure("Short glucose history page: \(frameData.count) bytes. Expected 1024")
+ }
+ return frameData as Data
+ }
internal func readPumpStatus() throws -> PumpStatus {
let clockResp: ReadTimeCarelinkMessageBody = try messageBody(to: .readTime)
diff --git a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift
index f9780be78..f410d36d5 100644
--- a/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift
+++ b/RileyLinkKit/UI/RileyLinkDeviceTableViewController.swift
@@ -151,6 +151,7 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel
case changeTime
case mySentryPair
case dumpHistory
+ case fetchGlucose
case getPumpModel
case pressDownButton
case readPumpStatus
@@ -282,6 +283,9 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel
case .dumpHistory:
cell.textLabel?.text = NSLocalizedString("Fetch Recent History", comment: "The title of the command to fetch recent history")
+ case .fetchGlucose:
+ cell.textLabel?.text = NSLocalizedString("Fetch Recent Glucose", comment: "The title of the command to fetch recent glucose")
+
case .getPumpModel:
cell.textLabel?.text = NSLocalizedString("Get Pump Model", comment: "The title of the command to get pump model")
@@ -452,6 +456,24 @@ public class RileyLinkDeviceTableViewController: UITableViewController, TextFiel
}
return NSLocalizedString("Fetching history…", comment: "Progress message for fetching pump history.")
}
+ case .fetchGlucose:
+ vc = CommandResponseViewController { [unowned self] (completionHandler) -> String in
+ let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
+ let oneDayAgo = calendar.date(byAdding: DateComponents(day: -1), to: Date())
+ self.device.ops?.getGlucoseHistoryEvents(since: oneDayAgo!) { (response) -> Void in
+ switch response {
+ case .success(let events):
+ var responseText = String(format:"Found %d events since %@", events.count, oneDayAgo! as NSDate)
+ for event in events {
+ responseText += String(format:"\nEvent: %@", event.dictionaryRepresentation)
+ }
+ completionHandler(responseText)
+ case .failure(let error):
+ completionHandler(String(describing: error))
+ }
+ }
+ return NSLocalizedString("Fetching glucose…", comment: "Progress message for fetching pump glucose.")
+ }
case .getPumpModel:
vc = CommandResponseViewController { [unowned self] (completionHandler) -> String in
self.device.ops?.getPumpModel({ (response) in
diff --git a/RileyLinkKitTests/Info.plist b/RileyLinkKitTests/Info.plist
index c0a7b8da5..8e0afffd2 100644
--- a/RileyLinkKitTests/Info.plist
+++ b/RileyLinkKitTests/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion
diff --git a/RileyLinkTests/RileyLinkTests-Info.plist b/RileyLinkTests/RileyLinkTests-Info.plist
index d80a918aa..4845fc698 100644
--- a/RileyLinkTests/RileyLinkTests-Info.plist
+++ b/RileyLinkTests/RileyLinkTests-Info.plist
@@ -13,7 +13,7 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 0.12.5
+ 0.12.6
CFBundleSignature
????
CFBundleVersion