diff --git a/MinimedKit/GlucoseEvents/GlucoseSensorDataGlucoseEvent.swift b/MinimedKit/GlucoseEvents/GlucoseSensorDataGlucoseEvent.swift index 2152fbdc3..16221a522 100644 --- a/MinimedKit/GlucoseEvents/GlucoseSensorDataGlucoseEvent.swift +++ b/MinimedKit/GlucoseEvents/GlucoseSensorDataGlucoseEvent.swift @@ -8,7 +8,7 @@ import Foundation -public struct GlucoseSensorDataGlucoseEvent: RelativeTimestampedGlucoseEvent { +public struct GlucoseSensorDataGlucoseEvent: SensorValueGlucoseEvent { public let length: Int public let rawData: Data public let sgv: Int diff --git a/MinimedKit/GlucoseEvents/ReferenceTimestampedGlucoseEvent.swift b/MinimedKit/GlucoseEvents/ReferenceTimestampedGlucoseEvent.swift deleted file mode 100644 index bab0a7de8..000000000 --- a/MinimedKit/GlucoseEvents/ReferenceTimestampedGlucoseEvent.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// ReferenceTimestampedGlucoseEvent.swift -// RileyLink -// -// Created by Timothy Mecklem on 10/17/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -import Foundation - -/// An event that supplies timestamp information that can be used to calculate a RelativeTimestampedGlucoseEvent -public protocol ReferenceTimestampedGlucoseEvent: GlucoseEvent { - -} - diff --git a/MinimedKit/GlucoseEvents/SensorDataHighGlucoseEvent.swift b/MinimedKit/GlucoseEvents/SensorDataHighGlucoseEvent.swift index c3f89c932..8a00d787b 100644 --- a/MinimedKit/GlucoseEvents/SensorDataHighGlucoseEvent.swift +++ b/MinimedKit/GlucoseEvents/SensorDataHighGlucoseEvent.swift @@ -8,7 +8,7 @@ import Foundation -public struct SensorDataHighGlucoseEvent: RelativeTimestampedGlucoseEvent { +public struct SensorDataHighGlucoseEvent: SensorValueGlucoseEvent { public let length: Int public let rawData: Data public let sgv: Int diff --git a/MinimedKit/GlucoseEvents/SensorDataLowGlucoseEvent.swift b/MinimedKit/GlucoseEvents/SensorDataLowGlucoseEvent.swift index b9c8c01c6..d80f6ee0f 100644 --- a/MinimedKit/GlucoseEvents/SensorDataLowGlucoseEvent.swift +++ b/MinimedKit/GlucoseEvents/SensorDataLowGlucoseEvent.swift @@ -8,7 +8,7 @@ import Foundation -public struct SensorDataLowGlucoseEvent: RelativeTimestampedGlucoseEvent { +public struct SensorDataLowGlucoseEvent: SensorValueGlucoseEvent { public let length: Int public let rawData: Data public let sgv: Int diff --git a/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift b/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift index 4101f9f0f..41041c598 100644 --- a/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift +++ b/MinimedKit/GlucoseEvents/SensorTimestampGlucoseEvent.swift @@ -8,11 +8,32 @@ import Foundation -public struct SensorTimestampGlucoseEvent: ReferenceTimestampedGlucoseEvent { +public enum SensorTimestampType: String { + case lastRf + case pageEnd + case gap + case unknown + + init(code: UInt8) { + switch code { + case 0x00: + self = .lastRf + case 0x01: + self = .pageEnd + case 0x02: + self = .gap + default: + self = .unknown + } + } + +} + +public struct SensorTimestampGlucoseEvent: GlucoseEvent { public let length: Int public let rawData: Data public let timestamp: DateComponents - private let timestampType: String + public let timestampType: SensorTimestampType public init?(availableData: Data, relativeTimestamp: DateComponents) { length = 5 @@ -21,24 +42,13 @@ public struct SensorTimestampGlucoseEvent: ReferenceTimestampedGlucoseEvent { return nil } - func d(_ idx:Int) -> Int { - return Int(availableData[idx] as UInt8) - } - rawData = availableData.subdata(in: 0..> 5 & 0b00000011) { - case 0x00: - timestampType = "last_rf" - case 0x01: - timestampType = "page_end" - case 0x02: - timestampType = "gap" - default: - timestampType = "unknown" - } - + timestampType = SensorTimestampType(code: availableData[3] >> 5 & 0b00000011) + } + + public func isForwardOffsetReference() -> Bool { + return timestampType == .lastRf || timestampType == .pageEnd } public var dictionaryRepresentation: [String: Any] { diff --git a/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift b/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift new file mode 100644 index 000000000..8bdeec3d9 --- /dev/null +++ b/MinimedKit/GlucoseEvents/SensorValueGlucoseEvent.swift @@ -0,0 +1,17 @@ +// +// SensorValueGlucoseEvent.swift +// RileyLink +// +// Created by Timothy Mecklem on 12/11/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +/// An event that contains an sgv +public protocol SensorValueGlucoseEvent: RelativeTimestampedGlucoseEvent { + + var sgv: Int { + get + } +} diff --git a/MinimedKit/GlucosePage.swift b/MinimedKit/GlucosePage.swift index e83c3d5ed..bd528b761 100644 --- a/MinimedKit/GlucosePage.swift +++ b/MinimedKit/GlucosePage.swift @@ -29,7 +29,6 @@ public class GlucosePage { //opcodes are at the end of each event let pageData = Data(pageData.subdata(in: 0..<1022).reversed()) - var needsTimestamp = false var offset = 0 let length = pageData.count var events = [GlucoseEvent]() @@ -64,16 +63,16 @@ public class GlucosePage { func initialTimestamp() -> DateComponents? { var tempOffset = offset - var relativeEventCount = 0 + var relativeEventCount: Double = 0 while tempOffset < length { let event = matchEvent(tempOffset, relativeTimestamp: DateComponents()) if event is RelativeTimestampedGlucoseEvent { relativeEventCount += 1 - } else if let event = event as? ReferenceTimestampedGlucoseEvent { - let offsetDate = calendar.date(byAdding: Calendar.Component.minute, value: 5 * relativeEventCount, to: event.timestamp.date!)! - var relativeTimestamp = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: offsetDate) - relativeTimestamp.calendar = calendar - return relativeTimestamp + } else if let sensorTimestampEvent = event as? SensorTimestampGlucoseEvent, + relativeEventCount == 0 || sensorTimestampEvent.isForwardOffsetReference() { + + let offsetDate = sensorTimestampEvent.timestamp.date!.addingTimeInterval(TimeInterval(minutes: relativeEventCount * 5)) + return calendar.dateComponents([.year, .month, .day, .hour, .minute, .calendar], from: offsetDate) } else if !(event is NineteenSomethingGlucoseEvent /* seems to be a filler byte */ || event is DataEndGlucoseEvent) { return nil } @@ -97,19 +96,18 @@ public class GlucosePage { } let event = matchEvent(offset, relativeTimestamp: relativeTimestamp) - if let event = event as? ReferenceTimestampedGlucoseEvent { + if let event = event as? SensorTimestampGlucoseEvent { relativeTimestamp = event.timestamp } else if event is RelativeTimestampedGlucoseEvent { - let offsetDate = calendar.date(byAdding: Calendar.Component.minute, value: -5, to: relativeTimestamp.date!)! - relativeTimestamp = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: offsetDate) - relativeTimestamp.calendar = calendar + let offsetDate = relativeTimestamp.date!.addingTimeInterval(TimeInterval(minutes: -5)) + relativeTimestamp = calendar.dateComponents([.year, .month, .day, .hour, .minute, .calendar], from: offsetDate) } events.insert(event, at: 0) offset += event.length } + self.needsTimestamp = false self.events = events - self.needsTimestamp = needsTimestamp } } diff --git a/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift b/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift index 87dfd2e9d..d9c9c7adb 100644 --- a/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift +++ b/MinimedKitTests/GlucoseEvents/SensorTimestampGlucoseEventTests.swift @@ -25,7 +25,7 @@ class SensorTimestampGlucoseEventTests: XCTestCase { let rawData = Data(hexadecimalString: "0814B62810")! let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - XCTAssertEqual(subject.dictionaryRepresentation["timestampType"] as! String, "page_end") + XCTAssertEqual(subject.timestampType, .pageEnd) let expectedTimestamp = DateComponents(calendar: Calendar.current, year: 2016, month: 02, day: 08, hour: 20, minute: 54) @@ -37,7 +37,7 @@ class SensorTimestampGlucoseEventTests: XCTestCase { let rawData = Data(hexadecimalString: "088d9b5d0c")! let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - XCTAssertEqual(subject.dictionaryRepresentation["timestampType"] as! String, "gap") + XCTAssertEqual(subject.timestampType, .gap) let expectedTimestamp = DateComponents(calendar: Calendar.current, year: 2012, month: 10, day: 29, hour: 13, minute: 27) @@ -48,7 +48,7 @@ class SensorTimestampGlucoseEventTests: XCTestCase { let rawData = Data(hexadecimalString: "088d9b1d0c")! let subject = SensorTimestampGlucoseEvent(availableData: rawData, relativeTimestamp: DateComponents())! - XCTAssertEqual(subject.dictionaryRepresentation["timestampType"] as! String, "last_rf") + XCTAssertEqual(subject.timestampType, .lastRf) let expectedTimestamp = DateComponents(calendar: Calendar.current, year: 2012, month: 10, day: 29, hour: 13, minute: 27) diff --git a/MinimedKitTests/GlucosePageTests.swift b/MinimedKitTests/GlucosePageTests.swift index c78686089..9dca340a0 100644 --- a/MinimedKitTests/GlucosePageTests.swift +++ b/MinimedKitTests/GlucosePageTests.swift @@ -84,7 +84,8 @@ class GlucosePageTests: XCTestCase { func testDoesNotNeedTimestamp() { do { - let pageData = Data(hexadecimalString: "1053b3940853535A".leftPadding(toLength: 2048, withPad: "0"))! + //sensor timestamp with timestampType of .lastRf + let pageData = Data(hexadecimalString: "1013b39408534232".leftPadding(toLength: 2048, withPad: "0"))! let page = try GlucosePage(pageData: pageData) XCTAssertFalse(page.needsTimestamp) @@ -97,4 +98,21 @@ class GlucosePageTests: XCTestCase { XCTFail("Unexpected exception...") } } + + func testLastSensorTimestampTypeGapNeedsTimestamp() { + do { + //sensor timestamp with timestampType of .gap + let pageData = Data(hexadecimalString: "1053b3940853535A".leftPadding(toLength: 2048, withPad: "0"))! + let page = try GlucosePage(pageData: pageData) + + XCTAssertTrue(page.needsTimestamp) + + } 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/NightscoutUploadKit/NightscoutEntry.swift b/NightscoutUploadKit/NightscoutEntry.swift index 92dc8e0e3..2f81a2704 100644 --- a/NightscoutUploadKit/NightscoutEntry.swift +++ b/NightscoutUploadKit/NightscoutEntry.swift @@ -37,7 +37,7 @@ public class NightscoutEntry: DictionaryRepresentable { } convenience init?(event: TimestampedGlucoseEvent, device: String) { - if let glucoseSensorData = event.glucoseEvent as? GlucoseSensorDataGlucoseEvent { + if let glucoseSensorData = event.glucoseEvent as? SensorValueGlucoseEvent { self.init(glucose: glucoseSensorData.sgv, timestamp: event.date, device: device, glucoseType: .Sensor) } else { return nil diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 8f6afd0e6..5cb86eb2f 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -118,7 +118,6 @@ 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 */; }; @@ -132,6 +131,7 @@ 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 */; }; + 54DA4E851DFDC0A70007F489 /* SensorValueGlucoseEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54DA4E841DFDC0A70007F489 /* SensorValueGlucoseEvent.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, ); }; }; @@ -548,7 +548,6 @@ 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 = ""; }; @@ -562,6 +561,7 @@ 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 = ""; }; + 54DA4E841DFDC0A70007F489 /* SensorValueGlucoseEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorValueGlucoseEvent.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; }; @@ -966,7 +966,6 @@ 54BC44771DB46C7D00340EED /* GlucoseEvent.swift */, 54BC447D1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift */, 54BC44991DB47DFE00340EED /* NineteenSomethingGlucoseEvent.swift */, - 54BC449D1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift */, 54BC449B1DB483F700340EED /* RelativeTimestampedGlucoseEvent.swift */, 54BC44831DB476F600340EED /* SensorCalFactorGlucoseEvent.swift */, 54BC448B1DB47BEA00340EED /* SensorCalGlucoseEvent.swift */, @@ -977,6 +976,7 @@ 54BC44931DB47CFB00340EED /* SensorStatusGlucoseEvent.swift */, 54BC44971DB47D5300340EED /* SensorSyncGlucoseEvent.swift */, 54BC448F1DB47C7400340EED /* SensorTimestampGlucoseEvent.swift */, + 54DA4E841DFDC0A70007F489 /* SensorValueGlucoseEvent.swift */, 54BC44891DB47BA500340EED /* SensorWeakSignalGlucoseEvent.swift */, 54BC447F1DB4762200340EED /* TenSomethingGlucoseEvent.swift */, 54A840D01DB85D0600B1F202 /* UnknownGlucoseEvent.swift */, @@ -2006,7 +2006,6 @@ C1274F861D8242BE0002912B /* PumpRegion.swift in Sources */, C15AF2AF1D7498930031FC9D /* RestoreMystery54PumpEvent.swift in Sources */, C10AB08D1C855613000F102E /* FindDeviceMessageBody.swift in Sources */, - 54BC449E1DB484BD00340EED /* ReferenceTimestampedGlucoseEvent.swift in Sources */, 545AEFB41DF5D99700DF9433 /* SensorDataLowGlucoseEvent.swift in Sources */, C1711A5A1C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift in Sources */, C1EB955D1C887FE5002517DF /* HistoryPage.swift in Sources */, @@ -2048,6 +2047,7 @@ C1842C011C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */, 54BC447E1DB4753A00340EED /* GlucoseSensorDataGlucoseEvent.swift in Sources */, C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */, + 54DA4E851DFDC0A70007F489 /* SensorValueGlucoseEvent.swift in Sources */, C1842BCB1C8F9A7200DB42AC /* RewindPumpEvent.swift in Sources */, C1842BCD1C8F9BBD00DB42AC /* PrimePumpEvent.swift in Sources */, C1842C071C8FA45100DB42AC /* ClearAlarmPumpEvent.swift in Sources */, diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift index c31f10579..06495d26e 100644 --- a/RileyLinkKit/PumpOpsSynchronous.swift +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -579,7 +579,7 @@ class PumpOpsSynchronous { logGlucoseHistory(pageData: pageData, pageNum: pageNum) page = try GlucosePage(pageData: pageData) - if page.needsTimestamp { + if page.needsTimestamp && pageNum == startPage { NSLog(String(format: "GlucosePage %02d needs a new sensor timestamp, writing...", pageNum)) let _ = try writeGlucoseHistoryTimestamp() @@ -606,7 +606,7 @@ class PumpOpsSynchronous { } if let date = timestamp.date { - if date < startDate && event is ReferenceTimestampedGlucoseEvent { + if date < startDate && event is SensorTimestampGlucoseEvent { NSLog("Found reference event at (%@) to be before startDate(%@)", date as NSDate, startDate as NSDate); break pages } else { @@ -662,7 +662,7 @@ class PumpOpsSynchronous { internal func writeGlucoseHistoryTimestamp() throws -> Void { let shortWriteTimestamp = makePumpMessage(to: .writeGlucoseHistoryTimestamp) - let shortResponse = try sendAndListen(shortWriteTimestamp, timeoutMS: 12000, repeatCount: 255, msBetweenPackets: 0, retryCount: 0) + let shortResponse = try sendAndListen(shortWriteTimestamp, timeoutMS: 12000) if shortResponse.messageType == .pumpAck { return