diff --git a/.gitignore b/.gitignore index b5e148115..63764e753 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ DerivedData *.hmap *.ipa *.xcuserstate +*.xcscmblueprint .DS_Store # CocoaPods diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..9f58ce62c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: objective-c +osx_image: xcode7.3 +xcode_sdk: + - iphonesimulator9.3 +xcode_project: RileyLink.xcodeproj +xcode_scheme: + - RileyLink +script: + - xcodebuild -project RileyLink.xcodeproj -scheme RileyLink -sdk iphonesimulator9.3 test diff --git a/MinimedKit/AlertType.swift b/MinimedKit/AlertType.swift new file mode 100644 index 000000000..0142869ae --- /dev/null +++ b/MinimedKit/AlertType.swift @@ -0,0 +1,23 @@ +// +// AlertType.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/13/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +public enum AlertType: UInt8 { + case NoDelivery = 0x04 + case MaxHourlyBolus = 0x33 + case LowReservoir = 0x52 + case HighGlucose = 0x65 + case LowGlucose = 0x66 + case MeterBGNow = 0x68 + case MeterBGSoon = 0x69 + case CalibrationError = 0x6a + case SensorEnd = 0x6b + case WeakSignal = 0x70 + case LostSensor = 0x71 + case HighPredicted = 0x72 + case LowPredicted = 0x73 +} \ No newline at end of file diff --git a/MinimedKit/CRC16.swift b/MinimedKit/CRC16.swift new file mode 100644 index 000000000..18621af63 --- /dev/null +++ b/MinimedKit/CRC16.swift @@ -0,0 +1,38 @@ +// +// CRC16.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +private let crcTable: [UInt16] = [0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879, 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374, 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368, 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920] + +func computeCRC16(data: NSData) -> UInt16 { + + var crc: UInt16 = 0xffff + var pdata = UnsafePointer(data.bytes) + var nbytes = data.length + /* loop over the buffer data */ + while nbytes > 0 { + let idx = ((crc >> 8) ^ UInt16(pdata.memory)) & 0xff + crc = ((crc << 8) ^ crcTable[Int(idx)]) & 0xffff + pdata = pdata.successor() + nbytes -= 1 + } + return crc +} + +func checkCRC16(data: NSData) -> Bool { + if data.length > 2 { + let lowByte: UInt8 = data[data.length - 1] + let hiByte: UInt8 = data[data.length - 2] + let packetCRC: UInt16 = (UInt16(hiByte) << 8) + UInt16(lowByte) + return packetCRC == computeCRC16(data.subdataWithRange(NSMakeRange(0, data.length-2))) + } else { + return false + } + +} diff --git a/MinimedKit/CRC8.swift b/MinimedKit/CRC8.swift new file mode 100644 index 000000000..5d017b487 --- /dev/null +++ b/MinimedKit/CRC8.swift @@ -0,0 +1,28 @@ +// +// CRC8.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +private let crcTable: [UInt8] = [0x0, 0x9B, 0xAD, 0x36, 0xC1, 0x5A, 0x6C, 0xF7, 0x19, 0x82, 0xB4, 0x2F, 0xD8, 0x43, 0x75, 0xEE, 0x32, 0xA9, 0x9F, 0x4, 0xF3, 0x68, 0x5E, 0xC5, 0x2B, 0xB0, 0x86, 0x1D, 0xEA, 0x71, 0x47, 0xDC, 0x64, 0xFF, 0xC9, 0x52, 0xA5, 0x3E, 0x8, 0x93, 0x7D, 0xE6, 0xD0, 0x4B, 0xBC, 0x27, 0x11, 0x8A, 0x56, 0xCD, 0xFB, 0x60, 0x97, 0xC, 0x3A, 0xA1, 0x4F, 0xD4, 0xE2, 0x79, 0x8E, 0x15, 0x23, 0xB8, 0xC8, 0x53, 0x65, 0xFE, 0x9, 0x92, 0xA4, 0x3F, 0xD1, 0x4A, 0x7C, 0xE7, 0x10, 0x8B, 0xBD, 0x26, 0xFA, 0x61, 0x57, 0xCC, 0x3B, 0xA0, 0x96, 0xD, 0xE3, 0x78, 0x4E, 0xD5, 0x22, 0xB9, 0x8F, 0x14, 0xAC, 0x37, 0x1, 0x9A, 0x6D, 0xF6, 0xC0, 0x5B, 0xB5, 0x2E, 0x18, 0x83, 0x74, 0xEF, 0xD9, 0x42, 0x9E, 0x5, 0x33, 0xA8, 0x5F, 0xC4, 0xF2, 0x69, 0x87, 0x1C, 0x2A, 0xB1, 0x46, 0xDD, 0xEB, 0x70, 0xB, 0x90, 0xA6, 0x3D, 0xCA, 0x51, 0x67, 0xFC, 0x12, 0x89, 0xBF, 0x24, 0xD3, 0x48, 0x7E, 0xE5, 0x39, 0xA2, 0x94, 0xF, 0xF8, 0x63, 0x55, 0xCE, 0x20, 0xBB, 0x8D, 0x16, 0xE1, 0x7A, 0x4C, 0xD7, 0x6F, 0xF4, 0xC2, 0x59, 0xAE, 0x35, 0x3, 0x98, 0x76, 0xED, 0xDB, 0x40, 0xB7, 0x2C, 0x1A, 0x81, 0x5D, 0xC6, 0xF0, 0x6B, 0x9C, 0x7, 0x31, 0xAA, 0x44, 0xDF, 0xE9, 0x72, 0x85, 0x1E, 0x28, 0xB3, 0xC3, 0x58, 0x6E, 0xF5, 0x2, 0x99, 0xAF, 0x34, 0xDA, 0x41, 0x77, 0xEC, 0x1B, 0x80, 0xB6, 0x2D, 0xF1, 0x6A, 0x5C, 0xC7, 0x30, 0xAB, 0x9D, 0x6, 0xE8, 0x73, 0x45, 0xDE, 0x29, 0xB2, 0x84, 0x1F, 0xA7, 0x3C, 0xA, 0x91, 0x66, 0xFD, 0xCB, 0x50, 0xBE, 0x25, 0x13, 0x88, 0x7F, 0xE4, 0xD2, 0x49, 0x95, 0xE, 0x38, 0xA3, 0x54, 0xCF, 0xF9, 0x62, 0x8C, 0x17, 0x21, 0xBA, 0x4D, 0xD6, 0xE0, 0x7B] + + +func computeCRC8(data: NSData) -> UInt8 { + + var crc: UInt8 = 0 + + var pdata = UnsafePointer(data.bytes) + var nbytes = data.length + /* loop over the buffer data */ + while nbytes > 0 { + crc = crcTable[Int((crc ^ pdata.memory) & 0xff)] + pdata = pdata.successor() + nbytes -= 1 + } + return crc +} + diff --git a/MinimedKit/Extensions/Int.swift b/MinimedKit/Extensions/Int.swift new file mode 100644 index 000000000..3d1cdbd86 --- /dev/null +++ b/MinimedKit/Extensions/Int.swift @@ -0,0 +1,24 @@ +// +// Int.swift +// Naterade +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +extension Int { + init(bigEndianBytes bytes: [UInt8]) { + assert(bytes.count <= 4) + var result: UInt = 0 + + for idx in 0..<(bytes.count) { + let shiftAmount = UInt((bytes.count) - idx - 1) * 8 + result += UInt(bytes[idx]) << shiftAmount + } + + self.init(result) + } +} diff --git a/MinimedKit/Extensions/NSData.swift b/MinimedKit/Extensions/NSData.swift new file mode 100644 index 000000000..fdad762e2 --- /dev/null +++ b/MinimedKit/Extensions/NSData.swift @@ -0,0 +1,113 @@ +// +// NSData.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/2/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +extension NSData { + @nonobjc subscript(index: Int) -> Int8 { + let bytes: [Int8] = self[index...index] + + return bytes[0] + } + + @nonobjc subscript(index: Int) -> UInt8 { + let bytes: [UInt8] = self[index...index] + + return bytes[0] + } + + @nonobjc subscript(range: Range) -> UInt16 { + return self[range][0] + } + + @nonobjc subscript(range: Range) -> UInt32 { + return self[range][0] + } + + subscript(range: Range) -> [Int8] { + var dataArray = [Int8](count: range.count, repeatedValue: 0) + self.getBytes(&dataArray, range: NSRange(range)) + + return dataArray + } + + subscript(range: Range) -> [UInt8] { + var dataArray = [UInt8](count: range.count, repeatedValue: 0) + self.getBytes(&dataArray, range: NSRange(range)) + + return dataArray + } + + subscript(range: Range) -> [UInt16] { + var dataArray = [UInt16](count: range.count / 2, repeatedValue: 0) + self.getBytes(&dataArray, range: NSRange(range)) + + return dataArray + } + + subscript(range: Range) -> [UInt32] { + var dataArray = [UInt32](count: range.count / 4, repeatedValue: 0) + self.getBytes(&dataArray, range: NSRange(range)) + + return dataArray + } + + subscript(range: Range) -> NSData { + return subdataWithRange(NSRange(range)) + } + + convenience init?(hexadecimalString: String) { + if let + chars = hexadecimalString.cStringUsingEncoding(NSUTF8StringEncoding), + mutableData = NSMutableData(capacity: chars.count / 2) + { + for i in 0..(start: UnsafePointer(bytes), count: length) + + let string = NSMutableString(capacity: length * 2) + + for byte in bytesCollection { + string.appendFormat("%02x", byte) + } + + return string as String + } +} diff --git a/MinimedKit/Extensions/NSDateComponents.swift b/MinimedKit/Extensions/NSDateComponents.swift new file mode 100644 index 000000000..c42b0badc --- /dev/null +++ b/MinimedKit/Extensions/NSDateComponents.swift @@ -0,0 +1,25 @@ +// +// NSDateComponents.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/13/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +extension NSDateComponents { + convenience init(mySentryBytes: [UInt8]) { + self.init() + + hour = Int(mySentryBytes[0]) + minute = Int(mySentryBytes[1]) + second = Int(mySentryBytes[2]) + year = Int(mySentryBytes[3]) + 2000 + month = Int(mySentryBytes[4]) + day = Int(mySentryBytes[5]) + + calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + } +} \ No newline at end of file diff --git a/MinimedKit/HistoryPage.swift b/MinimedKit/HistoryPage.swift new file mode 100644 index 000000000..e29d7bb23 --- /dev/null +++ b/MinimedKit/HistoryPage.swift @@ -0,0 +1,66 @@ +// +// HistoryPage.swift +// RileyLink +// +// Created by Pete Schwamb on 3/3/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +public class HistoryPage { + + public enum Error: ErrorType { + case InvalidCRC + case UnknownEventType(eventType: UInt8) + } + + public let events: [PumpEvent] + + public init(pageData: NSData, pumpModel: PumpModel) throws { + + guard checkCRC16(pageData) else { + events = [PumpEvent]() + throw Error.InvalidCRC + } + + let pageData = pageData.subdataWithRange(NSMakeRange(0, 1022)) + + func matchEvent(offset: Int) -> PumpEvent? { + if let eventType = PumpEventType(rawValue:(pageData[offset] as UInt8)) { + let remainingData = pageData.subdataWithRange(NSMakeRange(offset, pageData.length - offset)) + if let event = eventType.eventType.init(availableData: remainingData, pumpModel: pumpModel) { + return event + } + } + return nil + } + + var offset = 0 + let length = pageData.length + var unabsorbedInsulinRecord: UnabsorbedInsulinPumpEvent? + var tempEvents = [PumpEvent]() + + while offset < length { + // Slurp up 0's + if pageData[offset] as UInt8 == 0 { + offset += 1 + continue + } + guard let event = matchEvent(offset) else { + events = [PumpEvent]() + throw Error.UnknownEventType(eventType: pageData[offset] as UInt8) + } + if event.dynamicType == BolusNormalPumpEvent.self && unabsorbedInsulinRecord != nil { + let bolus: BolusNormalPumpEvent = event as! BolusNormalPumpEvent + bolus.unabsorbedInsulinRecord = unabsorbedInsulinRecord + unabsorbedInsulinRecord = nil + } + if event.dynamicType == UnabsorbedInsulinPumpEvent.self { + unabsorbedInsulinRecord = event as? UnabsorbedInsulinPumpEvent + } else { + tempEvents.append(event) + } + offset += event.length + } + events = tempEvents + } +} \ No newline at end of file diff --git a/MinimedKit/Info.plist b/MinimedKit/Info.plist new file mode 100644 index 000000000..6019f05bf --- /dev/null +++ b/MinimedKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/MinimedKit/MessageBody.swift b/MinimedKit/MessageBody.swift new file mode 100644 index 000000000..da6a6d5d8 --- /dev/null +++ b/MinimedKit/MessageBody.swift @@ -0,0 +1,36 @@ +// +// MessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/4/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public protocol MessageBody { + static var length: Int { + get + } + + init?(rxData: NSData) + + var txData: NSData { + get + } +} + + +extension MessageBody { + static var emptyBuffer: [UInt8] { + return [UInt8](count: self.length, repeatedValue: 0) + } +} + + +public protocol DictionaryRepresentable { + var dictionaryRepresentation: [String: AnyObject] { + get + } +} \ No newline at end of file diff --git a/MinimedKit/MessageType.swift b/MinimedKit/MessageType.swift new file mode 100644 index 000000000..872bd3861 --- /dev/null +++ b/MinimedKit/MessageType.swift @@ -0,0 +1,62 @@ +// +// MessageType.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/2/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +public enum MessageType: UInt8 { + case Alert = 0x01 + case AlertCleared = 0x02 + case DeviceTest = 0x03 + case PumpStatus = 0x04 + case PumpAck = 0x06 + case PumpBackfill = 0x08 + case FindDevice = 0x09 + case DeviceLink = 0x0A + case ChangeTime = 0x40 + case Bolus = 0x42 + case ChangeTempBasal = 0x4c + case ButtonPress = 0x5b + case PowerOn = 0x5d + case ReadTime = 0x70 + case GetBattery = 0x72 + case GetHistoryPage = 0x80 + case GetPumpModel = 0x8d + case ReadTempBasal = 0x98 + case ReadSettings = 0xc0 + + var bodyType: MessageBody.Type { + switch self { + case .Alert: + return MySentryAlertMessageBody.self + case .AlertCleared: + return MySentryAlertClearedMessageBody.self + case .PumpStatus: + return MySentryPumpStatusMessageBody.self + case .PumpAck: + return PumpAckMessageBody.self + case .ReadSettings: + return ReadSettingsCarelinkMessageBody.self + case .ReadTempBasal: + return ReadTempBasalCarelinkMessageBody.self + case .ReadTime: + return ReadTimeCarelinkMessageBody.self + case .FindDevice: + return FindDeviceMessageBody.self + case .DeviceLink: + return DeviceLinkMessageBody.self + case .ButtonPress: + return ButtonPressCarelinkMessageBody.self + case .GetPumpModel: + return GetPumpModelCarelinkMessageBody.self + case .GetHistoryPage: + return GetHistoryPageCarelinkMessageBody.self + case .GetBattery: + return GetBatteryCarelinkMessageBody.self + default: + return UnknownMessageBody.self + } + } +} diff --git a/MinimedKit/Messages/BolusCarelinkMessageBody.swift b/MinimedKit/Messages/BolusCarelinkMessageBody.swift new file mode 100644 index 000000000..78e76b304 --- /dev/null +++ b/MinimedKit/Messages/BolusCarelinkMessageBody.swift @@ -0,0 +1,43 @@ +// +// BolusCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/5/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class BolusCarelinkMessageBody: CarelinkLongMessageBody { + + public convenience init(units: Double, strokesPerUnit: Int = 10) { + + let length: Int + let scrollRate: Int + + if strokesPerUnit >= 40 { + length = 2 + + // 40-stroke pumps scroll faster for higher unit values + switch units { + case let u where u > 10: + scrollRate = 4 + case let u where u > 1: + scrollRate = 2 + default: + scrollRate = 1 + } + } else { + length = 1 + scrollRate = 1 + } + + let strokes = Int(units * Double(strokesPerUnit / scrollRate)) * scrollRate + + let data = NSData(hexadecimalString: String(format: "%02x%0\(2 * length)x", length, strokes))! + + self.init(rxData: data)! + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift b/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift new file mode 100644 index 000000000..cd5495603 --- /dev/null +++ b/MinimedKit/Messages/ButtonPressCarelinkMessageBody.swift @@ -0,0 +1,28 @@ +// +// ButtonPressCarelinkMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/12/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ButtonPressCarelinkMessageBody: CarelinkLongMessageBody { + + public enum ButtonType: UInt8 { + case Act = 0x02 + case Esc = 0x01 + case Down = 0x04 + case Up = 0x03 + case Easy = 0x00 + } + + public convenience init(buttonType: ButtonType) { + let numArgs = 1 + let data = NSData(hexadecimalString: String(format: "%02x%02x", numArgs, buttonType.rawValue))! + + self.init(rxData: data)! + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/CarelinkMessageBody.swift b/MinimedKit/Messages/CarelinkMessageBody.swift new file mode 100644 index 000000000..f123f0aec --- /dev/null +++ b/MinimedKit/Messages/CarelinkMessageBody.swift @@ -0,0 +1,53 @@ +// +// CarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class CarelinkLongMessageBody: MessageBody { + public static var length: Int = 65 + + let rxData: NSData + + public required init?(rxData: NSData) { + let data: NSMutableData = rxData.mutableCopy() as! NSMutableData + + if data.length < self.dynamicType.length { + data.increaseLengthBy(self.dynamicType.length - data.length) + } + + self.rxData = data + } + + public var txData: NSData { + return rxData + } +} + + +public class CarelinkShortMessageBody: MessageBody { + public static var length: Int = 1 + + let data: NSData + + public convenience init() { + self.init(rxData: NSData(hexadecimalString: "00")!)! + } + + public required init?(rxData: NSData) { + self.data = rxData + + if rxData.length != self.dynamicType.length { + return nil + } + } + + public var txData: NSData { + return data + } +} \ No newline at end of file diff --git a/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift b/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift new file mode 100644 index 000000000..95adcaadd --- /dev/null +++ b/MinimedKit/Messages/ChangeTempBasalCarelinkMessageBody.swift @@ -0,0 +1,26 @@ +// +// ChangeTempBasalCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/6/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class ChangeTempBasalCarelinkMessageBody: CarelinkLongMessageBody { + + public convenience init(unitsPerHour: Double, duration: NSTimeInterval) { + + let length = 3 + let strokesPerUnit: Double = 40 + let strokes = Int(unitsPerHour * strokesPerUnit) + let timeSegments = Int(duration / NSTimeInterval(30 * 60)) + + let data = NSData(hexadecimalString: String(format: "%02x%04x%02x", length, strokes, timeSegments))! + + self.init(rxData: data)! + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift b/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift new file mode 100644 index 000000000..fa7e4d6b9 --- /dev/null +++ b/MinimedKit/Messages/ChangeTimeCarelinkMessageBody.swift @@ -0,0 +1,26 @@ +// +// ChangeTimeCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/17/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class ChangeTimeCarelinkMessageBody: CarelinkLongMessageBody { + + public convenience init?(dateComponents: NSDateComponents) { + + guard dateComponents.isValidDateInCalendar(NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!) else { + return nil + } + + let length = 7 + let data = NSData(hexadecimalString: String(format: "%02x%02x%02x%02x%04x%02x%02x", length, dateComponents.hour, dateComponents.minute, dateComponents.second, dateComponents.year, dateComponents.month, dateComponents.day))! + + self.init(rxData: data) + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/DeviceLinkMessageBody.swift b/MinimedKit/Messages/DeviceLinkMessageBody.swift new file mode 100644 index 000000000..adeb6abf0 --- /dev/null +++ b/MinimedKit/Messages/DeviceLinkMessageBody.swift @@ -0,0 +1,42 @@ +// +// DeviceLinkMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 2/29/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public struct DeviceLinkMessageBody: MessageBody { + + public static let length = 5 + + public let deviceAddress: NSData + public let sequence: UInt8 + let rxData: NSData + + + public init?(rxData: NSData) { + self.rxData = rxData + + if rxData.length == self.dynamicType.length { + self.deviceAddress = rxData.subdataWithRange(NSRange(1...3)) + sequence = rxData[0] & 0b1111111 + } else { + return nil + } + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "sequence": Int(sequence), + "deviceAddress": deviceAddress.hexadecimalString, + ] + } + +} diff --git a/MinimedKit/Messages/FindDeviceMessageBody.swift b/MinimedKit/Messages/FindDeviceMessageBody.swift new file mode 100644 index 000000000..275e1d26e --- /dev/null +++ b/MinimedKit/Messages/FindDeviceMessageBody.swift @@ -0,0 +1,42 @@ +// +// FindDeviceMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 2/29/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public struct FindDeviceMessageBody: MessageBody { + + public static let length = 5 + + public let deviceAddress: NSData + public let sequence: UInt8 + let rxData: NSData + + + public init?(rxData: NSData) { + self.rxData = rxData + + if rxData.length == self.dynamicType.length { + self.deviceAddress = rxData.subdataWithRange(NSRange(1...3)) + sequence = rxData[0] & 0b1111111 + } else { + return nil + } + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "sequence": Int(sequence), + "deviceAddress": deviceAddress.hexadecimalString, + ] + } + +} diff --git a/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift b/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift new file mode 100644 index 000000000..142de38ae --- /dev/null +++ b/MinimedKit/Messages/GetBatteryCarelinkMessageBody.swift @@ -0,0 +1,33 @@ +// +// GetBatteryCarelinkMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/13/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class GetBatteryCarelinkMessageBody: CarelinkLongMessageBody { + public let status: String + public let volts: Double + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + status = "" + volts = 0 + super.init(rxData: rxData) + return nil + } + + volts = Double(Int(rxData[2] as UInt8) << 8 + Int(rxData[3] as UInt8)) / 100.0 + + if rxData[1] as UInt8 > 0 { + status = "Low" + } else { + status = "Normal" + } + + super.init(rxData: rxData) + } +} diff --git a/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift b/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift new file mode 100644 index 000000000..7065cbd69 --- /dev/null +++ b/MinimedKit/Messages/GetHistoryPageCarelinkMessageBody.swift @@ -0,0 +1,39 @@ +// +// GetHistoryPageCarelinkMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/14/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class GetHistoryPageCarelinkMessageBody: CarelinkLongMessageBody { + public var lastFrame: Bool + public var frameNumber: Int + public var frame: NSData + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + frameNumber = 0 + frame = NSData() + lastFrame = false + super.init(rxData: rxData) + return nil + } + frameNumber = Int(rxData[0] as UInt8) & 0b1111111 + lastFrame = (rxData[0] as UInt8) & 0b10000000 > 0 + frame = rxData.subdataWithRange(NSMakeRange(1, 64)) + super.init(rxData: rxData) + } + + public required init(pageNum: Int) { + let numArgs = 1 + lastFrame = false + frame = NSData() + frameNumber = 0 + let data = NSData(hexadecimalString: String(format: "%02x%02x", numArgs, UInt8(pageNum)))! + super.init(rxData: data)! + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/GetPumpModelCarelinkMessageBody.swift b/MinimedKit/Messages/GetPumpModelCarelinkMessageBody.swift new file mode 100644 index 000000000..c7af7babc --- /dev/null +++ b/MinimedKit/Messages/GetPumpModelCarelinkMessageBody.swift @@ -0,0 +1,24 @@ +// +// GetPumpModelCarelinkMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/12/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class GetPumpModelCarelinkMessageBody: CarelinkLongMessageBody { + public let model: String + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length, + let mdl = String(data: rxData.subdataWithRange(NSMakeRange(2, 3)), encoding: NSASCIIStringEncoding) else { + model = "" + super.init(rxData: rxData) + return nil + } + model = mdl + super.init(rxData: rxData) + } +} diff --git a/MinimedKit/Messages/MeterMessage.swift b/MinimedKit/Messages/MeterMessage.swift new file mode 100644 index 000000000..d376e93b2 --- /dev/null +++ b/MinimedKit/Messages/MeterMessage.swift @@ -0,0 +1,45 @@ +// +// MeterMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class MeterMessage { + + let length = 7 + + public let glucose: Int + public let ackFlag: Bool + let rxData: NSData + + public required init?(rxData: NSData) { + self.rxData = rxData + + if rxData.length == length, + let packetType = PacketType(rawValue: rxData[0]) where packetType == .Meter + { + let flags = ((rxData[4] as UInt8) & 0b110) >> 1 + ackFlag = flags == 0x03 + glucose = Int((rxData[4] as UInt8) & 0b1) << 8 + Int(rxData[4] as UInt8) + } else { + ackFlag = false + glucose = 0 + return nil + } + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "glucose": glucose, + "ackFlag": ackFlag, + ] + } +} diff --git a/MinimedKit/Messages/MySentryAckMessageBody.swift b/MinimedKit/Messages/MySentryAckMessageBody.swift new file mode 100644 index 000000000..dae6bf37d --- /dev/null +++ b/MinimedKit/Messages/MySentryAckMessageBody.swift @@ -0,0 +1,48 @@ +// +// MySentryAckMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/4/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +/// Describes an ACK message sent by a MySentry device in response to pump status messages. +/// a2 350535 06 59 000695 00 04000000 e2 +public struct MySentryAckMessageBody: MessageBody { + public static let length = 9 + static var MessageCounter: UInt8 = 0 + + let mySentryID: [UInt8] + let responseMessageTypes: [MessageType] + + public init(mySentryID: [UInt8], responseMessageTypes: [MessageType]) { + assert(mySentryID.count == 3) + assert(responseMessageTypes.count <= 4) + + self.mySentryID = mySentryID + self.responseMessageTypes = responseMessageTypes + } + + public init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + mySentryID = rxData[1...3] + responseMessageTypes = rxData[5...8].flatMap({ MessageType(rawValue: $0) }) + } + + public var txData: NSData { + var buffer = self.dynamicType.emptyBuffer + + buffer[0] = UInt8(self.dynamicType.MessageCounter += 1) + buffer.replaceRange(1...3, with: mySentryID) + + buffer.replaceRange(5..<5 + responseMessageTypes.count, with: responseMessageTypes.map({ $0.rawValue })) + + return NSData(bytes: &buffer, length: buffer.count) + } +} diff --git a/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift b/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift new file mode 100644 index 000000000..65582cf87 --- /dev/null +++ b/MinimedKit/Messages/MySentryAlertClearedMessageBody.swift @@ -0,0 +1,48 @@ +// +// MySentryAlertClearedMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/6/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +/** +Describes message sent immediately from the pump to any paired MySentry devices after a user clears an alert + +See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/alert_cleared.rb) + +``` +a2 594040 02 80 52 14 +``` +*/ +public struct MySentryAlertClearedMessageBody: MessageBody, DictionaryRepresentable { + public static let length = 2 + + public let alertType: AlertType? + + private let rxData: NSData + + public init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + self.rxData = rxData + + alertType = AlertType(rawValue: rxData[1]) + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "alertType": alertType != nil ? String(alertType!) : rxData.subdataWithRange(NSRange(1...1)).hexadecimalString, + "cleared": true + ] + } +} \ No newline at end of file diff --git a/MinimedKit/Messages/MySentryAlertMessageBody.swift b/MinimedKit/Messages/MySentryAlertMessageBody.swift new file mode 100644 index 000000000..ecd66f2e3 --- /dev/null +++ b/MinimedKit/Messages/MySentryAlertMessageBody.swift @@ -0,0 +1,59 @@ +// +// MySentryAlertMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/6/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +/** +Describes an alert message sent immediately from the pump to any paired MySentry devices + +See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/alert.rb) + +``` +a2 594040 01 7c 65 0727070f0906 0175 4c +``` +*/ +public struct MySentryAlertMessageBody: MessageBody, DictionaryRepresentable { + public static let length = 10 + + public let alertType: AlertType? + public let alertDate: NSDate + + private let rxData: NSData + + public init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length, let + alertDate = NSDateComponents(mySentryBytes: rxData[2...7]).date + else { + return nil + } + + self.rxData = rxData + + alertType = AlertType(rawValue: rxData[1]) + self.alertDate = alertDate + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + let dateFormatter = NSDateFormatter() + + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" + dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") + + return [ + "alertDate": dateFormatter.stringFromDate(alertDate), + "alertType": alertType != nil ? String(alertType!) : rxData.subdataWithRange(NSRange(1...1)).hexadecimalString, + "byte89": rxData.subdataWithRange(NSRange(8...9)).hexadecimalString + ] + + } +} \ No newline at end of file diff --git a/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift b/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift new file mode 100644 index 000000000..90fae4427 --- /dev/null +++ b/MinimedKit/Messages/MySentryPumpStatusMessageBody.swift @@ -0,0 +1,259 @@ +// +// MySentryPumpStatusMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/5/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public enum GlucoseTrend { + case Flat + case Up + case UpUp + case Down + case DownDown + + init?(byte: UInt8) { + switch byte & 0b1110 { + case 0b0000: + self = .Flat + case 0b0010: + self = .Up + case 0b0100: + self = .UpUp + case 0b0110: + self = .Down + case 0b1000: + self = .DownDown + default: + return nil + } + } +} + + +public enum SensorReading { + case Off + case Missing + case MeterBGNow + case WeakSignal + case CalError + case Warmup + case Ended + case HighBG // Above 400 mg/dL + case Lost + case Unknown + case Active(glucose: Int) + + init(glucose: Int) { + switch glucose { + case 0: + self = .Off + case 1: + self = .Missing + case 2: + self = .MeterBGNow + case 4: + self = .WeakSignal + case 6: + self = .CalError + case 8: + self = .Warmup + case 10: + self = .Ended + case 14: + self = .HighBG + case 20: + self = .Lost + case 0...20: + self = .Unknown + default: + self = .Active(glucose: glucose) + } + } +} + + +/** + Describes a status message sent periodically from the pump to any paired MySentry devices + + See: [MinimedRF Class](https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/messages/pump_status.rb) + ``` + -- ------ -- 00 01 020304050607 08 09 10 11 1213 14 15 16 17 18 19 20 21 2223 24 25 26 27 282930313233 3435 -- + se tr pump date 01 bh ph resv bt st sr nxcal iob bl sens date 0000 + a2 594040 04 c9 51 092c1e0f0904 01 32 33 00 037a 02 02 05 b0 18 30 13 2b 00d1 00 00 00 70 092b000f0904 0000 33 + a2 594040 04 fb 51 1205000f0906 01 05 05 02 0000 04 00 00 00 ff 00 ff ff 0040 00 00 00 71 1205000f0906 0000 2b + a2 594040 04 ff 50 1219000f0906 01 00 00 00 0000 04 00 00 00 00 00 00 00 005e 00 00 00 72 000000000000 0000 8b + a2 594040 04 01 50 1223000f0906 01 00 00 00 0000 04 00 00 00 00 00 00 00 0059 00 00 00 72 000000000000 0000 9f + a2 594040 04 2f 51 1727070f0905 01 84 85 00 00cd 01 01 05 b0 3e 0a 0a 1a 009d 03 00 00 71 1726000f0905 0000 d0 + a2 594040 04 9c 51 0003310f0905 01 39 37 00 025b 01 01 06 8d 26 22 08 15 0034 00 00 00 70 0003000f0905 0000 67 + a2 594040 04 87 51 0f18150f0907 01 03 71 00 045e 04 02 07 2c 04 44 ff ff 005e 02 00 00 73 0f16000f0907 0000 35 + ``` + */ +public struct MySentryPumpStatusMessageBody: MessageBody, DictionaryRepresentable { + private static let reservoirSignificantDigit = 0.1 + private static let iobSigificantDigit = 0.025 + public static let length = 36 + + public let pumpDateComponents: NSDateComponents + public let batteryRemainingPercent: Int + public let iob: Double + public let reservoirRemainingUnits: Double + public let reservoirRemainingPercent: Int + public let reservoirRemainingMinutes: Int + + public let glucoseTrend: GlucoseTrend + public let glucoseDateComponents: NSDateComponents? + public let glucose: SensorReading + public let previousGlucose: SensorReading + public let sensorAgeHours: Int + public let sensorRemainingHours: Int + + public let nextSensorCalibrationDateComponents: NSDateComponents? + + private let rxData: NSData + + public init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length, let trend = GlucoseTrend(byte: rxData[1]) else { + return nil + } + + self.rxData = rxData + + let pumpDateComponents = NSDateComponents(mySentryBytes: rxData[2...7]) + + guard let calendar = pumpDateComponents.calendar where pumpDateComponents.isValidDateInCalendar(calendar) else { + return nil + } + + self.pumpDateComponents = pumpDateComponents + + self.glucoseTrend = trend + + reservoirRemainingUnits = Double(Int(bigEndianBytes: rxData[12...13])) * self.dynamicType.reservoirSignificantDigit + + let reservoirRemainingPercent: UInt8 = rxData[15] + self.reservoirRemainingPercent = Int(round(Double(reservoirRemainingPercent) / 4.0 * 100)) + + reservoirRemainingMinutes = Int(bigEndianBytes: [rxData[16], rxData[17]]) + + iob = Double(Int(bigEndianBytes: rxData[22...23])) * self.dynamicType.iobSigificantDigit + + let batteryRemainingPercent: UInt8 = rxData[14] + self.batteryRemainingPercent = Int(round(Double(batteryRemainingPercent) / 4.0 * 100)) + + let glucoseValue = Int(bigEndianBytes: [rxData[9], rxData[24] << 7]) >> 7 + let previousGlucoseValue = Int(bigEndianBytes: [rxData[10], rxData[24] << 6]) >> 7 + + glucose = SensorReading(glucose: glucoseValue) + previousGlucose = SensorReading(glucose: previousGlucoseValue) + + switch glucose { + case .Off: + glucoseDateComponents = nil + default: + let glucoseDateComponents = NSDateComponents(mySentryBytes: rxData[28...33]) + + if glucoseDateComponents.isValidDateInCalendar(calendar) { + self.glucoseDateComponents = glucoseDateComponents + } else { + self.glucoseDateComponents = nil + } + } + + let sensorAgeHours: UInt8 = rxData[18] + self.sensorAgeHours = Int(sensorAgeHours) + + let sensorRemainingHours: UInt8 = rxData[19] + self.sensorRemainingHours = Int(sensorRemainingHours) + + let matchingHour: UInt8 = rxData[20] + nextSensorCalibrationDateComponents = NSDateComponents() + nextSensorCalibrationDateComponents?.hour = Int(matchingHour) + nextSensorCalibrationDateComponents?.minute = Int(rxData[21] as UInt8) + nextSensorCalibrationDateComponents?.calendar = calendar + } + + public var dictionaryRepresentation: [String: AnyObject] { + let dateComponentsString = { (components: NSDateComponents) -> String in + String( + format: "%04d-%02d-%02dT%02d:%02d:%02d", + components.year, + components.month, + components.day, + components.hour, + components.minute, + components.second + ) + } + + var dict: [String: AnyObject] = [ + "glucoseTrend": String(glucoseTrend), + "pumpDate": dateComponentsString(pumpDateComponents), + "reservoirRemaining": reservoirRemainingUnits, + "reservoirRemainingPercent": reservoirRemainingPercent, + "reservoirRemainingMinutes": reservoirRemainingMinutes, + "iob": iob + ] + + switch glucose { + case .Active(glucose: let glucose): + dict["glucose"] = glucose + default: + break + } + + if let glucoseDateComponents = glucoseDateComponents { + dict["glucoseDate"] = dateComponentsString(glucoseDateComponents) + } + dict["sensorStatus"] = String(glucose) + + switch previousGlucose { + case .Active(glucose: let glucose): + dict["lastGlucose"] = glucose + default: + break + } + dict["lastSensorStatus"] = String(previousGlucose) + + dict["sensorAgeHours"] = sensorAgeHours + dict["sensorRemainingHours"] = sensorRemainingHours + if let components = nextSensorCalibrationDateComponents { + dict["nextSensorCalibration"] = String(format: "%02d:%02d", components.hour, components.minute) + } + + dict["batteryRemainingPercent"] = batteryRemainingPercent + + dict["byte1"] = rxData.subdataWithRange(NSRange(1...1)).hexadecimalString + // {50} + let byte1: UInt8 = rxData[1] + dict["byte1High"] = String(format: "%02x", byte1 & 0b11110000) + // {1} + dict["byte1Low"] = Int(byte1 & 0b00000001) + // Observed values: 00, 01, 02, 03 + // These seem to correspond with carb/bolus activity + dict["byte11"] = rxData.subdataWithRange(NSRange(11...11)).hexadecimalString + // Current alarms? + // 25: {00,52,65} 4:49 AM - 4:59 AM + // 26: 00 + dict["byte2526"] = rxData.subdataWithRange(NSRange(25...26)).hexadecimalString + // 27: {73} + dict["byte27"] = rxData.subdataWithRange(NSRange(27...27)).hexadecimalString + + return dict + } + + public var txData: NSData { + return rxData + } +} + +extension MySentryPumpStatusMessageBody: Equatable { +} + +public func ==(lhs: MySentryPumpStatusMessageBody, rhs: MySentryPumpStatusMessageBody) -> Bool { + return lhs.pumpDateComponents == rhs.pumpDateComponents && lhs.glucoseDateComponents == rhs.glucoseDateComponents +} diff --git a/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift b/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift new file mode 100644 index 000000000..ec565d48a --- /dev/null +++ b/MinimedKit/Messages/PowerOnCarelinkMessageBody.swift @@ -0,0 +1,24 @@ +// +// PowerOnCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class PowerOnCarelinkMessageBody: CarelinkLongMessageBody { + + public convenience init(duration: NSTimeInterval) { + let numArgs = 2 + let on = 1 + let durationMinutes: Int = Int(ceil(duration / 60.0)) + + let data = NSData(hexadecimalString: String(format: "%02x%02x%02x", numArgs, on, durationMinutes))! + + self.init(rxData: data)! + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/PumpAckMessageBody.swift b/MinimedKit/Messages/PumpAckMessageBody.swift new file mode 100644 index 000000000..d5e69b4ba --- /dev/null +++ b/MinimedKit/Messages/PumpAckMessageBody.swift @@ -0,0 +1,23 @@ +// +// PumpAckMessageBody.swift +// RileyLink +// +// Created by Pete Schwamb on 3/14/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class PumpAckMessageBody: MessageBody { + public static let length = 1 + + let rxData: NSData + + public required init?(rxData: NSData) { + self.rxData = rxData + } + + public var txData: NSData { + return rxData + } +} \ No newline at end of file diff --git a/MinimedKit/Messages/ReadSettingsCarelinkMessageBody.swift b/MinimedKit/Messages/ReadSettingsCarelinkMessageBody.swift new file mode 100644 index 000000000..f4d7a05eb --- /dev/null +++ b/MinimedKit/Messages/ReadSettingsCarelinkMessageBody.swift @@ -0,0 +1,77 @@ +// +// ReadSettingsCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public enum BasalProfile { + + case Standard + case ProfileA + case ProfileB + + init(rawValue: UInt8) { + switch rawValue { + case 1: + self = .ProfileA + case 2: + self = .ProfileB + default: + self = .Standard + } + } +} + + +/** + Describes the response to the Read Settings command from the pump + + See: [Decocare Class](https://github.com/bewest/decoding-carelink/blob/master/decocare/commands.py#L1223) + ``` + -- ------ -- 00 01 02 03 04 05 06 07 0809 10 11 12 13141516171819 20 21 2223 24 25 26 27 282930313233 343536 -- + a7 594040 c0 19 00 01 00 01 01 00 96 008c 00 00 00 00000064010400 14 00 1901 01 01 00 00 000000000000 000000 00000000000000000000000000000000000000000000000000000000 e9 + ``` + */ +public class ReadSettingsCarelinkMessageBody: CarelinkLongMessageBody { + private static let maxBolusSignificantDigit = 0.1 + private static let maxBasalSignificantDigit = 0.025 + + public let maxBasal: Double + public let maxBolus: Double + + public let insulinActionCurveHours: Int + + public let selectedBasalProfile: BasalProfile + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + let maxBolusTicks: UInt8 = rxData[7] + maxBolus = Double(maxBolusTicks) * self.dynamicType.maxBolusSignificantDigit + + let maxBasalTicks: Int = Int(bigEndianBytes: rxData[8...9]) + maxBasal = Double(maxBasalTicks) * self.dynamicType.maxBasalSignificantDigit + + let rawSelectedBasalProfile: UInt8 = rxData[12] + selectedBasalProfile = BasalProfile(rawValue: rawSelectedBasalProfile) + + let rawInsulinActionCurveHours: UInt8 = rxData[18] + insulinActionCurveHours = Int(rawInsulinActionCurveHours) + + super.init(rxData: rxData) + } +} + + +extension ReadSettingsCarelinkMessageBody: DictionaryRepresentable { + public var dictionaryRepresentation: [String: AnyObject] { + return [:] + } +} diff --git a/MinimedKit/Messages/ReadTempBasalCarelinkMessageBody.swift b/MinimedKit/Messages/ReadTempBasalCarelinkMessageBody.swift new file mode 100644 index 000000000..d0206975b --- /dev/null +++ b/MinimedKit/Messages/ReadTempBasalCarelinkMessageBody.swift @@ -0,0 +1,54 @@ +// +// ReadTempBasalCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/7/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class ReadTempBasalCarelinkMessageBody: CarelinkLongMessageBody { + + // MMX12 and above + private static let strokesPerUnit = 40 + + public enum RateType { + case Absolute + case Percent + } + + public let timeRemaining: NSTimeInterval + public let rate: Double + public let rateType: RateType + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + let rawRateType: UInt8 = rxData[1] + switch rawRateType { + case 0: + rateType = .Absolute + let strokes = Int(bigEndianBytes: rxData[3...4]) + rate = Double(strokes) / Double(self.dynamicType.strokesPerUnit) + case 1: + rateType = .Percent + let rawRate: UInt8 = rxData[2] + rate = Double(rawRate) + default: + timeRemaining = 0 + rate = 0 + rateType = .Absolute + super.init(rxData: rxData) + return nil + } + + let minutesRemaining = Int(bigEndianBytes: rxData[5...6]) + timeRemaining = NSTimeInterval(minutesRemaining * 60) + + super.init(rxData: rxData) + } +} \ No newline at end of file diff --git a/MinimedKit/Messages/ReadTimeCarelinkMessageBody.swift b/MinimedKit/Messages/ReadTimeCarelinkMessageBody.swift new file mode 100644 index 000000000..e49c17cb5 --- /dev/null +++ b/MinimedKit/Messages/ReadTimeCarelinkMessageBody.swift @@ -0,0 +1,32 @@ +// +// ReadTimeCarelinkMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/17/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public class ReadTimeCarelinkMessageBody: CarelinkLongMessageBody { + + public let dateComponents = NSDateComponents() + + public required init?(rxData: NSData) { + guard rxData.length == self.dynamicType.length else { + return nil + } + + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.hour = Int(rxData[1] as UInt8) + dateComponents.minute = Int(rxData[2] as UInt8) + dateComponents.second = Int(rxData[3] as UInt8) + dateComponents.year = Int(bigEndianBytes: rxData[4...5]) + dateComponents.month = Int(rxData[6] as UInt8) + dateComponents.day = Int(rxData[7] as UInt8) + + super.init(rxData: rxData) + } + +} \ No newline at end of file diff --git a/MinimedKit/Messages/UnknownMessageBody.swift b/MinimedKit/Messages/UnknownMessageBody.swift new file mode 100644 index 000000000..7f163011f --- /dev/null +++ b/MinimedKit/Messages/UnknownMessageBody.swift @@ -0,0 +1,28 @@ +// +// UnknownMessageBody.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/16/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +public struct UnknownMessageBody: MessageBody, DictionaryRepresentable { + public static var length = 0 + + let rxData: NSData + + public init?(rxData: NSData) { + self.rxData = rxData + } + + public var txData: NSData { + return rxData + } + + public var dictionaryRepresentation: [String: AnyObject] { + return ["rawData": rxData] + } +} \ No newline at end of file diff --git a/MinimedKit/MinimedKit.h b/MinimedKit/MinimedKit.h new file mode 100644 index 000000000..b4f1d1cc9 --- /dev/null +++ b/MinimedKit/MinimedKit.h @@ -0,0 +1,19 @@ +// +// MinimedKit.h +// MinimedKit +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +#import + +//! Project version number for MinimedKit. +FOUNDATION_EXPORT double MinimedKitVersionNumber; + +//! Project version string for MinimedKit. +FOUNDATION_EXPORT const unsigned char MinimedKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/MinimedKit/PacketType.swift b/MinimedKit/PacketType.swift new file mode 100644 index 000000000..c00b27003 --- /dev/null +++ b/MinimedKit/PacketType.swift @@ -0,0 +1,14 @@ +// +// PacketType.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/2/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +public enum PacketType: UInt8 { + case MySentry = 0xA2 + case Meter = 0xA5 + case Carelink = 0xA7 + case Sensor = 0xA8 +} diff --git a/MinimedKit/PumpEventType.swift b/MinimedKit/PumpEventType.swift new file mode 100644 index 000000000..eac760b0e --- /dev/null +++ b/MinimedKit/PumpEventType.swift @@ -0,0 +1,182 @@ +// +// PumpEventType.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + + +public enum PumpEventType: UInt8 { + case BolusNormal = 0x01 + case Prime = 0x03 + case AlarmPump = 0x06 + case ResultDailyTotal = 0x07 + case ChangeBasalProfilePattern = 0x08 + case ChangeBasalProfile = 0x09 + case CalBGForPH = 0x0a + case AlarmSensor = 0x0b + case ClearAlarm = 0x0c + case TempBasalDuration = 0x16 + case ChangeTime = 0x17 + case JournalEntryPumpLowBattery = 0x19 + case Battery = 0x1a + case Suspend = 0x1e + case Resume = 0x1f + case Rewind = 0x21 + case ChangeChildBlockEnable = 0x23 + case ChangeMaxBolus = 0x24 + case EnableDisableRemote = 0x26 + case ChangeMaxBasal = 0x2c + case ChangeBGReminderOffset = 0x31 + case ChangeAlarmClockTime = 0x32 + case TempBasal = 0x33 + case JournalEntryPumpLowReservoir = 0x34 + case AlarmClockReminder = 0x35 + case ChangeParadigmLinkID = 0x3c + case BGReceived = 0x3f + case JournalEntryExerciseMarker = 0x41 + case ChangeSensorSetup2 = 0x50 + case ChangeSensorRateOfChangeAlertSetup = 0x56 + case ChangeBolusScrollStepSize = 0x57 + case ChangeBolusWizardSetup = 0x5a + case BolusWizardBolusEstimate = 0x5b + case UnabsorbedInsulin = 0x5c + case ChangeVariableBolus = 0x5e + case ChangeAudioBolus = 0x5f + case ChangeBGReminderEnable = 0x60 + case ChangeAlarmClockEnable = 0x61 + case ChangeTempBasalType = 0x62 + case ChangeAlarmNotifyMode = 0x63 + case ChangeTimeFormat = 0x64 + case ChangeReservoirWarningTime = 0x65 + case ChangeBolusReminderEnable = 0x66 + case ChangeBolusReminderTime = 0x67 + case DeleteBolusReminderTime = 0x68 + case DeleteAlarmClockTime = 0x6a + case Model522ResultTotals = 0x6d + case Sara6E = 0x6e + case ChangeCarbUnits = 0x6f + case BasalProfileStart = 0x7b + case ChangeWatchdogEnable = 0x7c + case ChangeOtherDeviceID = 0x7d + case ChangeWatchdogMarriageProfile = 0x81 + case DeleteOtherDeviceID = 0x82 + case ChangeCaptureEventEnable = 0x83 + + var eventType: PumpEvent.Type { + switch self { + case .BolusNormal: + return BolusNormalPumpEvent.self + case .Prime: + return PrimePumpEvent.self + case .AlarmPump: + return PumpAlarmPumpEvent.self + case .ResultDailyTotal: + return ResultDailyTotalPumpEvent.self + case .ChangeBasalProfilePattern: + return ChangeBasalProfilePatternPumpEvent.self + case .ChangeBasalProfile: + return ChangeBasalProfilePumpEvent.self + case .CalBGForPH: + return CalBGForPHPumpEvent.self + case .AlarmSensor: + return AlarmSensorPumpEvent.self + case .ClearAlarm: + return ClearAlarmPumpEvent.self + case TempBasalDuration: + return TempBasalDurationPumpEvent.self + case .ChangeTime: + return ChangeTimePumpEvent.self + case .JournalEntryPumpLowBattery: + return JournalEntryPumpLowBatteryPumpEvent.self + case .Battery: + return BatteryPumpEvent.self + case .Suspend: + return SuspendPumpEvent.self + case .Resume: + return ResumePumpEvent.self + case .Rewind: + return RewindPumpEvent.self + case .ChangeChildBlockEnable: + return ChangeChildBlockEnablePumpEvent.self + case .ChangeMaxBolus: + return ChangeMaxBolusPumpEvent.self + case .EnableDisableRemote: + return EnableDisableRemotePumpEvent.self + case .ChangeMaxBasal: + return ChangeMaxBasalPumpEvent.self + case .ChangeBGReminderOffset: + return ChangeBGReminderOffsetPumpEvent.self + case .ChangeAlarmClockTime: + return ChangeAlarmClockTimePumpEvent.self + case .TempBasal: + return TempBasalPumpEvent.self + case .JournalEntryPumpLowReservoir: + return JournalEntryPumpLowReservoirPumpEvent.self + case .AlarmClockReminder: + return AlarmClockReminderPumpEvent.self + case .ChangeParadigmLinkID: + return ChangeParadigmLinkIDPumpEvent.self + case .BGReceived: + return BGReceivedPumpEvent.self + case .JournalEntryExerciseMarker: + return JournalEntryExerciseMarkerPumpEvent.self + case .ChangeSensorSetup2: + return ChangeSensorSetup2PumpEvent.self + case .ChangeSensorRateOfChangeAlertSetup: + return ChangeSensorRateOfChangeAlertSetupPumpEvent.self + case .ChangeBolusScrollStepSize: + return ChangeBolusScrollStepSizePumpEvent.self + case .ChangeBolusWizardSetup: + return ChangeBolusWizardSetupPumpEvent.self + case .BolusWizardBolusEstimate: + return BolusWizardEstimatePumpEvent.self + case .UnabsorbedInsulin: + return UnabsorbedInsulinPumpEvent.self + case .ChangeVariableBolus: + return ChangeVariableBolusPumpEvent.self + case .ChangeAudioBolus: + return ChangeAudioBolusPumpEvent.self + case .ChangeBGReminderEnable: + return ChangeBGReminderEnablePumpEvent.self + case .ChangeAlarmClockEnable: + return ChangeAlarmClockEnablePumpEvent.self + case .ChangeTempBasalType: + return ChangeTempBasalTypePumpEvent.self + case .ChangeAlarmNotifyMode: + return ChangeAlarmNotifyModePumpEvent.self + case .ChangeTimeFormat: + return ChangeTimeFormatPumpEvent.self + case .ChangeReservoirWarningTime: + return ChangeReservoirWarningTimePumpEvent.self + case .ChangeBolusReminderEnable: + return ChangeBolusReminderEnablePumpEvent.self + case .ChangeBolusReminderTime: + return ChangeBolusReminderTimePumpEvent.self + case .DeleteBolusReminderTime: + return DeleteBolusReminderTimePumpEvent.self + case .DeleteAlarmClockTime: + return DeleteAlarmClockTimePumpEvent.self + case .Model522ResultTotals: + return Model522ResultTotalsPumpEvent.self + case .Sara6E: + return Sara6EPumpEvent.self + case .ChangeCarbUnits: + return ChangeCarbUnitsPumpEvent.self + case .BasalProfileStart: + return BasalProfileStartPumpEvent.self + case .ChangeWatchdogEnable: + return ChangeWatchdogEnablePumpEvent.self + case .ChangeOtherDeviceID: + return ChangeOtherDeviceIDPumpEvent.self + case .ChangeWatchdogMarriageProfile: + return ChangeWatchdogMarriageProfilePumpEvent.self + case .DeleteOtherDeviceID: + return DeleteOtherDeviceIDPumpEvent.self + case .ChangeCaptureEventEnable: + return ChangeCaptureEventEnablePumpEvent.self + } + } +} + diff --git a/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift b/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift new file mode 100644 index 000000000..9f1a6799d --- /dev/null +++ b/MinimedKit/PumpEvents/AlarmClockReminderPumpEvent.swift @@ -0,0 +1,32 @@ +// +// AlarmClockReminderPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class AlarmClockReminderPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "AlarmClockReminder", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/AlarmSensorPumpEvent.swift b/MinimedKit/PumpEvents/AlarmSensorPumpEvent.swift new file mode 100644 index 000000000..0c2d07855 --- /dev/null +++ b/MinimedKit/PumpEvents/AlarmSensorPumpEvent.swift @@ -0,0 +1,32 @@ +// +// AlarmSensorPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class AlarmSensorPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 8 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "AlarmSensor", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/BGReceivedPumpEvent.swift b/MinimedKit/PumpEvents/BGReceivedPumpEvent.swift new file mode 100644 index 000000000..158dcf291 --- /dev/null +++ b/MinimedKit/PumpEvents/BGReceivedPumpEvent.swift @@ -0,0 +1,44 @@ +// +// BGReceived.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BGReceivedPumpEvent: PumpEvent { + public let length: Int + public let timestamp: NSDateComponents + public let amount: Int + public let meter: String + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 10 + + if length > availableData.length { + timestamp = NSDateComponents() + amount = 0 + meter = "Invalid" + return nil + } + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + amount = (d(1) << 3) + (d(4) >> 5) + meter = availableData.subdataWithRange(NSMakeRange(7, 3)).hexadecimalString + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "BGReceivedPumpEvent", + "timestamp": TimeFormat.timestampStr(timestamp), + "amount": amount, + "meter": meter, + ] + } +} diff --git a/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift b/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift new file mode 100644 index 000000000..391e05aee --- /dev/null +++ b/MinimedKit/PumpEvents/BasalProfileStartPumpEvent.swift @@ -0,0 +1,50 @@ +// +// BasalProfileStartPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BasalProfileStartPumpEvent: TimestampedPumpEvent { + public let length: Int + public let timestamp: NSDateComponents + let rate: Double + let profileIndex: Int + let offset: Int + + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 10 + + if length > availableData.length { + timestamp = NSDateComponents() + rate = 0 + profileIndex = 0 + offset = 0 + return nil + } + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + rate = Double(d(8)) / 40.0 + profileIndex = d(1) + offset = d(7) * 30 * 1000 * 60 + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "BasalProfileStart", + "timestamp": TimeFormat.timestampStr(timestamp), + "offset": offset, + "rate": rate, + "profileIndex": profileIndex, + ] + } + +} diff --git a/MinimedKit/PumpEvents/BatteryPumpEvent.swift b/MinimedKit/PumpEvents/BatteryPumpEvent.swift new file mode 100644 index 000000000..57005a6eb --- /dev/null +++ b/MinimedKit/PumpEvents/BatteryPumpEvent.swift @@ -0,0 +1,32 @@ +// +// BatteryPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BatteryPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Battery", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/BolusNormalPumpEvent.swift b/MinimedKit/PumpEvents/BolusNormalPumpEvent.swift new file mode 100644 index 000000000..48d439176 --- /dev/null +++ b/MinimedKit/PumpEvents/BolusNormalPumpEvent.swift @@ -0,0 +1,87 @@ +// +// BolusNormalPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BolusNormalPumpEvent: TimestampedPumpEvent { + public let length: Int + public let timestamp: NSDateComponents + public var unabsorbedInsulinRecord: UnabsorbedInsulinPumpEvent? + public let amount: Double + public let programmed: Double + public let unabsorbedInsulinTotal: Double + public let bolusType: String + public let duration: Int + + public required init?(availableData: NSData, pumpModel: PumpModel) { + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + func insulinDecode(a: Int, b: Int) -> Double { + return Double((a << 8) + b) / 40.0 + } + + if pumpModel.larger { + length = 13 + } else { + length = 9 + } + + if length > availableData.length { + amount = 0 + programmed = 0 + unabsorbedInsulinTotal = 0 + duration = 0 + bolusType = "Unset" + timestamp = NSDateComponents() + return nil + } + + if pumpModel.larger { + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 8) + amount = insulinDecode(d(3), b: d(4)) + programmed = insulinDecode(d(1), b: d(2)) + unabsorbedInsulinTotal = insulinDecode(d(5), b: d(6)) + duration = d(7) * 30 + } else { + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 4) + amount = Double(d(2))/10.0 + programmed = Double(d(1))/10.0 + duration = d(3) * 30 + unabsorbedInsulinTotal = 0 + } + bolusType = duration > 0 ? "square" : "normal" + } + + public var dictionaryRepresentation: [String: AnyObject] { + var dictionary: [String: AnyObject] = [ + "_type": "BolusNormal", + "amount": amount, + "programmed": programmed, + "type": bolusType, + "timestamp": TimeFormat.timestampStr(timestamp), + ] + + if let unabsorbedInsulinRecord = unabsorbedInsulinRecord { + dictionary["appended"] = unabsorbedInsulinRecord.dictionaryRepresentation + } + + if unabsorbedInsulinTotal > 0 { + dictionary["unabsorbed"] = unabsorbedInsulinTotal + } + + if duration > 0 { + dictionary["duration"] = duration + } + + return dictionary + } + +} diff --git a/MinimedKit/PumpEvents/BolusWizardEstimatePumpEvent.swift b/MinimedKit/PumpEvents/BolusWizardEstimatePumpEvent.swift new file mode 100644 index 000000000..2aebc8ba8 --- /dev/null +++ b/MinimedKit/PumpEvents/BolusWizardEstimatePumpEvent.swift @@ -0,0 +1,101 @@ +// +// BolusWizardEstimatePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BolusWizardEstimatePumpEvent: TimestampedPumpEvent { + public let length: Int + public let timestamp: NSDateComponents + public let carbohydrates: Int + public let bloodGlucose: Int + public let foodEstimate: Double + public let correctionEstimate: Double + public let bolusEstimate: Double + public let unabsorbedInsulinTotal: Double + public let bgTargetLow: Int + public let bgTargetHigh: Int + public let insulinSensitivity: Int + public let carbRatio: Double + + public required init?(availableData: NSData, pumpModel: PumpModel) { + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + func insulinDecode(a: Int, b: Int) -> Double { + return Double((a << 8) + b) / 40.0 + } + + if pumpModel.larger { + length = 22 + } else { + length = 20 + } + + if length >= availableData.length { + carbohydrates = 0 + bloodGlucose = 0 + foodEstimate = 0 + correctionEstimate = 0 + bolusEstimate = 0 + unabsorbedInsulinTotal = 0 + bgTargetLow = 0 + bgTargetHigh = 0 + insulinSensitivity = 0 + carbRatio = 0 + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + + if pumpModel.larger { + carbohydrates = ((d(8) & 0xc) << 6) + d(7) + bloodGlucose = ((d(8) & 0x3) << 8) + d(1) + foodEstimate = insulinDecode(d(14), b: d(15)) + correctionEstimate = Double(((d(16) & 0b111000) << 5) + d(13)) / 40.0 + bolusEstimate = insulinDecode(d(19), b: d(20)) + unabsorbedInsulinTotal = insulinDecode(d(17), b: d(18)) + bgTargetLow = d(12) + bgTargetHigh = d(21) + insulinSensitivity = d(11) + carbRatio = Double(((d(9) & 0x7) << 8) + d(10)) / 10.0 + } else { + carbohydrates = d(7) + bloodGlucose = ((d(8) & 0x3) << 8) + d(1) + foodEstimate = Double(d(13))/10.0 + correctionEstimate = Double((d(14) << 8) + d(12)) / 10.0 + bolusEstimate = Double(d(18))/10.0 + unabsorbedInsulinTotal = Double(d(16))/10.0 + bgTargetLow = d(11) + bgTargetHigh = d(19) + insulinSensitivity = d(10) + carbRatio = Double(d(9)) + } + + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "BolusWizardBolusEstimate", + "timestamp": TimeFormat.timestampStr(timestamp), + "bg": bloodGlucose, + "bgTargetHigh": bgTargetHigh, + "correctionEstimate": correctionEstimate, + "carbInput": carbohydrates, + "unabsorbedInsulinTotal": unabsorbedInsulinTotal, + "bolusEstimate": bolusEstimate, + "carbRatio": carbRatio, + "foodEstimate": foodEstimate, + "bgTargetLow": bgTargetLow, + "insulinSensitivity": insulinSensitivity + ] + } + +} diff --git a/MinimedKit/PumpEvents/CalBGForPHPumpEvent.swift b/MinimedKit/PumpEvents/CalBGForPHPumpEvent.swift new file mode 100644 index 000000000..5deaf15b8 --- /dev/null +++ b/MinimedKit/PumpEvents/CalBGForPHPumpEvent.swift @@ -0,0 +1,40 @@ +// +// CalBGForPHPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class CalBGForPHPumpEvent: PumpEvent { + public let length: Int + public let timestamp: NSDateComponents + public let amount: Int + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + amount = 0 + return nil + } + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + amount = ((d(6) & 0b10000000) << 1) + d(1) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "CalBGForPH", + "timestamp": TimeFormat.timestampStr(timestamp), + "amount": amount, + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift new file mode 100644 index 000000000..331404c7a --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeAlarmClockEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeAlarmClockEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeAlarmClockEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeAlarmClockEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeAlarmClockTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeAlarmClockTimePumpEvent.swift new file mode 100644 index 000000000..cb9fb7f53 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeAlarmClockTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeAlarmClockTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeAlarmClockTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 14 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeAlarmClockTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeAlarmNotifyModePumpEvent.swift b/MinimedKit/PumpEvents/ChangeAlarmNotifyModePumpEvent.swift new file mode 100644 index 000000000..c9af67215 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeAlarmNotifyModePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeAlarmNotifyModePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeAlarmNotifyModePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeAlarmNotifyMode", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeAudioBolusPumpEvent.swift b/MinimedKit/PumpEvents/ChangeAudioBolusPumpEvent.swift new file mode 100644 index 000000000..ce85966b6 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeAudioBolusPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeAudioBolusPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeAudioBolusPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeAudioBolus", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBGReminderEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeBGReminderEnablePumpEvent.swift new file mode 100644 index 000000000..3429ad176 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBGReminderEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBGReminderEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBGReminderEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBGReminderEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBGReminderOffsetPumpEvent.swift b/MinimedKit/PumpEvents/ChangeBGReminderOffsetPumpEvent.swift new file mode 100644 index 000000000..562d1f54e --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBGReminderOffsetPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBGReminderOffsetPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBGReminderOffsetPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBGReminderOffset", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBasalProfilePatternPumpEvent.swift b/MinimedKit/PumpEvents/ChangeBasalProfilePatternPumpEvent.swift new file mode 100644 index 000000000..c820f9841 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBasalProfilePatternPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBasalProfilePatternPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBasalProfilePatternPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 152 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBasalProfilePattern", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBasalProfilePumpEvent.swift b/MinimedKit/PumpEvents/ChangeBasalProfilePumpEvent.swift new file mode 100644 index 000000000..bf3dd0763 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBasalProfilePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBasalProfilePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBasalProfilePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 152 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBasalProfile", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBolusReminderEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeBolusReminderEnablePumpEvent.swift new file mode 100644 index 000000000..4932dd4f3 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBolusReminderEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBolusReminderEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBolusReminderEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBolusReminderEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBolusReminderTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeBolusReminderTimePumpEvent.swift new file mode 100644 index 000000000..3653cca85 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBolusReminderTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBolusReminderTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBolusReminderTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 9 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBolusReminderTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBolusScrollStepSizePumpEvent.swift b/MinimedKit/PumpEvents/ChangeBolusScrollStepSizePumpEvent.swift new file mode 100644 index 000000000..5a6adca0d --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBolusScrollStepSizePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBolusScrollStepSizePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBolusScrollStepSizePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBolusScrollStepSize", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeBolusWizardSetupPumpEvent.swift b/MinimedKit/PumpEvents/ChangeBolusWizardSetupPumpEvent.swift new file mode 100644 index 000000000..15964fb8d --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeBolusWizardSetupPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeBolusWizardSetupPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeBolusWizardSetupPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 144 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeBolusWizardSetup", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeCaptureEventEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeCaptureEventEnablePumpEvent.swift new file mode 100644 index 000000000..d5232396e --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeCaptureEventEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeCaptureEventEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeCaptureEventEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeCaptureEventEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeCarbUnitsPumpEvent.swift b/MinimedKit/PumpEvents/ChangeCarbUnitsPumpEvent.swift new file mode 100644 index 000000000..d418a8636 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeCarbUnitsPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeCarbUnitsPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeCarbUnitsPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeCarbUnits", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeChildBlockEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeChildBlockEnablePumpEvent.swift new file mode 100644 index 000000000..e57b971e0 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeChildBlockEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeChildBlockEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeChildBlockEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeChildBlockEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeMaxBasalPumpEvent.swift b/MinimedKit/PumpEvents/ChangeMaxBasalPumpEvent.swift new file mode 100644 index 000000000..1bd9c9d79 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeMaxBasalPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeMaxBasalPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeMaxBasalPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeMaxBasal", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeMaxBolusPumpEvent.swift b/MinimedKit/PumpEvents/ChangeMaxBolusPumpEvent.swift new file mode 100644 index 000000000..9cf9f15ba --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeMaxBolusPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeMaxBolusPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeMaxBolusPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeMaxBolus", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeOtherDeviceIDPumpEvent.swift b/MinimedKit/PumpEvents/ChangeOtherDeviceIDPumpEvent.swift new file mode 100644 index 000000000..6c49cbe2d --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeOtherDeviceIDPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeOtherDeviceIDPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeOtherDeviceIDPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 37 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeOtherDeviceID", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeParadigmLinkIDPumpEvent.swift b/MinimedKit/PumpEvents/ChangeParadigmLinkIDPumpEvent.swift new file mode 100644 index 000000000..cf758b338 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeParadigmLinkIDPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeParadigmLinkIDPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeParadigmLinkIDPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 21 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeParadigmLinkID", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeReservoirWarningTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeReservoirWarningTimePumpEvent.swift new file mode 100644 index 000000000..f48ab16a7 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeReservoirWarningTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeReservoirWarningTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeReservoirWarningTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeReservoirWarningTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeSensorRateOfChangeAlertSetupPumpEvent.swift b/MinimedKit/PumpEvents/ChangeSensorRateOfChangeAlertSetupPumpEvent.swift new file mode 100644 index 000000000..e8a750f7b --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeSensorRateOfChangeAlertSetupPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeSensorRateOfChangeAlertSetupPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeSensorRateOfChangeAlertSetupPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 12 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeSensorRateOfChangeAlertSetup", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeSensorSetup2PumpEvent.swift b/MinimedKit/PumpEvents/ChangeSensorSetup2PumpEvent.swift new file mode 100644 index 000000000..332b3187d --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeSensorSetup2PumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeSensorSetup2PumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeSensorSetup2PumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 37 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeSensorSetup2", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeTempBasalTypePumpEvent.swift b/MinimedKit/PumpEvents/ChangeTempBasalTypePumpEvent.swift new file mode 100644 index 000000000..7017e8b25 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeTempBasalTypePumpEvent.swift @@ -0,0 +1,40 @@ +// +// ChangeTempBasalTypePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/20/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeTempBasalTypePumpEvent: PumpEvent { + public let length: Int + public let basalType: String + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + if length > availableData.length { + timestamp = NSDateComponents() + basalType = "" + return nil + } + + basalType = d(1) == 1 ? "percent" : "absolute" + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "TempBasal", + "temp": basalType, + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeTimeFormatPumpEvent.swift b/MinimedKit/PumpEvents/ChangeTimeFormatPumpEvent.swift new file mode 100644 index 000000000..071a9b73e --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeTimeFormatPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeTimeFormatPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeTimeFormatPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeTimeFormat", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift new file mode 100644 index 000000000..8e708afd1 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 14 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeVariableBolusPumpEvent.swift b/MinimedKit/PumpEvents/ChangeVariableBolusPumpEvent.swift new file mode 100644 index 000000000..e2f4aad96 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeVariableBolusPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeVariableBolusPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeVariableBolusPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeVariableBolus", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeWatchdogEnablePumpEvent.swift b/MinimedKit/PumpEvents/ChangeWatchdogEnablePumpEvent.swift new file mode 100644 index 000000000..698f77586 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeWatchdogEnablePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeWatchdogEnablePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeWatchdogEnablePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeWatchdogEnable", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ChangeWatchdogMarriageProfilePumpEvent.swift b/MinimedKit/PumpEvents/ChangeWatchdogMarriageProfilePumpEvent.swift new file mode 100644 index 000000000..e49acfae6 --- /dev/null +++ b/MinimedKit/PumpEvents/ChangeWatchdogMarriageProfilePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ChangeWatchdogMarriageProfilePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ChangeWatchdogMarriageProfilePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 12 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ChangeWatchdogMarriageProfile", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/ClearAlarmPumpEvent.swift b/MinimedKit/PumpEvents/ClearAlarmPumpEvent.swift new file mode 100644 index 000000000..3cbb626f0 --- /dev/null +++ b/MinimedKit/PumpEvents/ClearAlarmPumpEvent.swift @@ -0,0 +1,32 @@ +// +// ClearAlarmPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ClearAlarmPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ClearAlarm", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/DeleteAlarmClockTimePumpEvent.swift b/MinimedKit/PumpEvents/DeleteAlarmClockTimePumpEvent.swift new file mode 100644 index 000000000..c7c59e8d9 --- /dev/null +++ b/MinimedKit/PumpEvents/DeleteAlarmClockTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// DeleteAlarmClockTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class DeleteAlarmClockTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 14 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "DeleteAlarmClockTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/DeleteBolusReminderTimePumpEvent.swift b/MinimedKit/PumpEvents/DeleteBolusReminderTimePumpEvent.swift new file mode 100644 index 000000000..0bb407bf5 --- /dev/null +++ b/MinimedKit/PumpEvents/DeleteBolusReminderTimePumpEvent.swift @@ -0,0 +1,32 @@ +// +// DeleteBolusReminderTimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class DeleteBolusReminderTimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 9 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "DeleteBolusReminderTime", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/DeleteOtherDeviceIDPumpEvent.swift b/MinimedKit/PumpEvents/DeleteOtherDeviceIDPumpEvent.swift new file mode 100644 index 000000000..3083a9ab0 --- /dev/null +++ b/MinimedKit/PumpEvents/DeleteOtherDeviceIDPumpEvent.swift @@ -0,0 +1,32 @@ +// +// DeleteOtherDeviceIDPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class DeleteOtherDeviceIDPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 12 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "DeleteOtherDeviceID", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/EnableDisableRemotePumpEvent.swift b/MinimedKit/PumpEvents/EnableDisableRemotePumpEvent.swift new file mode 100644 index 000000000..40f4c8b92 --- /dev/null +++ b/MinimedKit/PumpEvents/EnableDisableRemotePumpEvent.swift @@ -0,0 +1,32 @@ +// +// EnableDisableRemotePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class EnableDisableRemotePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 21 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "EnableDisableRemote", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/JournalEntryExerciseMarkerPumpEvent.swift b/MinimedKit/PumpEvents/JournalEntryExerciseMarkerPumpEvent.swift new file mode 100644 index 000000000..088c2f629 --- /dev/null +++ b/MinimedKit/PumpEvents/JournalEntryExerciseMarkerPumpEvent.swift @@ -0,0 +1,32 @@ +// +// JournalEntryExerciseMarkerPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class JournalEntryExerciseMarkerPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 8 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "JournalEntryExerciseMarker", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/JournalEntryPumpLowBatteryPumpEvent.swift b/MinimedKit/PumpEvents/JournalEntryPumpLowBatteryPumpEvent.swift new file mode 100644 index 000000000..dcd17a917 --- /dev/null +++ b/MinimedKit/PumpEvents/JournalEntryPumpLowBatteryPumpEvent.swift @@ -0,0 +1,32 @@ +// +// JournalEntryPumpLowBatteryPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class JournalEntryPumpLowBatteryPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "JournalEntryPumpLowBattery", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/JournalEntryPumpLowReservoirPumpEvent.swift b/MinimedKit/PumpEvents/JournalEntryPumpLowReservoirPumpEvent.swift new file mode 100644 index 000000000..97ea83b9c --- /dev/null +++ b/MinimedKit/PumpEvents/JournalEntryPumpLowReservoirPumpEvent.swift @@ -0,0 +1,32 @@ +// +// JournalEntryPumpLowReservoirPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class JournalEntryPumpLowReservoirPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "JournalEntryPumpLowReservoir", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/Model522ResultTotalsPumpEvent.swift b/MinimedKit/PumpEvents/Model522ResultTotalsPumpEvent.swift new file mode 100644 index 000000000..2d9b3f531 --- /dev/null +++ b/MinimedKit/PumpEvents/Model522ResultTotalsPumpEvent.swift @@ -0,0 +1,32 @@ +// +// Model522ResultTotalsPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class Model522ResultTotalsPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 44 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Model522ResultTotals", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/PrimePumpEvent.swift b/MinimedKit/PumpEvents/PrimePumpEvent.swift new file mode 100644 index 000000000..2720d6c74 --- /dev/null +++ b/MinimedKit/PumpEvents/PrimePumpEvent.swift @@ -0,0 +1,48 @@ +// +// PrimePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class PrimePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + let amount: Double + let primeType: String + let programmedAmount: Double + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 10 + + if length > availableData.length { + timestamp = NSDateComponents() + amount = 0 + primeType = "Unknown" + programmedAmount = 0 + return nil + } + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 5) + amount = Double(d(4) << 2) / 40.0 + programmedAmount = Double(d(2) << 2) / 40.0 + primeType = programmedAmount == 0 ? "manual" : "fixed" + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Prime", + "amount": amount, + "programmedAmount": programmedAmount, + "timestamp": TimeFormat.timestampStr(timestamp), + "primeType": primeType, + ] + } +} diff --git a/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift new file mode 100644 index 000000000..ce541be06 --- /dev/null +++ b/MinimedKit/PumpEvents/PumpAlarmPumpEvent.swift @@ -0,0 +1,36 @@ +// +// PumpAlarmPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class PumpAlarmPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + let rawType: Int + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 9 + + if length > availableData.length { + timestamp = NSDateComponents() + rawType = 0 + return nil + } + + rawType = Int(availableData[1] as UInt8) + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 4) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "AlarmPump", + "rawType": rawType, + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/PumpEvent.swift b/MinimedKit/PumpEvents/PumpEvent.swift new file mode 100644 index 000000000..ad4dc874c --- /dev/null +++ b/MinimedKit/PumpEvents/PumpEvent.swift @@ -0,0 +1,19 @@ +// +// PumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public protocol PumpEvent : DictionaryRepresentable { + + init?(availableData: NSData, pumpModel: PumpModel) + + var length: Int { + get + } + +} diff --git a/MinimedKit/PumpEvents/ResultDailyTotalPumpEvent.swift b/MinimedKit/PumpEvents/ResultDailyTotalPumpEvent.swift new file mode 100644 index 000000000..61d1af6e2 --- /dev/null +++ b/MinimedKit/PumpEvents/ResultDailyTotalPumpEvent.swift @@ -0,0 +1,42 @@ +// +// ResultDailyTotalPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ResultDailyTotalPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + let validDateStr: String + + public required init?(availableData: NSData, pumpModel: PumpModel) { + + if pumpModel.larger { + length = 10 + } else { + length = 7 + } + + if length > availableData.length { + timestamp = NSDateComponents() + validDateStr = "Invalid" + return nil + } + + let dateComponents = TimeFormat.parse2ByteDate(availableData, offset: 5) + validDateStr = String(format: "%04d-%02d-%02d", dateComponents.year, dateComponents.month, dateComponents.day) + timestamp = dateComponents + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "ResultDailyTotal", + "timestamp": TimeFormat.timestampStr(TimeFormat.nextMidnightForDateComponents(timestamp)), + "validDate": validDateStr, + ] + } +} diff --git a/MinimedKit/PumpEvents/ResumePumpEvent.swift b/MinimedKit/PumpEvents/ResumePumpEvent.swift new file mode 100644 index 000000000..02cf9a7bc --- /dev/null +++ b/MinimedKit/PumpEvents/ResumePumpEvent.swift @@ -0,0 +1,32 @@ +// +// ResumePumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class ResumePumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Resume", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/RewindPumpEvent.swift b/MinimedKit/PumpEvents/RewindPumpEvent.swift new file mode 100644 index 000000000..cb2619bac --- /dev/null +++ b/MinimedKit/PumpEvents/RewindPumpEvent.swift @@ -0,0 +1,32 @@ +// +// RewindPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class RewindPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Rewind", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/Sara6EPumpEvent.swift b/MinimedKit/PumpEvents/Sara6EPumpEvent.swift new file mode 100644 index 000000000..0ae6fe421 --- /dev/null +++ b/MinimedKit/PumpEvents/Sara6EPumpEvent.swift @@ -0,0 +1,40 @@ +// +// Sara6EPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class Sara6EPumpEvent: TimestampedPumpEvent { + + public var length: Int + public var timestamp: NSDateComponents + let validDateStr: String + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 52 + + // Sometimes we encounter this at the end of a page, and it can be less characters??? + // need at least 16, I think. + if 16 > availableData.length { + timestamp = NSDateComponents() + validDateStr = "Invalid" + return nil + } + + let dateComponents = TimeFormat.parse2ByteDate(availableData, offset: 1) + validDateStr = String(format: "%04d-%02d-%02d", dateComponents.year, dateComponents.month, dateComponents.day) + timestamp = dateComponents + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Sara6E", + "timestamp": TimeFormat.timestampStr(TimeFormat.nextMidnightForDateComponents(timestamp)), + "validDate": validDateStr, + ] + } +} diff --git a/MinimedKit/PumpEvents/SuspendPumpEvent.swift b/MinimedKit/PumpEvents/SuspendPumpEvent.swift new file mode 100644 index 000000000..89031fe09 --- /dev/null +++ b/MinimedKit/PumpEvents/SuspendPumpEvent.swift @@ -0,0 +1,32 @@ +// +// SuspendPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class SuspendPumpEvent: PumpEvent { + public let length: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + if length > availableData.length { + timestamp = NSDateComponents() + return nil + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "Suspend", + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/TempBasalDurationPumpEvent.swift b/MinimedKit/PumpEvents/TempBasalDurationPumpEvent.swift new file mode 100644 index 000000000..bd2deded4 --- /dev/null +++ b/MinimedKit/PumpEvents/TempBasalDurationPumpEvent.swift @@ -0,0 +1,40 @@ +// +// TempBasalDurationPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/20/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class TempBasalDurationPumpEvent: PumpEvent { + public let length: Int + public let duration: Int + let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 7 + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + if length > availableData.length { + timestamp = NSDateComponents() + duration = 0 + return nil + } + + duration = d(1) * 30 + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "TempBasal", + "duration": duration, + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} diff --git a/MinimedKit/PumpEvents/TempBasalPumpEvent.swift b/MinimedKit/PumpEvents/TempBasalPumpEvent.swift new file mode 100644 index 000000000..3b9715625 --- /dev/null +++ b/MinimedKit/PumpEvents/TempBasalPumpEvent.swift @@ -0,0 +1,57 @@ +// +// TempBasalPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class TempBasalPumpEvent: PumpEvent { + + public enum RateType : String { + case Absolute = "absolute" + case Percent = "percent" + } + + + public let length: Int + public let rateType: RateType + public let rate: Double + public let timestamp: NSDateComponents + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = 8 + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + if length > availableData.length { + timestamp = NSDateComponents() + rate = 0 + rateType = .Absolute + return nil + } + + rateType = (d(7) >> 3) == 0 ? .Absolute : .Percent + if rateType == .Absolute { + rate = Double(d(1)) / 40.0 + } else { + rate = Double(d(1)) + } + + timestamp = TimeFormat.parse5ByteDate(availableData, offset: 2) + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "TempBasal", + "rate": rate, + "temp": rateType.rawValue, + "timestamp": TimeFormat.timestampStr(timestamp), + ] + } +} + diff --git a/MinimedKit/PumpEvents/TimestampedPumpEvent.swift b/MinimedKit/PumpEvents/TimestampedPumpEvent.swift new file mode 100644 index 000000000..c993885b6 --- /dev/null +++ b/MinimedKit/PumpEvents/TimestampedPumpEvent.swift @@ -0,0 +1,17 @@ +// +// TimestampedPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public protocol TimestampedPumpEvent: PumpEvent { + + var timestamp: NSDateComponents { + get + } + +} diff --git a/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift b/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift new file mode 100644 index 000000000..8145949fa --- /dev/null +++ b/MinimedKit/PumpEvents/UnabsorbedInsulinPumpEvent.swift @@ -0,0 +1,64 @@ +// +// UnabsorbedInsulinPumpEvent.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class UnabsorbedInsulinPumpEvent: PumpEvent { + + public struct Record : DictionaryRepresentable { + var amount: Double + var age: Int + + init(amount: Double, age: Int) { + self.amount = amount + self.age = age + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "amount": amount, + "age": age, + ] + } + } + + public let length: Int + + public var records: [Record] + + public required init?(availableData: NSData, pumpModel: PumpModel) { + length = Int(max(availableData[1] as UInt8, UInt8(2))) + records = [Record]() + + if length > availableData.length { + return nil + } + + func d(idx:Int) -> Int { + return Int(availableData[idx] as UInt8) + } + + let numRecords = (d(1) - 2) / 3 + + for idx in 0...(numRecords-1) { + let record = Record( + amount: Double(d(2 + idx * 3)) / 40, + age: d(3 + idx * 3) + ((d(4 + idx * 3) & 0b110000) << 4)) + records.append(record) + } + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "_type": "UnabsorbedInsulin", + "data": records.map({ (r: Record) -> [String: AnyObject] in + return r.dictionaryRepresentation + }), + ] + } +} diff --git a/MinimedKit/PumpMessage.swift b/MinimedKit/PumpMessage.swift new file mode 100644 index 000000000..fb1649883 --- /dev/null +++ b/MinimedKit/PumpMessage.swift @@ -0,0 +1,53 @@ +// +// PumpMessage.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/2/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import Foundation + +public struct PumpMessage { + public let packetType: PacketType + public let address: NSData + public let messageType: MessageType + public let messageBody: MessageBody + + public init(packetType: PacketType, address: String, messageType: MessageType, messageBody: MessageBody) { + self.packetType = packetType + self.address = NSData(hexadecimalString: address)! + self.messageType = messageType + self.messageBody = messageBody + } + + public init?(rxData: NSData) { + guard rxData.length >= 7, + let packetType = PacketType(rawValue: rxData[0]) where packetType != .Meter, + let messageType = MessageType(rawValue: rxData[4]), + messageBody = messageType.bodyType.init(rxData: rxData.subdataWithRange(NSRange(5..= 23 + } + + var hasLowSuspend: Bool { + return generation >= 51 + } + + /// The number of turns of the stepper motor required to deliver 1 U of U-100 insulin. + /// This is a measure of motor precision. + public var strokesPerUnit: Int { + return (generation >= 23) ? 40 : 10 + } +} + + +extension PumpModel: CustomStringConvertible { + public var description: String { + return rawValue + } +} diff --git a/MinimedKit/RFTools.swift b/MinimedKit/RFTools.swift new file mode 100644 index 000000000..6ae54555f --- /dev/null +++ b/MinimedKit/RFTools.swift @@ -0,0 +1,65 @@ +// +// RFTools.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +private let codesRev:Dictionary = [21: 0, 49: 1, 50: 2, 35: 3, 52: 4, 37: 5, 38: 6, 22: 7, 26: 8, 25: 9, 42: 10, 11: 11, 44: 12, 13: 13, 14: 14, 28: 15] + +private let codes = [21,49,50,35,52,37,38,22,26,25,42,11,44,13,14,28] + +public func decode4b6b(rawData: NSData) -> NSData? { + var buffer = [UInt8]() + let bytes: [UInt8] = rawData[0..= 12 { + guard let + hiNibble = codesRev[x >> (availBits - 6)], + loNibble = codesRev[(x >> (availBits - 12)) & 0b111111] + else { + return nil + } + let decoded = UInt8((hiNibble << 4) + loNibble) + buffer.append(decoded) + availBits -= 12 + x = x & (0xffff >> (16-availBits)) + } + } + return NSData(bytes: &buffer, length: buffer.count) +} + +public func encode4b6b(rawData: NSData) -> NSData { + var buffer = [UInt8]() + let bytes: [UInt8] = rawData[0..> 4)] + bitcount += 6 + + acc <<= 6 + acc |= codes[Int(byte & 0x0f)] + bitcount += 6 + + while bitcount >= 8 { + buffer.append(UInt8(acc >> (bitcount-8)) & 0xff) + bitcount -= 8 + acc &= (0xffff >> (16-bitcount)) + } + } + if bitcount > 0 { + acc <<= (8-bitcount) + buffer.append(UInt8(acc) & 0xff) + } + return NSData(bytes: &buffer, length: buffer.count) +} + diff --git a/MinimedKit/TimeFormat.swift b/MinimedKit/TimeFormat.swift new file mode 100644 index 000000000..ebb8289b6 --- /dev/null +++ b/MinimedKit/TimeFormat.swift @@ -0,0 +1,84 @@ +// +// TimeFormat.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class TimeFormat: NSObject { + static var formatterISO8601: NSDateFormatter = { + let formatter = NSDateFormatter() + formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601) + formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") + formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssX" + return formatter + }() + + public static func parse2ByteDate(data: NSData, offset: Int) -> NSDateComponents { + let comps = NSDateComponents() + comps.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + comps.year = 2000 + Int(data[offset + 1] as UInt8 & UInt8(0b1111111)) + comps.month = (Int(data[offset + 0] as UInt8 & UInt8(0xe0)) >> 4) + + (Int(data[offset + 1] as UInt8 & UInt8(0x80)) >> 7) + comps.day = Int(data[offset + 0] as UInt8 & UInt8(0x1f)) + return comps; + } + + static func parse5ByteDate(data: NSData, offset: Int) -> NSDateComponents { + let comps = NSDateComponents() + comps.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + comps.second = Int(data[offset + 0] as UInt8 & UInt8(0x3f)) + comps.minute = Int(data[offset + 1] as UInt8 & UInt8(0x3f)) + comps.hour = Int(data[offset + 2] as UInt8 & UInt8(0x1f)) + comps.day = Int(data[offset + 3] as UInt8 & UInt8(0x1f)) + comps.month = Int((((data[offset] as UInt8) >> 4) & UInt8(0x0c)) + (data[offset + 1] as UInt8 >> 6)) + comps.year = 2000 + Int(data[offset + 4] as UInt8 & UInt8(0b1111111)) + return comps; + } + + public static func timestampAsLocalDate(comps: NSDateComponents) -> NSDate? { + let cal = comps.calendar ?? NSCalendar.currentCalendar() + cal.timeZone = comps.timeZone ?? NSTimeZone.localTimeZone() + return cal.dateFromComponents(comps) + } + + public static func timestampStr(comps: NSDateComponents) -> String { + if let date = timestampAsLocalDate(comps) { + return formatterISO8601.stringFromDate(date) + } else { + return "Invalid" + } + } + + public static func timestampStrFromDate(date: NSDate) -> String { + return formatterISO8601.stringFromDate(date) + } + + + static func nextMidnightForDateComponents(comps: NSDateComponents) -> NSDateComponents { + // Used to find the next midnight for the given date comps, for compatibility with decocare/nightscout. + // The thinking is to represent the time the entry was recorded (which is midnight at the end of the day) + + var rval: NSDateComponents + + if let date = comps.date, cal = comps.calendar { + if let nextDate = cal.dateByAddingUnit(.Day, value: 1, toDate: date, options: []) { + let unitFlags: NSCalendarUnit = [.Second, .Minute, .Hour, .Day, .Month, .Year] + rval = cal.components(unitFlags, fromDate: nextDate) + rval.calendar = cal + rval.timeZone = comps.timeZone + } + else { + rval = comps + } + } else { + rval = comps + } + return rval + } + +} diff --git a/MinimedKitTests/CRC16Tests.swift b/MinimedKitTests/CRC16Tests.swift new file mode 100644 index 000000000..919ddf3af --- /dev/null +++ b/MinimedKitTests/CRC16Tests.swift @@ -0,0 +1,29 @@ +// +// CRC16Tests.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class CRC16Tests: 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 testComputeCRC16() { + let input = NSData(hexadecimalString: "5be409a20a1510325000784b502800a400002400a8965c0b404fc038cbd008d5d0010080008000240009a24a15107b0500800c1510180a000ade19a32c15105bde2ba30c1510325000b44b5024006c0000200070965c0b4c78c03482c040c8c001007000700020002ba34c15100a0c22932d75903f2122938d7510c527ad5b0006900f15101a5000b44b500000380000000038965c0e70a1c04c19d03423d04069d00100380038000c0006904f15107b060080101510200e005b0034ab1015100d5000784b500000280000000028965c113858c070f8c04c70d0347ad040c0d00100280028001c0034ab5015100ab005863175903f360586117510c527ad5bb01486111510005100784b50940000000038005c965c14281fc0386fc0700fd04c87d03491d040d7d001005c005c00380014865115105b002291121510285000784b500000840000000084965c145c48c02866c038b6c07056d04cced034d8d0010084008400480022915215107b0700801315102610002100038414151003000000360785341510064a097e009e54b5100c4a03a11415107b0704a11415102610007b0704a11415102610007b0710a1141510261000030003000306a11415100ae937a23475103f1d37a2347510c527ad5be91ea3141510165000784b502c00480000140060965c0e848cc05cd2c028f0c03840d001006000600014001ea35415107b0800801515102a13000a5621ba3515905b5623ba151510005100b455505800000000340024965c116053c084dfc05c25d02843d03893d0010024002400340023ba5515105b00188c161510005000b455500000000000000000965c142411c06061c084edc05c33d02851d038a1d00100180018004c00188c56151000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")! + XCTAssertTrue(0x803a == computeCRC16(input)) + } +} diff --git a/MinimedKitTests/CRC8Tests.swift b/MinimedKitTests/CRC8Tests.swift new file mode 100644 index 000000000..8ed09924a --- /dev/null +++ b/MinimedKitTests/CRC8Tests.swift @@ -0,0 +1,29 @@ +// +// CRC8Tests.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class CRC8Tests: 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 testComputeCRC8() { + let input = NSData(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b0000")! + XCTAssertEqual(0x71, computeCRC8(input)) + } +} diff --git a/MinimedKitTests/HistoryPageTests.swift b/MinimedKitTests/HistoryPageTests.swift new file mode 100644 index 000000000..2e44bb5e7 --- /dev/null +++ b/MinimedKitTests/HistoryPageTests.swift @@ -0,0 +1,195 @@ +// +// HistoryPageTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class HistoryPageTests: 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 testHistoryPageCRC() { + let pumpModel = PumpModel.Model551 + do { + let _ = try HistoryPage(pageData: NSData(hexadecimalString: "6e2190050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0802101122007b0200c01602102c1c007b0000c000031000160007000002be22900000006e2290050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08031011220034640edc120310810123ef12031000101111117d0223ef12031000a2ce8aa0001011111100000000000000000000000000000000000000007b0200c01603102c1c0021001cce16031003000000100fd03603107b021edb1603102c1c0003000100011cdb160310820106dc16031000a2ce8aa0820108dc16031000101111117b0000c000041000160007000002b823900000006e2390050000000000000002b802b8640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0804101122007b0200c01604102c1c007b0000c000051000160007000002be24900000006e2490050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0805101122007b0200c01605102c1c007b0000c000061000160007000002be25900000006e2590050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0806101122007b0200c01606102c1c007b0000c000071000160007000002be26900000006e2690050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08071011220081010bec0a071000a2ce8aa07d010bec0a071000a2ce8aa000000000000000000000000000000000000000000000000000820108c40b071000a2ce8aa081010cc40b071000a2ce8aa07d010cc40b071000a2ce8aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004475")!, pumpModel: pumpModel) + } catch HistoryPage.Error.InvalidCRC { + XCTFail("page decoding threw invalid crc") + } catch HistoryPage.Error.UnknownEventType(let eventType) { + XCTFail("unknown event type" + String(eventType)) + } catch { + NSLog("Unexpected exception...") + } + } + + func testHistoryPageInvalidCRC() { + let pumpModel = PumpModel.Model551 + do { + let _ = try HistoryPage(pageData: NSData(hexadecimalString: "6e2190050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0802101122007b0200c01602102c1c007b0000c000031000160007000002be22900000006e2290050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08031011220034640edc120310810123ef12031000101111117d0223ef12031000a2ce8aa0001011111100000000000000000000000000000000000000007b0200c01603102c1c0021001cce16031003000000100fd03603107b021edb1603102c1c0003000100011cdb160310820106dc16031000a2ce8aa0820108dc16031000101111117b0000c000041000160007000002b823900000006e2390050000000000000002b802b8640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0804101122007b0200c01604102c1c007b0000c000051000160007000002be24900000006e2490050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0805101122007b0200c01605102c1c007b0000c000061000160007000002be25900000006e2590050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0806101122007b0200c01606102c1c007b0000c000071000160007000002be26900000006e2690050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de08071011220081010bec0a071000a2ce8aa07d010bec0a071000a2ce8aa000000000000000000000000000000000000000000000000000820108c40b071000a2ce8aa081010cc40b071000a2ce8aa07d010cc40b071000a2ce8aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004455")!, pumpModel: pumpModel) + XCTFail("Should have thrown InvalidCRC") + } catch HistoryPage.Error.InvalidCRC { + // Happy path + } catch HistoryPage.Error.UnknownEventType(let eventType) { + XCTFail("unknown event type" + String(eventType)) + } catch { + NSLog("Unexpected exception...") + } + } + + + func testTempBasalDecoding() { + let pumpModel = PumpModel.Model551 + do { + let page = try HistoryPage(pageData: NSData(hexadecimalString: "160179230c121033104a2a0c12100016014a2a0c1210330854000d121000160154000d12107b05541e0d1210180a007b064000101210200e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004876")!, pumpModel: pumpModel) + + let events = page.events + XCTAssertEqual(events.count, 7) + + let duration = events[0] as! TempBasalDurationPumpEvent + XCTAssertEqual(duration.duration, 30) + XCTAssertEqual(duration.timestamp, NSDateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 35, second: 57)) + + let tempBasal = events[1] as! TempBasalPumpEvent + XCTAssertEqual(tempBasal.rateType, TempBasalPumpEvent.RateType.Absolute) + XCTAssertEqual(tempBasal.rate, 0.4) + XCTAssertEqual(tempBasal.timestamp, NSDateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 42, second: 10)) + + let duration2 = events[2] as! TempBasalDurationPumpEvent + XCTAssertEqual(duration2.duration, 30) + XCTAssertEqual(duration2.timestamp, NSDateComponents(gregorianYear: 2016, month: 4, day: 18, hour: 12, minute: 42, second: 10)) + + } catch HistoryPage.Error.InvalidCRC { + XCTFail("page decoding threw invalid crc") + } catch HistoryPage.Error.UnknownEventType(_) { + XCTFail("unknown event type") + } catch { + NSLog("Unexpected exception...") + } + } + + func testHistoryDecoding() { + let pumpModel = PumpModel.Model551 + do { + let page = try HistoryPage(pageData: NSData(hexadecimalString: "5be409a20a1510325000784b502800a400002400a8965c0b404fc038cbd008d5d0010080008000240009a24a15107b0500800c1510180a000ade19a32c15105bde2ba30c1510325000b44b5024006c0000200070965c0b4c78c03482c040c8c001007000700020002ba34c15100a0c22932d75903f2122938d7510c527ad5b0006900f15101a5000b44b500000380000000038965c0e70a1c04c19d03423d04069d00100380038000c0006904f15107b060080101510200e005b0034ab1015100d5000784b500000280000000028965c113858c070f8c04c70d0347ad040c0d00100280028001c0034ab5015100ab005863175903f360586117510c527ad5bb01486111510005100784b50940000000038005c965c14281fc0386fc0700fd04c87d03491d040d7d001005c005c00380014865115105b002291121510285000784b500000840000000084965c145c48c02866c038b6c07056d04cced034d8d0010084008400480022915215107b0700801315102610002100038414151003000000360785341510064a097e009e54b5100c4a03a11415107b0704a11415102610007b0704a11415102610007b0710a1141510261000030003000306a11415100ae937a23475103f1d37a2347510c527ad5be91ea3141510165000784b502c00480000140060965c0e848cc05cd2c028f0c03840d001006000600014001ea35415107b0800801515102a13000a5621ba3515905b5623ba151510005100b455505800000000340024965c116053c084dfc05c25d02843d03893d0010024002400340023ba5515105b00188c161510005000b455500000000000000000965c142411c06061c084edc05c33d02851d038a1d00100180018004c00188c5615100a7339ac3615905b7305ad161510005100b455506800000000480020965c171828c02432c06082c0840ed05c54d02872d038c2d0010034003400440005ad5615100a55158c3775903f2a158cb77510c527ad5b55278c171510005100b455505800000000600000965c1a341bc01843c0244dc0609dc08429d05c6fd0288dd038ddd00100180018006000278c5715100a1930b73715905b1901b8171510005100b455503c00000000440000965c1a1833c03447c0186fc02479c060c9c08455d05c9bd028b9d0010018001800440001b85715107b000080001610000e0007000004f035100000006e351005112ce9b00a000004f001401903b04b00dd01a4013c00d0000005070200040000000000000000de730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fc5e")!, pumpModel: pumpModel) + + let events = page.events + XCTAssertGreaterThan(events.count, 20) + + let bolusWizard = events[0] as! BolusWizardEstimatePumpEvent + XCTAssertEqual(bolusWizard.bgTargetHigh, 150) + XCTAssertEqual(bolusWizard.bgTargetLow, 80) + XCTAssertEqual(bolusWizard.bloodGlucose, 228) + XCTAssertEqual(bolusWizard.bolusEstimate, 4.2) + XCTAssertEqual(bolusWizard.carbohydrates, 50) + XCTAssertEqual(bolusWizard.carbRatio, 12.0) + XCTAssertEqual(bolusWizard.correctionEstimate, 1.0) + XCTAssertEqual(bolusWizard.foodEstimate, 4.1) + XCTAssertEqual(bolusWizard.insulinSensitivity, 75) + XCTAssertEqual(bolusWizard.unabsorbedInsulinTotal, 0.9) + XCTAssertEqual(bolusWizard.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 10, minute: 34, second: 9)) + + let bolus = events[1] as! BolusNormalPumpEvent + XCTAssertEqual(bolus.amount, 3.2) + XCTAssertEqual(bolus.bolusType, "normal") + XCTAssertEqual(bolus.duration, 0) + XCTAssertEqual(bolus.programmed, 3.2) + XCTAssertEqual(bolus.unabsorbedInsulinTotal, 0.9) + XCTAssertEqual(bolus.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 10, minute: 34, second: 9)) + + let unabsorbedInsulinRecords = bolus.unabsorbedInsulinRecord!.records + XCTAssertEqual(unabsorbedInsulinRecords.count, 3) + XCTAssertEqual(unabsorbedInsulinRecords[0].amount, 1.6) + XCTAssertEqual(unabsorbedInsulinRecords[0].age, 79) + XCTAssertEqual(unabsorbedInsulinRecords[1].amount, 1.4) + XCTAssertEqual(unabsorbedInsulinRecords[1].age, 459) + XCTAssertEqual(unabsorbedInsulinRecords[2].amount, 0.2) + XCTAssertEqual(unabsorbedInsulinRecords[2].age, 469) + + let basalProfileStart = events[2] as! BasalProfileStartPumpEvent + XCTAssertEqual(basalProfileStart.offset, 43200000) + XCTAssertEqual(basalProfileStart.rate, 0.25) + XCTAssertEqual(basalProfileStart.profileIndex, 5) + XCTAssertEqual(basalProfileStart.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 12, minute: 0, second: 0)) + + let calBGForPH = events[3] as! CalBGForPHPumpEvent + XCTAssertEqual(calBGForPH.amount, 222) + XCTAssertEqual(calBGForPH.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 12, minute: 35, second: 25)) + + let bgReceived = events[7] as! BGReceivedPumpEvent + XCTAssertEqual(bgReceived.amount, 268) + XCTAssertEqual(bgReceived.meter, "c527ad") + XCTAssertEqual(bgReceived.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 13, minute: 19, second: 34)) + + let rewind = events[20] as! RewindPumpEvent + XCTAssertEqual(rewind.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 20, minute: 4, second: 3)) + + let prime = events[21] as! PrimePumpEvent + XCTAssertEqual(prime.amount, 5.4) + XCTAssertEqual(prime.primeType, "manual") + XCTAssertEqual(prime.programmedAmount, 0.0) + XCTAssertEqual(prime.timestamp, NSDateComponents(gregorianYear: 2016, month: 2, day: 21, hour: 20, minute: 5, second: 7)) + + let sara6e = events[50] as! Sara6EPumpEvent + // 2016-02-22T00:00:00 + let sara6eDate = NSDateComponents() + sara6eDate.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + sara6eDate.year = 2016 + sara6eDate.month = 2 + sara6eDate.day = 21 + + XCTAssertEqual(sara6e.timestamp, sara6eDate) + + sara6e.timestamp.timeZone = NSTimeZone(forSecondsFromGMT: -5 * 60 * 60) + + XCTAssertEqual(sara6e.dictionaryRepresentation["timestamp"] as? String, "2016-02-22T05:00:00Z") + + } catch HistoryPage.Error.InvalidCRC { + XCTFail("page decoding threw invalid crc") + } catch HistoryPage.Error.UnknownEventType(_) { + XCTFail("unknown event type") + } catch { + NSLog("Unexpected exception...") + } + } + + func testHistoryDecoding523() { + let pumpModel = PumpModel.Model523 + do { + let page = try HistoryPage(pageData: NSData(hexadecimalString: "010052005200000042225465105b00443b1465100e5000784b5000002e000000002e785c0e1a18c03822c01658d002dad001002e002e004c00443b5465100a3361023605905b337202166510005100b455505800000000420016785c0e2e43c01a57c03861c01697d0010016001600420072025665107b00400000061000100007000002cb45100000006e45100500e7000002000002cb01512f017a35007b00d60016008e0000040101000400000000000000009b3300000000000000007b014000010610020c000aca48092106105bca4b09010610005000c850502800000000000028785c0e16c2c02efec01a12d0381cd001002800280000004c094106107b024000040610080d007b0340000606100c10005b006a130966101450006e4b5000004800000000487801004800480000006a134966107b0440000a0610140b000afa41362b06105bfa67360b6610475000b44b5044009c00000800d8785c05489fc001006800680008045d38ab6610010070007000080067368b66107b0540000c0610180a007b064000100610200e005b0043191266103c5000784b500000c800000000c8785c2c020ed00818d00822d00a2cd00836d00840d00a4ad00854d0085ed00a68d00872d0087cd06286d01690d0010064001c0000066b1ab26610010064006400000043199266107b0740001306102610001e0165121306107b076e121306102610001f206e12130610210074121306101a0062141306101a01771413061003000000436a153306107b07661b13061026100003000300035c1b1306107b08401e1406102915000a825b103506905b826010150610005100b455507c000000000c0070785c200279c00483c0068dc00697c006a1c068abc002b9d008c3d008cdd00ad7d05b826210150610005100b455507c000000000c0070785c200279c00483c0068dc00697c006a1c068abc002b9d008c3d008cdd00ad7d00100700070000c0062105506100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c4d")!, pumpModel: pumpModel) + + let events = page.events + XCTAssertGreaterThan(events.count, 20) + + let bolus = events[0] as! BolusNormalPumpEvent + XCTAssertEqual(bolus.amount, 2.05) + XCTAssertEqual(bolus.bolusType, "normal") + XCTAssertEqual(bolus.duration, 0) + XCTAssertEqual(bolus.programmed, 2.05) + XCTAssertEqual(bolus.unabsorbedInsulinTotal, 0.0) + + let timestamp = NSDateComponents(gregorianYear: 2016, month: 4, day: 5, hour: 20, minute: 34, second: 02) + + XCTAssertEqual(bolus.timestamp, timestamp) + + } catch HistoryPage.Error.InvalidCRC { + XCTFail("page decoding threw invalid crc") + } catch HistoryPage.Error.UnknownEventType(_) { + XCTFail("unknown event type") + } catch { + NSLog("Unexpected exception...") + } + + } +} diff --git a/MinimedKitTests/Info.plist b/MinimedKitTests/Info.plist new file mode 100644 index 000000000..9c88642be --- /dev/null +++ b/MinimedKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift b/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..a4c3c2d0a --- /dev/null +++ b/MinimedKitTests/Messages/BolusCarelinkMessageBodyTests.swift @@ -0,0 +1,60 @@ +// +// BolusCarelinkMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/5/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation +import XCTest +@testable import MinimedKit + + +class BolusCarelinkMessageBodyTests: XCTestCase { + + func testBolusMessageBody() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: 1.1, strokesPerUnit: 40)) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564202002C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testBolusMessageBody522() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: 1.1, strokesPerUnit: 10)) + + XCTAssertEqual( + NSData(hexadecimalString: "a712345642010B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testBolusMessageBodyRounding() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: 1.475, strokesPerUnit: 40)) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564202003A0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testBolusMessageBodyTwoByte() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: 7.9, strokesPerUnit: 40)) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564202013C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testBolusMessageBodyGreaterThanTenUnits() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: 10.25, strokesPerUnit: 40)) + + XCTAssertEqual( + NSData(hexadecimalString: "a7123456420201980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } +} \ No newline at end of file diff --git a/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift b/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..19d1a60f5 --- /dev/null +++ b/MinimedKitTests/Messages/ChangeTempBasalCarelinkMessageBodyTests.swift @@ -0,0 +1,42 @@ +// +// ChangeTempBasalCarelinkMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/6/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class ChangeTempBasalCarelinkMessageBodyTests: XCTestCase { + + func testTempBasalMessageBody() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .ChangeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 1.1, duration: NSTimeInterval(30 * 60))) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564C03002C0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testTempBasalMessageBodyLarge() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .ChangeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 6.5, duration: NSTimeInterval(150 * 60))) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564C0301040500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + + func testTempBasalMessageBodyRounding() { + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .ChangeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: 1.442, duration: NSTimeInterval(65.5 * 60))) + + XCTAssertEqual( + NSData(hexadecimalString: "a71234564C0300390200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + message.txData + ) + } + +} diff --git a/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift b/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift new file mode 100644 index 000000000..b1f67347e --- /dev/null +++ b/MinimedKitTests/Messages/ChangeTimeCarelinMessageBodyTests.swift @@ -0,0 +1,31 @@ +// +// ChangeTimeCarelinMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/17/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class ChangeTimeCarelinMessageBodyTests: XCTestCase { + + func testChangeTime() { + let components = NSDateComponents() + components.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + + components.year = 2017 + components.month = 12 + components.day = 29 + components.hour = 9 + components.minute = 22 + components.second = 59 + + let message = PumpMessage(packetType: .Carelink, address: "123456", messageType: .ChangeTime, messageBody: ChangeTimeCarelinkMessageBody(dateComponents: components)!) + + XCTAssertEqual(NSData(hexadecimalString: "a7123456400709163B07E10C1D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), message.txData) + } + +} diff --git a/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift b/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift new file mode 100644 index 000000000..193755910 --- /dev/null +++ b/MinimedKitTests/Messages/DeviceLinkMessageBodyTests.swift @@ -0,0 +1,42 @@ +// +// DeviceLinkMessageBodyTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class DeviceLinkMessageBodyTests: 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 testValidDeviceLinkMessage() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a23505350a93ce8aa000ba")!) + + if let message = message { + XCTAssertTrue(message.messageBody is DeviceLinkMessageBody) + } else { + XCTFail("\(message) is nil") + } + } + + func testMidnightSensor() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a23505350a93ce8aa000ba")!)! + + let body = message.messageBody as! DeviceLinkMessageBody + + XCTAssertEqual(body.sequence, 19) + XCTAssertEqual(body.deviceAddress.hexadecimalString, "ce8aa0") + } +} diff --git a/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift b/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift new file mode 100644 index 000000000..ddce6bb47 --- /dev/null +++ b/MinimedKitTests/Messages/FindDeviceMessageBodyTests.swift @@ -0,0 +1,42 @@ +// +// FindDeviceMessageBodyTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/7/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class FindDeviceMessageBodyTests: 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 testValidFindDeviceMessage() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a235053509cf9999990062")!) + + if let message = message { + XCTAssertTrue(message.messageBody is FindDeviceMessageBody) + } else { + XCTFail("\(message) is nil") + } + } + + func testMidnightSensor() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a235053509cf9999990062")!)! + + let body = message.messageBody as! FindDeviceMessageBody + + XCTAssertEqual(body.sequence, 79) + XCTAssertEqual(body.deviceAddress.hexadecimalString, "999999") + } +} diff --git a/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift b/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..70bc7d8a1 --- /dev/null +++ b/MinimedKitTests/Messages/GetBatteryCarelinkMessageBodyTests.swift @@ -0,0 +1,37 @@ +// +// GetBatteryCarelinkMessageBodyTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/16/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class GetBatteryCarelinkMessageBodyTests: 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 testValidGetBatteryResponse() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a7350535720300008c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a")!) + + if let message = message { + XCTAssertTrue(message.messageBody is GetBatteryCarelinkMessageBody) + let body = message.messageBody as! GetBatteryCarelinkMessageBody + XCTAssertEqual(body.volts, 1.4) + XCTAssertEqual(body.status, "Normal") + } else { + XCTFail("\(message) is nil") + } + } + +} diff --git a/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift b/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..9436c5bb7 --- /dev/null +++ b/MinimedKitTests/Messages/GetPumpModelCarelinkMessageBodyTests.swift @@ -0,0 +1,36 @@ +// +// GetPumpModelCarelinkMessageBodyTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/14/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class GetPumpModelCarelinkMessageBodyTests: 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 testValidGetModelResponse() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a73505358d09033532330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f")!) + + if let message = message { + XCTAssertTrue(message.messageBody is GetPumpModelCarelinkMessageBody) + let body = message.messageBody as! GetPumpModelCarelinkMessageBody + XCTAssertEqual(body.model, "523") + } else { + XCTFail("\(message) is nil") + } + } + +} diff --git a/MinimedKitTests/Messages/MeterMessageTests.swift b/MinimedKitTests/Messages/MeterMessageTests.swift new file mode 100644 index 000000000..6cb206422 --- /dev/null +++ b/MinimedKitTests/Messages/MeterMessageTests.swift @@ -0,0 +1,35 @@ +// +// MeterMessageTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class MeterMessageTests: 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 testValidMeterMessage() { + let message = MeterMessage(rxData: NSData(hexadecimalString: "a5c527ad018e77")!) + + if let message = message { + XCTAssertEqual(message.glucose, 257) + XCTAssertEqual(message.ackFlag, false) + } else { + XCTFail("\(message) is nil") + } + } + +} diff --git a/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift b/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..ba8f5c269 --- /dev/null +++ b/MinimedKitTests/Messages/ReadTempBasalCarelinkMessageBodyTests.swift @@ -0,0 +1,36 @@ +// +// ReadTempBasalCarelinkMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 3/7/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class ReadTempBasalCarelinkMessageBodyTests: XCTestCase { + + func testReadTempBasal() { + // 06 00 00 00 37 00 17 -> 1.375 U @ 23 min remaining + let message = PumpMessage(rxData: NSData(hexadecimalString: "a7123456980600000037001700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff")!)! + + let body = message.messageBody as! ReadTempBasalCarelinkMessageBody + + XCTAssertEqual(NSTimeInterval(23 * 60), body.timeRemaining) + XCTAssertEqual(1.375, body.rate) + XCTAssertEqual(ReadTempBasalCarelinkMessageBody.RateType.Absolute, body.rateType) + } + + func testReadTempBasalZero() { + // 06 00 00 00 00 00 1d -> 0 U @ 29 min remaining + let message = PumpMessage(rxData: NSData(hexadecimalString: "a7123456980600000000001d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff")!)! + + let body = message.messageBody as! ReadTempBasalCarelinkMessageBody + + XCTAssertEqual(NSTimeInterval(29 * 60), body.timeRemaining) + XCTAssertEqual(0, body.rate) + XCTAssertEqual(ReadTempBasalCarelinkMessageBody.RateType.Absolute, body.rateType) + } +} diff --git a/MinimedKitTests/MinimedKitTests.swift b/MinimedKitTests/MinimedKitTests.swift new file mode 100644 index 000000000..2719dedb5 --- /dev/null +++ b/MinimedKitTests/MinimedKitTests.swift @@ -0,0 +1,23 @@ +// +// MinimedKitTests.swift +// MinimedKitTests +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import XCTest + +class MinimedKitTests: 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() + } + +} diff --git a/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift b/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift new file mode 100644 index 000000000..87bb8d597 --- /dev/null +++ b/MinimedKitTests/MySentryPumpStatusMessageBodyTests.swift @@ -0,0 +1,219 @@ +// +// MySentryPumpStatusMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/6/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class MySentryPumpStatusMessageBodyTests: 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 testValidPumpStatusMessage() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a2594040042f511727070f09050184850000cd010105b03e0a0a1a009d030000711726000f09050000d0")!) + + if let message = message { + XCTAssertTrue(message.messageBody is MySentryPumpStatusMessageBody) + } else { + XCTFail("\(message) is nil") + } + } + + func testGlucoseTrendFlat() { + XCTAssertEqual(GlucoseTrend.Flat, GlucoseTrend(byte: 0b00000000)) + XCTAssertEqual(GlucoseTrend.Flat, GlucoseTrend(byte: 0b11110001)) + XCTAssertEqual(GlucoseTrend.Flat, GlucoseTrend(byte: 0b11110001)) + XCTAssertEqual(GlucoseTrend.Flat, GlucoseTrend(byte: 0b000)) + XCTAssertEqual(GlucoseTrend.Flat, GlucoseTrend(byte: 0x51)) + } + + func testMidnightSensor() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a2594040049c510003310f090501393700025b0101068d262208150034000000700003000f0905000067")!)! + + let body = message.messageBody as! MySentryPumpStatusMessageBody + + switch body.glucose { + case .Active(glucose: let glucose): + XCTAssertEqual(114, glucose) + default: + XCTFail("\(body.glucose) is not .Active") + } + + switch body.previousGlucose { + case .Active(glucose: let glucose): + XCTAssertEqual(110, glucose) + default: + XCTFail("\(body.previousGlucose) is not .Active") + } + + let dateComponents = NSDateComponents() + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.year = 2015 + dateComponents.month = 9 + dateComponents.day = 5 + dateComponents.hour = 0 + dateComponents.minute = 3 + dateComponents.second = 49 + + XCTAssertEqual(dateComponents, body.pumpDateComponents) + + dateComponents.second = 0 + + XCTAssertEqual(dateComponents, body.glucoseDateComponents) + + XCTAssertEqual(GlucoseTrend.Flat, body.glucoseTrend) + } + + func testActiveSensor() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a2594040042f511727070f09050184850000cd010105b03e0a0a1a009d030000711726000f09050000d0")!)! + + let body = message.messageBody as! MySentryPumpStatusMessageBody + + switch body.glucose { + case .Active(glucose: let glucose): + XCTAssertEqual(265, glucose) + default: + XCTFail("\(body.glucose) is not .Active") + } + + switch body.previousGlucose { + case .Active(glucose: let glucose): + XCTAssertEqual(267, glucose) + default: + XCTFail("\(body.previousGlucose) is not .Active") + } + + let dateComponents = NSDateComponents() + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.year = 2015 + dateComponents.month = 9 + dateComponents.day = 5 + dateComponents.hour = 23 + dateComponents.minute = 39 + dateComponents.second = 7 + + XCTAssertEqual(dateComponents, body.pumpDateComponents) + + dateComponents.minute = 38 + dateComponents.second = 0 + + XCTAssertEqual(dateComponents, body.glucoseDateComponents) + + XCTAssertEqual(GlucoseTrend.Flat, body.glucoseTrend) + } + + func testSensorEndEmptyReservoir() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a259404004fb511205000f090601050502000004000000ff00ffff0040000000711205000f090600002b")!)! + + let body = message.messageBody as! MySentryPumpStatusMessageBody + + switch body.glucose { + case .Ended: + break + default: + XCTFail("\(body.glucose) is not .Ended") + } + + switch body.previousGlucose { + case .Ended: + break + default: + XCTFail("\(body.previousGlucose) is not .Ended") + } + + let dateComponents = NSDateComponents() + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.year = 2015 + dateComponents.month = 9 + dateComponents.day = 6 + dateComponents.hour = 18 + dateComponents.minute = 5 + dateComponents.second = 0 + + XCTAssertEqual(dateComponents, body.pumpDateComponents) + XCTAssertEqual(dateComponents, body.glucoseDateComponents) + + XCTAssertEqual(GlucoseTrend.Flat, body.glucoseTrend) + } + + func testSensorOffEmptyReservoir() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a259404004ff501219000f09060100000000000400000000000000005e0000007200000000000000008b")!)! + + let body = message.messageBody as! MySentryPumpStatusMessageBody + + switch body.glucose { + case .Off: + break + default: + XCTFail("\(body.glucose) is not .Off") + } + + switch body.previousGlucose { + case .Off: + break + default: + XCTFail("\(body.previousGlucose) is not .Off") + } + + let dateComponents = NSDateComponents() + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.year = 2015 + dateComponents.month = 9 + dateComponents.day = 6 + dateComponents.hour = 18 + dateComponents.minute = 25 + dateComponents.second = 0 + + XCTAssertEqual(dateComponents, body.pumpDateComponents) + XCTAssertNil(body.glucoseDateComponents) + + XCTAssertEqual(GlucoseTrend.Flat, body.glucoseTrend) + } + + func testSensorOffEmptyReservoirSuspended() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a25940400401501223000f0906010000000000040000000000000000590000007200000000000000009f")!)! + + let body = message.messageBody as! MySentryPumpStatusMessageBody + + switch body.glucose { + case .Off: + break + default: + XCTFail("\(body.glucose) is not .Off") + } + + switch body.previousGlucose { + case .Off: + break + default: + XCTFail("\(body.previousGlucose) is not .Off") + } + + let dateComponents = NSDateComponents() + dateComponents.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + dateComponents.year = 2015 + dateComponents.month = 9 + dateComponents.day = 6 + dateComponents.hour = 18 + dateComponents.minute = 35 + dateComponents.second = 0 + + XCTAssertEqual(dateComponents, body.pumpDateComponents) + XCTAssertNil(body.glucoseDateComponents) + + XCTAssertEqual(GlucoseTrend.Flat, body.glucoseTrend) + } + +} \ No newline at end of file diff --git a/MinimedKitTests/NSDataTests.swift b/MinimedKitTests/NSDataTests.swift new file mode 100644 index 000000000..a2ada5554 --- /dev/null +++ b/MinimedKitTests/NSDataTests.swift @@ -0,0 +1,52 @@ +// +// NSDataTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 9/5/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class NSDataTests: 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 testInitWithHexadecimalStringEmpty() { + let data = NSData(hexadecimalString: "") + XCTAssertEqual(0, data!.length) + } + + func testInitWithHexadecimalStringOdd() { + let data = NSData(hexadecimalString: "a") + XCTAssertNil(data) + } + + func testInitWithHexadecimalStringZeros() { + let data = NSData(hexadecimalString: "00") + XCTAssertEqual(1, data!.length) + + var bytes = [UInt8](count: 1, repeatedValue: 1) + data?.getBytes(&bytes, length: 1) + XCTAssertEqual(0, bytes[0]) + } + + func testInitWithHexadecimalStringShortData() { + let data = NSData(hexadecimalString: "a2594040") + + XCTAssertEqual(4, data!.length) + + var bytes = [UInt8](count: 4, repeatedValue: 0) + data?.getBytes(&bytes, length: 4) + XCTAssertEqual([0xa2, 0x59, 0x40, 0x40], bytes) + } +} diff --git a/MinimedKitTests/NSDateComponents.swift b/MinimedKitTests/NSDateComponents.swift new file mode 100644 index 000000000..8454f6e07 --- /dev/null +++ b/MinimedKitTests/NSDateComponents.swift @@ -0,0 +1,27 @@ +// +// NSDateComponents.swift +// RileyLink +// +// Created by Nathan Racklyeft on 4/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + + +extension NSDateComponents { + + convenience init(gregorianYear year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) { + self.init() + + self.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) + + self.year = year + self.month = month + self.day = day + self.hour = hour + self.minute = minute + self.second = second + } + +} \ No newline at end of file diff --git a/MinimedKitTests/PumpMessageTests.swift b/MinimedKitTests/PumpMessageTests.swift new file mode 100644 index 000000000..4ba4f2035 --- /dev/null +++ b/MinimedKitTests/PumpMessageTests.swift @@ -0,0 +1,25 @@ +// +// PumpMessageTests.swift +// RileyLink +// +// Created by Pete Schwamb on 2/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + + +class PumpMessageTests: 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() + } + +} diff --git a/MinimedKitTests/RFToolsTests.swift b/MinimedKitTests/RFToolsTests.swift new file mode 100644 index 000000000..20d33895d --- /dev/null +++ b/MinimedKitTests/RFToolsTests.swift @@ -0,0 +1,56 @@ +// +// RFToolsTests.swift +// RileyLink +// +// Created by Pete Schwamb on 2/27/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class RFToolsTests: 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 testDecode4b6b() { + let input = NSData(hexadecimalString: "ab2959595965574ab2d31c565748ea54e55a54b5558cd8cd55557194b56357156535ac5659956a55c55555556355555568bc5657255554e55a54b5555555b100")! + + let result = decode4b6b(input) + + if let result = result { + let expectedOutput = NSData(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b000071") + XCTAssertTrue(result == expectedOutput) + } else { + XCTFail("\(result) is nil") + } + } + + func testDecode4b6bWithBadData() { + let input = NSData(hexadecimalString: "0102030405")! + + let result = decode4b6b(input) + XCTAssertTrue(result == nil) + } + + + func testEncode4b6b() { + let input = NSData(hexadecimalString: "a259705504a24117043a0e080b003d3d00015b030105d817790a0f00000300008b1702000e080b000071")! + + let result = encode4b6b(input) + + NSLog("output = %@", result) + let expectedOutput = NSData(hexadecimalString: "ab2959595965574ab2d31c565748ea54e55a54b5558cd8cd55557194b56357156535ac5659956a55c55555556355555568bc5657255554e55a54b5555555b1") + XCTAssertTrue(result == expectedOutput) + } + + +} \ No newline at end of file diff --git a/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift b/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift new file mode 100644 index 000000000..37cd4a6c7 --- /dev/null +++ b/MinimedKitTests/ReadSettingsCarelinkMessageBodyTests.swift @@ -0,0 +1,42 @@ +// +// ReadSettingsCarelinkMessageBodyTests.swift +// Naterade +// +// Created by Nathan Racklyeft on 12/26/15. +// Copyright © 2015 Nathan Racklyeft. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class ReadSettingsCarelinkMessageBodyTests: 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 testValidSettings() { + let message = PumpMessage(rxData: NSData(hexadecimalString: "a7594040c01900010001010096008c00000000000064010400140019010101000000000000000000000000000000000000000000000000000000000000000000000000000000e9")!) + + if let message = message { + XCTAssertTrue(message.messageBody is ReadSettingsCarelinkMessageBody) + + if let body = message.messageBody as? ReadSettingsCarelinkMessageBody { + XCTAssertEqual(3.5, body.maxBasal) + XCTAssertEqual(15, body.maxBolus) + XCTAssertEqual(BasalProfile.Standard, body.selectedBasalProfile) + XCTAssertEqual(4, body.insulinActionCurveHours) + } + + } else { + XCTFail("Message is nil") + } + } + +} diff --git a/MinimedKitTests/TimeFormatTests.swift b/MinimedKitTests/TimeFormatTests.swift new file mode 100644 index 000000000..de7af54d6 --- /dev/null +++ b/MinimedKitTests/TimeFormatTests.swift @@ -0,0 +1,43 @@ +// +// TimeFormatTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit + +class TimeFormatTests: 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 testParse2ByteDate() { + let input = NSData(hexadecimalString: "6e351005112ce9b00a000004f001401903b04b00dd01a4013c")! + let comps = TimeFormat.parse2ByteDate(input, offset: 1) + XCTAssertEqual(2016, comps.year) + XCTAssertEqual(21, comps.day) + XCTAssertEqual(2, comps.month) + } + + func testParse5ByteDate() { + let input = NSData(hexadecimalString: "010018001800440001b8571510")! + let comps = TimeFormat.parse5ByteDate(input, offset: 8) + XCTAssertEqual(2016, comps.year) + XCTAssertEqual(21, comps.day) + XCTAssertEqual(2, comps.month) + XCTAssertEqual(23, comps.hour) + XCTAssertEqual(56, comps.minute) + XCTAssertEqual(1, comps.second) + } + +} diff --git a/README.md b/README.md index 1271f4185..bb067a8fc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RileyLink iOS App -[![Join the chat at https://gitter.im/ps2/rileylink](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ps2/rileylink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/ps2/rileylink](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ps2/rileylink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/ps2/rileylink_ios.svg?branch=master)](https://travis-ci.org/ps2/rileylink_ios) The RileyLink iOS app connects to a RileyLink device via Bluetooth Low Energy (BLE, or Bluetooth Smart) and uploads CGM and pump data to a Nightscout instance via the REST API. The Nightscout web page is also displayed in the App. diff --git a/RileyLink.podspec b/RileyLink.podspec deleted file mode 100644 index f23863176..000000000 --- a/RileyLink.podspec +++ /dev/null @@ -1,129 +0,0 @@ -# -# Be sure to run `pod spec lint rileylink.podspec' to ensure this is a -# valid spec and to remove all comments including this before submitting the spec. -# -# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html -# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ -# - -Pod::Spec.new do |s| - - # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # These will help people to find your library, and whilst it - # can feel like a chore to fill in it's definitely to your advantage. The - # summary should be tweet-length, and the description more in depth. - # - - s.name = "RileyLink" - s.version = "0.1.4" - s.summary = "Client adaptor for the RileyLink, a 916MHz to BLE bridge peripheral" - - s.description = <<-DESC - RileyLink is a custom designed Bluetooth Smart (BLE) to 916MHz module. - It can be used to bridge any BLE capable smartphone to the world of 916Mhz based devices. - This project is focused on talking to Medtronic insulin pumps and sensors. - - Please understand that this project: - - * Has no affiliation with Medtronic - * Is highly experimental - * Is not intended for therapy - DESC - - s.homepage = "https://github.com/ps2/rileylink_ios" - # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" - - - # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # Licensing your code is important. See http://choosealicense.com for more info. - # CocoaPods will detect a license file if there is a named LICENSE* - # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. - # - - s.license = { :type => "MIT", :file => "LICENSE" } - - - # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # Specify the authors of the library, with email addresses. Email addresses - # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also - # accepts just a name if you'd rather not provide an email address. - # - # Specify a social_media_url where others can refer to, for example a twitter - # profile URL. - # - - s.author = "Pete Schwamb" - - # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # If this Pod runs only on iOS or OS X, then specify the platform and - # the deployment target. You can optionally include the target after the platform. - # - - s.platform = :ios, "7.0" - - # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # Specify the location from where the source should be retrieved. - # Supports git, hg, bzr, svn and HTTP. - # - - s.source = { :git => "https://github.com/ps2/rileylink_ios.git", :tag => "0.1.1" } - - - # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # CocoaPods is smart about how it includes source code. For source files - # giving a folder will include any swift, h, m, mm, c & cpp files. - # For header files it will include any header in the folder. - # Not including the public_header_files will make all headers public. - # - - s.source_files = "RileyLink/RileyLinkBLE*.{h,m}", "RileyLink/{MinimedPacket,NSData+Conversion,SendDataTask}.{h,m}" - # s.exclude_files = "Classes/Exclude" - - s.public_header_files = "RileyLink/RileyLinkBLE*.h" - - - # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # A list of resources included with the Pod. These are copied into the - # target bundle with a build phase script. Anything else will be cleaned. - # You can preserve files from being cleaned, please don't preserve - # non-essential files like tests, examples and documentation. - # - - # s.resource = "icon.png" - # s.resources = "Resources/*.png" - - # s.preserve_paths = "FilesToSave", "MoreFilesToSave" - - - # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # Link your library with frameworks, or libraries. Libraries do not include - # the lib prefix of their name. - # - - s.framework = "CoreBluetooth" - # s.frameworks = "SomeFramework", "AnotherFramework" - - # s.library = "iconv" - # s.libraries = "iconv", "xml2" - - - # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # - # - # If your library depends on compiler flags you can set them in the xcconfig hash - # where they will only apply to your library. If you depend on other Podspecs - # you can include multiple dependencies to ensure it works. - - # s.requires_arc = true - - # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } - # s.dependency "JSONKit", "~> 1.4" - -end diff --git a/RileyLink.xcodeproj/project.pbxproj b/RileyLink.xcodeproj/project.pbxproj index 640eb79b6..5c944b9bf 100644 --- a/RileyLink.xcodeproj/project.pbxproj +++ b/RileyLink.xcodeproj/project.pbxproj @@ -7,20 +7,81 @@ objects = { /* Begin PBXBuildFile section */ - 43737CE11B7F06F100835F8D /* MySentryPairingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43737CE01B7F06F100835F8D /* MySentryPairingViewController.m */; }; + 430D64CE1CB855AB00FCA750 /* RileyLinkBLEKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64CD1CB855AB00FCA750 /* RileyLinkBLEKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D64D51CB855AB00FCA750 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; }; + 430D64DC1CB855AB00FCA750 /* RileyLinkBLEKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64DB1CB855AB00FCA750 /* RileyLinkBLEKitTests.m */; }; + 430D64E01CB855AB00FCA750 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; }; + 430D64E11CB855AB00FCA750 /* RileyLinkBLEKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 430D64EC1CB85A4300FCA750 /* RileyLinkBLEDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64E81CB85A4300FCA750 /* RileyLinkBLEDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D64ED1CB85A4300FCA750 /* RileyLinkBLEDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64E91CB85A4300FCA750 /* RileyLinkBLEDevice.m */; }; + 430D64EE1CB85A4300FCA750 /* RileyLinkBLEManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64EA1CB85A4300FCA750 /* RileyLinkBLEManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D64EF1CB85A4300FCA750 /* RileyLinkBLEManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64EB1CB85A4300FCA750 /* RileyLinkBLEManager.m */; }; + 430D65001CB89FC000FCA750 /* CmdBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64F01CB89FC000FCA750 /* CmdBase.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D65011CB89FC000FCA750 /* CmdBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64F11CB89FC000FCA750 /* CmdBase.m */; }; + 430D65021CB89FC000FCA750 /* GetPacketCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64F21CB89FC000FCA750 /* GetPacketCmd.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D65031CB89FC000FCA750 /* GetPacketCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64F31CB89FC000FCA750 /* GetPacketCmd.m */; }; + 430D65041CB89FC000FCA750 /* GetVersionCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64F41CB89FC000FCA750 /* GetVersionCmd.h */; }; + 430D65051CB89FC000FCA750 /* GetVersionCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64F51CB89FC000FCA750 /* GetVersionCmd.m */; }; + 430D65061CB89FC000FCA750 /* ReceivingPacketCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64F61CB89FC000FCA750 /* ReceivingPacketCmd.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D65071CB89FC000FCA750 /* ReceivingPacketCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64F71CB89FC000FCA750 /* ReceivingPacketCmd.m */; }; + 430D65081CB89FC000FCA750 /* RFPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64F81CB89FC000FCA750 /* RFPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D65091CB89FC000FCA750 /* RFPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64F91CB89FC000FCA750 /* RFPacket.m */; }; + 430D650A1CB89FC000FCA750 /* SendAndListenCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64FA1CB89FC000FCA750 /* SendAndListenCmd.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D650B1CB89FC000FCA750 /* SendAndListenCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64FB1CB89FC000FCA750 /* SendAndListenCmd.m */; }; + 430D650C1CB89FC000FCA750 /* SendPacketCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64FC1CB89FC000FCA750 /* SendPacketCmd.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D650D1CB89FC000FCA750 /* SendPacketCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64FD1CB89FC000FCA750 /* SendPacketCmd.m */; }; + 430D650E1CB89FC000FCA750 /* UpdateRegisterCmd.h in Headers */ = {isa = PBXBuildFile; fileRef = 430D64FE1CB89FC000FCA750 /* UpdateRegisterCmd.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 430D650F1CB89FC000FCA750 /* UpdateRegisterCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = 430D64FF1CB89FC000FCA750 /* UpdateRegisterCmd.m */; }; + 43462E8B1CCB06F500F958A8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */; }; + 434AB0951CBA0DF600422F4A /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0911CBA0DF600422F4A /* Either.swift */; }; + 434AB0961CBA0DF600422F4A /* PumpOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0921CBA0DF600422F4A /* PumpOps.swift */; }; + 434AB0971CBA0DF600422F4A /* PumpOpsSynchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0931CBA0DF600422F4A /* PumpOpsSynchronous.swift */; }; + 434AB0981CBA0DF600422F4A /* PumpState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0941CBA0DF600422F4A /* PumpState.swift */; }; + 434AB09E1CBA28F100422F4A /* NSTimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB09D1CBA28F100422F4A /* NSTimeInterval.swift */; }; + 434AB0BE1CBB4E3200422F4A /* RileyLinkDeviceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0BD1CBB4E3200422F4A /* RileyLinkDeviceManager.swift */; }; + 434AB0C61CBCB41500422F4A /* RileyLinkDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 434AB0C51CBCB41500422F4A /* RileyLinkDevice.swift */; }; + 434AB0C71CBCB76400422F4A /* NSData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* NSData.swift */; }; + 43523ED71CC2C558001850F1 /* NSData+Conversion.m in Sources */ = {isa = PBXBuildFile; fileRef = C1E535E91991E36700C2AC49 /* NSData+Conversion.m */; }; + 43722FB11CB9F7640038B7F2 /* RileyLinkKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43722FB81CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; }; + 43722FBF1CB9F7640038B7F2 /* RileyLinkKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43722FBE1CB9F7640038B7F2 /* RileyLinkKitTests.swift */; }; + 43722FC31CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; }; + 43722FC41CB9F7640038B7F2 /* RileyLinkKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 43722FCB1CB9F7DB0038B7F2 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10D9BC11C8269D500378342 /* MinimedKit.framework */; }; + 43722FCC1CB9F7DB0038B7F2 /* RileyLinkBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; }; 43C99C6F1B898B7100BC03D4 /* MenuHeaderTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C99C6E1B898B7100BC03D4 /* MenuHeaderTableViewCell.m */; }; + 43CA93251CB8BB33000026B5 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */; }; + 43CA93291CB8CF22000026B5 /* ChangeTempBasalCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA93281CB8CF22000026B5 /* ChangeTempBasalCarelinkMessageBody.swift */; }; + 43CA932B1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA932A1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift */; }; + 43CA932E1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA932C1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift */; }; + 43CA932F1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA932D1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift */; }; + 43CA93311CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA93301CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift */; }; + 43CA93331CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA93321CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift */; }; + 43CA93351CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CA93341CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift */; }; 43EC9DCB1B786C6200DB0D18 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43EC9DCA1B786C6200DB0D18 /* LaunchScreen.xib */; }; - C10A62921C55F8E200E635EE /* UpdateRegisterCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = C10A62911C55F8E200E635EE /* UpdateRegisterCmd.m */; }; - C10EAA9D1C5AE9A600B0838F /* GetVersionCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = C10EAA9C1C5AE9A600B0838F /* GetVersionCmd.m */; }; - C10EAAA31C5B3A0800B0838F /* PumpOpsSynchronous.m in Sources */ = {isa = PBXBuildFile; fileRef = C10EAAA21C5B3A0800B0838F /* PumpOpsSynchronous.m */; }; - C10EAAA61C5C507E00B0838F /* PumpOps.m in Sources */ = {isa = PBXBuildFile; fileRef = C10EAAA51C5C507E00B0838F /* PumpOps.m */; }; - C11F993D1BC406970013158C /* PumpState.m in Sources */ = {isa = PBXBuildFile; fileRef = C11F993C1BC406970013158C /* PumpState.m */; }; + 43FF221C1CB9B9DE00024F30 /* NSDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */; }; + C10AB08B1C8519E2000F102E /* MySentryPairViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10AB08A1C8519E2000F102E /* MySentryPairViewController.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, ); }; }; + C10D9BCB1C8269D500378342 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10D9BC11C8269D500378342 /* MinimedKit.framework */; }; + C10D9BD61C8269D500378342 /* MinimedKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10D9BC11C8269D500378342 /* MinimedKit.framework */; }; + C10D9BD71C8269D500378342 /* MinimedKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C10D9BC11C8269D500378342 /* MinimedKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + C121985F1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C121985E1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift */; }; + C12198611C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198601C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift */; }; + C12198631C8DF4C800BC374C /* HistoryPageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198621C8DF4C800BC374C /* HistoryPageTests.swift */; }; + C121989F1C8DFC2200BC374C /* BolusCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C121989E1C8DFC2200BC374C /* BolusCarelinkMessageBody.swift */; }; + C12198A31C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198A21C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift */; }; + C12198A91C8F2AF200BC374C /* Sara6EPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198A81C8F2AF200BC374C /* Sara6EPumpEvent.swift */; }; + C12198AD1C8F332500BC374C /* TimestampedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198AC1C8F332500BC374C /* TimestampedPumpEvent.swift */; }; + C12198AF1C8F46FF00BC374C /* TimeFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198AE1C8F46FF00BC374C /* TimeFormat.swift */; }; + C12198B11C8F6DD800BC374C /* TimeFormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198B01C8F6DD800BC374C /* TimeFormatTests.swift */; }; + C12198B31C8F730700BC374C /* BolusWizardEstimatePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12198B21C8F730700BC374C /* BolusWizardEstimatePumpEvent.swift */; }; C126162C1B65E9BF001FAD87 /* RileyLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C126162B1B65E9BF001FAD87 /* RileyLinkDeviceViewController.m */; }; C12616321B65F4BC001FAD87 /* RileyLinkListTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616311B65F4BC001FAD87 /* RileyLinkListTableViewController.m */; }; C126163C1B67CBC2001FAD87 /* RileyLinkTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C126163B1B67CBC2001FAD87 /* RileyLinkTableViewCell.m */; }; C12616441B685F0A001FAD87 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12616431B685F0A001FAD87 /* CoreData.framework */; }; C126164B1B685F93001FAD87 /* RileyLink.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C12616491B685F93001FAD87 /* RileyLink.xcdatamodeld */; }; - C12616511B688D9C001FAD87 /* RileyLinkBLEDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616501B688D9C001FAD87 /* RileyLinkBLEDevice.m */; }; C12616541B6892DB001FAD87 /* RileyLinkRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616531B6892DB001FAD87 /* RileyLinkRecord.m */; }; C12616571B6A6130001FAD87 /* PacketLogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616561B6A6130001FAD87 /* PacketLogViewController.m */; }; C126165A1B6B2D20001FAD87 /* PacketTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616591B6B2D20001FAD87 /* PacketTableViewCell.m */; }; @@ -29,15 +90,11 @@ C12616681B76E8DC001FAD87 /* TPKeyboardAvoidingScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616621B76E8DC001FAD87 /* TPKeyboardAvoidingScrollView.m */; }; C12616691B76E8DC001FAD87 /* TPKeyboardAvoidingTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616641B76E8DC001FAD87 /* TPKeyboardAvoidingTableView.m */; }; C126166A1B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = C12616661B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.m */; }; - C126166D1B76ECBA001FAD87 /* PumpChatViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C126166C1B76ECBA001FAD87 /* PumpChatViewController.m */; }; - C12616701B7790DF001FAD87 /* SendAndListenCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = C126166F1B7790DF001FAD87 /* SendAndListenCmd.m */; }; C1271B071A9A34E900B7C949 /* Log.m in Sources */ = {isa = PBXBuildFile; fileRef = C1271B061A9A34E900B7C949 /* Log.m */; }; C12EA23B198B436800309FA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23A198B436800309FA4 /* Foundation.framework */; }; C12EA23D198B436800309FA4 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23C198B436800309FA4 /* CoreGraphics.framework */; }; C12EA23F198B436800309FA4 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23E198B436800309FA4 /* UIKit.framework */; }; C12EA245198B436800309FA4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C12EA243198B436800309FA4 /* InfoPlist.strings */; }; - C12EA247198B436800309FA4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C12EA246198B436800309FA4 /* main.m */; }; - C12EA24B198B436800309FA4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C12EA24A198B436800309FA4 /* AppDelegate.m */; }; C12EA24D198B436800309FA4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C12EA24C198B436800309FA4 /* Images.xcassets */; }; C12EA254198B436800309FA4 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA253198B436800309FA4 /* XCTest.framework */; }; C12EA255198B436800309FA4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C12EA23A198B436800309FA4 /* Foundation.framework */; }; @@ -46,81 +103,113 @@ C12EA260198B436900309FA4 /* RileyLinkTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C12EA25F198B436900309FA4 /* RileyLinkTests.m */; }; C12EA26A198B442100309FA4 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C12EA269198B442100309FA4 /* Storyboard.storyboard */; }; C12EA26D198B456D00309FA4 /* NightscoutWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = C12EA26C198B456D00309FA4 /* NightscoutWebView.m */; }; - C137A3901C08114600569851 /* CRC8.m in Sources */ = {isa = PBXBuildFile; fileRef = C137A38F1C08114600569851 /* CRC8.m */; }; - C137A3931C08142E00569851 /* CRC16.m in Sources */ = {isa = PBXBuildFile; fileRef = C137A3921C08142E00569851 /* CRC16.m */; }; - C137A3961C08A35C00569851 /* NightScoutBolus.m in Sources */ = {isa = PBXBuildFile; fileRef = C137A3951C08A35C00569851 /* NightScoutBolus.m */; }; - C137A39C1C08A48100569851 /* NightScoutPump.m in Sources */ = {isa = PBXBuildFile; fileRef = C137A39B1C08A48100569851 /* NightScoutPump.m */; }; - C139AB911BFD6A9000B0518F /* PumpHistoryEventBase.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AB901BFD6A9000B0518F /* PumpHistoryEventBase.m */; }; - C139AC211BFD847F00B0518F /* HistoryPage.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC201BFD847F00B0518F /* HistoryPage.m */; }; + C12FB2761CC5893C00879B80 /* TempBasalNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */; }; C139AC241BFD84B500B0518F /* RuntimeUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC231BFD84B500B0518F /* RuntimeUtils.m */; }; - C139AC811BFD8CF800B0518F /* PHEAlarmPump.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC261BFD8CF800B0518F /* PHEAlarmPump.m */; }; - C139AC821BFD8CF800B0518F /* PHEAlarmSensor.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC281BFD8CF800B0518F /* PHEAlarmSensor.m */; }; - C139AC831BFD8CF800B0518F /* PHEBasalProfileStart.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC2A1BFD8CF800B0518F /* PHEBasalProfileStart.m */; }; - C139AC841BFD8CF800B0518F /* PHEBattery.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC2C1BFD8CF800B0518F /* PHEBattery.m */; }; - C139AC851BFD8CF800B0518F /* PHEBgReceived.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC2E1BFD8CF800B0518F /* PHEBgReceived.m */; }; - C139AC861BFD8CF800B0518F /* PHEBolusNormal.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC301BFD8CF800B0518F /* PHEBolusNormal.m */; }; - C139AC881BFD8CF800B0518F /* PHECalBGForPH.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC341BFD8CF800B0518F /* PHECalBGForPH.m */; }; - C139AC891BFD8CF800B0518F /* PHEChangeAlarmClockEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC361BFD8CF800B0518F /* PHEChangeAlarmClockEnable.m */; }; - C139AC8A1BFD8CF800B0518F /* PHEChangeAlarmClockTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC381BFD8CF800B0518F /* PHEChangeAlarmClockTime.m */; }; - C139AC8B1BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC3A1BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.m */; }; - C139AC8C1BFD8CF800B0518F /* PHEChangeAudioBolus.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC3C1BFD8CF800B0518F /* PHEChangeAudioBolus.m */; }; - C139AC8D1BFD8CF800B0518F /* PHEChangeBasalProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC3E1BFD8CF800B0518F /* PHEChangeBasalProfile.m */; }; - C139AC8E1BFD8CF800B0518F /* PHEChangeBasalProfilePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC401BFD8CF800B0518F /* PHEChangeBasalProfilePattern.m */; }; - C139AC8F1BFD8CF800B0518F /* PHEChangeBGReminderEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC421BFD8CF800B0518F /* PHEChangeBGReminderEnable.m */; }; - C139AC901BFD8CF800B0518F /* PHEChangeBGReminderOffset.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC441BFD8CF800B0518F /* PHEChangeBGReminderOffset.m */; }; - C139AC911BFD8CF800B0518F /* PHEChangeBolusReminderEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC461BFD8CF800B0518F /* PHEChangeBolusReminderEnable.m */; }; - C139AC921BFD8CF800B0518F /* PHEChangeBolusReminderTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC481BFD8CF800B0518F /* PHEChangeBolusReminderTime.m */; }; - C139AC931BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC4A1BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.m */; }; - C139AC941BFD8CF800B0518F /* PHEChangeBolusWizardSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC4C1BFD8CF800B0518F /* PHEChangeBolusWizardSetup.m */; }; - C139AC951BFD8CF800B0518F /* PHEChangeCaptureEventEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC4E1BFD8CF800B0518F /* PHEChangeCaptureEventEnable.m */; }; - C139AC961BFD8CF800B0518F /* PHEChangeCarbUnits.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC501BFD8CF800B0518F /* PHEChangeCarbUnits.m */; }; - C139AC971BFD8CF800B0518F /* PHEChangeChildBlockEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC521BFD8CF800B0518F /* PHEChangeChildBlockEnable.m */; }; - C139AC981BFD8CF800B0518F /* PHEChangeMaxBolus.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC541BFD8CF800B0518F /* PHEChangeMaxBolus.m */; }; - C139AC991BFD8CF800B0518F /* PHEChangeParadigmLinkID.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC561BFD8CF800B0518F /* PHEChangeParadigmLinkID.m */; }; - C139AC9A1BFD8CF800B0518F /* PHEChangeReservoirWarningTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC581BFD8CF800B0518F /* PHEChangeReservoirWarningTime.m */; }; - C139AC9B1BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC5A1BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.m */; }; - C139AC9C1BFD8CF800B0518F /* PHEChangeSensorSetup2.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC5C1BFD8CF800B0518F /* PHEChangeSensorSetup2.m */; }; - C139AC9D1BFD8CF800B0518F /* PHEChangeTempBasalPercent.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC5E1BFD8CF800B0518F /* PHEChangeTempBasalPercent.m */; }; - C139AC9E1BFD8CF800B0518F /* PHEChangeTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC601BFD8CF800B0518F /* PHEChangeTime.m */; }; - C139AC9F1BFD8CF800B0518F /* PHEChangeTimeFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC621BFD8CF800B0518F /* PHEChangeTimeFormat.m */; }; - C139ACA01BFD8CF800B0518F /* PHEChangeVariableBolus.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC641BFD8CF800B0518F /* PHEChangeVariableBolus.m */; }; - C139ACA11BFD8CF800B0518F /* PHEChangeWatchdogEnable.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC661BFD8CF800B0518F /* PHEChangeWatchdogEnable.m */; }; - C139ACA21BFD8CF800B0518F /* PHEClearAlarm.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC681BFD8CF800B0518F /* PHEClearAlarm.m */; }; - C139ACA31BFD8CF800B0518F /* PHEDeleteAlarmClockTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC6A1BFD8CF800B0518F /* PHEDeleteAlarmClockTime.m */; }; - C139ACA41BFD8CF800B0518F /* PHEDeleteBolusReminderTime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC6C1BFD8CF800B0518F /* PHEDeleteBolusReminderTime.m */; }; - C139ACA51BFD8CF800B0518F /* PHEEnableDisableRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC6E1BFD8CF800B0518F /* PHEEnableDisableRemote.m */; }; - C139ACA61BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC701BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.m */; }; - C139ACA71BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC721BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.m */; }; - C139ACA81BFD8CF800B0518F /* PHEPrime.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC741BFD8CF800B0518F /* PHEPrime.m */; }; - C139ACA91BFD8CF800B0518F /* PHEResultDailyTotal.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC761BFD8CF800B0518F /* PHEResultDailyTotal.m */; }; - C139ACAA1BFD8CF800B0518F /* PHEResume.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC781BFD8CF800B0518F /* PHEResume.m */; }; - C139ACAB1BFD8CF800B0518F /* PHERewind.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC7A1BFD8CF800B0518F /* PHERewind.m */; }; - C139ACAC1BFD8CF800B0518F /* PHESara6E.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC7C1BFD8CF800B0518F /* PHESara6E.m */; }; - C139ACAD1BFD8CF800B0518F /* PHESuspend.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC7E1BFD8CF800B0518F /* PHESuspend.m */; }; - C139ACAE1BFD8CF800B0518F /* PHEUnabsorbedInsulin.m in Sources */ = {isa = PBXBuildFile; fileRef = C139AC801BFD8CF800B0518F /* PHEUnabsorbedInsulin.m */; }; - C139ACB11BFEDD9E00B0518F /* PumpModel.m in Sources */ = {isa = PBXBuildFile; fileRef = C139ACB01BFEDD9E00B0518F /* PumpModel.m */; }; - C139ACBA1C00046D00B0518F /* PHEAlarmClockReminder.m in Sources */ = {isa = PBXBuildFile; fileRef = C139ACB31C00046D00B0518F /* PHEAlarmClockReminder.m */; }; - C139ACBB1C00046D00B0518F /* PHEBolusWizardBolusEstimate.m in Sources */ = {isa = PBXBuildFile; fileRef = C139ACB51C00046D00B0518F /* PHEBolusWizardBolusEstimate.m */; }; - C139ACBC1C00046D00B0518F /* PHEJournalEntryPumpLowBattery.m in Sources */ = {isa = PBXBuildFile; fileRef = C139ACB71C00046D00B0518F /* PHEJournalEntryPumpLowBattery.m */; }; - C139ACBD1C00046D00B0518F /* PHEModel522ResultTotals.m in Sources */ = {isa = PBXBuildFile; fileRef = C139ACB91C00046D00B0518F /* PHEModel522ResultTotals.m */; }; - C13DB3A51B1583E900121E02 /* MessageBase.m in Sources */ = {isa = PBXBuildFile; fileRef = C13DB3A41B1583E900121E02 /* MessageBase.m */; }; - C14AA33B1B1A2FB100299A55 /* MeterMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C14AA33A1B1A2FB100299A55 /* MeterMessage.m */; }; - C152C19C1C3875EA0009B4B8 /* GetPacketCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C19B1C3875EA0009B4B8 /* GetPacketCmd.m */; }; - C152C19F1C38B5A30009B4B8 /* DeviceLinkMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C19E1C38B5A30009B4B8 /* DeviceLinkMessage.m */; }; - C152C1A21C38B8850009B4B8 /* FindDeviceMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C1A11C38B8850009B4B8 /* FindDeviceMessage.m */; }; - C152C1A51C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C1A41C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.m */; }; - C152C1A81C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C1A71C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.m */; }; - C152C1AB1C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.m in Sources */ = {isa = PBXBuildFile; fileRef = C152C1AA1C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.m */; }; - C1743CDF199D374500ED623E /* PumpStatusMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = C1743CDE199D374500ED623E /* PumpStatusMessage.m */; }; + 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 */; }; + C14C8A801C9CFBEE000F72C5 /* NightscoutPumpEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14C8A7F1C9CFBEE000F72C5 /* NightscoutPumpEventsTests.swift */; }; + C14D2B051C9F5D5800C98E4C /* TempBasalDurationPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D2B041C9F5D5800C98E4C /* TempBasalDurationPumpEvent.swift */; }; + C14D2B091C9F5EDA00C98E4C /* ChangeTempBasalTypePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D2B081C9F5EDA00C98E4C /* ChangeTempBasalTypePumpEvent.swift */; }; + C1711A561C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A551C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift */; }; + C1711A5A1C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A591C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift */; }; + C1711A5C1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A5B1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift */; }; + C1711A5E1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */; }; C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - C1A47EBF1B117DE900756B99 /* NightScoutUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = C1A47EBE1B117DE900756B99 /* NightScoutUploader.m */; }; - C1A47EC21B1190D800756B99 /* NSString+Hashes.m in Sources */ = {isa = PBXBuildFile; fileRef = C1A47EC11B1190D800756B99 /* NSString+Hashes.m */; }; + C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBA1C8E184300DB42AC /* PumpModel.swift */; }; + C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */; }; + C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */; }; + C1842BC11C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BC01C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift */; }; + C1842BC31C8E931E00DB42AC /* BolusNormalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BC21C8E931E00DB42AC /* BolusNormalPumpEvent.swift */; }; + C1842BC51C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BC41C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift */; }; + C1842BC71C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BC61C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift */; }; + C1842BC91C8F968B00DB42AC /* BGReceivedPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BC81C8F968B00DB42AC /* BGReceivedPumpEvent.swift */; }; + C1842BCB1C8F9A7200DB42AC /* RewindPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BCA1C8F9A7200DB42AC /* RewindPumpEvent.swift */; }; + C1842BCD1C8F9BBD00DB42AC /* PrimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BCC1C8F9BBD00DB42AC /* PrimePumpEvent.swift */; }; + C1842BCF1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BCE1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift */; }; + C1842BD11C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD01C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift */; }; + C1842BFC1C8FA45100DB42AC /* SuspendPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD21C8FA45100DB42AC /* SuspendPumpEvent.swift */; }; + C1842BFD1C8FA45100DB42AC /* ResumePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD31C8FA45100DB42AC /* ResumePumpEvent.swift */; }; + C1842BFE1C8FA45100DB42AC /* ResultDailyTotalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD41C8FA45100DB42AC /* ResultDailyTotalPumpEvent.swift */; }; + C1842BFF1C8FA45100DB42AC /* Model522ResultTotalsPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD51C8FA45100DB42AC /* Model522ResultTotalsPumpEvent.swift */; }; + C1842C001C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD61C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift */; }; + C1842C011C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD71C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift */; }; + C1842C021C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD81C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift */; }; + C1842C031C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BD91C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift */; }; + C1842C041C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDA1C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift */; }; + C1842C051C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDB1C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift */; }; + C1842C061C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDC1C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift */; }; + C1842C071C8FA45100DB42AC /* ClearAlarmPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDD1C8FA45100DB42AC /* ClearAlarmPumpEvent.swift */; }; + C1842C081C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDE1C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift */; }; + C1842C091C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BDF1C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift */; }; + C1842C0A1C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE01C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift */; }; + C1842C0B1C8FA45100DB42AC /* ChangeTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE11C8FA45100DB42AC /* ChangeTimePumpEvent.swift */; }; + C1842C0C1C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE21C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift */; }; + C1842C0D1C8FA45100DB42AC /* TempBasalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE31C8FA45100DB42AC /* TempBasalPumpEvent.swift */; }; + C1842C0E1C8FA45100DB42AC /* ChangeSensorSetup2PumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE41C8FA45100DB42AC /* ChangeSensorSetup2PumpEvent.swift */; }; + C1842C0F1C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE51C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */; }; + C1842C101C8FA45100DB42AC /* ChangeReservoirWarningTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE61C8FA45100DB42AC /* ChangeReservoirWarningTimePumpEvent.swift */; }; + C1842C111C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE71C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift */; }; + C1842C121C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE81C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift */; }; + C1842C131C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BE91C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift */; }; + C1842C141C8FA45100DB42AC /* ChangeMaxBasalPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BEA1C8FA45100DB42AC /* ChangeMaxBasalPumpEvent.swift */; }; + C1842C151C8FA45100DB42AC /* ChangeChildBlockEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BEB1C8FA45100DB42AC /* ChangeChildBlockEnablePumpEvent.swift */; }; + C1842C161C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BEC1C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift */; }; + C1842C171C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BED1C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift */; }; + C1842C181C8FA45100DB42AC /* ChangeBolusWizardSetupPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BEE1C8FA45100DB42AC /* ChangeBolusWizardSetupPumpEvent.swift */; }; + C1842C191C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BEF1C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift */; }; + C1842C1A1C8FA45100DB42AC /* ChangeBolusReminderTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF01C8FA45100DB42AC /* ChangeBolusReminderTimePumpEvent.swift */; }; + C1842C1B1C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF11C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift */; }; + C1842C1C1C8FA45100DB42AC /* ChangeBGReminderOffsetPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF21C8FA45100DB42AC /* ChangeBGReminderOffsetPumpEvent.swift */; }; + C1842C1D1C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF31C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift */; }; + C1842C1E1C8FA45100DB42AC /* ChangeBasalProfilePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF41C8FA45100DB42AC /* ChangeBasalProfilePumpEvent.swift */; }; + C1842C1F1C8FA45100DB42AC /* ChangeBasalProfilePatternPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF51C8FA45100DB42AC /* ChangeBasalProfilePatternPumpEvent.swift */; }; + C1842C201C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF61C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift */; }; + C1842C211C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF71C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift */; }; + C1842C221C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF81C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift */; }; + C1842C231C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BF91C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift */; }; + C1842C241C8FA45100DB42AC /* BatteryPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFA1C8FA45100DB42AC /* BatteryPumpEvent.swift */; }; + C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */; }; + C1842C291C908A3C00DB42AC /* NightscoutUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */; }; + C1842C2B1C90DFB600DB42AC /* NightscoutPumpEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */; }; + C1842C2F1C90F6D900DB42AC /* NightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */; }; + C1842C311C91D56400DB42AC /* BGCheckNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */; }; + C1842C331C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */; }; + C1890B5F1C94B9D9005F7474 /* PumpChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1890B5E1C94B9D9005F7474 /* PumpChatViewController.swift */; }; + C19F94AB1C91DF6E00018F7D /* BolusNightscoutTreatment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */; }; C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */; }; - C1D2B67E1C2FAD0100DB4AEA /* CmdBase.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2B67D1C2FAD0100DB4AEA /* CmdBase.m */; }; - C1D2B6811C30AAE000DB4AEA /* SendPacketCmd.m in Sources */ = {isa = PBXBuildFile; fileRef = C1D2B6801C30AAE000DB4AEA /* SendPacketCmd.m */; }; + C1C3578F1C927303009BDD4F /* MeterMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C3578E1C927303009BDD4F /* MeterMessage.swift */; }; + C1C357911C92733A009BDD4F /* MeterMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C357901C92733A009BDD4F /* MeterMessageTests.swift */; }; + C1C357941C929529009BDD4F /* StringCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C357931C929529009BDD4F /* StringCrypto.swift */; }; C1E535EA1991E36700C2AC49 /* NSData+Conversion.m in Sources */ = {isa = PBXBuildFile; fileRef = C1E535E91991E36700C2AC49 /* NSData+Conversion.m */; }; - C1E535ED1991E49600C2AC49 /* RileyLinkBLEManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C1E535EC1991E49600C2AC49 /* RileyLinkBLEManager.m */; }; - C1E535F01991E6A200C2AC49 /* MinimedPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = C1E535EF1991E6A200C2AC49 /* MinimedPacket.m */; }; + C1EAD6B31C826B6D006DBA60 /* AlertType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6AE1C826B6D006DBA60 /* AlertType.swift */; }; + C1EAD6B41C826B6D006DBA60 /* MessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6AF1C826B6D006DBA60 /* MessageBody.swift */; }; + C1EAD6B51C826B6D006DBA60 /* MessageType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6B01C826B6D006DBA60 /* MessageType.swift */; }; + C1EAD6B61C826B6D006DBA60 /* PacketType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6B11C826B6D006DBA60 /* PacketType.swift */; }; + C1EAD6B71C826B6D006DBA60 /* PumpMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6B21C826B6D006DBA60 /* PumpMessage.swift */; }; + C1EAD6C51C826B92006DBA60 /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6B91C826B92006DBA60 /* Int.swift */; }; + C1EAD6C61C826B92006DBA60 /* NSData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BA1C826B92006DBA60 /* NSData.swift */; }; + C1EAD6C71C826B92006DBA60 /* NSDateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BB1C826B92006DBA60 /* NSDateComponents.swift */; }; + C1EAD6C81C826B92006DBA60 /* CarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BD1C826B92006DBA60 /* CarelinkMessageBody.swift */; }; + C1EAD6C91C826B92006DBA60 /* MySentryAckMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BE1C826B92006DBA60 /* MySentryAckMessageBody.swift */; }; + C1EAD6CA1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6BF1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift */; }; + C1EAD6CB1C826B92006DBA60 /* MySentryAlertMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6C01C826B92006DBA60 /* MySentryAlertMessageBody.swift */; }; + C1EAD6CC1C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6C11C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift */; }; + C1EAD6CD1C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6C21C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift */; }; + C1EAD6CE1C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6C31C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift */; }; + C1EAD6CF1C826B92006DBA60 /* UnknownMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6C41C826B92006DBA60 /* UnknownMessageBody.swift */; }; + C1EAD6D51C826C43006DBA60 /* MinimedKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6D11C826C43006DBA60 /* MinimedKitTests.swift */; }; + C1EAD6D61C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6D21C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift */; }; + C1EAD6D71C826C43006DBA60 /* NSDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6D31C826C43006DBA60 /* NSDataTests.swift */; }; + C1EAD6D81C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6D41C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift */; }; + C1EAD6DA1C829104006DBA60 /* RFTools.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6D91C829104006DBA60 /* RFTools.swift */; }; + C1EAD6DC1C82A4AB006DBA60 /* RFToolsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6DB1C82A4AB006DBA60 /* RFToolsTests.swift */; }; + C1EAD6DE1C82B78C006DBA60 /* CRC8.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6DD1C82B78C006DBA60 /* CRC8.swift */; }; + C1EAD6E01C82B910006DBA60 /* CRC8Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6DF1C82B910006DBA60 /* CRC8Tests.swift */; }; + C1EAD6E21C82BA7A006DBA60 /* CRC16.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6E11C82BA7A006DBA60 /* CRC16.swift */; }; + C1EAD6E41C82BA87006DBA60 /* CRC16Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6E31C82BA87006DBA60 /* CRC16Tests.swift */; }; + C1EAD6E61C83966D006DBA60 /* PumpMessageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EAD6E51C83966D006DBA60 /* PumpMessageTests.swift */; }; + C1EB955D1C887FE5002517DF /* HistoryPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1EB955C1C887FE5002517DF /* HistoryPage.swift */; }; C1EF58851B3E5DA4001C8C80 /* ConfigureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1EF58841B3E5DA4001C8C80 /* ConfigureViewController.m */; }; C1EF58881B3F93FE001C8C80 /* Config.m in Sources */ = {isa = PBXBuildFile; fileRef = C1EF58871B3F93FE001C8C80 /* Config.m */; }; C1EF588C1B3F9748001C8C80 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C1EF588A1B3F9748001C8C80 /* SWRevealViewController.m */; }; @@ -129,6 +218,48 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 430D64D61CB855AB00FCA750 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 430D64CA1CB855AB00FCA750; + remoteInfo = RileyLinkBLEKit; + }; + 430D64DE1CB855AB00FCA750 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 430D64CA1CB855AB00FCA750; + remoteInfo = RileyLinkBLEKit; + }; + 43722FB91CB9F7640038B7F2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43722FAD1CB9F7630038B7F2; + remoteInfo = RileyLinkKit; + }; + 43722FC11CB9F7640038B7F2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 43722FAD1CB9F7630038B7F2; + remoteInfo = RileyLinkKit; + }; + C10D9BCC1C8269D500378342 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C10D9BC01C8269D500378342; + remoteInfo = MinimedKit; + }; + C10D9BD41C8269D500378342 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = C12EA22F198B436800309FA4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = C10D9BC01C8269D500378342; + remoteInfo = MinimedKit; + }; C12EA257198B436900309FA4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = C12EA22F198B436800309FA4 /* Project object */; @@ -138,22 +269,93 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + C10D9BB81C82614F00378342 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 43722FC41CB9F7640038B7F2 /* RileyLinkKit.framework in Embed Frameworks */, + C10D9BD71C8269D500378342 /* MinimedKit.framework in Embed Frameworks */, + 430D64E11CB855AB00FCA750 /* RileyLinkBLEKit.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ - 43737CDF1B7F06F100835F8D /* MySentryPairingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MySentryPairingViewController.h; sourceTree = ""; }; - 43737CE01B7F06F100835F8D /* MySentryPairingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MySentryPairingViewController.m; sourceTree = ""; }; + 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RileyLinkBLEKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 430D64CD1CB855AB00FCA750 /* RileyLinkBLEKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEKit.h; sourceTree = ""; }; + 430D64CF1CB855AB00FCA750 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 430D64D41CB855AB00FCA750 /* RileyLinkBLEKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RileyLinkBLEKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 430D64DB1CB855AB00FCA750 /* RileyLinkBLEKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RileyLinkBLEKitTests.m; sourceTree = ""; }; + 430D64DD1CB855AB00FCA750 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 430D64E81CB85A4300FCA750 /* RileyLinkBLEDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEDevice.h; sourceTree = ""; }; + 430D64E91CB85A4300FCA750 /* RileyLinkBLEDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RileyLinkBLEDevice.m; sourceTree = ""; tabWidth = 2; }; + 430D64EA1CB85A4300FCA750 /* RileyLinkBLEManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEManager.h; sourceTree = ""; }; + 430D64EB1CB85A4300FCA750 /* RileyLinkBLEManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkBLEManager.m; sourceTree = ""; }; + 430D64F01CB89FC000FCA750 /* CmdBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CmdBase.h; sourceTree = ""; }; + 430D64F11CB89FC000FCA750 /* CmdBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CmdBase.m; sourceTree = ""; }; + 430D64F21CB89FC000FCA750 /* GetPacketCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPacketCmd.h; sourceTree = ""; }; + 430D64F31CB89FC000FCA750 /* GetPacketCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetPacketCmd.m; sourceTree = ""; }; + 430D64F41CB89FC000FCA750 /* GetVersionCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetVersionCmd.h; sourceTree = ""; }; + 430D64F51CB89FC000FCA750 /* GetVersionCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetVersionCmd.m; sourceTree = ""; }; + 430D64F61CB89FC000FCA750 /* ReceivingPacketCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReceivingPacketCmd.h; sourceTree = ""; }; + 430D64F71CB89FC000FCA750 /* ReceivingPacketCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReceivingPacketCmd.m; sourceTree = ""; }; + 430D64F81CB89FC000FCA750 /* RFPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RFPacket.h; sourceTree = ""; }; + 430D64F91CB89FC000FCA750 /* RFPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RFPacket.m; sourceTree = ""; }; + 430D64FA1CB89FC000FCA750 /* SendAndListenCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendAndListenCmd.h; sourceTree = ""; }; + 430D64FB1CB89FC000FCA750 /* SendAndListenCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendAndListenCmd.m; sourceTree = ""; }; + 430D64FC1CB89FC000FCA750 /* SendPacketCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendPacketCmd.h; sourceTree = ""; }; + 430D64FD1CB89FC000FCA750 /* SendPacketCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendPacketCmd.m; sourceTree = ""; }; + 430D64FE1CB89FC000FCA750 /* UpdateRegisterCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateRegisterCmd.h; sourceTree = ""; }; + 430D64FF1CB89FC000FCA750 /* UpdateRegisterCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UpdateRegisterCmd.m; sourceTree = ""; }; + 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 434AB0911CBA0DF600422F4A /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; }; + 434AB0921CBA0DF600422F4A /* PumpOps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOps.swift; sourceTree = ""; }; + 434AB0931CBA0DF600422F4A /* PumpOpsSynchronous.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpOpsSynchronous.swift; sourceTree = ""; }; + 434AB0941CBA0DF600422F4A /* PumpState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpState.swift; sourceTree = ""; }; + 434AB09D1CBA28F100422F4A /* NSTimeInterval.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSTimeInterval.swift; sourceTree = ""; }; + 434AB0BD1CBB4E3200422F4A /* RileyLinkDeviceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDeviceManager.swift; sourceTree = ""; }; + 434AB0C51CBCB41500422F4A /* RileyLinkDevice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RileyLinkDevice.swift; sourceTree = ""; }; + 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RileyLinkKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RileyLinkKit.h; sourceTree = ""; }; + 43722FB21CB9F7640038B7F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 43722FB71CB9F7640038B7F2 /* RileyLinkKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RileyLinkKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 43722FBE1CB9F7640038B7F2 /* RileyLinkKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RileyLinkKitTests.swift; sourceTree = ""; }; + 43722FC01CB9F7640038B7F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 43C99C6D1B898B7100BC03D4 /* MenuHeaderTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuHeaderTableViewCell.h; sourceTree = ""; }; 43C99C6E1B898B7100BC03D4 /* MenuHeaderTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuHeaderTableViewCell.m; sourceTree = ""; }; + 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; + 43CA93281CB8CF22000026B5 /* ChangeTempBasalCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalCarelinkMessageBody.swift; sourceTree = ""; }; + 43CA932A1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeCarelinkMessageBody.swift; sourceTree = ""; }; + 43CA932C1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTempBasalCarelinkMessageBody.swift; sourceTree = ""; }; + 43CA932D1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTimeCarelinkMessageBody.swift; sourceTree = ""; }; + 43CA93301CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadTempBasalCarelinkMessageBodyTests.swift; sourceTree = ""; }; + 43CA93321CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeCarelinMessageBodyTests.swift; sourceTree = ""; }; + 43CA93341CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalCarelinkMessageBodyTests.swift; sourceTree = ""; }; 43EC9DCA1B786C6200DB0D18 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; - C10A62901C55F8E200E635EE /* UpdateRegisterCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateRegisterCmd.h; sourceTree = ""; }; - C10A62911C55F8E200E635EE /* UpdateRegisterCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UpdateRegisterCmd.m; sourceTree = ""; }; - C10EAA9B1C5AE9A600B0838F /* GetVersionCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetVersionCmd.h; sourceTree = ""; }; - C10EAA9C1C5AE9A600B0838F /* GetVersionCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetVersionCmd.m; sourceTree = ""; }; - C10EAAA11C5B3A0800B0838F /* PumpOpsSynchronous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpOpsSynchronous.h; sourceTree = ""; }; - C10EAAA21C5B3A0800B0838F /* PumpOpsSynchronous.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpOpsSynchronous.m; sourceTree = ""; }; - C10EAAA41C5C507E00B0838F /* PumpOps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpOps.h; sourceTree = ""; }; - C10EAAA51C5C507E00B0838F /* PumpOps.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpOps.m; sourceTree = ""; }; - C11F993B1BC406970013158C /* PumpState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpState.h; sourceTree = ""; }; - C11F993C1BC406970013158C /* PumpState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpState.m; sourceTree = ""; }; + 43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponents.swift; sourceTree = ""; }; + C10AB08A1C8519E2000F102E /* MySentryPairViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MySentryPairViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 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; }; + C10D9BC31C8269D500378342 /* MinimedKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MinimedKit.h; sourceTree = ""; }; + C10D9BC51C8269D500378342 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C10D9BCA1C8269D500378342 /* MinimedKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MinimedKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + C10D9BD31C8269D500378342 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C121985E1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindDeviceMessageBodyTests.swift; sourceTree = ""; }; + C12198601C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceLinkMessageBodyTests.swift; sourceTree = ""; }; + C12198621C8DF4C800BC374C /* HistoryPageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryPageTests.swift; sourceTree = ""; }; + C121989E1C8DFC2200BC374C /* BolusCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusCarelinkMessageBody.swift; sourceTree = ""; }; + C12198A21C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusCarelinkMessageBodyTests.swift; sourceTree = ""; }; + C12198A81C8F2AF200BC374C /* Sara6EPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sara6EPumpEvent.swift; sourceTree = ""; }; + C12198AC1C8F332500BC374C /* TimestampedPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampedPumpEvent.swift; sourceTree = ""; }; + C12198AE1C8F46FF00BC374C /* TimeFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeFormat.swift; sourceTree = ""; }; + C12198B01C8F6DD800BC374C /* TimeFormatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeFormatTests.swift; sourceTree = ""; }; + C12198B21C8F730700BC374C /* BolusWizardEstimatePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BolusWizardEstimatePumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C126162A1B65E9BF001FAD87 /* RileyLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkDeviceViewController.h; sourceTree = ""; }; C126162B1B65E9BF001FAD87 /* RileyLinkDeviceViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkDeviceViewController.m; sourceTree = ""; }; C12616301B65F4BC001FAD87 /* RileyLinkListTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkListTableViewController.h; sourceTree = ""; }; @@ -162,8 +364,6 @@ C126163B1B67CBC2001FAD87 /* RileyLinkTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkTableViewCell.m; sourceTree = ""; }; C12616431B685F0A001FAD87 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; C126164A1B685F93001FAD87 /* RileyLink.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = RileyLink.xcdatamodel; sourceTree = ""; }; - C126164F1B688D9C001FAD87 /* RileyLinkBLEDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEDevice.h; sourceTree = ""; }; - C12616501B688D9C001FAD87 /* RileyLinkBLEDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkBLEDevice.m; sourceTree = ""; }; C12616521B6892DB001FAD87 /* RileyLinkRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkRecord.h; sourceTree = ""; }; C12616531B6892DB001FAD87 /* RileyLinkRecord.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkRecord.m; sourceTree = ""; }; C12616551B6A6130001FAD87 /* PacketLogViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PacketLogViewController.h; sourceTree = ""; }; @@ -179,11 +379,7 @@ C12616631B76E8DC001FAD87 /* TPKeyboardAvoidingTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPKeyboardAvoidingTableView.h; sourceTree = ""; }; C12616641B76E8DC001FAD87 /* TPKeyboardAvoidingTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPKeyboardAvoidingTableView.m; sourceTree = ""; }; C12616651B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+TPKeyboardAvoidingAdditions.h"; sourceTree = ""; }; - C12616661B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+TPKeyboardAvoidingAdditions.m"; sourceTree = ""; }; - C126166B1B76ECBA001FAD87 /* PumpChatViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpChatViewController.h; sourceTree = ""; }; - C126166C1B76ECBA001FAD87 /* PumpChatViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpChatViewController.m; sourceTree = ""; }; - C126166E1B7790DF001FAD87 /* SendAndListenCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendAndListenCmd.h; sourceTree = ""; }; - C126166F1B7790DF001FAD87 /* SendAndListenCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendAndListenCmd.m; sourceTree = ""; }; + C12616661B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "UIScrollView+TPKeyboardAvoidingAdditions.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; C1271B061A9A34E900B7C949 /* Log.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Log.m; sourceTree = ""; }; C1271B081A9A350400B7C949 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; C12EA237198B436800309FA4 /* RileyLink.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RileyLink.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -192,10 +388,6 @@ C12EA23E198B436800309FA4 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; C12EA242198B436800309FA4 /* RileyLink-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RileyLink-Info.plist"; sourceTree = ""; }; C12EA244198B436800309FA4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - C12EA246198B436800309FA4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - C12EA248198B436800309FA4 /* RileyLink-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RileyLink-Prefix.pch"; sourceTree = ""; }; - C12EA249198B436800309FA4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - C12EA24A198B436800309FA4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; C12EA24C198B436800309FA4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; C12EA252198B436800309FA4 /* RileyLinkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RileyLinkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C12EA253198B436800309FA4 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; @@ -205,162 +397,124 @@ C12EA269198B442100309FA4 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; }; C12EA26B198B456D00309FA4 /* NightscoutWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NightscoutWebView.h; sourceTree = ""; }; C12EA26C198B456D00309FA4 /* NightscoutWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NightscoutWebView.m; sourceTree = ""; }; - C137A38E1C08114600569851 /* CRC8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRC8.h; sourceTree = ""; }; - C137A38F1C08114600569851 /* CRC8.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CRC8.m; sourceTree = ""; }; - C137A3911C08142E00569851 /* CRC16.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRC16.h; sourceTree = ""; }; - C137A3921C08142E00569851 /* CRC16.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CRC16.m; sourceTree = ""; }; - C137A3941C08A35C00569851 /* NightScoutBolus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NightScoutBolus.h; sourceTree = ""; }; - C137A3951C08A35C00569851 /* NightScoutBolus.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.objc; path = NightScoutBolus.m; sourceTree = ""; }; - C137A39A1C08A48100569851 /* NightScoutPump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NightScoutPump.h; sourceTree = ""; }; - C137A39B1C08A48100569851 /* NightScoutPump.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NightScoutPump.m; sourceTree = ""; }; - C139AB8F1BFD6A9000B0518F /* PumpHistoryEventBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpHistoryEventBase.h; sourceTree = ""; }; - C139AB901BFD6A9000B0518F /* PumpHistoryEventBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpHistoryEventBase.m; sourceTree = ""; }; - C139AC1F1BFD847F00B0518F /* HistoryPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryPage.h; sourceTree = ""; }; - C139AC201BFD847F00B0518F /* HistoryPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryPage.m; sourceTree = ""; }; + C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalNightscoutTreatment.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 = ""; }; - C139AC251BFD8CF800B0518F /* PHEAlarmPump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEAlarmPump.h; sourceTree = ""; }; - C139AC261BFD8CF800B0518F /* PHEAlarmPump.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEAlarmPump.m; sourceTree = ""; }; - C139AC271BFD8CF800B0518F /* PHEAlarmSensor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEAlarmSensor.h; sourceTree = ""; }; - C139AC281BFD8CF800B0518F /* PHEAlarmSensor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEAlarmSensor.m; sourceTree = ""; }; - C139AC291BFD8CF800B0518F /* PHEBasalProfileStart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEBasalProfileStart.h; sourceTree = ""; }; - C139AC2A1BFD8CF800B0518F /* PHEBasalProfileStart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEBasalProfileStart.m; sourceTree = ""; }; - C139AC2B1BFD8CF800B0518F /* PHEBattery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEBattery.h; sourceTree = ""; }; - C139AC2C1BFD8CF800B0518F /* PHEBattery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEBattery.m; sourceTree = ""; }; - C139AC2D1BFD8CF800B0518F /* PHEBgReceived.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEBgReceived.h; sourceTree = ""; }; - C139AC2E1BFD8CF800B0518F /* PHEBgReceived.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEBgReceived.m; sourceTree = ""; }; - C139AC2F1BFD8CF800B0518F /* PHEBolusNormal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEBolusNormal.h; sourceTree = ""; }; - C139AC301BFD8CF800B0518F /* PHEBolusNormal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEBolusNormal.m; sourceTree = ""; }; - C139AC331BFD8CF800B0518F /* PHECalBGForPH.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHECalBGForPH.h; sourceTree = ""; }; - C139AC341BFD8CF800B0518F /* PHECalBGForPH.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHECalBGForPH.m; sourceTree = ""; }; - C139AC351BFD8CF800B0518F /* PHEChangeAlarmClockEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeAlarmClockEnable.h; sourceTree = ""; }; - C139AC361BFD8CF800B0518F /* PHEChangeAlarmClockEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeAlarmClockEnable.m; sourceTree = ""; }; - C139AC371BFD8CF800B0518F /* PHEChangeAlarmClockTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeAlarmClockTime.h; sourceTree = ""; }; - C139AC381BFD8CF800B0518F /* PHEChangeAlarmClockTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeAlarmClockTime.m; sourceTree = ""; }; - C139AC391BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeAlarmNotifyMode.h; sourceTree = ""; }; - C139AC3A1BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeAlarmNotifyMode.m; sourceTree = ""; }; - C139AC3B1BFD8CF800B0518F /* PHEChangeAudioBolus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeAudioBolus.h; sourceTree = ""; }; - C139AC3C1BFD8CF800B0518F /* PHEChangeAudioBolus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeAudioBolus.m; sourceTree = ""; }; - C139AC3D1BFD8CF800B0518F /* PHEChangeBasalProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBasalProfile.h; sourceTree = ""; }; - C139AC3E1BFD8CF800B0518F /* PHEChangeBasalProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBasalProfile.m; sourceTree = ""; }; - C139AC3F1BFD8CF800B0518F /* PHEChangeBasalProfilePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBasalProfilePattern.h; sourceTree = ""; }; - C139AC401BFD8CF800B0518F /* PHEChangeBasalProfilePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBasalProfilePattern.m; sourceTree = ""; }; - C139AC411BFD8CF800B0518F /* PHEChangeBGReminderEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBGReminderEnable.h; sourceTree = ""; }; - C139AC421BFD8CF800B0518F /* PHEChangeBGReminderEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBGReminderEnable.m; sourceTree = ""; }; - C139AC431BFD8CF800B0518F /* PHEChangeBGReminderOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBGReminderOffset.h; sourceTree = ""; }; - C139AC441BFD8CF800B0518F /* PHEChangeBGReminderOffset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBGReminderOffset.m; sourceTree = ""; }; - C139AC451BFD8CF800B0518F /* PHEChangeBolusReminderEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBolusReminderEnable.h; sourceTree = ""; }; - C139AC461BFD8CF800B0518F /* PHEChangeBolusReminderEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBolusReminderEnable.m; sourceTree = ""; }; - C139AC471BFD8CF800B0518F /* PHEChangeBolusReminderTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBolusReminderTime.h; sourceTree = ""; }; - C139AC481BFD8CF800B0518F /* PHEChangeBolusReminderTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBolusReminderTime.m; sourceTree = ""; }; - C139AC491BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBolusScrollStepSize.h; sourceTree = ""; }; - C139AC4A1BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBolusScrollStepSize.m; sourceTree = ""; }; - C139AC4B1BFD8CF800B0518F /* PHEChangeBolusWizardSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeBolusWizardSetup.h; sourceTree = ""; }; - C139AC4C1BFD8CF800B0518F /* PHEChangeBolusWizardSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeBolusWizardSetup.m; sourceTree = ""; }; - C139AC4D1BFD8CF800B0518F /* PHEChangeCaptureEventEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeCaptureEventEnable.h; sourceTree = ""; }; - C139AC4E1BFD8CF800B0518F /* PHEChangeCaptureEventEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeCaptureEventEnable.m; sourceTree = ""; }; - C139AC4F1BFD8CF800B0518F /* PHEChangeCarbUnits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeCarbUnits.h; sourceTree = ""; }; - C139AC501BFD8CF800B0518F /* PHEChangeCarbUnits.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeCarbUnits.m; sourceTree = ""; }; - C139AC511BFD8CF800B0518F /* PHEChangeChildBlockEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeChildBlockEnable.h; sourceTree = ""; }; - C139AC521BFD8CF800B0518F /* PHEChangeChildBlockEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeChildBlockEnable.m; sourceTree = ""; }; - C139AC531BFD8CF800B0518F /* PHEChangeMaxBolus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeMaxBolus.h; sourceTree = ""; }; - C139AC541BFD8CF800B0518F /* PHEChangeMaxBolus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeMaxBolus.m; sourceTree = ""; }; - C139AC551BFD8CF800B0518F /* PHEChangeParadigmLinkID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeParadigmLinkID.h; sourceTree = ""; }; - C139AC561BFD8CF800B0518F /* PHEChangeParadigmLinkID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeParadigmLinkID.m; sourceTree = ""; }; - C139AC571BFD8CF800B0518F /* PHEChangeReservoirWarningTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeReservoirWarningTime.h; sourceTree = ""; }; - C139AC581BFD8CF800B0518F /* PHEChangeReservoirWarningTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeReservoirWarningTime.m; sourceTree = ""; }; - C139AC591BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeSensorRateOfChangeAlertSetup.h; sourceTree = ""; }; - C139AC5A1BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeSensorRateOfChangeAlertSetup.m; sourceTree = ""; }; - C139AC5B1BFD8CF800B0518F /* PHEChangeSensorSetup2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeSensorSetup2.h; sourceTree = ""; }; - C139AC5C1BFD8CF800B0518F /* PHEChangeSensorSetup2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeSensorSetup2.m; sourceTree = ""; }; - C139AC5D1BFD8CF800B0518F /* PHEChangeTempBasalPercent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeTempBasalPercent.h; sourceTree = ""; }; - C139AC5E1BFD8CF800B0518F /* PHEChangeTempBasalPercent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeTempBasalPercent.m; sourceTree = ""; }; - C139AC5F1BFD8CF800B0518F /* PHEChangeTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeTime.h; sourceTree = ""; }; - C139AC601BFD8CF800B0518F /* PHEChangeTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeTime.m; sourceTree = ""; }; - C139AC611BFD8CF800B0518F /* PHEChangeTimeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeTimeFormat.h; sourceTree = ""; }; - C139AC621BFD8CF800B0518F /* PHEChangeTimeFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeTimeFormat.m; sourceTree = ""; }; - C139AC631BFD8CF800B0518F /* PHEChangeVariableBolus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeVariableBolus.h; sourceTree = ""; }; - C139AC641BFD8CF800B0518F /* PHEChangeVariableBolus.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeVariableBolus.m; sourceTree = ""; }; - C139AC651BFD8CF800B0518F /* PHEChangeWatchdogEnable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeWatchdogEnable.h; sourceTree = ""; }; - C139AC661BFD8CF800B0518F /* PHEChangeWatchdogEnable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeWatchdogEnable.m; sourceTree = ""; }; - C139AC671BFD8CF800B0518F /* PHEClearAlarm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEClearAlarm.h; sourceTree = ""; }; - C139AC681BFD8CF800B0518F /* PHEClearAlarm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEClearAlarm.m; sourceTree = ""; }; - C139AC691BFD8CF800B0518F /* PHEDeleteAlarmClockTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEDeleteAlarmClockTime.h; sourceTree = ""; }; - C139AC6A1BFD8CF800B0518F /* PHEDeleteAlarmClockTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEDeleteAlarmClockTime.m; sourceTree = ""; }; - C139AC6B1BFD8CF800B0518F /* PHEDeleteBolusReminderTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEDeleteBolusReminderTime.h; sourceTree = ""; }; - C139AC6C1BFD8CF800B0518F /* PHEDeleteBolusReminderTime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEDeleteBolusReminderTime.m; sourceTree = ""; }; - C139AC6D1BFD8CF800B0518F /* PHEEnableDisableRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEEnableDisableRemote.h; sourceTree = ""; }; - C139AC6E1BFD8CF800B0518F /* PHEEnableDisableRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEEnableDisableRemote.m; sourceTree = ""; }; - C139AC6F1BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEJournalEntryExerciseMarker.h; sourceTree = ""; }; - C139AC701BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEJournalEntryExerciseMarker.m; sourceTree = ""; }; - C139AC711BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEJournalEntryPumpLowReservoir.h; sourceTree = ""; }; - C139AC721BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEJournalEntryPumpLowReservoir.m; sourceTree = ""; }; - C139AC731BFD8CF800B0518F /* PHEPrime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEPrime.h; sourceTree = ""; }; - C139AC741BFD8CF800B0518F /* PHEPrime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEPrime.m; sourceTree = ""; }; - C139AC751BFD8CF800B0518F /* PHEResultDailyTotal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEResultDailyTotal.h; sourceTree = ""; }; - C139AC761BFD8CF800B0518F /* PHEResultDailyTotal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEResultDailyTotal.m; sourceTree = ""; }; - C139AC771BFD8CF800B0518F /* PHEResume.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEResume.h; sourceTree = ""; }; - C139AC781BFD8CF800B0518F /* PHEResume.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEResume.m; sourceTree = ""; }; - C139AC791BFD8CF800B0518F /* PHERewind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHERewind.h; sourceTree = ""; }; - C139AC7A1BFD8CF800B0518F /* PHERewind.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHERewind.m; sourceTree = ""; }; - C139AC7B1BFD8CF800B0518F /* PHESara6E.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHESara6E.h; sourceTree = ""; }; - C139AC7C1BFD8CF800B0518F /* PHESara6E.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHESara6E.m; sourceTree = ""; }; - C139AC7D1BFD8CF800B0518F /* PHESuspend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHESuspend.h; sourceTree = ""; }; - C139AC7E1BFD8CF800B0518F /* PHESuspend.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHESuspend.m; sourceTree = ""; }; - C139AC7F1BFD8CF800B0518F /* PHEUnabsorbedInsulin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEUnabsorbedInsulin.h; sourceTree = ""; }; - C139AC801BFD8CF800B0518F /* PHEUnabsorbedInsulin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEUnabsorbedInsulin.m; sourceTree = ""; }; - C139ACAF1BFEDD9E00B0518F /* PumpModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpModel.h; sourceTree = ""; }; - C139ACB01BFEDD9E00B0518F /* PumpModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpModel.m; sourceTree = ""; }; - C139ACB21C00046D00B0518F /* PHEAlarmClockReminder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEAlarmClockReminder.h; sourceTree = ""; }; - C139ACB31C00046D00B0518F /* PHEAlarmClockReminder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEAlarmClockReminder.m; sourceTree = ""; }; - C139ACB41C00046D00B0518F /* PHEBolusWizardBolusEstimate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEBolusWizardBolusEstimate.h; sourceTree = ""; }; - C139ACB51C00046D00B0518F /* PHEBolusWizardBolusEstimate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEBolusWizardBolusEstimate.m; sourceTree = ""; }; - C139ACB61C00046D00B0518F /* PHEJournalEntryPumpLowBattery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEJournalEntryPumpLowBattery.h; sourceTree = ""; }; - C139ACB71C00046D00B0518F /* PHEJournalEntryPumpLowBattery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEJournalEntryPumpLowBattery.m; sourceTree = ""; }; - C139ACB81C00046D00B0518F /* PHEModel522ResultTotals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEModel522ResultTotals.h; sourceTree = ""; }; - C139ACB91C00046D00B0518F /* PHEModel522ResultTotals.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEModel522ResultTotals.m; sourceTree = ""; }; - C13DB3A31B1583E900121E02 /* MessageBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageBase.h; sourceTree = ""; }; - C13DB3A41B1583E900121E02 /* MessageBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageBase.m; sourceTree = ""; }; - C14AA3391B1A2FB100299A55 /* MeterMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeterMessage.h; sourceTree = ""; }; - C14AA33A1B1A2FB100299A55 /* MeterMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MeterMessage.m; sourceTree = ""; }; - C152C19A1C3875EA0009B4B8 /* GetPacketCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPacketCmd.h; sourceTree = ""; }; - C152C19B1C3875EA0009B4B8 /* GetPacketCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GetPacketCmd.m; sourceTree = ""; }; - C152C19D1C38B5A30009B4B8 /* DeviceLinkMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceLinkMessage.h; sourceTree = ""; }; - C152C19E1C38B5A30009B4B8 /* DeviceLinkMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceLinkMessage.m; sourceTree = ""; }; - C152C1A01C38B8850009B4B8 /* FindDeviceMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FindDeviceMessage.h; sourceTree = ""; }; - C152C1A11C38B8850009B4B8 /* FindDeviceMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FindDeviceMessage.m; sourceTree = ""; }; - C152C1A31C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeOtherDeviceID.h; sourceTree = ""; }; - C152C1A41C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeOtherDeviceID.m; sourceTree = ""; }; - C152C1A61C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEChangeWatchdogMarriageProfile.h; sourceTree = ""; }; - C152C1A71C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEChangeWatchdogMarriageProfile.m; sourceTree = ""; }; - C152C1A91C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PHEDeleteOtherDeviceID.h; sourceTree = ""; }; - C152C1AA1C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PHEDeleteOtherDeviceID.m; sourceTree = ""; }; - C1743CDD199D374500ED623E /* PumpStatusMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PumpStatusMessage.h; sourceTree = ""; }; - C1743CDE199D374500ED623E /* PumpStatusMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PumpStatusMessage.m; 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 = ""; }; + C14C8A7F1C9CFBEE000F72C5 /* NightscoutPumpEventsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutPumpEventsTests.swift; sourceTree = ""; }; + C14D2B041C9F5D5800C98E4C /* TempBasalDurationPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalDurationPumpEvent.swift; sourceTree = ""; }; + C14D2B081C9F5EDA00C98E4C /* ChangeTempBasalTypePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTempBasalTypePumpEvent.swift; sourceTree = ""; }; + C1711A551C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonPressCarelinkMessageBody.swift; sourceTree = ""; }; + C1711A591C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetPumpModelCarelinkMessageBody.swift; sourceTree = ""; }; + C1711A5B1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBatteryCarelinkMessageBody.swift; sourceTree = ""; }; + C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetHistoryPageCarelinkMessageBody.swift; sourceTree = ""; }; C174F26919EB824D00398C72 /* ISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601DateFormatter.h; sourceTree = ""; }; - C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISO8601DateFormatter.m; sourceTree = ""; }; - C1A47EBD1B117DE900756B99 /* NightScoutUploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NightScoutUploader.h; sourceTree = ""; }; - C1A47EBE1B117DE900756B99 /* NightScoutUploader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NightScoutUploader.m; sourceTree = ""; }; - C1A47EC01B1190D800756B99 /* NSString+Hashes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Hashes.h"; sourceTree = ""; }; - C1A47EC11B1190D800756B99 /* NSString+Hashes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Hashes.m"; sourceTree = ""; }; + C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ISO8601DateFormatter.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + C1842BBA1C8E184300DB42AC /* PumpModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpModel.swift; sourceTree = ""; }; + C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEvent.swift; sourceTree = ""; }; + C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpEventType.swift; sourceTree = ""; }; + C1842BC01C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = UnabsorbedInsulinPumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + C1842BC21C8E931E00DB42AC /* BolusNormalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BolusNormalPumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + C1842BC41C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasalProfileStartPumpEvent.swift; sourceTree = ""; }; + C1842BC61C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalBGForPHPumpEvent.swift; sourceTree = ""; }; + C1842BC81C8F968B00DB42AC /* BGReceivedPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGReceivedPumpEvent.swift; sourceTree = ""; }; + C1842BCA1C8F9A7200DB42AC /* RewindPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RewindPumpEvent.swift; sourceTree = ""; }; + C1842BCC1C8F9BBD00DB42AC /* PrimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PrimePumpEvent.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + C1842BCE1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpAlarmPumpEvent.swift; sourceTree = ""; }; + C1842BD01C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlarmClockReminderPumpEvent.swift; sourceTree = ""; }; + C1842BD21C8FA45100DB42AC /* SuspendPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuspendPumpEvent.swift; sourceTree = ""; }; + C1842BD31C8FA45100DB42AC /* ResumePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResumePumpEvent.swift; sourceTree = ""; }; + C1842BD41C8FA45100DB42AC /* ResultDailyTotalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultDailyTotalPumpEvent.swift; sourceTree = ""; }; + C1842BD51C8FA45100DB42AC /* Model522ResultTotalsPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Model522ResultTotalsPumpEvent.swift; sourceTree = ""; }; + C1842BD61C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryPumpLowReservoirPumpEvent.swift; sourceTree = ""; }; + C1842BD71C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryPumpLowBatteryPumpEvent.swift; sourceTree = ""; }; + C1842BD81C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JournalEntryExerciseMarkerPumpEvent.swift; sourceTree = ""; }; + C1842BD91C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableDisableRemotePumpEvent.swift; sourceTree = ""; }; + C1842BDA1C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteOtherDeviceIDPumpEvent.swift; sourceTree = ""; }; + C1842BDB1C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteBolusReminderTimePumpEvent.swift; sourceTree = ""; }; + C1842BDC1C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteAlarmClockTimePumpEvent.swift; sourceTree = ""; }; + C1842BDD1C8FA45100DB42AC /* ClearAlarmPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClearAlarmPumpEvent.swift; sourceTree = ""; }; + C1842BDE1C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeWatchdogMarriageProfilePumpEvent.swift; sourceTree = ""; }; + C1842BDF1C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeWatchdogEnablePumpEvent.swift; sourceTree = ""; }; + C1842BE01C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeVariableBolusPumpEvent.swift; sourceTree = ""; }; + C1842BE11C8FA45100DB42AC /* ChangeTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimePumpEvent.swift; sourceTree = ""; }; + C1842BE21C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTimeFormatPumpEvent.swift; sourceTree = ""; }; + C1842BE31C8FA45100DB42AC /* TempBasalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TempBasalPumpEvent.swift; sourceTree = ""; }; + C1842BE41C8FA45100DB42AC /* ChangeSensorSetup2PumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeSensorSetup2PumpEvent.swift; sourceTree = ""; }; + C1842BE51C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeSensorRateOfChangeAlertSetupPumpEvent.swift; sourceTree = ""; }; + C1842BE61C8FA45100DB42AC /* ChangeReservoirWarningTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeReservoirWarningTimePumpEvent.swift; sourceTree = ""; }; + C1842BE71C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeParadigmLinkIDPumpEvent.swift; sourceTree = ""; }; + C1842BE81C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeOtherDeviceIDPumpEvent.swift; sourceTree = ""; }; + C1842BE91C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBolusPumpEvent.swift; sourceTree = ""; }; + C1842BEA1C8FA45100DB42AC /* ChangeMaxBasalPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeMaxBasalPumpEvent.swift; sourceTree = ""; }; + C1842BEB1C8FA45100DB42AC /* ChangeChildBlockEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeChildBlockEnablePumpEvent.swift; sourceTree = ""; }; + C1842BEC1C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeCarbUnitsPumpEvent.swift; sourceTree = ""; }; + C1842BED1C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeCaptureEventEnablePumpEvent.swift; sourceTree = ""; }; + C1842BEE1C8FA45100DB42AC /* ChangeBolusWizardSetupPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusWizardSetupPumpEvent.swift; sourceTree = ""; }; + C1842BEF1C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusScrollStepSizePumpEvent.swift; sourceTree = ""; }; + C1842BF01C8FA45100DB42AC /* ChangeBolusReminderTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusReminderTimePumpEvent.swift; sourceTree = ""; }; + C1842BF11C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBolusReminderEnablePumpEvent.swift; sourceTree = ""; }; + C1842BF21C8FA45100DB42AC /* ChangeBGReminderOffsetPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBGReminderOffsetPumpEvent.swift; sourceTree = ""; }; + C1842BF31C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBGReminderEnablePumpEvent.swift; sourceTree = ""; }; + C1842BF41C8FA45100DB42AC /* ChangeBasalProfilePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBasalProfilePumpEvent.swift; sourceTree = ""; }; + C1842BF51C8FA45100DB42AC /* ChangeBasalProfilePatternPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeBasalProfilePatternPumpEvent.swift; sourceTree = ""; }; + C1842BF61C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAudioBolusPumpEvent.swift; sourceTree = ""; }; + C1842BF71C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAlarmNotifyModePumpEvent.swift; sourceTree = ""; }; + C1842BF81C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAlarmClockTimePumpEvent.swift; sourceTree = ""; }; + C1842BF91C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAlarmClockEnablePumpEvent.swift; sourceTree = ""; }; + C1842BFA1C8FA45100DB42AC /* BatteryPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatteryPumpEvent.swift; sourceTree = ""; }; + C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlarmSensorPumpEvent.swift; sourceTree = ""; }; + C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutUploader.swift; sourceTree = ""; }; + C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutPumpEvents.swift; sourceTree = ""; }; + C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NightscoutTreatment.swift; sourceTree = ""; }; + C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGCheckNightscoutTreatment.swift; sourceTree = ""; }; + C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MealBolusNightscoutTreatment.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + C1890B5E1C94B9D9005F7474 /* PumpChatViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpChatViewController.swift; sourceTree = ""; }; + C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BolusNightscoutTreatment.swift; sourceTree = ""; }; C1AA39921AB6804000BC9E33 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; - C1D2B67C1C2FAD0100DB4AEA /* CmdBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CmdBase.h; sourceTree = ""; }; - C1D2B67D1C2FAD0100DB4AEA /* CmdBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CmdBase.m; sourceTree = ""; }; - C1D2B67F1C30AAE000DB4AEA /* SendPacketCmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SendPacketCmd.h; sourceTree = ""; }; - C1D2B6801C30AAE000DB4AEA /* SendPacketCmd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SendPacketCmd.m; sourceTree = ""; }; + C1C3578E1C927303009BDD4F /* MeterMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MeterMessage.swift; path = Messages/MeterMessage.swift; sourceTree = ""; }; + C1C357901C92733A009BDD4F /* MeterMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MeterMessageTests.swift; path = Messages/MeterMessageTests.swift; sourceTree = ""; }; + C1C357931C929529009BDD4F /* StringCrypto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringCrypto.swift; sourceTree = ""; }; C1E535E81991E36700C2AC49 /* NSData+Conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Conversion.h"; sourceTree = ""; }; C1E535E91991E36700C2AC49 /* NSData+Conversion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Conversion.m"; sourceTree = ""; }; - C1E535EB1991E49600C2AC49 /* RileyLinkBLEManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RileyLinkBLEManager.h; sourceTree = ""; }; - C1E535EC1991E49600C2AC49 /* RileyLinkBLEManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RileyLinkBLEManager.m; sourceTree = ""; }; - C1E535EE1991E6A200C2AC49 /* MinimedPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MinimedPacket.h; sourceTree = ""; }; - C1E535EF1991E6A200C2AC49 /* MinimedPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MinimedPacket.m; sourceTree = ""; }; + C1EAD6AE1C826B6D006DBA60 /* AlertType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertType.swift; sourceTree = ""; }; + C1EAD6AF1C826B6D006DBA60 /* MessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageBody.swift; sourceTree = ""; }; + C1EAD6B01C826B6D006DBA60 /* MessageType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MessageType.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + C1EAD6B11C826B6D006DBA60 /* PacketType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacketType.swift; sourceTree = ""; }; + C1EAD6B21C826B6D006DBA60 /* PumpMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpMessage.swift; sourceTree = ""; }; + C1EAD6B91C826B92006DBA60 /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Int.swift; sourceTree = ""; }; + C1EAD6BA1C826B92006DBA60 /* NSData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSData.swift; sourceTree = ""; }; + C1EAD6BB1C826B92006DBA60 /* NSDateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateComponents.swift; sourceTree = ""; }; + C1EAD6BD1C826B92006DBA60 /* CarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarelinkMessageBody.swift; sourceTree = ""; }; + C1EAD6BE1C826B92006DBA60 /* MySentryAckMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAckMessageBody.swift; sourceTree = ""; }; + C1EAD6BF1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAlertClearedMessageBody.swift; sourceTree = ""; }; + C1EAD6C01C826B92006DBA60 /* MySentryAlertMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryAlertMessageBody.swift; sourceTree = ""; }; + C1EAD6C11C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryPumpStatusMessageBody.swift; sourceTree = ""; }; + C1EAD6C21C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PowerOnCarelinkMessageBody.swift; sourceTree = ""; }; + C1EAD6C31C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadSettingsCarelinkMessageBody.swift; sourceTree = ""; }; + C1EAD6C41C826B92006DBA60 /* UnknownMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnknownMessageBody.swift; sourceTree = ""; }; + C1EAD6D11C826C43006DBA60 /* MinimedKitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimedKitTests.swift; sourceTree = ""; }; + C1EAD6D21C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MySentryPumpStatusMessageBodyTests.swift; path = ../MySentryPumpStatusMessageBodyTests.swift; sourceTree = ""; }; + C1EAD6D31C826C43006DBA60 /* NSDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDataTests.swift; sourceTree = ""; }; + C1EAD6D41C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReadSettingsCarelinkMessageBodyTests.swift; path = ../ReadSettingsCarelinkMessageBodyTests.swift; sourceTree = ""; }; + C1EAD6D91C829104006DBA60 /* RFTools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RFTools.swift; sourceTree = ""; }; + C1EAD6DB1C82A4AB006DBA60 /* RFToolsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RFToolsTests.swift; sourceTree = ""; }; + C1EAD6DD1C82B78C006DBA60 /* CRC8.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC8.swift; sourceTree = ""; }; + C1EAD6DF1C82B910006DBA60 /* CRC8Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC8Tests.swift; sourceTree = ""; }; + C1EAD6E11C82BA7A006DBA60 /* CRC16.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16.swift; sourceTree = ""; }; + C1EAD6E31C82BA87006DBA60 /* CRC16Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CRC16Tests.swift; sourceTree = ""; }; + C1EAD6E51C83966D006DBA60 /* PumpMessageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PumpMessageTests.swift; sourceTree = ""; }; + C1EAD6EA1C8409A9006DBA60 /* RileyLink-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RileyLink-Bridging-Header.h"; sourceTree = ""; }; + C1EB955C1C887FE5002517DF /* HistoryPage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryPage.swift; sourceTree = ""; }; C1EF58831B3E5DA4001C8C80 /* ConfigureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigureViewController.h; sourceTree = ""; }; C1EF58841B3E5DA4001C8C80 /* ConfigureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConfigureViewController.m; sourceTree = ""; }; C1EF58861B3F93FE001C8C80 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = ""; }; C1EF58871B3F93FE001C8C80 /* Config.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Config.m; sourceTree = ""; }; - C1EF588A1B3F9748001C8C80 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = ""; }; - C1EF588B1B3F9748001C8C80 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = ""; }; + C1EF588A1B3F9748001C8C80 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = SWRevealViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + C1EF588B1B3F9748001C8C80 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SWRevealViewController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; C1EF58951B3FA462001C8C80 /* MenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuController.h; sourceTree = ""; }; C1EF58961B3FA462001C8C80 /* MenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuController.m; sourceTree = ""; }; C1EF589C1B3FBFE7001C8C80 /* MainAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainAppViewController.h; sourceTree = ""; }; @@ -368,13 +522,64 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 430D64C71CB855AB00FCA750 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43CA93251CB8BB33000026B5 /* CoreBluetooth.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 430D64D11CB855AB00FCA750 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 430D64D51CB855AB00FCA750 /* RileyLinkBLEKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FAA1CB9F7630038B7F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43722FCB1CB9F7DB0038B7F2 /* MinimedKit.framework in Frameworks */, + 43722FCC1CB9F7DB0038B7F2 /* RileyLinkBLEKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FB41CB9F7640038B7F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43722FB81CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BBD1C8269D500378342 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BC71C8269D500378342 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C10D9BCB1C8269D500378342 /* MinimedKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; C12EA234198B436800309FA4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 430D64E01CB855AB00FCA750 /* RileyLinkBLEKit.framework in Frameworks */, C12EA23D198B436800309FA4 /* CoreGraphics.framework in Frameworks */, C12EA23F198B436800309FA4 /* UIKit.framework in Frameworks */, + 43722FC31CB9F7640038B7F2 /* RileyLinkKit.framework in Frameworks */, C12EA23B198B436800309FA4 /* Foundation.framework in Frameworks */, + C10D9BD61C8269D500378342 /* MinimedKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,17 +597,128 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - C11F993A1BC405AA0013158C /* Pump */ = { + 430D64CC1CB855AB00FCA750 /* RileyLinkBLEKit */ = { + isa = PBXGroup; + children = ( + 430D64F01CB89FC000FCA750 /* CmdBase.h */, + 430D64F11CB89FC000FCA750 /* CmdBase.m */, + 430D64F21CB89FC000FCA750 /* GetPacketCmd.h */, + 430D64F31CB89FC000FCA750 /* GetPacketCmd.m */, + 430D64F41CB89FC000FCA750 /* GetVersionCmd.h */, + 430D64F51CB89FC000FCA750 /* GetVersionCmd.m */, + 430D64CF1CB855AB00FCA750 /* Info.plist */, + 430D64F61CB89FC000FCA750 /* ReceivingPacketCmd.h */, + 430D64F71CB89FC000FCA750 /* ReceivingPacketCmd.m */, + 430D64F81CB89FC000FCA750 /* RFPacket.h */, + 430D64F91CB89FC000FCA750 /* RFPacket.m */, + 430D64E81CB85A4300FCA750 /* RileyLinkBLEDevice.h */, + 430D64E91CB85A4300FCA750 /* RileyLinkBLEDevice.m */, + 430D64CD1CB855AB00FCA750 /* RileyLinkBLEKit.h */, + 430D64EA1CB85A4300FCA750 /* RileyLinkBLEManager.h */, + 430D64EB1CB85A4300FCA750 /* RileyLinkBLEManager.m */, + 430D64FA1CB89FC000FCA750 /* SendAndListenCmd.h */, + 430D64FB1CB89FC000FCA750 /* SendAndListenCmd.m */, + 430D64FC1CB89FC000FCA750 /* SendPacketCmd.h */, + 430D64FD1CB89FC000FCA750 /* SendPacketCmd.m */, + 430D64FE1CB89FC000FCA750 /* UpdateRegisterCmd.h */, + 430D64FF1CB89FC000FCA750 /* UpdateRegisterCmd.m */, + ); + path = RileyLinkBLEKit; + sourceTree = ""; + }; + 430D64DA1CB855AB00FCA750 /* RileyLinkBLEKitTests */ = { + isa = PBXGroup; + children = ( + 430D64DB1CB855AB00FCA750 /* RileyLinkBLEKitTests.m */, + 430D64DD1CB855AB00FCA750 /* Info.plist */, + ); + path = RileyLinkBLEKitTests; + sourceTree = ""; + }; + 43722FAF1CB9F7630038B7F2 /* RileyLinkKit */ = { + isa = PBXGroup; + children = ( + 43722FB01CB9F7640038B7F2 /* RileyLinkKit.h */, + 43722FB21CB9F7640038B7F2 /* Info.plist */, + 434AB0911CBA0DF600422F4A /* Either.swift */, + 434AB09D1CBA28F100422F4A /* NSTimeInterval.swift */, + 434AB0921CBA0DF600422F4A /* PumpOps.swift */, + 434AB0931CBA0DF600422F4A /* PumpOpsSynchronous.swift */, + 434AB0941CBA0DF600422F4A /* PumpState.swift */, + 434AB0C51CBCB41500422F4A /* RileyLinkDevice.swift */, + 434AB0BD1CBB4E3200422F4A /* RileyLinkDeviceManager.swift */, + ); + path = RileyLinkKit; + sourceTree = ""; + }; + 43722FBD1CB9F7640038B7F2 /* RileyLinkKitTests */ = { isa = PBXGroup; children = ( - C11F993B1BC406970013158C /* PumpState.h */, - C11F993C1BC406970013158C /* PumpState.m */, - C10EAAA11C5B3A0800B0838F /* PumpOpsSynchronous.h */, - C10EAAA21C5B3A0800B0838F /* PumpOpsSynchronous.m */, - C10EAAA41C5C507E00B0838F /* PumpOps.h */, - C10EAAA51C5C507E00B0838F /* PumpOps.m */, - ); - name = Pump; + 43722FBE1CB9F7640038B7F2 /* RileyLinkKitTests.swift */, + 43722FC01CB9F7640038B7F2 /* Info.plist */, + ); + path = RileyLinkKitTests; + sourceTree = ""; + }; + C10D9BC21C8269D500378342 /* MinimedKit */ = { + isa = PBXGroup; + children = ( + C10D9BC31C8269D500378342 /* MinimedKit.h */, + C10D9BC51C8269D500378342 /* Info.plist */, + C1EAD6AE1C826B6D006DBA60 /* AlertType.swift */, + C1EAD6DD1C82B78C006DBA60 /* CRC8.swift */, + C1EAD6E11C82BA7A006DBA60 /* CRC16.swift */, + C1EB955C1C887FE5002517DF /* HistoryPage.swift */, + C1EAD6AF1C826B6D006DBA60 /* MessageBody.swift */, + C1EAD6B01C826B6D006DBA60 /* MessageType.swift */, + C1C3578E1C927303009BDD4F /* MeterMessage.swift */, + C1EAD6B11C826B6D006DBA60 /* PacketType.swift */, + C1842BBE1C8E855A00DB42AC /* PumpEventType.swift */, + C1EAD6B21C826B6D006DBA60 /* PumpMessage.swift */, + C1842BBA1C8E184300DB42AC /* PumpModel.swift */, + C1EAD6D91C829104006DBA60 /* RFTools.swift */, + C12198AE1C8F46FF00BC374C /* TimeFormat.swift */, + C1EAD6B81C826B92006DBA60 /* Extensions */, + C1EAD6BC1C826B92006DBA60 /* Messages */, + C1842BB91C8E15C600DB42AC /* PumpEvents */, + ); + path = MinimedKit; + sourceTree = ""; + }; + C10D9BD01C8269D500378342 /* MinimedKitTests */ = { + isa = PBXGroup; + children = ( + C10D9BD31C8269D500378342 /* Info.plist */, + C1EAD6DF1C82B910006DBA60 /* CRC8Tests.swift */, + C1EAD6E31C82BA87006DBA60 /* CRC16Tests.swift */, + C12198621C8DF4C800BC374C /* HistoryPageTests.swift */, + C1C357901C92733A009BDD4F /* MeterMessageTests.swift */, + C1EAD6D11C826C43006DBA60 /* MinimedKitTests.swift */, + C1EAD6D31C826C43006DBA60 /* NSDataTests.swift */, + 43FF221B1CB9B9DE00024F30 /* NSDateComponents.swift */, + C1EAD6E51C83966D006DBA60 /* PumpMessageTests.swift */, + C1EAD6DB1C82A4AB006DBA60 /* RFToolsTests.swift */, + C12198B01C8F6DD800BC374C /* TimeFormatTests.swift */, + C121985D1C8DE72500BC374C /* Messages */, + ); + path = MinimedKitTests; + sourceTree = ""; + }; + C121985D1C8DE72500BC374C /* Messages */ = { + isa = PBXGroup; + children = ( + C12198A21C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift */, + 43CA93341CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift */, + 43CA93321CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift */, + C12198601C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift */, + C121985E1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift */, + C14303191C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift */, + C14303171C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift */, + C1EAD6D21C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift */, + C1EAD6D41C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift */, + 43CA93301CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift */, + ); + path = Messages; sourceTree = ""; }; C12616391B67CB9C001FAD87 /* TableViewCells */ = { @@ -443,23 +759,17 @@ path = TPKeyboardAvoiding; sourceTree = ""; }; - C12964E91B1581D200516761 /* MinimedRF */ = { - isa = PBXGroup; - children = ( - C1E535EE1991E6A200C2AC49 /* MinimedPacket.h */, - C1E535EF1991E6A200C2AC49 /* MinimedPacket.m */, - C137A38E1C08114600569851 /* CRC8.h */, - C137A38F1C08114600569851 /* CRC8.m */, - C137A3911C08142E00569851 /* CRC16.h */, - C137A3921C08142E00569851 /* CRC16.m */, - ); - name = MinimedRF; - sourceTree = ""; - }; C12EA22E198B436800309FA4 = { isa = PBXGroup; children = ( C12EA240198B436800309FA4 /* RileyLink */, + C12EA259198B436900309FA4 /* RileyLinkTests */, + C10D9BC21C8269D500378342 /* MinimedKit */, + C10D9BD01C8269D500378342 /* MinimedKitTests */, + 430D64CC1CB855AB00FCA750 /* RileyLinkBLEKit */, + 430D64DA1CB855AB00FCA750 /* RileyLinkBLEKitTests */, + 43722FAF1CB9F7630038B7F2 /* RileyLinkKit */, + 43722FBD1CB9F7640038B7F2 /* RileyLinkKitTests */, C12EA239198B436800309FA4 /* Frameworks */, C12EA238198B436800309FA4 /* Products */, ); @@ -470,6 +780,12 @@ children = ( C12EA237198B436800309FA4 /* RileyLink.app */, C12EA252198B436800309FA4 /* RileyLinkTests.xctest */, + C10D9BC11C8269D500378342 /* MinimedKit.framework */, + C10D9BCA1C8269D500378342 /* MinimedKitTests.xctest */, + 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */, + 430D64D41CB855AB00FCA750 /* RileyLinkBLEKitTests.xctest */, + 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */, + 43722FB71CB9F7640038B7F2 /* RileyLinkKitTests.xctest */, ); name = Products; sourceTree = ""; @@ -477,6 +793,7 @@ C12EA239198B436800309FA4 /* Frameworks */ = { isa = PBXGroup; children = ( + 43CA93241CB8BB33000026B5 /* CoreBluetooth.framework */, C12616431B685F0A001FAD87 /* CoreData.framework */, C12EA23A198B436800309FA4 /* Foundation.framework */, C12EA23C198B436800309FA4 /* CoreGraphics.framework */, @@ -489,31 +806,26 @@ C12EA240198B436800309FA4 /* RileyLink */ = { isa = PBXGroup; children = ( - C11F993A1BC405AA0013158C /* Pump */, - C126165E1B76E8DC001FAD87 /* TPKeyboardAvoiding */, + C1AA398B1AB67F6A00BC9E33 /* Categories */, C12616451B685F35001FAD87 /* CoreData */, + C1EF589B1B3FBA5D001C8C80 /* NightscoutUploadKit */, + C12EA241198B436800309FA4 /* Supporting Files */, + C1EF58891B3F9730001C8C80 /* SWRevealViewController */, C12616391B67CB9C001FAD87 /* TableViewCells */, + C126165E1B76E8DC001FAD87 /* TPKeyboardAvoiding */, C1EF589A1B3FBA32001C8C80 /* ViewControllers */, - C1EF589B1B3FBA5D001C8C80 /* Nightscout */, - C1EF58981B3FA7D1001C8C80 /* RileyLink */, - C1EF58891B3F9730001C8C80 /* SWRevealViewController */, - C14B4EDF1B85A31F00776647 /* MinimedProtocol */, - C12964E91B1581D200516761 /* MinimedRF */, - C1AA398B1AB67F6A00BC9E33 /* Categories */, + 43462E8A1CCB06F500F958A8 /* AppDelegate.swift */, + C1EF58861B3F93FE001C8C80 /* Config.h */, + C1EF58871B3F93FE001C8C80 /* Config.m */, + C12EA24C198B436800309FA4 /* Images.xcassets */, C174F26919EB824D00398C72 /* ISO8601DateFormatter.h */, C174F26A19EB824D00398C72 /* ISO8601DateFormatter.m */, - C12EA249198B436800309FA4 /* AppDelegate.h */, - C12EA24A198B436800309FA4 /* AppDelegate.m */, 43EC9DCA1B786C6200DB0D18 /* LaunchScreen.xib */, - C12EA269198B442100309FA4 /* Storyboard.storyboard */, - C12EA24C198B436800309FA4 /* Images.xcassets */, - C12EA241198B436800309FA4 /* Supporting Files */, - C1271B061A9A34E900B7C949 /* Log.m */, C1271B081A9A350400B7C949 /* Log.h */, - C1EF58861B3F93FE001C8C80 /* Config.h */, - C1EF58871B3F93FE001C8C80 /* Config.m */, + C1271B061A9A34E900B7C949 /* Log.m */, C139AC221BFD84B500B0518F /* RuntimeUtils.h */, C139AC231BFD84B500B0518F /* RuntimeUtils.m */, + C12EA269198B442100309FA4 /* Storyboard.storyboard */, ); path = RileyLink; sourceTree = ""; @@ -521,11 +833,9 @@ C12EA241198B436800309FA4 /* Supporting Files */ = { isa = PBXGroup; children = ( + C1EAD6EA1C8409A9006DBA60 /* RileyLink-Bridging-Header.h */, C12EA242198B436800309FA4 /* RileyLink-Info.plist */, C12EA243198B436800309FA4 /* InfoPlist.strings */, - C12EA246198B436800309FA4 /* main.m */, - C12EA248198B436800309FA4 /* RileyLink-Prefix.pch */, - C12EA259198B436900309FA4 /* RileyLinkTests */, ); name = "Supporting Files"; sourceTree = ""; @@ -534,6 +844,7 @@ isa = PBXGroup; children = ( C12EA25F198B436900309FA4 /* RileyLinkTests.m */, + C14C8A7F1C9CFBEE000F72C5 /* NightscoutPumpEventsTests.swift */, C12EA25A198B436900309FA4 /* Supporting Files */, ); path = RileyLinkTests; @@ -548,139 +859,75 @@ name = "Supporting Files"; sourceTree = ""; }; - C139AB8E1BFD6A6000B0518F /* PumpHistoryEvents */ = { + C12FB2741CC588FB00879B80 /* Treatments */ = { isa = PBXGroup; children = ( - C139ACB21C00046D00B0518F /* PHEAlarmClockReminder.h */, - C139ACB31C00046D00B0518F /* PHEAlarmClockReminder.m */, - C139AC251BFD8CF800B0518F /* PHEAlarmPump.h */, - C139AC261BFD8CF800B0518F /* PHEAlarmPump.m */, - C139AC271BFD8CF800B0518F /* PHEAlarmSensor.h */, - C139AC281BFD8CF800B0518F /* PHEAlarmSensor.m */, - C139AC291BFD8CF800B0518F /* PHEBasalProfileStart.h */, - C139AC2A1BFD8CF800B0518F /* PHEBasalProfileStart.m */, - C139AC2B1BFD8CF800B0518F /* PHEBattery.h */, - C139AC2C1BFD8CF800B0518F /* PHEBattery.m */, - C139AC2D1BFD8CF800B0518F /* PHEBgReceived.h */, - C139AC2E1BFD8CF800B0518F /* PHEBgReceived.m */, - C139AC2F1BFD8CF800B0518F /* PHEBolusNormal.h */, - C139AC301BFD8CF800B0518F /* PHEBolusNormal.m */, - C139ACB41C00046D00B0518F /* PHEBolusWizardBolusEstimate.h */, - C139ACB51C00046D00B0518F /* PHEBolusWizardBolusEstimate.m */, - C139AC331BFD8CF800B0518F /* PHECalBGForPH.h */, - C139AC341BFD8CF800B0518F /* PHECalBGForPH.m */, - C139AC351BFD8CF800B0518F /* PHEChangeAlarmClockEnable.h */, - C139AC361BFD8CF800B0518F /* PHEChangeAlarmClockEnable.m */, - C139AC371BFD8CF800B0518F /* PHEChangeAlarmClockTime.h */, - C139AC381BFD8CF800B0518F /* PHEChangeAlarmClockTime.m */, - C139AC391BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.h */, - C139AC3A1BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.m */, - C139AC3B1BFD8CF800B0518F /* PHEChangeAudioBolus.h */, - C139AC3C1BFD8CF800B0518F /* PHEChangeAudioBolus.m */, - C139AC3D1BFD8CF800B0518F /* PHEChangeBasalProfile.h */, - C139AC3E1BFD8CF800B0518F /* PHEChangeBasalProfile.m */, - C139AC3F1BFD8CF800B0518F /* PHEChangeBasalProfilePattern.h */, - C139AC401BFD8CF800B0518F /* PHEChangeBasalProfilePattern.m */, - C139AC411BFD8CF800B0518F /* PHEChangeBGReminderEnable.h */, - C139AC421BFD8CF800B0518F /* PHEChangeBGReminderEnable.m */, - C139AC431BFD8CF800B0518F /* PHEChangeBGReminderOffset.h */, - C139AC441BFD8CF800B0518F /* PHEChangeBGReminderOffset.m */, - C139AC451BFD8CF800B0518F /* PHEChangeBolusReminderEnable.h */, - C139AC461BFD8CF800B0518F /* PHEChangeBolusReminderEnable.m */, - C139AC471BFD8CF800B0518F /* PHEChangeBolusReminderTime.h */, - C139AC481BFD8CF800B0518F /* PHEChangeBolusReminderTime.m */, - C139AC491BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.h */, - C139AC4A1BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.m */, - C139AC4B1BFD8CF800B0518F /* PHEChangeBolusWizardSetup.h */, - C139AC4C1BFD8CF800B0518F /* PHEChangeBolusWizardSetup.m */, - C139AC4D1BFD8CF800B0518F /* PHEChangeCaptureEventEnable.h */, - C139AC4E1BFD8CF800B0518F /* PHEChangeCaptureEventEnable.m */, - C139AC4F1BFD8CF800B0518F /* PHEChangeCarbUnits.h */, - C139AC501BFD8CF800B0518F /* PHEChangeCarbUnits.m */, - C139AC511BFD8CF800B0518F /* PHEChangeChildBlockEnable.h */, - C139AC521BFD8CF800B0518F /* PHEChangeChildBlockEnable.m */, - C139AC531BFD8CF800B0518F /* PHEChangeMaxBolus.h */, - C139AC541BFD8CF800B0518F /* PHEChangeMaxBolus.m */, - C139AC551BFD8CF800B0518F /* PHEChangeParadigmLinkID.h */, - C139AC561BFD8CF800B0518F /* PHEChangeParadigmLinkID.m */, - C139AC571BFD8CF800B0518F /* PHEChangeReservoirWarningTime.h */, - C139AC581BFD8CF800B0518F /* PHEChangeReservoirWarningTime.m */, - C139AC591BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.h */, - C139AC5A1BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.m */, - C139AC5B1BFD8CF800B0518F /* PHEChangeSensorSetup2.h */, - C139AC5C1BFD8CF800B0518F /* PHEChangeSensorSetup2.m */, - C139AC5D1BFD8CF800B0518F /* PHEChangeTempBasalPercent.h */, - C139AC5E1BFD8CF800B0518F /* PHEChangeTempBasalPercent.m */, - C139AC5F1BFD8CF800B0518F /* PHEChangeTime.h */, - C139AC601BFD8CF800B0518F /* PHEChangeTime.m */, - C139AC611BFD8CF800B0518F /* PHEChangeTimeFormat.h */, - C139AC621BFD8CF800B0518F /* PHEChangeTimeFormat.m */, - C139AC631BFD8CF800B0518F /* PHEChangeVariableBolus.h */, - C139AC641BFD8CF800B0518F /* PHEChangeVariableBolus.m */, - C139AC651BFD8CF800B0518F /* PHEChangeWatchdogEnable.h */, - C139AC661BFD8CF800B0518F /* PHEChangeWatchdogEnable.m */, - C139AC671BFD8CF800B0518F /* PHEClearAlarm.h */, - C139AC681BFD8CF800B0518F /* PHEClearAlarm.m */, - C139AC691BFD8CF800B0518F /* PHEDeleteAlarmClockTime.h */, - C139AC6A1BFD8CF800B0518F /* PHEDeleteAlarmClockTime.m */, - C139AC6B1BFD8CF800B0518F /* PHEDeleteBolusReminderTime.h */, - C139AC6C1BFD8CF800B0518F /* PHEDeleteBolusReminderTime.m */, - C139AC6D1BFD8CF800B0518F /* PHEEnableDisableRemote.h */, - C139AC6E1BFD8CF800B0518F /* PHEEnableDisableRemote.m */, - C139AC6F1BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.h */, - C139AC701BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.m */, - C139ACB61C00046D00B0518F /* PHEJournalEntryPumpLowBattery.h */, - C139ACB71C00046D00B0518F /* PHEJournalEntryPumpLowBattery.m */, - C139AC711BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.h */, - C139AC721BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.m */, - C139ACB81C00046D00B0518F /* PHEModel522ResultTotals.h */, - C139ACB91C00046D00B0518F /* PHEModel522ResultTotals.m */, - C139AC731BFD8CF800B0518F /* PHEPrime.h */, - C139AC741BFD8CF800B0518F /* PHEPrime.m */, - C139AC751BFD8CF800B0518F /* PHEResultDailyTotal.h */, - C139AC761BFD8CF800B0518F /* PHEResultDailyTotal.m */, - C139AC771BFD8CF800B0518F /* PHEResume.h */, - C139AC781BFD8CF800B0518F /* PHEResume.m */, - C139AC791BFD8CF800B0518F /* PHERewind.h */, - C139AC7A1BFD8CF800B0518F /* PHERewind.m */, - C139AC7B1BFD8CF800B0518F /* PHESara6E.h */, - C139AC7C1BFD8CF800B0518F /* PHESara6E.m */, - C139AC7D1BFD8CF800B0518F /* PHESuspend.h */, - C139AC7E1BFD8CF800B0518F /* PHESuspend.m */, - C139AC7F1BFD8CF800B0518F /* PHEUnabsorbedInsulin.h */, - C139AC801BFD8CF800B0518F /* PHEUnabsorbedInsulin.m */, - C139AB8F1BFD6A9000B0518F /* PumpHistoryEventBase.h */, - C139AB901BFD6A9000B0518F /* PumpHistoryEventBase.m */, - C152C1A31C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.h */, - C152C1A41C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.m */, - C152C1A61C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.h */, - C152C1A71C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.m */, - C152C1A91C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.h */, - C152C1AA1C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.m */, - ); - path = PumpHistoryEvents; + ); + name = Treatments; sourceTree = ""; }; - C14B4EDF1B85A31F00776647 /* MinimedProtocol */ = { + C1842BB91C8E15C600DB42AC /* PumpEvents */ = { isa = PBXGroup; children = ( - C139AB8E1BFD6A6000B0518F /* PumpHistoryEvents */, - C1743CDD199D374500ED623E /* PumpStatusMessage.h */, - C1743CDE199D374500ED623E /* PumpStatusMessage.m */, - C13DB3A31B1583E900121E02 /* MessageBase.h */, - C13DB3A41B1583E900121E02 /* MessageBase.m */, - C14AA3391B1A2FB100299A55 /* MeterMessage.h */, - C14AA33A1B1A2FB100299A55 /* MeterMessage.m */, - C139AC1F1BFD847F00B0518F /* HistoryPage.h */, - C139AC201BFD847F00B0518F /* HistoryPage.m */, - C139ACAF1BFEDD9E00B0518F /* PumpModel.h */, - C139ACB01BFEDD9E00B0518F /* PumpModel.m */, - C152C19D1C38B5A30009B4B8 /* DeviceLinkMessage.h */, - C152C19E1C38B5A30009B4B8 /* DeviceLinkMessage.m */, - C152C1A01C38B8850009B4B8 /* FindDeviceMessage.h */, - C152C1A11C38B8850009B4B8 /* FindDeviceMessage.m */, - ); - name = MinimedProtocol; + C1842BD01C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift */, + C1842BFB1C8FA45100DB42AC /* AlarmSensorPumpEvent.swift */, + C1842BC41C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift */, + C1842BFA1C8FA45100DB42AC /* BatteryPumpEvent.swift */, + C1842BC81C8F968B00DB42AC /* BGReceivedPumpEvent.swift */, + C1842BC21C8E931E00DB42AC /* BolusNormalPumpEvent.swift */, + C12198B21C8F730700BC374C /* BolusWizardEstimatePumpEvent.swift */, + C1842BC61C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift */, + C1842BF91C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift */, + C1842BF81C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift */, + C1842BF71C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift */, + C1842BF61C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift */, + C1842BF51C8FA45100DB42AC /* ChangeBasalProfilePatternPumpEvent.swift */, + C1842BF41C8FA45100DB42AC /* ChangeBasalProfilePumpEvent.swift */, + C1842BF31C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift */, + C1842BF21C8FA45100DB42AC /* ChangeBGReminderOffsetPumpEvent.swift */, + C1842BF11C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift */, + C1842BF01C8FA45100DB42AC /* ChangeBolusReminderTimePumpEvent.swift */, + C1842BEF1C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift */, + C1842BEE1C8FA45100DB42AC /* ChangeBolusWizardSetupPumpEvent.swift */, + C1842BED1C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift */, + C1842BEC1C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift */, + C1842BEB1C8FA45100DB42AC /* ChangeChildBlockEnablePumpEvent.swift */, + C1842BEA1C8FA45100DB42AC /* ChangeMaxBasalPumpEvent.swift */, + C1842BE91C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift */, + C1842BE81C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift */, + C1842BE71C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift */, + C1842BE61C8FA45100DB42AC /* ChangeReservoirWarningTimePumpEvent.swift */, + C1842BE51C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift */, + C1842BE41C8FA45100DB42AC /* ChangeSensorSetup2PumpEvent.swift */, + C14D2B081C9F5EDA00C98E4C /* ChangeTempBasalTypePumpEvent.swift */, + C1842BE21C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift */, + C1842BE11C8FA45100DB42AC /* ChangeTimePumpEvent.swift */, + C1842BE01C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift */, + C1842BDF1C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift */, + C1842BDE1C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift */, + C1842BDD1C8FA45100DB42AC /* ClearAlarmPumpEvent.swift */, + C1842BDC1C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift */, + C1842BDB1C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift */, + C1842BDA1C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift */, + C1842BD91C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift */, + C1842BD81C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift */, + C1842BD71C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift */, + C1842BD61C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift */, + C1842BD51C8FA45100DB42AC /* Model522ResultTotalsPumpEvent.swift */, + C1842BCC1C8F9BBD00DB42AC /* PrimePumpEvent.swift */, + C1842BCE1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift */, + C1842BBC1C8E7C6E00DB42AC /* PumpEvent.swift */, + C1842BD41C8FA45100DB42AC /* ResultDailyTotalPumpEvent.swift */, + C1842BD31C8FA45100DB42AC /* ResumePumpEvent.swift */, + C1842BCA1C8F9A7200DB42AC /* RewindPumpEvent.swift */, + C12198A81C8F2AF200BC374C /* Sara6EPumpEvent.swift */, + C1842BD21C8FA45100DB42AC /* SuspendPumpEvent.swift */, + C14D2B041C9F5D5800C98E4C /* TempBasalDurationPumpEvent.swift */, + C1842BE31C8FA45100DB42AC /* TempBasalPumpEvent.swift */, + C12198AC1C8F332500BC374C /* TimestampedPumpEvent.swift */, + C1842BC01C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift */, + ); + path = PumpEvents; sourceTree = ""; }; C1AA398B1AB67F6A00BC9E33 /* Categories */ = { @@ -688,44 +935,64 @@ children = ( C1E535E81991E36700C2AC49 /* NSData+Conversion.h */, C1E535E91991E36700C2AC49 /* NSData+Conversion.m */, - C1A47EC01B1190D800756B99 /* NSString+Hashes.h */, - C1A47EC11B1190D800756B99 /* NSString+Hashes.m */, C1AA39921AB6804000BC9E33 /* UIAlertView+Blocks.h */, C1AA39931AB6804000BC9E33 /* UIAlertView+Blocks.m */, ); name = Categories; sourceTree = ""; }; - C1EF58891B3F9730001C8C80 /* SWRevealViewController */ = { + C1C357921C929507009BDD4F /* Extensions */ = { isa = PBXGroup; children = ( - C1EF588A1B3F9748001C8C80 /* SWRevealViewController.m */, - C1EF588B1B3F9748001C8C80 /* SWRevealViewController.h */, + C1C357931C929529009BDD4F /* StringCrypto.swift */, ); - name = SWRevealViewController; + path = Extensions; sourceTree = ""; }; - C1EF58981B3FA7D1001C8C80 /* RileyLink */ = { + C1EAD6B81C826B92006DBA60 /* Extensions */ = { isa = PBXGroup; children = ( - C1E535EB1991E49600C2AC49 /* RileyLinkBLEManager.h */, - C1E535EC1991E49600C2AC49 /* RileyLinkBLEManager.m */, - C126164F1B688D9C001FAD87 /* RileyLinkBLEDevice.h */, - C12616501B688D9C001FAD87 /* RileyLinkBLEDevice.m */, - C1D2B67C1C2FAD0100DB4AEA /* CmdBase.h */, - C1D2B67D1C2FAD0100DB4AEA /* CmdBase.m */, - C126166E1B7790DF001FAD87 /* SendAndListenCmd.h */, - C126166F1B7790DF001FAD87 /* SendAndListenCmd.m */, - C1D2B67F1C30AAE000DB4AEA /* SendPacketCmd.h */, - C1D2B6801C30AAE000DB4AEA /* SendPacketCmd.m */, - C152C19A1C3875EA0009B4B8 /* GetPacketCmd.h */, - C152C19B1C3875EA0009B4B8 /* GetPacketCmd.m */, - C10A62901C55F8E200E635EE /* UpdateRegisterCmd.h */, - C10A62911C55F8E200E635EE /* UpdateRegisterCmd.m */, - C10EAA9B1C5AE9A600B0838F /* GetVersionCmd.h */, - C10EAA9C1C5AE9A600B0838F /* GetVersionCmd.m */, + C1EAD6B91C826B92006DBA60 /* Int.swift */, + C1EAD6BA1C826B92006DBA60 /* NSData.swift */, + C1EAD6BB1C826B92006DBA60 /* NSDateComponents.swift */, ); - name = RileyLink; + path = Extensions; + sourceTree = ""; + }; + C1EAD6BC1C826B92006DBA60 /* Messages */ = { + isa = PBXGroup; + children = ( + C121989E1C8DFC2200BC374C /* BolusCarelinkMessageBody.swift */, + C1711A551C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift */, + C1EAD6BD1C826B92006DBA60 /* CarelinkMessageBody.swift */, + 43CA93281CB8CF22000026B5 /* ChangeTempBasalCarelinkMessageBody.swift */, + 43CA932A1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift */, + C10AB08E1C855F34000F102E /* DeviceLinkMessageBody.swift */, + C10AB08C1C855613000F102E /* FindDeviceMessageBody.swift */, + C1711A5B1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift */, + C1711A5D1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift */, + C1711A591C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift */, + C1EAD6BE1C826B92006DBA60 /* MySentryAckMessageBody.swift */, + C1EAD6BF1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift */, + C1EAD6C01C826B92006DBA60 /* MySentryAlertMessageBody.swift */, + C1EAD6C11C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift */, + C1EAD6C21C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift */, + C14303151C97C98000A40450 /* PumpAckMessageBody.swift */, + C1EAD6C31C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift */, + 43CA932C1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift */, + 43CA932D1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift */, + C1EAD6C41C826B92006DBA60 /* UnknownMessageBody.swift */, + ); + path = Messages; + sourceTree = ""; + }; + C1EF58891B3F9730001C8C80 /* SWRevealViewController */ = { + isa = PBXGroup; + children = ( + C1EF588A1B3F9748001C8C80 /* SWRevealViewController.m */, + C1EF588B1B3F9748001C8C80 /* SWRevealViewController.h */, + ); + name = SWRevealViewController; sourceTree = ""; }; C1EF589A1B3FBA32001C8C80 /* ViewControllers */ = { @@ -737,16 +1004,14 @@ C1EF589D1B3FBFE7001C8C80 /* MainAppViewController.m */, C1EF58951B3FA462001C8C80 /* MenuController.h */, C1EF58961B3FA462001C8C80 /* MenuController.m */, - 43737CDF1B7F06F100835F8D /* MySentryPairingViewController.h */, - 43737CE01B7F06F100835F8D /* MySentryPairingViewController.m */, + C10AB08A1C8519E2000F102E /* MySentryPairViewController.swift */, C12EA26B198B456D00309FA4 /* NightscoutWebView.h */, C12EA26C198B456D00309FA4 /* NightscoutWebView.m */, C126165B1B6C8076001FAD87 /* PacketGeneratorViewController.h */, C126165C1B6C8076001FAD87 /* PacketGeneratorViewController.m */, C12616551B6A6130001FAD87 /* PacketLogViewController.h */, C12616561B6A6130001FAD87 /* PacketLogViewController.m */, - C126166B1B76ECBA001FAD87 /* PumpChatViewController.h */, - C126166C1B76ECBA001FAD87 /* PumpChatViewController.m */, + C1890B5E1C94B9D9005F7474 /* PumpChatViewController.swift */, C126162A1B65E9BF001FAD87 /* RileyLinkDeviceViewController.h */, C126162B1B65E9BF001FAD87 /* RileyLinkDeviceViewController.m */, C12616301B65F4BC001FAD87 /* RileyLinkListTableViewController.h */, @@ -755,34 +1020,185 @@ name = ViewControllers; sourceTree = ""; }; - C1EF589B1B3FBA5D001C8C80 /* Nightscout */ = { + C1EF589B1B3FBA5D001C8C80 /* NightscoutUploadKit */ = { isa = PBXGroup; children = ( - C1A47EBD1B117DE900756B99 /* NightScoutUploader.h */, - C1A47EBE1B117DE900756B99 /* NightScoutUploader.m */, - C137A3941C08A35C00569851 /* NightScoutBolus.h */, - C137A3951C08A35C00569851 /* NightScoutBolus.m */, - C137A39A1C08A48100569851 /* NightScoutPump.h */, - C137A39B1C08A48100569851 /* NightScoutPump.m */, - ); - name = Nightscout; + C12FB2741CC588FB00879B80 /* Treatments */, + C1C357921C929507009BDD4F /* Extensions */, + C1842C281C908A3C00DB42AC /* NightscoutUploader.swift */, + C1842C2A1C90DFB600DB42AC /* NightscoutPumpEvents.swift */, + C1842C2E1C90F6D900DB42AC /* NightscoutTreatment.swift */, + C1842C301C91D56400DB42AC /* BGCheckNightscoutTreatment.swift */, + C1842C321C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift */, + C19F94AA1C91DF6E00018F7D /* BolusNightscoutTreatment.swift */, + C12FB2751CC5893C00879B80 /* TempBasalNightscoutTreatment.swift */, + ); + path = NightscoutUploadKit; sourceTree = ""; }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + 430D64C81CB855AB00FCA750 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 430D65081CB89FC000FCA750 /* RFPacket.h in Headers */, + 430D650C1CB89FC000FCA750 /* SendPacketCmd.h in Headers */, + 430D650E1CB89FC000FCA750 /* UpdateRegisterCmd.h in Headers */, + 430D650A1CB89FC000FCA750 /* SendAndListenCmd.h in Headers */, + 430D64EE1CB85A4300FCA750 /* RileyLinkBLEManager.h in Headers */, + 430D64EC1CB85A4300FCA750 /* RileyLinkBLEDevice.h in Headers */, + 430D65021CB89FC000FCA750 /* GetPacketCmd.h in Headers */, + 430D65001CB89FC000FCA750 /* CmdBase.h in Headers */, + 430D64CE1CB855AB00FCA750 /* RileyLinkBLEKit.h in Headers */, + 430D65061CB89FC000FCA750 /* ReceivingPacketCmd.h in Headers */, + 430D65041CB89FC000FCA750 /* GetVersionCmd.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FAB1CB9F7630038B7F2 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43722FB11CB9F7640038B7F2 /* RileyLinkKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BBE1C8269D500378342 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + C10D9BC41C8269D500378342 /* MinimedKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ + 430D64CA1CB855AB00FCA750 /* RileyLinkBLEKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 430D64E61CB855AB00FCA750 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKit" */; + buildPhases = ( + 430D64C61CB855AB00FCA750 /* Sources */, + 430D64C71CB855AB00FCA750 /* Frameworks */, + 430D64C81CB855AB00FCA750 /* Headers */, + 430D64C91CB855AB00FCA750 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RileyLinkBLEKit; + productName = RileyLinkBLEKit; + productReference = 430D64CB1CB855AB00FCA750 /* RileyLinkBLEKit.framework */; + productType = "com.apple.product-type.framework"; + }; + 430D64D31CB855AB00FCA750 /* RileyLinkBLEKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 430D64E71CB855AB00FCA750 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKitTests" */; + buildPhases = ( + 430D64D01CB855AB00FCA750 /* Sources */, + 430D64D11CB855AB00FCA750 /* Frameworks */, + 430D64D21CB855AB00FCA750 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 430D64D71CB855AB00FCA750 /* PBXTargetDependency */, + ); + name = RileyLinkBLEKitTests; + productName = RileyLinkBLEKitTests; + productReference = 430D64D41CB855AB00FCA750 /* RileyLinkBLEKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43722FC91CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKit" */; + buildPhases = ( + 43722FA91CB9F7630038B7F2 /* Sources */, + 43722FAA1CB9F7630038B7F2 /* Frameworks */, + 43722FAB1CB9F7630038B7F2 /* Headers */, + 43722FAC1CB9F7630038B7F2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RileyLinkKit; + productName = RileyLinkKit; + productReference = 43722FAE1CB9F7630038B7F2 /* RileyLinkKit.framework */; + productType = "com.apple.product-type.framework"; + }; + 43722FB61CB9F7640038B7F2 /* RileyLinkKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43722FCA1CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKitTests" */; + buildPhases = ( + 43722FB31CB9F7640038B7F2 /* Sources */, + 43722FB41CB9F7640038B7F2 /* Frameworks */, + 43722FB51CB9F7640038B7F2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 43722FBA1CB9F7640038B7F2 /* PBXTargetDependency */, + ); + name = RileyLinkKitTests; + productName = RileyLinkKitTests; + productReference = 43722FB71CB9F7640038B7F2 /* RileyLinkKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + C10D9BC01C8269D500378342 /* MinimedKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = C10D9BD81C8269D600378342 /* Build configuration list for PBXNativeTarget "MinimedKit" */; + buildPhases = ( + C10D9BBC1C8269D500378342 /* Sources */, + C10D9BBD1C8269D500378342 /* Frameworks */, + C10D9BBE1C8269D500378342 /* Headers */, + C10D9BBF1C8269D500378342 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MinimedKit; + productName = MinimedKit; + productReference = C10D9BC11C8269D500378342 /* MinimedKit.framework */; + productType = "com.apple.product-type.framework"; + }; + C10D9BC91C8269D500378342 /* MinimedKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = C10D9BDB1C8269D600378342 /* Build configuration list for PBXNativeTarget "MinimedKitTests" */; + buildPhases = ( + C10D9BC61C8269D500378342 /* Sources */, + C10D9BC71C8269D500378342 /* Frameworks */, + C10D9BC81C8269D500378342 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + C10D9BCD1C8269D500378342 /* PBXTargetDependency */, + ); + name = MinimedKitTests; + productName = MinimedKitTests; + productReference = C10D9BCA1C8269D500378342 /* MinimedKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; C12EA236198B436800309FA4 /* RileyLink */ = { isa = PBXNativeTarget; buildConfigurationList = C12EA263198B436900309FA4 /* Build configuration list for PBXNativeTarget "RileyLink" */; buildPhases = ( - 43F3CA7E1B8ED50E005A1DC1 /* ShellScript */, C12EA233198B436800309FA4 /* Sources */, C12EA234198B436800309FA4 /* Frameworks */, C12EA235198B436800309FA4 /* Resources */, + C10D9BB81C82614F00378342 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + C10D9BD51C8269D500378342 /* PBXTargetDependency */, + 430D64DF1CB855AB00FCA750 /* PBXTargetDependency */, + 43722FC21CB9F7640038B7F2 /* PBXTargetDependency */, ); name = RileyLink; productName = RileyLink; @@ -813,9 +1229,31 @@ C12EA22F198B436800309FA4 /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0510; ORGANIZATIONNAME = "Pete Schwamb"; TargetAttributes = { + 430D64CA1CB855AB00FCA750 = { + CreatedOnToolsVersion = 7.3; + DevelopmentTeam = UY678SP37Q; + }; + 430D64D31CB855AB00FCA750 = { + CreatedOnToolsVersion = 7.3; + }; + 43722FAD1CB9F7630038B7F2 = { + CreatedOnToolsVersion = 7.3; + DevelopmentTeam = UY678SP37Q; + }; + 43722FB61CB9F7640038B7F2 = { + CreatedOnToolsVersion = 7.3; + }; + C10D9BC01C8269D500378342 = { + CreatedOnToolsVersion = 7.2.1; + DevelopmentTeam = UY678SP37Q; + }; + C10D9BC91C8269D500378342 = { + CreatedOnToolsVersion = 7.2.1; + }; C12EA236198B436800309FA4 = { DevelopmentTeam = UY678SP37Q; }; @@ -838,11 +1276,59 @@ targets = ( C12EA236198B436800309FA4 /* RileyLink */, C12EA251198B436800309FA4 /* RileyLinkTests */, + C10D9BC01C8269D500378342 /* MinimedKit */, + C10D9BC91C8269D500378342 /* MinimedKitTests */, + 430D64CA1CB855AB00FCA750 /* RileyLinkBLEKit */, + 430D64D31CB855AB00FCA750 /* RileyLinkBLEKitTests */, + 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */, + 43722FB61CB9F7640038B7F2 /* RileyLinkKitTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 430D64C91CB855AB00FCA750 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 430D64D21CB855AB00FCA750 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FAC1CB9F7630038B7F2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FB51CB9F7640038B7F2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BBF1C8269D500378342 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BC81C8269D500378342 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; C12EA235198B436800309FA4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -864,133 +1350,222 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 43F3CA7E1B8ED50E005A1DC1 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; +/* Begin PBXSourcesBuildPhase section */ + 430D64C61CB855AB00FCA750 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 430D64ED1CB85A4300FCA750 /* RileyLinkBLEDevice.m in Sources */, + 43523ED71CC2C558001850F1 /* NSData+Conversion.m in Sources */, + 430D65031CB89FC000FCA750 /* GetPacketCmd.m in Sources */, + 430D65091CB89FC000FCA750 /* RFPacket.m in Sources */, + 430D65011CB89FC000FCA750 /* CmdBase.m in Sources */, + 430D64EF1CB85A4300FCA750 /* RileyLinkBLEManager.m in Sources */, + 430D650B1CB89FC000FCA750 /* SendAndListenCmd.m in Sources */, + 430D65051CB89FC000FCA750 /* GetVersionCmd.m in Sources */, + 430D650D1CB89FC000FCA750 /* SendPacketCmd.m in Sources */, + 430D650F1CB89FC000FCA750 /* UpdateRegisterCmd.m in Sources */, + 430D65071CB89FC000FCA750 /* ReceivingPacketCmd.m in Sources */, ); - inputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + }; + 430D64D01CB855AB00FCA750 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 430D64DC1CB855AB00FCA750 /* RileyLinkBLEKitTests.m in Sources */, ); - outputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FA91CB9F7630038B7F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 434AB0961CBA0DF600422F4A /* PumpOps.swift in Sources */, + 434AB0C61CBCB41500422F4A /* RileyLinkDevice.swift in Sources */, + 434AB0C71CBCB76400422F4A /* NSData.swift in Sources */, + 434AB0981CBA0DF600422F4A /* PumpState.swift in Sources */, + 434AB0971CBA0DF600422F4A /* PumpOpsSynchronous.swift in Sources */, + 434AB0BE1CBB4E3200422F4A /* RileyLinkDeviceManager.swift in Sources */, + 434AB09E1CBA28F100422F4A /* NSTimeInterval.swift in Sources */, + 434AB0951CBA0DF600422F4A /* Either.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43722FB31CB9F7640038B7F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43722FBF1CB9F7640038B7F2 /* RileyLinkKitTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BBC1C8269D500378342 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C1842C1C1C8FA45100DB42AC /* ChangeBGReminderOffsetPumpEvent.swift in Sources */, + C12198AF1C8F46FF00BC374C /* TimeFormat.swift in Sources */, + C1842BD11C8FA3D200DB42AC /* AlarmClockReminderPumpEvent.swift in Sources */, + C1842C1B1C8FA45100DB42AC /* ChangeBolusReminderEnablePumpEvent.swift in Sources */, + C1842BC51C8F897E00DB42AC /* BasalProfileStartPumpEvent.swift in Sources */, + C1842C081C8FA45100DB42AC /* ChangeWatchdogMarriageProfilePumpEvent.swift in Sources */, + C1842BFF1C8FA45100DB42AC /* Model522ResultTotalsPumpEvent.swift in Sources */, + C1842C1A1C8FA45100DB42AC /* ChangeBolusReminderTimePumpEvent.swift in Sources */, + C12198B31C8F730700BC374C /* BolusWizardEstimatePumpEvent.swift in Sources */, + C1842BBF1C8E855A00DB42AC /* PumpEventType.swift in Sources */, + C1842BC11C8E8B2500DB42AC /* UnabsorbedInsulinPumpEvent.swift in Sources */, + C1EAD6B51C826B6D006DBA60 /* MessageType.swift in Sources */, + C1842C111C8FA45100DB42AC /* ChangeParadigmLinkIDPumpEvent.swift in Sources */, + C1C3578F1C927303009BDD4F /* MeterMessage.swift in Sources */, + C1842BFC1C8FA45100DB42AC /* SuspendPumpEvent.swift in Sources */, + C1842C131C8FA45100DB42AC /* ChangeMaxBolusPumpEvent.swift in Sources */, + C1EAD6B61C826B6D006DBA60 /* PacketType.swift in Sources */, + C1842C041C8FA45100DB42AC /* DeleteOtherDeviceIDPumpEvent.swift in Sources */, + C1842C0B1C8FA45100DB42AC /* ChangeTimePumpEvent.swift in Sources */, + C1842C0D1C8FA45100DB42AC /* TempBasalPumpEvent.swift in Sources */, + C1842C0C1C8FA45100DB42AC /* ChangeTimeFormatPumpEvent.swift in Sources */, + C10AB08D1C855613000F102E /* FindDeviceMessageBody.swift in Sources */, + C1711A5A1C952D2900CB25BD /* GetPumpModelCarelinkMessageBody.swift in Sources */, + C1EB955D1C887FE5002517DF /* HistoryPage.swift in Sources */, + C1EAD6CA1C826B92006DBA60 /* MySentryAlertClearedMessageBody.swift in Sources */, + C1842C181C8FA45100DB42AC /* ChangeBolusWizardSetupPumpEvent.swift in Sources */, + C1842C201C8FA45100DB42AC /* ChangeAudioBolusPumpEvent.swift in Sources */, + C1EAD6B31C826B6D006DBA60 /* AlertType.swift in Sources */, + C1842C051C8FA45100DB42AC /* DeleteBolusReminderTimePumpEvent.swift in Sources */, + C1711A5C1C953F3000CB25BD /* GetBatteryCarelinkMessageBody.swift in Sources */, + C1842C1D1C8FA45100DB42AC /* ChangeBGReminderEnablePumpEvent.swift in Sources */, + C1842C061C8FA45100DB42AC /* DeleteAlarmClockTimePumpEvent.swift in Sources */, + C10AB08F1C855F34000F102E /* DeviceLinkMessageBody.swift in Sources */, + C1842C091C8FA45100DB42AC /* ChangeWatchdogEnablePumpEvent.swift in Sources */, + C1842BC91C8F968B00DB42AC /* BGReceivedPumpEvent.swift in Sources */, + C1842C0F1C8FA45100DB42AC /* ChangeSensorRateOfChangeAlertSetupPumpEvent.swift in Sources */, + C1842BFE1C8FA45100DB42AC /* ResultDailyTotalPumpEvent.swift in Sources */, + 43CA93291CB8CF22000026B5 /* ChangeTempBasalCarelinkMessageBody.swift in Sources */, + C1EAD6CD1C826B92006DBA60 /* PowerOnCarelinkMessageBody.swift in Sources */, + C1EAD6C81C826B92006DBA60 /* CarelinkMessageBody.swift in Sources */, + C1842C121C8FA45100DB42AC /* ChangeOtherDeviceIDPumpEvent.swift in Sources */, + C1842C231C8FA45100DB42AC /* ChangeAlarmClockEnablePumpEvent.swift in Sources */, + C1EAD6CF1C826B92006DBA60 /* UnknownMessageBody.swift in Sources */, + C1842C161C8FA45100DB42AC /* ChangeCarbUnitsPumpEvent.swift in Sources */, + C1842C241C8FA45100DB42AC /* BatteryPumpEvent.swift in Sources */, + C1842C1F1C8FA45100DB42AC /* ChangeBasalProfilePatternPumpEvent.swift in Sources */, + C1711A561C94F13400CB25BD /* ButtonPressCarelinkMessageBody.swift in Sources */, + C1842C011C8FA45100DB42AC /* JournalEntryPumpLowBatteryPumpEvent.swift in Sources */, + C1842BBD1C8E7C6E00DB42AC /* PumpEvent.swift in Sources */, + C1842BCB1C8F9A7200DB42AC /* RewindPumpEvent.swift in Sources */, + C1842BCD1C8F9BBD00DB42AC /* PrimePumpEvent.swift in Sources */, + C1842C071C8FA45100DB42AC /* ClearAlarmPumpEvent.swift in Sources */, + C1EAD6C91C826B92006DBA60 /* MySentryAckMessageBody.swift in Sources */, + C1EAD6CE1C826B92006DBA60 /* ReadSettingsCarelinkMessageBody.swift in Sources */, + C12198AD1C8F332500BC374C /* TimestampedPumpEvent.swift in Sources */, + C1EAD6DE1C82B78C006DBA60 /* CRC8.swift in Sources */, + C1EAD6C51C826B92006DBA60 /* Int.swift in Sources */, + C1842C021C8FA45100DB42AC /* JournalEntryExerciseMarkerPumpEvent.swift in Sources */, + C1EAD6CB1C826B92006DBA60 /* MySentryAlertMessageBody.swift in Sources */, + C1842BC71C8F8DC200DB42AC /* CalBGForPHPumpEvent.swift in Sources */, + C1842C251C8FA45100DB42AC /* AlarmSensorPumpEvent.swift in Sources */, + C1842BBB1C8E184300DB42AC /* PumpModel.swift in Sources */, + C14D2B091C9F5EDA00C98E4C /* ChangeTempBasalTypePumpEvent.swift in Sources */, + C1842C1E1C8FA45100DB42AC /* ChangeBasalProfilePumpEvent.swift in Sources */, + C14D2B051C9F5D5800C98E4C /* TempBasalDurationPumpEvent.swift in Sources */, + C1842C151C8FA45100DB42AC /* ChangeChildBlockEnablePumpEvent.swift in Sources */, + C1EAD6B41C826B6D006DBA60 /* MessageBody.swift in Sources */, + C1842C001C8FA45100DB42AC /* JournalEntryPumpLowReservoirPumpEvent.swift in Sources */, + C1842BCF1C8F9E5100DB42AC /* PumpAlarmPumpEvent.swift in Sources */, + C1EAD6C61C826B92006DBA60 /* NSData.swift in Sources */, + C1842C211C8FA45100DB42AC /* ChangeAlarmNotifyModePumpEvent.swift in Sources */, + C1842BC31C8E931E00DB42AC /* BolusNormalPumpEvent.swift in Sources */, + 43CA932F1CB8CFA1000026B5 /* ReadTimeCarelinkMessageBody.swift in Sources */, + C1842C221C8FA45100DB42AC /* ChangeAlarmClockTimePumpEvent.swift in Sources */, + C1842BFD1C8FA45100DB42AC /* ResumePumpEvent.swift in Sources */, + C1EAD6CC1C826B92006DBA60 /* MySentryPumpStatusMessageBody.swift in Sources */, + C1842C141C8FA45100DB42AC /* ChangeMaxBasalPumpEvent.swift in Sources */, + C1842C101C8FA45100DB42AC /* ChangeReservoirWarningTimePumpEvent.swift in Sources */, + 43CA932E1CB8CFA1000026B5 /* ReadTempBasalCarelinkMessageBody.swift in Sources */, + C1EAD6E21C82BA7A006DBA60 /* CRC16.swift in Sources */, + C1711A5E1C977BD000CB25BD /* GetHistoryPageCarelinkMessageBody.swift in Sources */, + C14303161C97C98000A40450 /* PumpAckMessageBody.swift in Sources */, + C1EAD6C71C826B92006DBA60 /* NSDateComponents.swift in Sources */, + C1842C0E1C8FA45100DB42AC /* ChangeSensorSetup2PumpEvent.swift in Sources */, + C1842C0A1C8FA45100DB42AC /* ChangeVariableBolusPumpEvent.swift in Sources */, + C1842C191C8FA45100DB42AC /* ChangeBolusScrollStepSizePumpEvent.swift in Sources */, + C1842C171C8FA45100DB42AC /* ChangeCaptureEventEnablePumpEvent.swift in Sources */, + C1EAD6DA1C829104006DBA60 /* RFTools.swift in Sources */, + 43CA932B1CB8CF76000026B5 /* ChangeTimeCarelinkMessageBody.swift in Sources */, + C121989F1C8DFC2200BC374C /* BolusCarelinkMessageBody.swift in Sources */, + C1842C031C8FA45100DB42AC /* EnableDisableRemotePumpEvent.swift in Sources */, + C1EAD6B71C826B6D006DBA60 /* PumpMessage.swift in Sources */, + C12198A91C8F2AF200BC374C /* Sara6EPumpEvent.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C10D9BC61C8269D500378342 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C12198631C8DF4C800BC374C /* HistoryPageTests.swift in Sources */, + C1EAD6D61C826C43006DBA60 /* MySentryPumpStatusMessageBodyTests.swift in Sources */, + C1EAD6D81C826C43006DBA60 /* ReadSettingsCarelinkMessageBodyTests.swift in Sources */, + C1C357911C92733A009BDD4F /* MeterMessageTests.swift in Sources */, + C12198611C8DEB7B00BC374C /* DeviceLinkMessageBodyTests.swift in Sources */, + C12198B11C8F6DD800BC374C /* TimeFormatTests.swift in Sources */, + C14303181C97CC6B00A40450 /* GetPumpModelCarelinkMessageBodyTests.swift in Sources */, + C1EAD6E41C82BA87006DBA60 /* CRC16Tests.swift in Sources */, + C1EAD6E61C83966D006DBA60 /* PumpMessageTests.swift in Sources */, + 43CA93311CB97191000026B5 /* ReadTempBasalCarelinkMessageBodyTests.swift in Sources */, + 43FF221C1CB9B9DE00024F30 /* NSDateComponents.swift in Sources */, + C12198A31C8DFC3600BC374C /* BolusCarelinkMessageBodyTests.swift in Sources */, + C121985F1C8DE77D00BC374C /* FindDeviceMessageBodyTests.swift in Sources */, + C1EAD6D71C826C43006DBA60 /* NSDataTests.swift in Sources */, + C143031A1C9A610B00A40450 /* GetBatteryCarelinkMessageBodyTests.swift in Sources */, + 43CA93351CB9727F000026B5 /* ChangeTempBasalCarelinkMessageBodyTests.swift in Sources */, + C1EAD6E01C82B910006DBA60 /* CRC8Tests.swift in Sources */, + 43CA93331CB9726A000026B5 /* ChangeTimeCarelinMessageBodyTests.swift in Sources */, + C1EAD6DC1C82A4AB006DBA60 /* RFToolsTests.swift in Sources */, + C1EAD6D51C826C43006DBA60 /* MinimedKitTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/sync_version.rb\""; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ C12EA233198B436800309FA4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C12EA24B198B436800309FA4 /* AppDelegate.m in Sources */, - C139ACA71BFD8CF800B0518F /* PHEJournalEntryPumpLowReservoir.m in Sources */, + C1842C311C91D56400DB42AC /* BGCheckNightscoutTreatment.swift in Sources */, C12616691B76E8DC001FAD87 /* TPKeyboardAvoidingTableView.m in Sources */, - C139AC841BFD8CF800B0518F /* PHEBattery.m in Sources */, - C139ACBC1C00046D00B0518F /* PHEJournalEntryPumpLowBattery.m in Sources */, - C152C19C1C3875EA0009B4B8 /* GetPacketCmd.m in Sources */, - C139ACBD1C00046D00B0518F /* PHEModel522ResultTotals.m in Sources */, + C1842C2B1C90DFB600DB42AC /* NightscoutPumpEvents.swift in Sources */, C12616681B76E8DC001FAD87 /* TPKeyboardAvoidingScrollView.m in Sources */, - C10A62921C55F8E200E635EE /* UpdateRegisterCmd.m in Sources */, - C1743CDF199D374500ED623E /* PumpStatusMessage.m in Sources */, - C126166D1B76ECBA001FAD87 /* PumpChatViewController.m in Sources */, C12616321B65F4BC001FAD87 /* RileyLinkListTableViewController.m in Sources */, - C139AC9B1BFD8CF800B0518F /* PHEChangeSensorRateOfChangeAlertSetup.m in Sources */, - C137A3961C08A35C00569851 /* NightScoutBolus.m in Sources */, C1EF58971B3FA462001C8C80 /* MenuController.m in Sources */, - C139ACAE1BFD8CF800B0518F /* PHEUnabsorbedInsulin.m in Sources */, C139AC241BFD84B500B0518F /* RuntimeUtils.m in Sources */, C1EF58851B3E5DA4001C8C80 /* ConfigureViewController.m in Sources */, - C139AC951BFD8CF800B0518F /* PHEChangeCaptureEventEnable.m in Sources */, - C139AC9E1BFD8CF800B0518F /* PHEChangeTime.m in Sources */, - C1D2B67E1C2FAD0100DB4AEA /* CmdBase.m in Sources */, - C139ACA61BFD8CF800B0518F /* PHEJournalEntryExerciseMarker.m in Sources */, - C1E535ED1991E49600C2AC49 /* RileyLinkBLEManager.m in Sources */, C12EA26D198B456D00309FA4 /* NightscoutWebView.m in Sources */, C12616541B6892DB001FAD87 /* RileyLinkRecord.m in Sources */, - C1D2B6811C30AAE000DB4AEA /* SendPacketCmd.m in Sources */, - C13DB3A51B1583E900121E02 /* MessageBase.m in Sources */, - C139ACB11BFEDD9E00B0518F /* PumpModel.m in Sources */, C12616671B76E8DC001FAD87 /* TPKeyboardAvoidingCollectionView.m in Sources */, - C12616511B688D9C001FAD87 /* RileyLinkBLEDevice.m in Sources */, - C139AC851BFD8CF800B0518F /* PHEBgReceived.m in Sources */, C126165A1B6B2D20001FAD87 /* PacketTableViewCell.m in Sources */, - C139AC8B1BFD8CF800B0518F /* PHEChangeAlarmNotifyMode.m in Sources */, - C139AC8E1BFD8CF800B0518F /* PHEChangeBasalProfilePattern.m in Sources */, + 43462E8B1CCB06F500F958A8 /* AppDelegate.swift in Sources */, C174F26B19EB824D00398C72 /* ISO8601DateFormatter.m in Sources */, - C139AC991BFD8CF800B0518F /* PHEChangeParadigmLinkID.m in Sources */, + C12FB2761CC5893C00879B80 /* TempBasalNightscoutTreatment.swift in Sources */, C126166A1B76E8DC001FAD87 /* UIScrollView+TPKeyboardAvoidingAdditions.m in Sources */, - C1E535F01991E6A200C2AC49 /* MinimedPacket.m in Sources */, - C139ACBB1C00046D00B0518F /* PHEBolusWizardBolusEstimate.m in Sources */, - C139ACA31BFD8CF800B0518F /* PHEDeleteAlarmClockTime.m in Sources */, - C139AC961BFD8CF800B0518F /* PHEChangeCarbUnits.m in Sources */, C1AA39941AB6804000BC9E33 /* UIAlertView+Blocks.m in Sources */, - C139AB911BFD6A9000B0518F /* PumpHistoryEventBase.m in Sources */, - C12616701B7790DF001FAD87 /* SendAndListenCmd.m in Sources */, - C152C1A21C38B8850009B4B8 /* FindDeviceMessage.m in Sources */, - C139ACA51BFD8CF800B0518F /* PHEEnableDisableRemote.m in Sources */, + C1890B5F1C94B9D9005F7474 /* PumpChatViewController.swift in Sources */, C126162C1B65E9BF001FAD87 /* RileyLinkDeviceViewController.m in Sources */, C1EF58881B3F93FE001C8C80 /* Config.m in Sources */, - C139AC901BFD8CF800B0518F /* PHEChangeBGReminderOffset.m in Sources */, - C139AC811BFD8CF800B0518F /* PHEAlarmPump.m in Sources */, C126164B1B685F93001FAD87 /* RileyLink.xcdatamodeld in Sources */, - C139AC8F1BFD8CF800B0518F /* PHEChangeBGReminderEnable.m in Sources */, C126165D1B6C8076001FAD87 /* PacketGeneratorViewController.m in Sources */, - C137A3931C08142E00569851 /* CRC16.m in Sources */, - C139AC911BFD8CF800B0518F /* PHEChangeBolusReminderEnable.m in Sources */, - C137A3901C08114600569851 /* CRC8.m in Sources */, + C1C357941C929529009BDD4F /* StringCrypto.swift in Sources */, + C1842C291C908A3C00DB42AC /* NightscoutUploader.swift in Sources */, + C1842C2F1C90F6D900DB42AC /* NightscoutTreatment.swift in Sources */, C12616571B6A6130001FAD87 /* PacketLogViewController.m in Sources */, - C14AA33B1B1A2FB100299A55 /* MeterMessage.m in Sources */, - C139AC941BFD8CF800B0518F /* PHEChangeBolusWizardSetup.m in Sources */, - C137A39C1C08A48100569851 /* NightScoutPump.m in Sources */, - C139ACA11BFD8CF800B0518F /* PHEChangeWatchdogEnable.m in Sources */, - C139AC8D1BFD8CF800B0518F /* PHEChangeBasalProfile.m in Sources */, - 43737CE11B7F06F100835F8D /* MySentryPairingViewController.m in Sources */, - C139ACA21BFD8CF800B0518F /* PHEClearAlarm.m in Sources */, C1EF589E1B3FBFE7001C8C80 /* MainAppViewController.m in Sources */, C1EF588C1B3F9748001C8C80 /* SWRevealViewController.m in Sources */, 43C99C6F1B898B7100BC03D4 /* MenuHeaderTableViewCell.m in Sources */, - C139AC211BFD847F00B0518F /* HistoryPage.m in Sources */, - C139AC931BFD8CF800B0518F /* PHEChangeBolusScrollStepSize.m in Sources */, - C139ACA41BFD8CF800B0518F /* PHEDeleteBolusReminderTime.m in Sources */, - C139AC971BFD8CF800B0518F /* PHEChangeChildBlockEnable.m in Sources */, C126163C1B67CBC2001FAD87 /* RileyLinkTableViewCell.m in Sources */, - C139ACAC1BFD8CF800B0518F /* PHESara6E.m in Sources */, - C139AC921BFD8CF800B0518F /* PHEChangeBolusReminderTime.m in Sources */, C1271B071A9A34E900B7C949 /* Log.m in Sources */, - C139ACA91BFD8CF800B0518F /* PHEResultDailyTotal.m in Sources */, - C152C1A81C3A40760009B4B8 /* PHEChangeWatchdogMarriageProfile.m in Sources */, - C139ACBA1C00046D00B0518F /* PHEAlarmClockReminder.m in Sources */, - C139AC9A1BFD8CF800B0518F /* PHEChangeReservoirWarningTime.m in Sources */, - C139AC891BFD8CF800B0518F /* PHEChangeAlarmClockEnable.m in Sources */, - C10EAAA61C5C507E00B0838F /* PumpOps.m in Sources */, - C152C1AB1C3A40A80009B4B8 /* PHEDeleteOtherDeviceID.m in Sources */, - C139ACAA1BFD8CF800B0518F /* PHEResume.m in Sources */, - C139ACAD1BFD8CF800B0518F /* PHESuspend.m in Sources */, + C19F94AB1C91DF6E00018F7D /* BolusNightscoutTreatment.swift in Sources */, + C10AB08B1C8519E2000F102E /* MySentryPairViewController.swift in Sources */, C1E535EA1991E36700C2AC49 /* NSData+Conversion.m in Sources */, - C10EAA9D1C5AE9A600B0838F /* GetVersionCmd.m in Sources */, - C139AC881BFD8CF800B0518F /* PHECalBGForPH.m in Sources */, - C139AC8C1BFD8CF800B0518F /* PHEChangeAudioBolus.m in Sources */, - C10EAAA31C5B3A0800B0838F /* PumpOpsSynchronous.m in Sources */, - C139AC821BFD8CF800B0518F /* PHEAlarmSensor.m in Sources */, - C139ACA81BFD8CF800B0518F /* PHEPrime.m in Sources */, - C139AC861BFD8CF800B0518F /* PHEBolusNormal.m in Sources */, - C139AC9C1BFD8CF800B0518F /* PHEChangeSensorSetup2.m in Sources */, - C139ACAB1BFD8CF800B0518F /* PHERewind.m in Sources */, - C12EA247198B436800309FA4 /* main.m in Sources */, - C139AC831BFD8CF800B0518F /* PHEBasalProfileStart.m in Sources */, - C1A47EBF1B117DE900756B99 /* NightScoutUploader.m in Sources */, - C1A47EC21B1190D800756B99 /* NSString+Hashes.m in Sources */, - C152C1A51C3A3FF40009B4B8 /* PHEChangeOtherDeviceID.m in Sources */, - C139AC9D1BFD8CF800B0518F /* PHEChangeTempBasalPercent.m in Sources */, - C139AC9F1BFD8CF800B0518F /* PHEChangeTimeFormat.m in Sources */, - C139AC8A1BFD8CF800B0518F /* PHEChangeAlarmClockTime.m in Sources */, - C139AC981BFD8CF800B0518F /* PHEChangeMaxBolus.m in Sources */, - C152C19F1C38B5A30009B4B8 /* DeviceLinkMessage.m in Sources */, - C11F993D1BC406970013158C /* PumpState.m in Sources */, - C139ACA01BFD8CF800B0518F /* PHEChangeVariableBolus.m in Sources */, + C1842C331C91DAFA00DB42AC /* MealBolusNightscoutTreatment.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -998,6 +1573,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + C14C8A801C9CFBEE000F72C5 /* NightscoutPumpEventsTests.swift in Sources */, C12EA260198B436900309FA4 /* RileyLinkTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1005,6 +1581,36 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 430D64D71CB855AB00FCA750 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 430D64CA1CB855AB00FCA750 /* RileyLinkBLEKit */; + targetProxy = 430D64D61CB855AB00FCA750 /* PBXContainerItemProxy */; + }; + 430D64DF1CB855AB00FCA750 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 430D64CA1CB855AB00FCA750 /* RileyLinkBLEKit */; + targetProxy = 430D64DE1CB855AB00FCA750 /* PBXContainerItemProxy */; + }; + 43722FBA1CB9F7640038B7F2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */; + targetProxy = 43722FB91CB9F7640038B7F2 /* PBXContainerItemProxy */; + }; + 43722FC21CB9F7640038B7F2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 43722FAD1CB9F7630038B7F2 /* RileyLinkKit */; + targetProxy = 43722FC11CB9F7640038B7F2 /* PBXContainerItemProxy */; + }; + C10D9BCD1C8269D500378342 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C10D9BC01C8269D500378342 /* MinimedKit */; + targetProxy = C10D9BCC1C8269D500378342 /* PBXContainerItemProxy */; + }; + C10D9BD51C8269D500378342 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C10D9BC01C8269D500378342 /* MinimedKit */; + targetProxy = C10D9BD41C8269D500378342 /* PBXContainerItemProxy */; + }; C12EA258198B436900309FA4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = C12EA236198B436800309FA4 /* RileyLink */; @@ -1032,6 +1638,282 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 430D64E21CB855AB00FCA750 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 430D64E31CB855AB00FCA750 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkBLEKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 430D64E41CB855AB00FCA750 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkBLEKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 430D64E51CB855AB00FCA750 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkBLEKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkBLEKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 43722FC51CB9F7640038B7F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 43722FC61CB9F7640038B7F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 43722FC71CB9F7640038B7F2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 43722FC81CB9F7640038B7F2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = RileyLinkKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.RileyLinkKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + C10D9BD91C8269D600378342 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = MinimedKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.MinimedKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + C10D9BDA1C8269D600378342 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 2; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = MinimedKit/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.MinimedKit; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + C10D9BDC1C8269D600378342 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = MinimedKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.MinimedKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + C10D9BDD1C8269D600378342 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = MinimedKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.MinimedKitTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; C12EA261198B436900309FA4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1049,6 +1931,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 2; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; @@ -1064,10 +1947,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; WARNING_CFLAGS = "-Wall"; }; name = Debug; @@ -1089,6 +1973,7 @@ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 2; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -1097,10 +1982,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; WARNING_CFLAGS = "-Wall"; }; name = Release; @@ -1109,14 +1995,18 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "RileyLink/RileyLink-Prefix.pch"; + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "RileyLink/RileyLink-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.rlapp; PRODUCT_NAME = RileyLink; PROVISIONING_PROFILE = ""; + SWIFT_OBJC_BRIDGING_HEADER = "RileyLink/RileyLink-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -1125,14 +2015,17 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "RileyLink/RileyLink-Prefix.pch"; + EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "RileyLink/RileyLink-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.rileylink.rlapp; PRODUCT_NAME = RileyLink; PROVISIONING_PROFILE = ""; + SWIFT_OBJC_BRIDGING_HEADER = "RileyLink/RileyLink-Bridging-Header.h"; WRAPPER_EXTENSION = app; }; name = Release; @@ -1141,18 +2034,20 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/RileyLink.app/RileyLink"; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "RileyLink/RileyLink-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "RileyLinkTests/RileyLinkTests-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.glucoselink.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = RileyLinkTests; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = xctest; }; @@ -1162,15 +2057,16 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/RileyLink.app/RileyLink"; + CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "RileyLink/RileyLink-Prefix.pch"; INFOPLIST_FILE = "RileyLinkTests/RileyLinkTests-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.glucoselink.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = RileyLinkTests; TEST_HOST = "$(BUNDLE_LOADER)"; @@ -1181,6 +2077,60 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 430D64E61CB855AB00FCA750 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 430D64E21CB855AB00FCA750 /* Debug */, + 430D64E31CB855AB00FCA750 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 430D64E71CB855AB00FCA750 /* Build configuration list for PBXNativeTarget "RileyLinkBLEKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 430D64E41CB855AB00FCA750 /* Debug */, + 430D64E51CB855AB00FCA750 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43722FC91CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43722FC51CB9F7640038B7F2 /* Debug */, + 43722FC61CB9F7640038B7F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 43722FCA1CB9F7640038B7F2 /* Build configuration list for PBXNativeTarget "RileyLinkKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43722FC71CB9F7640038B7F2 /* Debug */, + 43722FC81CB9F7640038B7F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C10D9BD81C8269D600378342 /* Build configuration list for PBXNativeTarget "MinimedKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C10D9BD91C8269D600378342 /* Debug */, + C10D9BDA1C8269D600378342 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C10D9BDB1C8269D600378342 /* Build configuration list for PBXNativeTarget "MinimedKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C10D9BDC1C8269D600378342 /* Debug */, + C10D9BDD1C8269D600378342 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; C12EA232198B436800309FA4 /* Build configuration list for PBXProject "RileyLink" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata index bee4bffa0..94c213d25 100644 --- a/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/RileyLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:RileyLink.xcodeproj"> diff --git a/RileyLink.xcodeproj/xcshareddata/xcschemes/MinimedKit.xcscheme b/RileyLink.xcodeproj/xcshareddata/xcschemes/MinimedKit.xcscheme new file mode 100644 index 000000000..b0ecbd3b9 --- /dev/null +++ b/RileyLink.xcodeproj/xcshareddata/xcschemes/MinimedKit.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLink.xcscheme b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLink.xcscheme new file mode 100644 index 000000000..c4d936820 --- /dev/null +++ b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLink.xcscheme @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkBLEKit.xcscheme b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkBLEKit.xcscheme new file mode 100644 index 000000000..1a1dc05a7 --- /dev/null +++ b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkBLEKit.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkKit.xcscheme b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkKit.xcscheme new file mode 100644 index 000000000..71879be12 --- /dev/null +++ b/RileyLink.xcodeproj/xcshareddata/xcschemes/RileyLinkKit.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RileyLink/AppDelegate.h b/RileyLink/AppDelegate.h deleted file mode 100644 index 7d88d93d5..000000000 --- a/RileyLink/AppDelegate.h +++ /dev/null @@ -1,25 +0,0 @@ -// -// AppDelegate.h -// GlucoseLink -// -// Created by Pete Schwamb on 7/31/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import -#import "PumpState.h" - -@interface AppDelegate : UIResponder - -@property (strong, nonatomic) UIWindow *window; - -@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; -@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; -@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; - -@property (nonatomic, readonly, copy) NSURL *applicationDocumentsDirectory; - -@property (strong, nonatomic) PumpState *pump; - - -@end diff --git a/RileyLink/AppDelegate.m b/RileyLink/AppDelegate.m deleted file mode 100644 index 265f999cf..000000000 --- a/RileyLink/AppDelegate.m +++ /dev/null @@ -1,149 +0,0 @@ -// -// AppDelegate.m -// GlucoseLink -// -// Created by Pete Schwamb on 7/31/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import "AppDelegate.h" -#import "Config.h" - -@implementation AppDelegate - -@synthesize managedObjectContext = _managedObjectContext; -@synthesize managedObjectModel = _managedObjectModel; -@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - - // Remove old log file - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = paths[0]; - NSString *path = [documentsDirectory stringByAppendingPathComponent:@"logfile.txt"]; - NSError *error; - [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; - if (error != nil) { - NSLog(@"Could not remove file: %@", path); - } - - self.pump = [[PumpState alloc] initWithPumpId:[[Config sharedInstance] pumpID]]; - - return YES; -} - -- (void)applicationWillResignActive:(UIApplication *)application -{ - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - NSLog(@"applicationWillResignActive"); -} - -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - NSLog(@"applicationDidEnterBackground"); -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - NSLog(@"applicationWillEnterForeground"); -} - -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - NSLog(@"applicationDidBecomeActive"); -} - -- (void)applicationWillTerminate:(UIApplication *)application -{ - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - NSLog(@"applicationWillTerminate"); -} - -#pragma mark - Core Data stack - -// Returns the managed object context for the application. -// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. -- (NSManagedObjectContext *)managedObjectContext -{ - if (_managedObjectContext != nil) { - return _managedObjectContext; - } - - NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; - if (coordinator != nil) { - _managedObjectContext = [[NSManagedObjectContext alloc] init]; - [_managedObjectContext setPersistentStoreCoordinator:coordinator]; - } - return _managedObjectContext; -} - -// Returns the managed object model for the application. -// If the model doesn't already exist, it is created from the application's model. -- (NSManagedObjectModel *)managedObjectModel -{ - if (_managedObjectModel != nil) { - return _managedObjectModel; - } - NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"RileyLink" withExtension:@"momd"]; - _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; - return _managedObjectModel; -} - -// Returns the persistent store coordinator for the application. -// If the coordinator doesn't already exist, it is created and the application's store added to it. -- (NSPersistentStoreCoordinator *)persistentStoreCoordinator -{ - if (_persistentStoreCoordinator != nil) { - return _persistentStoreCoordinator; - } - - NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"RileyLink.sqlite"]; - - NSError *error = nil; - _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; - if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { - /* - Replace this implementation with code to handle the error appropriately. - - abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - - Typical reasons for an error here include: - * The persistent store is not accessible; - * The schema for the persistent store is incompatible with current managed object model. - Check the error message to determine what the actual problem was. - - If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. - - If you encounter schema incompatibility errors during development, you can reduce their frequency by: - * Simply deleting the existing store: - [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] - - * Performing automatic lightweight migration by passing the following dictionary as the options parameter: - @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} - - Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. - - */ - NSLog(@"Unresolved error %@, %@", error, [error userInfo]); - abort(); - } - - return _persistentStoreCoordinator; -} - -#pragma mark - Application's Documents directory - -// Returns the URL to the application's Documents directory. -- (NSURL *)applicationDocumentsDirectory -{ - return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; -} - - -@end diff --git a/RileyLink/AppDelegate.swift b/RileyLink/AppDelegate.swift new file mode 100644 index 000000000..4a323ae98 --- /dev/null +++ b/RileyLink/AppDelegate.swift @@ -0,0 +1,111 @@ +// +// AppDelegate.swift +// RileyLink +// +// Created by Nathan Racklyeft on 4/22/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import UIKit +import CoreData +import RileyLinkKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + var pump: PumpState! + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + let logFileURL = applicationDocumentsDirectory().URLByAppendingPathComponent("logfile.txt") + + do { + try NSFileManager.defaultManager().removeItemAtURL(logFileURL) + } catch let error { + NSLog("Could not remove file at path: \(logFileURL): \(error)") + } + + if let pumpID = Config.sharedInstance().pumpID { + pump = PumpState(pumpID: pumpID) + } + + return true + } + + func applicationWillResignActive(application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + NSLog(#function) + } + + func applicationDidEnterBackground(application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + NSLog(#function) + } + + func applicationWillEnterForeground(application: UIApplication) { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + NSLog(#function) + } + + func applicationDidBecomeActive(application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + NSLog(#function) + } + + func applicationWillTerminate(application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + NSLog(#function) + } + + // MARK: - Notifications + + func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) { + + } + + func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) { + + completionHandler() + } + + // MARK: - 3D Touch + + func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) { + completionHandler(false) + } + + // MARK: - Core Data + + lazy var managedObjectContext: NSManagedObjectContext? = { + guard let managedObjectModel = { () -> NSManagedObjectModel? in + let modelURL = NSBundle.mainBundle().URLForResource("RileyLink", withExtension: "momd")! + return NSManagedObjectModel(contentsOfURL: modelURL) + }() else { + return nil + } + + guard let coordinator = { () -> NSPersistentStoreCoordinator? in + let storeURL = applicationDocumentsDirectory().URLByAppendingPathComponent("RileyLink.sqlite") + let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) + + try! coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil) + + return coordinator + }() else { + return nil + } + + let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) + context.persistentStoreCoordinator = coordinator + return context + }() +} + + +private func applicationDocumentsDirectory() -> NSURL { + return NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last! +} + diff --git a/RileyLink/CRC16.h b/RileyLink/CRC16.h deleted file mode 100644 index 1f21b6875..000000000 --- a/RileyLink/CRC16.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// CRC16.h -// RileyLink -// -// Created by Pete Schwamb on 11/26/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import - -@interface CRC16 : NSObject - -+ (uint16_t) compute:(NSData*)data; - -@end diff --git a/RileyLink/CRC16.m b/RileyLink/CRC16.m deleted file mode 100644 index 5277ffcbe..000000000 --- a/RileyLink/CRC16.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// CRC16.m -// RileyLink -// -// Created by Pete Schwamb on 11/26/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "CRC16.h" - -@implementation CRC16 - -static const uint16_t crcTable[256] = { 0, 4129, 8258, 12387, 16516, 20645, 24774, 28903, 33032, 37161, 41290, 45419, 49548, 53677, 57806, 61935, 4657, 528, 12915, 8786, 21173, 17044, 29431, 25302, 37689, 33560, 45947, 41818, 54205, 50076, 62463, 58334, 9314, 13379, 1056, 5121, 25830, 29895, 17572, 21637, 42346, 46411, 34088, 38153, 58862, 62927, 50604, 54669, 13907, 9842, 5649, 1584, 30423, 26358, 22165, 18100, 46939, 42874, 38681, 34616, 63455, 59390, 55197, 51132, 18628, 22757, 26758, 30887, 2112, 6241, 10242, 14371, 51660, 55789, 59790, 63919, 35144, 39273, 43274, 47403, 23285, 19156, 31415, 27286, 6769, 2640, 14899, 10770, 56317, 52188, 64447, 60318, 39801, 35672, 47931, 43802, 27814, 31879, 19684, 23749, 11298, 15363, 3168, 7233, 60846, 64911, 52716, 56781, 44330, 48395, 36200, 40265, 32407, 28342, 24277, 20212, 15891, 11826, 7761, 3696, 65439, 61374, 57309, 53244, 48923, 44858, 40793, 36728, 37256, 33193, 45514, 41451, 53516, 49453, 61774, 57711, 4224, 161, 12482, 8419, 20484, 16421, 28742, 24679, 33721, 37784, 41979, 46042, 49981, 54044, 58239, 62302, 689, 4752, 8947, 13010, 16949, 21012, 25207, 29270, 46570, 42443, 38312, 34185, 62830, 58703, 54572, 50445, 13538, 9411, 5280, 1153, 29798, 25671, 21540, 17413, 42971, 47098, 34713, 38840, 59231, 63358, 50973, 55100, 9939, 14066, 1681, 5808, 26199, 30326, 17941, 22068, 55628, 51565, 63758, 59695, 39368, 35305, 47498, 43435, 22596, 18533, 30726, 26663, 6336, 2273, 14466, 10403, 52093, 56156, 60223, 64286, 35833, 39896, 43963, 48026, 19061, 23124, 27191, 31254, 2801, 6864, 10931, 14994, 64814, 60687, 56684, 52557, 48554, 44427, 40424, 36297, 31782, 27655, 23652, 19525, 15522, 11395, 7392, 3265, 61215, 65342, 53085, 57212, 44955, 49082, 36825, 40952, 28183, 32310, 20053, 24180, 11923, 16050, 3793, 7920 }; - - -+ (uint16_t) compute:(NSData*)data { - uint16_t crc = 0xffff; - const uint8_t *pdata = data.bytes; - unsigned long nbytes = data.length; - /* loop over the buffer data */ - while (nbytes-- > 0) { - crc = ((crc << 8) ^ crcTable[((crc >> 8) ^ *pdata++) & 0xff]) & 0xffff; - } - return crc; -} - -@end diff --git a/RileyLink/CRC8.h b/RileyLink/CRC8.h deleted file mode 100644 index e28fbeab1..000000000 --- a/RileyLink/CRC8.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// CRC8.h -// RileyLink -// -// Created by Pete Schwamb on 11/26/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import - -@interface CRC8 : NSObject - -+ (uint8_t) compute:(NSData*)data; - -@end diff --git a/RileyLink/CRC8.m b/RileyLink/CRC8.m deleted file mode 100644 index f7ab3ba99..000000000 --- a/RileyLink/CRC8.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// CRC8.m -// RileyLink -// -// Created by Pete Schwamb on 11/26/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "CRC8.h" - -@implementation CRC8 - -static const unsigned char crcTable[256] = { 0x0, 0x9B, 0xAD, 0x36, 0xC1, 0x5A, 0x6C, 0xF7, 0x19, 0x82, 0xB4, 0x2F, 0xD8, 0x43, 0x75, 0xEE, 0x32, 0xA9, 0x9F, 0x4, 0xF3, 0x68, 0x5E, 0xC5, 0x2B, 0xB0, 0x86, 0x1D, 0xEA, 0x71, 0x47, 0xDC, 0x64, 0xFF, 0xC9, 0x52, 0xA5, 0x3E, 0x8, 0x93, 0x7D, 0xE6, 0xD0, 0x4B, 0xBC, 0x27, 0x11, 0x8A, 0x56, 0xCD, 0xFB, 0x60, 0x97, 0xC, 0x3A, 0xA1, 0x4F, 0xD4, 0xE2, 0x79, 0x8E, 0x15, 0x23, 0xB8, 0xC8, 0x53, 0x65, 0xFE, 0x9, 0x92, 0xA4, 0x3F, 0xD1, 0x4A, 0x7C, 0xE7, 0x10, 0x8B, 0xBD, 0x26, 0xFA, 0x61, 0x57, 0xCC, 0x3B, 0xA0, 0x96, 0xD, 0xE3, 0x78, 0x4E, 0xD5, 0x22, 0xB9, 0x8F, 0x14, 0xAC, 0x37, 0x1, 0x9A, 0x6D, 0xF6, 0xC0, 0x5B, 0xB5, 0x2E, 0x18, 0x83, 0x74, 0xEF, 0xD9, 0x42, 0x9E, 0x5, 0x33, 0xA8, 0x5F, 0xC4, 0xF2, 0x69, 0x87, 0x1C, 0x2A, 0xB1, 0x46, 0xDD, 0xEB, 0x70, 0xB, 0x90, 0xA6, 0x3D, 0xCA, 0x51, 0x67, 0xFC, 0x12, 0x89, 0xBF, 0x24, 0xD3, 0x48, 0x7E, 0xE5, 0x39, 0xA2, 0x94, 0xF, 0xF8, 0x63, 0x55, 0xCE, 0x20, 0xBB, 0x8D, 0x16, 0xE1, 0x7A, 0x4C, 0xD7, 0x6F, 0xF4, 0xC2, 0x59, 0xAE, 0x35, 0x3, 0x98, 0x76, 0xED, 0xDB, 0x40, 0xB7, 0x2C, 0x1A, 0x81, 0x5D, 0xC6, 0xF0, 0x6B, 0x9C, 0x7, 0x31, 0xAA, 0x44, 0xDF, 0xE9, 0x72, 0x85, 0x1E, 0x28, 0xB3, 0xC3, 0x58, 0x6E, 0xF5, 0x2, 0x99, 0xAF, 0x34, 0xDA, 0x41, 0x77, 0xEC, 0x1B, 0x80, 0xB6, 0x2D, 0xF1, 0x6A, 0x5C, 0xC7, 0x30, 0xAB, 0x9D, 0x6, 0xE8, 0x73, 0x45, 0xDE, 0x29, 0xB2, 0x84, 0x1F, 0xA7, 0x3C, 0xA, 0x91, 0x66, 0xFD, 0xCB, 0x50, 0xBE, 0x25, 0x13, 0x88, 0x7F, 0xE4, 0xD2, 0x49, 0x95, 0xE, 0x38, 0xA3, 0x54, 0xCF, 0xF9, 0x62, 0x8C, 0x17, 0x21, 0xBA, 0x4D, 0xD6, 0xE0, 0x7B }; - - -+ (uint8_t) compute:(NSData*)data { - uint8_t crc = 0; - const uint8_t *pdata = data.bytes; - unsigned long nbytes = data.length; - /* loop over the buffer data */ - while (nbytes-- > 0) { - crc = crcTable[(crc ^ *pdata++) & 0xff]; - } - return crc; -} - - - -@end diff --git a/RileyLink/Config.h b/RileyLink/Config.h index 4b6b87794..4c5e0361b 100644 --- a/RileyLink/Config.h +++ b/RileyLink/Config.h @@ -12,11 +12,11 @@ NSUserDefaults *_defaults; } -+ (Config *)sharedInstance; ++ (nonnull Config *)sharedInstance; -@property (nonatomic, strong) NSString *nightscoutURL; -@property (nonatomic, strong) NSString *nightscoutAPISecret; -@property (nonatomic, strong) NSString *pumpID; +@property (nonatomic, nullable, strong) NSString *nightscoutURL; +@property (nonatomic, nullable, strong) NSString *nightscoutAPISecret; +@property (nonatomic, nullable, strong) NSString *pumpID; @property (nonatomic, readonly) BOOL hasValidConfiguration; diff --git a/RileyLink/ConfigureViewController.m b/RileyLink/ConfigureViewController.m index 76ee99931..e4741d727 100644 --- a/RileyLink/ConfigureViewController.m +++ b/RileyLink/ConfigureViewController.m @@ -30,7 +30,7 @@ - (void)viewDidLoad { [super viewDidLoad]; if (self.revealViewController != nil) { menuButton.target = self.revealViewController; - [menuButton setAction:@selector(revealToggle:)]; + menuButton.action = @selector(revealToggle:); [self.view addGestureRecognizer: self.revealViewController.panGestureRecognizer]; } @@ -85,15 +85,15 @@ - (void)viewDidAppear:(BOOL)animated { } - (void) loadValues { - nightscoutURL.text = [[Config sharedInstance] nightscoutURL]; - nightscoutAPISecret.text = [[Config sharedInstance] nightscoutAPISecret]; - pumpId.text = [[Config sharedInstance] pumpID]; + nightscoutURL.text = [Config sharedInstance].nightscoutURL; + nightscoutAPISecret.text = [Config sharedInstance].nightscoutAPISecret; + pumpId.text = [Config sharedInstance].pumpID; } - (void) saveValues { - [[Config sharedInstance] setNightscoutURL: nightscoutURL.text]; - [[Config sharedInstance] setNightscoutAPISecret: nightscoutAPISecret.text]; - [[Config sharedInstance] setPumpID:pumpId.text]; + [Config sharedInstance].nightscoutURL = nightscoutURL.text; + [Config sharedInstance].nightscoutAPISecret = nightscoutAPISecret.text; + [Config sharedInstance].pumpID = pumpId.text; } diff --git a/RileyLink/DeviceLinkMessage.h b/RileyLink/DeviceLinkMessage.h deleted file mode 100644 index 38d33d4ea..000000000 --- a/RileyLink/DeviceLinkMessage.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// DeviceLink.h -// RileyLink -// -// Created by Pete Schwamb on 1/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import -#import "MessageBase.h" - -@interface DeviceLinkMessage : MessageBase - -@property (nonatomic, readonly) NSInteger sequence; -@property (nonatomic, readonly) NSString *deviceAddress; - -@end diff --git a/RileyLink/DeviceLinkMessage.m b/RileyLink/DeviceLinkMessage.m deleted file mode 100644 index 641d9bfb6..000000000 --- a/RileyLink/DeviceLinkMessage.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// DeviceLink.m -// RileyLink -// -// Created by Pete Schwamb on 1/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "DeviceLinkMessage.h" -#import "NSData+Conversion.h" - -@implementation DeviceLinkMessage - -- (NSDictionary*) bitBlocks { - return @{@"sequence": @[@1, @7] - }; -} - -- (NSInteger) sequence { - return [self getBits:@"sequence"]; -} - -- (NSString*) deviceAddress { - return [[self.data hexadecimalString] substringWithRange:NSMakeRange(2, 6)]; -} - -@end diff --git a/RileyLink/FindDeviceMessage.h b/RileyLink/FindDeviceMessage.h deleted file mode 100644 index 5ec301a53..000000000 --- a/RileyLink/FindDeviceMessage.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// FindDeviceMessage.h -// RileyLink -// -// Created by Pete Schwamb on 1/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import -#import "MessageBase.h" - -@interface FindDeviceMessage : MessageBase - -@property (nonatomic, readonly) NSInteger sequence; -@property (nonatomic, readonly) NSString *deviceAddress; - -@end diff --git a/RileyLink/FindDeviceMessage.m b/RileyLink/FindDeviceMessage.m deleted file mode 100644 index 41479bd9f..000000000 --- a/RileyLink/FindDeviceMessage.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// FindDeviceMessage.m -// RileyLink -// -// Created by Pete Schwamb on 1/2/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "FindDeviceMessage.h" -#import "NSData+Conversion.h" - -@implementation FindDeviceMessage - -- (NSDictionary*) bitBlocks { - return @{@"sequence": @[@1, @7] - }; -} - -- (NSInteger) sequence { - return [self getBits:@"sequence"]; -} - -- (NSString*) deviceAddress { - return [[self.data hexadecimalString] substringWithRange:NSMakeRange(2, 6)]; -} - -@end diff --git a/RileyLink/HistoryPage.h b/RileyLink/HistoryPage.h deleted file mode 100644 index 33ff48531..000000000 --- a/RileyLink/HistoryPage.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// HistoryPage.h -// RileyLink -// -// Created by Pete Schwamb on 11/18/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "PumpModel.h" - -@interface HistoryPage : NSObject - -@property (nonatomic, nonnull, readonly, strong) NSData *data; -@property (nonatomic, nullable, readonly, strong) PumpModel *pumpModel; -@property (nonatomic, nullable, readonly, strong) NSDictionary *registry; - -- (nonnull instancetype)initWithData:(nonnull NSData *)data andPumpModel:(nullable PumpModel *)model; -- (nonnull NSArray*) decode; -- (BOOL) isCRCValid; - -@end diff --git a/RileyLink/HistoryPage.m b/RileyLink/HistoryPage.m deleted file mode 100644 index 3a2f80ffc..000000000 --- a/RileyLink/HistoryPage.m +++ /dev/null @@ -1,105 +0,0 @@ -// -// HistoryPage.m -// RileyLink -// -// Created by Pete Schwamb on 11/18/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "HistoryPage.h" -#import "RuntimeUtils.h" -#import "PumpHistoryEventBase.h" -#import "CRC16.h" -#import "PHEUnabsorbedInsulin.h" -#import "PHEBolusNormal.h" - -@implementation HistoryPage - -- (nonnull instancetype)initWithData:(nonnull NSData *)data andPumpModel:(nullable PumpModel *)model -{ - self = [super init]; - if (self) { - _data = data; - _pumpModel = model; - - //@registry = self.class.type_registry - NSMutableDictionary *d = [NSMutableDictionary dictionary]; - for (NSString *classStr in [RuntimeUtils classStringsForClassesOfType:[PumpHistoryEventBase class]]) { - Class eventClass = NSClassFromString(classStr); - SEL selector = NSSelectorFromString(@"eventTypeCode"); - if ([eventClass respondsToSelector:selector]) { - NSMethodSignature *sig = [[eventClass class] methodSignatureForSelector:selector]; - if (sig == nil) { - [NSException raise:@"Missing class method" format:@"%@ does not implement +eventTypeCode.", eventClass]; - } - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; - [invocation setSelector:selector]; - [invocation setTarget:eventClass]; - [invocation invoke]; - int returnValue; - [invocation getReturnValue:&returnValue]; - NSNumber *eventCode = [NSNumber numberWithInt:returnValue]; - d[eventCode] = eventClass; - } - } - _registry = d; - } - return self; -} - -- (NSArray*) decode { - NSMutableArray *events = [NSMutableArray array]; - NSUInteger offset = 0; - NSUInteger length = _data.length; - PumpHistoryEventBase *event; - PHEUnabsorbedInsulin *unabsorbedInsulinRecord; - while (offset < length) { - event = [self matchEvent:offset]; - if (event) { - if ([event class] == [PHEBolusNormal class] && unabsorbedInsulinRecord != nil) { - PHEBolusNormal *bolus = (PHEBolusNormal*)event; - bolus.unabsorbedInsulinRecord = unabsorbedInsulinRecord; - unabsorbedInsulinRecord = nil; - } - if ([event class] == [PHEUnabsorbedInsulin class]) { - unabsorbedInsulinRecord = (PHEUnabsorbedInsulin*)event; - } else { - [events addObject:event]; - } - offset += [event length]; - } else { - // TODO: Track bytes we skipped over - offset += 1; - } - } - return events; -} - -- (BOOL) isCRCValid { - if (_data.length < 3) { - return NO; - } - uint8_t *bytes = (uint8_t*)_data.bytes; - uint16_t packetCRC = bytes[_data.length-1] + (bytes[_data.length-2] << 8); - return packetCRC == [CRC16 compute:[_data subdataWithRange:NSMakeRange(0, _data.length-2)]]; -} - -- (nonnull const unsigned char *) bytes { - return [_data bytes]; -} - -- (PumpHistoryEventBase*) matchEvent:(NSUInteger) offset { - NSNumber *code = [NSNumber numberWithInt:[self bytes][offset]]; - Class klazz = _registry[code]; - if (klazz) { - NSData *eventData = [_data subdataWithRange:NSMakeRange(offset, _data.length - offset)]; - PumpHistoryEventBase *event = [[klazz alloc] initWithData:eventData andPumpModel:self.pumpModel]; - if (event.length > event.data.length) { - return nil; - } - return event; - } - return nil; -} - -@end diff --git a/RileyLink/ISO8601DateFormatter.m b/RileyLink/ISO8601DateFormatter.m index c4790098e..785bcc6b0 100644 --- a/RileyLink/ISO8601DateFormatter.m +++ b/RileyLink/ISO8601DateFormatter.m @@ -241,7 +241,7 @@ - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out if (strict) timeSep = ISO8601DefaultTimeSeparatorCharacter; NSAssert(timeSep != '\0', @"Time separator must not be NUL."); - BOOL isValidDate = ([string length] > 0U); + BOOL isValidDate = (string.length > 0U); NSTimeZone *timeZone = nil; const unichar *ch = (const unichar *)[string cStringUsingEncoding:NSUnicodeStringEncoding]; @@ -728,7 +728,7 @@ - (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(u [timeFormatMutable replaceOccurrencesOfString:@":" withString:[NSString stringWithCharacters:&timeSep length:1U] options:NSBackwardsSearch | NSLiteralSearch - range:(NSRange){ 0UL, [timeFormat length] }]; + range:(NSRange){ 0UL, timeFormat.length }]; timeFormat = timeFormatMutable; } return timeFormat; diff --git a/RileyLink/Images.xcassets/AppIcon.appiconset/Contents.json b/RileyLink/Images.xcassets/AppIcon.appiconset/Contents.json index e07deaa1e..0234619ca 100644 --- a/RileyLink/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/RileyLink/Images.xcassets/AppIcon.appiconset/Contents.json @@ -45,9 +45,8 @@ "scale" : "2x" }, { - "size" : "60x60", "idiom" : "iphone", - "filename" : "Icon-60@3x.png", + "size" : "60x60", "scale" : "3x" }, { diff --git a/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60.png b/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60.png deleted file mode 100644 index 1b1737e95..000000000 Binary files a/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60.png and /dev/null differ diff --git a/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png deleted file mode 100644 index b73aa6128..000000000 Binary files a/RileyLink/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png and /dev/null differ diff --git a/RileyLink/LaunchScreen.xib b/RileyLink/LaunchScreen.xib index 34fa0ea68..402471489 100644 --- a/RileyLink/LaunchScreen.xib +++ b/RileyLink/LaunchScreen.xib @@ -1,8 +1,8 @@ - + - + @@ -20,7 +20,7 @@ - + diff --git a/RileyLink/Log.h b/RileyLink/Log.h index d02bdeb01..90b2d686c 100644 --- a/RileyLink/Log.h +++ b/RileyLink/Log.h @@ -9,7 +9,7 @@ #ifndef RILEYLINK_Log_h #define RILEYLINK_Log_h -#define LOG_TO_NS 0 +//#define LOG_TO_NS 1 #define NSLog(args...) _Log(@"DEBUG ", __FILE__,__LINE__,__PRETTY_FUNCTION__,args); @interface Log : NSObject diff --git a/RileyLink/Log.m b/RileyLink/Log.m index 641e47969..440dbc890 100644 --- a/RileyLink/Log.m +++ b/RileyLink/Log.m @@ -63,7 +63,7 @@ void append(NSString *msg){ NSString *path = [documentsDirectory stringByAppendingPathComponent:@"logfile.txt"]; // create if needed if (![[NSFileManager defaultManager] fileExistsAtPath:path]){ - fprintf(stderr,"Creating file at %s",[path UTF8String]); + fprintf(stderr,"Creating file at %s",path.UTF8String); [[NSData data] writeToFile:path atomically:YES]; } // append @@ -78,7 +78,7 @@ void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcNa static NSDateFormatter *dateFormat = nil; if (nil == dateFormat) { dateFormat = [[NSDateFormatter alloc] init]; // NOT NSDateFormatter *dateFormat = ... - [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; + dateFormat.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; } va_list ap; @@ -87,7 +87,7 @@ void _Log(NSString *prefix, const char *file, int lineNumber, const char *funcNa NSDate *time = [NSDate date]; NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:@"%@: %@", [dateFormat stringFromDate:time], format] arguments:ap]; va_end (ap); - fprintf(stderr,"%s", [msg UTF8String]); + fprintf(stderr,"%s", msg.UTF8String); append(msg); } @end \ No newline at end of file diff --git a/RileyLink/MainAppViewController.m b/RileyLink/MainAppViewController.m index c2d996dd8..d45c6fcca 100644 --- a/RileyLink/MainAppViewController.m +++ b/RileyLink/MainAppViewController.m @@ -6,17 +6,14 @@ // Copyright (c) 2015 Pete Schwamb. All rights reserved. // -#import "RileyLinkBLEManager.h" +@import RileyLinkBLEKit; + #import "NSData+Conversion.h" -#import "PumpStatusMessage.h" -#import "NightScoutUploader.h" #import "Config.h" -#import "AppDelegate.h" #import "RileyLinkRecord.h" -#import "RileyLinkBLEManager.h" -#import "PumpState.h" - #import "MainAppViewController.h" +#import "RileyLink-Swift.h" + @interface MainAppViewController () { NSDictionary *lastStatus; @@ -38,10 +35,10 @@ - (void)viewDidLoad { [UIView setAnimationsEnabled:NO]; self.uploader = [[NightScoutUploader alloc] init]; - self.uploader.siteURL = [[Config sharedInstance] nightscoutURL]; - self.uploader.APISecret = [[Config sharedInstance] nightscoutAPISecret]; + self.uploader.siteURL = [Config sharedInstance].nightscoutURL; + self.uploader.APISecret = [Config sharedInstance].nightscoutAPISecret; - AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; self.managedObjectContext = appDelegate.managedObjectContext; [self setupAutoConnect]; @@ -59,17 +56,17 @@ - (void)setupAutoConnect { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"RileyLinkRecord" inManagedObjectContext:self.managedObjectContext]; - [fetchRequest setEntity:entity]; + fetchRequest.entity = entity; NSError *error; NSMutableSet *autoConnectIds = [[NSMutableSet alloc] init]; NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; for (RileyLinkRecord *record in fetchedObjects) { NSLog(@"Loaded: %@ from db", record.name); - if ([record.autoConnect boolValue]) { + if ((record.autoConnect).boolValue) { [autoConnectIds addObject:record.peripheralId]; } } - [[RileyLinkBLEManager sharedManager] setAutoConnectIds:autoConnectIds]; + [RileyLinkBLEManager sharedManager].autoConnectIds = autoConnectIds; } diff --git a/RileyLink/MessageBase.h b/RileyLink/MessageBase.h deleted file mode 100644 index 8f54bf341..000000000 --- a/RileyLink/MessageBase.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// MessageBase.h -// GlucoseLink -// -// Created by Pete Schwamb on 5/26/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "MinimedPacket.h" - -@interface MessageBase : NSObject - -@property (nonatomic, nonnull, readonly, strong) NSData *data; - -- (nonnull instancetype)initWithData:(nonnull NSData*)data NS_DESIGNATED_INITIALIZER; -@property (nonatomic, nonnull, readonly, copy) NSDictionary *bitBlocks; -- (NSInteger) getBits:(nullable NSString*)key; -- (void) setBits:(nonnull NSString*)key toValue:(NSInteger)val; -- (unsigned char) getBitAtIndex:(NSInteger)idx; -- (NSInteger)bitsOffset; - -@property (nonatomic, readonly) PacketType packetType; -@property (nonatomic, readonly) MessageType messageType; -@property (nonatomic, nonnull, readonly, copy) NSString *address; - -@end diff --git a/RileyLink/MessageBase.m b/RileyLink/MessageBase.m deleted file mode 100644 index 56062e8e6..000000000 --- a/RileyLink/MessageBase.m +++ /dev/null @@ -1,89 +0,0 @@ -// -// MessageBase.m -// GlucoseLink -// -// Created by Pete Schwamb on 5/26/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import "MessageBase.h" - -@interface MessageBase () - -@property (nonatomic, nonnull, strong) NSData *data; - -@end - -@implementation MessageBase - -- (instancetype)init NS_UNAVAILABLE -{ - return nil; -} - -- (instancetype)initWithData:(NSData*)data -{ - self = [super init]; - if (self) { - _data = data; - } - return self; -} - -- (NSDictionary*) bitBlocks { - return @{}; -} - -- (unsigned char) getBitAtIndex:(NSInteger)idx { - NSInteger byteOffset = idx/8; - int posBit = idx%8; - if (byteOffset < _data.length) { - unsigned char valByte = ((unsigned char*)_data.bytes)[byteOffset]; - return valByte>>(8-(posBit+1)) & 0x1; - } else { - return 0; - } -} - -- (NSInteger)bitsOffset { - return 5; -} - -- (NSInteger) getBits:(NSString*)key { - NSArray *range = [self bitBlocks][key]; - NSInteger bitsNeeded = [[range lastObject] integerValue]; - // bitBlocks start at byte idx 5 - NSInteger offset = [[range firstObject] integerValue] + ([self bitsOffset]*8); - NSInteger rval = 0; - while (bitsNeeded > 0) { - rval = (rval << 1) + [self getBitAtIndex:offset++]; - bitsNeeded--; - } - return rval; -} - -- (void) setBits:(NSString*)key toValue:(NSInteger)val { - //TODO -} - -- (unsigned char)byteAt:(NSInteger)index { - if (_data && index < [_data length]) { - return ((unsigned char*)[_data bytes])[index]; - } else { - return 0; - } -} - -- (PacketType) packetType { - return [self byteAt:0]; -} - -- (MessageType) messageType { - return [self byteAt:4]; -} - -- (NSString*) address { - return [NSString stringWithFormat:@"%02x%02x%02x", [self byteAt:1], [self byteAt:2], [self byteAt:3]]; -} - -@end diff --git a/RileyLink/MeterMessage.h b/RileyLink/MeterMessage.h deleted file mode 100644 index 9936bf2f0..000000000 --- a/RileyLink/MeterMessage.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// MeterMessage.h -// GlucoseLink -// -// Created by Pete Schwamb on 5/30/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "MessageBase.h" - -@interface MeterMessage : MessageBase - -@property (nonatomic, strong) NSDate *dateReceived; - -@property (nonatomic, readonly) NSInteger glucose; - -- (BOOL) isAck; - - -@end diff --git a/RileyLink/MeterMessage.m b/RileyLink/MeterMessage.m deleted file mode 100644 index 7e9d89c20..000000000 --- a/RileyLink/MeterMessage.m +++ /dev/null @@ -1,31 +0,0 @@ -// -// MeterMessage.m -// GlucoseLink -// -// Created by Pete Schwamb on 5/30/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import "MeterMessage.h" - -@implementation MeterMessage - -- (NSDictionary*) bitBlocks { - return @{@"flags": @[@37, @2], - @"glucose": @[@39, @9] - }; -} - -- (BOOL) isAck { - return [self getBits:@"flags"] == 3; -} - -- (NSInteger) glucose { - return [self getBits:@"glucose"]; -} - -- (NSInteger) bitsOffset { - return 0; -} - -@end diff --git a/RileyLink/MinimedPacket.h b/RileyLink/MinimedPacket.h deleted file mode 100644 index febb418c9..000000000 --- a/RileyLink/MinimedPacket.h +++ /dev/null @@ -1,54 +0,0 @@ -// -// MinimedPacket.h -// GlucoseLink -// -// Created by Pete Schwamb on 8/5/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import - -@class MessageBase; - -@interface MinimedPacket : NSObject - -typedef NS_ENUM(unsigned char, PacketType) { - PacketTypeSentry = 0xa2, - PacketTypeMeter = 0xa5, - PacketTypeCarelink = 0xa7, - PacketTypeSensor = 0xa8 -}; - -typedef NS_ENUM(unsigned char, MessageType) { - MESSAGE_TYPE_ALERT = 0x01, - MESSAGE_TYPE_ALERT_CLEARED = 0x02, - MESSAGE_TYPE_DEVICE_TEST = 0x03, - MESSAGE_TYPE_PUMP_STATUS = 0x04, - MESSAGE_TYPE_ACK = 0x06, - MESSAGE_TYPE_PUMP_BACKFILL = 0x08, - MESSAGE_TYPE_FIND_DEVICE = 0x09, - MESSAGE_TYPE_DEVICE_LINK = 0x0a, - MESSAGE_TYPE_PUMP_DUMP = 0x0a, - MESSAGE_TYPE_POWER = 0x5d, - MESSAGE_TYPE_BUTTON_PRESS = 0x5b, - MESSAGE_TYPE_GET_PUMP_MODEL = 0x8d, - MESSAGE_TYPE_GET_BATTERY = 0x72, - MESSAGE_TYPE_READ_HISTORY = 0x80, -}; - -- ( MessageBase* _Nullable)toMessage; - -- (nonnull instancetype)initWithData:(nonnull NSData*)data NS_DESIGNATED_INITIALIZER; -@property (nonatomic, getter=isValid, readonly) BOOL valid; -@property (nonatomic, nullable, readonly, copy) NSString *hexadecimalString; -@property (nonatomic, readonly) PacketType packetType; -@property (nonatomic, readonly) MessageType messageType; -@property (nonatomic, nonnull, readonly, copy) NSString *address; -+ (nonnull NSData*)encodeData:(nonnull NSData*)data; - -@property (nonatomic, nullable, strong) NSData *data; -@property (nonatomic, nullable, strong) NSDate *capturedAt; -@property (nonatomic, assign) int rssi; -@property (nonatomic, assign) int packetNumber; - -@end diff --git a/RileyLink/MySentryPairViewController.swift b/RileyLink/MySentryPairViewController.swift new file mode 100644 index 000000000..579af4bcd --- /dev/null +++ b/RileyLink/MySentryPairViewController.swift @@ -0,0 +1,284 @@ +// +// MySentryPairViewController.swift +// RileyLink +// +// Created by Pete Schwamb on 2/29/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import UIKit +import MinimedKit +import RileyLinkBLEKit + + +class MySentryPairViewController: UIViewController, UITextFieldDelegate { + + enum PairingState { + case Complete + case NeedsConfig + case Ready + case Started + case ReceivedFindPacket + case ReceivedLinkPacket + } + + var device: RileyLinkBLEDevice! + var wasDismissed = false + + @IBOutlet var instructionLabel: UILabel! + @IBOutlet var deviceIDTextField: UITextField! + @IBOutlet var startButton: UIButton! + @IBOutlet var progressView: UIProgressView! + + lazy var flailGestureRecognizer: UITapGestureRecognizer = { + let r = UITapGestureRecognizer(target: self, action: #selector(MySentryPairViewController.closeKeyboard(_:))) + r.cancelsTouchesInView = false; + r.enabled = false; + return r + }() + + var sendCounter: UInt8 = 0 + + override func viewDidLoad() { + super.viewDidLoad() + + deviceIDTextField.text = (device.peripheral.identifier.UUIDString as NSString).substringToIndex(6); + deviceIDTextField.delegate = self + + view.addGestureRecognizer(flailGestureRecognizer) + + textFieldDidEndEditing(deviceIDTextField) + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + override func viewDidDisappear(animated: Bool) { + wasDismissed = true + } + + + // MARK: - UITextFieldDelegate + + func textFieldDidBeginEditing(textField: UITextField) { + flailGestureRecognizer.enabled = true + } + + func textFieldDidEndEditing(textField: UITextField) { + flailGestureRecognizer.enabled = false + + if textField.text?.characters.count == 6 { + state = .Ready + } else if .Ready == self.state { + state = .NeedsConfig + } + } + + func textField(textField: UITextField, + shouldChangeCharactersInRange range: NSRange, + replacementString string: String) -> Bool { + let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString:string) + + if newString.characters.count > 6 { + return false + } else if newString.characters.count == 6 { + textField.text = newString + textField.resignFirstResponder() + return false + } else if .Ready == self.state { + state = .NeedsConfig + } + + return true + } + + func textFieldShouldReturn(textField: UITextField) -> Bool { + return true + } + + // MARK: - Other + + func listenForPairing() { + if wasDismissed { + return + } + + let cmd = GetPacketCmd() + cmd.listenChannel = 0; + cmd.timeoutMS = 30000; + runCommand(cmd) + } + + var state: PairingState = .NeedsConfig { + didSet { + if (oldValue == state) { + return + } + switch state { + case .NeedsConfig: + startButton.enabled = false + startButton.hidden = true + instructionLabel.text = NSLocalizedString( + "Enter a 6-digit numeric value to identify your MySentry.", + comment: "Device ID instruction") + instructionLabel.hidden = false + case .Ready: + startButton.enabled = true + startButton.hidden = false + progressView.progress = 0 + + instructionLabel.hidden = true + case .Started: + startButton.enabled = false + startButton.hidden = true + deviceIDTextField.enabled = false + progressView.setProgress(1.0 / 4.0, animated:true) + + instructionLabel.text = NSLocalizedString( + "On your pump, go to the Find Device screen and select \"Find Device\"." + + "\n" + + "\nMain Menu >" + + "\nUtilities >" + + "\nConnect Devices >" + + "\nOther Devices >" + + "\nOn >" + + "\nFind Device", + comment: "Pump find device instruction") + instructionLabel.hidden = false + case .ReceivedFindPacket: + progressView.setProgress(2.0 / 4.0, animated:true) + + instructionLabel.text = NSLocalizedString( + "Pairing in process, please wait.", + comment: "Pairing waiting instruction") + case .ReceivedLinkPacket: + progressView.setProgress(3.0 / 4.0, animated:true) + instructionLabel.text = NSLocalizedString( + "Pump accepted pairing. " + + "Waiting for MySentry update from pump. " + + "This could take up to five minutes...", + comment: "Pairing waiting instruction") + case .Complete: + progressView.setProgress(4.0 / 4.0, animated:true) + + instructionLabel.text = NSLocalizedString( + "Congratulations! Pairing is complete.", + comment: "Pairing waiting instruction") + } + } + } + + // MARK: - Actions + + func packetReceived(packet: RFPacket) { + + var handled = false + + if let data = packet.data, msg = PumpMessage(rxData: data) { + if msg.packetType == PacketType.MySentry && + msg.address.hexadecimalString == Config.sharedInstance().pumpID { + switch (msg.messageType) { + case MessageType.FindDevice: + handleFindDevice(msg.messageBody as! FindDeviceMessageBody) + handled = true + case MessageType.DeviceLink: + handleDeviceLink(msg.messageBody as! DeviceLinkMessageBody) + handled = true + case MessageType.PumpStatus: + handlePumpStatus(msg.messageBody as! MySentryPumpStatusMessageBody) + handled = true + default: + NSLog("Unexpected packet received: " + String(msg.messageType)) + } + } + } + if (!handled && .Complete != self.state) { + // Other random packet; ignore and start listening again. + performSelector(#selector(MySentryPairViewController.listenForPairing), withObject:nil, afterDelay:0) + } + } + + func makeCommandForAckAndListen(sequence: UInt8, messageType: MessageType) -> ReceivingPacketCmd { + let replyString = String(format: "%02x%@%02x%02x%@00%02x000000", + PacketType.MySentry.rawValue, + Config.sharedInstance().pumpID!, + MessageType.PumpAck.rawValue, + sequence, + self.deviceIDTextField.text!, + messageType.rawValue) + let data = NSData(hexadecimalString: replyString) + let send = SendAndListenCmd() + send.sendChannel = 0 + send.timeoutMS = 180 + send.listenChannel = 0 + send.packet = RFPacket(data: data!) + return send; + } + + func runCommand(cmd: ReceivingPacketCmd) { + device.runSession { + (session: RileyLinkCmdSession) -> Void in + if (session.doCmd(cmd, withTimeoutMs: 31000)) { + dispatch_async(dispatch_get_main_queue(), { () -> Void in + let rxPacket = cmd.receivedPacket + self.packetReceived(rxPacket) + }) + } else { + // Timed out. Try again + self.performSelector(#selector(MySentryPairViewController.listenForPairing), withObject:nil, afterDelay:0) + } + } + } + + func handleFindDevice(msg: FindDeviceMessageBody) { + if .Started == self.state { + self.state = .ReceivedFindPacket + } + + let cmd = makeCommandForAckAndListen(msg.sequence, messageType: MessageType.FindDevice) + runCommand(cmd) + } + + func handleDeviceLink(msg: DeviceLinkMessageBody) { + if .ReceivedFindPacket == self.state { + self.state = .ReceivedLinkPacket + } + + let cmd = makeCommandForAckAndListen(msg.sequence, messageType: MessageType.DeviceLink) + runCommand(cmd) + } + + func handlePumpStatus(msg: MySentryPumpStatusMessageBody) { + if .ReceivedLinkPacket == self.state { + self.state = .Complete; + } + let cmd = makeCommandForAckAndListen(0, messageType: MessageType.PumpStatus) + runCommand(cmd) + } + + func closeKeyboard(recognizer: UITapGestureRecognizer) { + self.view.endEditing(true) + } + + @IBAction func startPairing(sender: UIButton) { + if (.Ready == self.state) { + self.state = .Started + listenForPairing() + } + } + + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/RileyLink/MySentryPairingViewController.h b/RileyLink/MySentryPairingViewController.h deleted file mode 100644 index 4bac23184..000000000 --- a/RileyLink/MySentryPairingViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// MySentryPairingViewController.h -// RileyLink -// -// Created by Nathan Racklyeft on 8/14/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "RileyLinkBLEDevice.h" - -@interface MySentryPairingViewController : UIViewController - -@property (nonatomic, strong) RileyLinkBLEDevice *device; - -@end diff --git a/RileyLink/MySentryPairingViewController.m b/RileyLink/MySentryPairingViewController.m deleted file mode 100644 index f647cdf8e..000000000 --- a/RileyLink/MySentryPairingViewController.m +++ /dev/null @@ -1,296 +0,0 @@ -// -// MySentryPairingViewController.m -// RileyLink -// -// Created by Nathan Racklyeft on 8/14/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import "MySentryPairingViewController.h" -#import "Config.h" -#import "MinimedPacket.h" -#import "NSData+Conversion.h" -#import "RileyLinkBLEManager.h" -#import "GetPacketCmd.h" -#import "SendAndListenCmd.h" -#import "DeviceLinkMessage.h" -#import "FindDeviceMessage.h" -#import "PumpStatusMessage.h" - -typedef NS_ENUM(NSUInteger, PairingState) { - PairingStateComplete, - PairingStateNeedsConfig, - PairingStateReady, - PairingStateStarted, - PairingStateReceivedFindPacket, - PairingStateReceivedLinkPacket -}; - - -@interface MySentryPairingViewController () { - BOOL wasDismissed; -} - -@property (weak, nonatomic) IBOutlet UILabel *instructionLabel; -@property (weak, nonatomic) IBOutlet UITextField *deviceIDTextField; -@property (weak, nonatomic) IBOutlet UIButton *startButton; -@property (weak, nonatomic) IBOutlet UIProgressView *progressView; -@property (strong, nonatomic) UITapGestureRecognizer *flailGestureRecognizer; - -@property (nonatomic) PairingState state; -@property (nonatomic) unsigned char sendCounter; - -@end - -@implementation MySentryPairingViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.sendCounter = 0; - self.state = PairingStateNeedsConfig; - - self.deviceIDTextField.text = [self.device.peripheral.identifier.UUIDString substringToIndex:6]; - self.deviceIDTextField.delegate = self; - [self.view addGestureRecognizer:self.flailGestureRecognizer]; - - [self textFieldDidEndEditing:self.deviceIDTextField]; -} - -- (void)viewDidDisappear:(BOOL)animated { - wasDismissed = YES; -} - -- (void)listenForPairing { - if (wasDismissed) { - return; - } - GetPacketCmd *cmd = [[GetPacketCmd alloc] init]; - cmd.listenChannel = 2; - cmd.timeoutMS = 30000; - - // TODO: Upgrade to new api -// [self.device doCmd:cmd withCompletionHandler:^(CmdBase * _Nonnull cmd) { -// if (cmd.response) { -// MinimedPacket *rxPacket = [[MinimedPacket alloc] initWithData:cmd.response]; -// [self packetReceived:rxPacket]; -// } -// }]; -} - -- (void)handleResponse:(NSData*)response { - if (response) { - MinimedPacket *rxPacket = [[MinimedPacket alloc] initWithData:response]; - [self packetReceived:rxPacket]; - } -} - -- (UITapGestureRecognizer *)flailGestureRecognizer -{ - if (!_flailGestureRecognizer) { - _flailGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)]; - _flailGestureRecognizer.cancelsTouchesInView = NO; - _flailGestureRecognizer.enabled = NO; - } - return _flailGestureRecognizer; -} - -- (void)setState:(PairingState)state { - if (state == _state) { - return; - } - - _state = state; - - switch (state) { - case PairingStateNeedsConfig: - self.startButton.enabled = NO; - self.startButton.hidden = YES; - self.instructionLabel.text = NSLocalizedString(@"Enter a 6-digit numeric value to identify your MySentry.", - @"Device ID instruction"); - self.instructionLabel.hidden = NO; - break; - case PairingStateReady: - self.startButton.enabled = YES; - self.startButton.hidden = NO; - self.progressView.progress = 0; - - self.instructionLabel.hidden = YES; - break; - case PairingStateStarted: - self.startButton.enabled = NO; - self.startButton.hidden = YES; - self.deviceIDTextField.enabled = NO; - [self.progressView setProgress:1.0 / 4.0 animated:YES]; - - self.instructionLabel.text = NSLocalizedString(@"On your pump, go to the Find Device screen and select \"Find Device\"." - @"\n" - @"\nMain Menu >" - @"\nUtilities >" - @"\nConnect Devices >" - @"\nOther Devices >" - @"\nOn >" - @"\nFind Device", - @"Pump find device instruction"); - self.instructionLabel.hidden = NO; - break; - case PairingStateReceivedFindPacket: - [self.progressView setProgress:2.0 / 4.0 animated:YES]; - - self.instructionLabel.text = NSLocalizedString(@"Pairing in process, please wait.", - @"Pairing waiting instruction"); - break; - case PairingStateReceivedLinkPacket: - [self.progressView setProgress:3.0 / 4.0 animated:YES]; - self.instructionLabel.text = NSLocalizedString(@"Pump accepted pairing. " - @"Waiting for MySentry update from pump. " - @"This could take up to five minutes...", - @"Pairing waiting instruction"); - break; - case PairingStateComplete: - [self.progressView setProgress:4.0 / 4.0 animated:YES]; - - self.instructionLabel.text = NSLocalizedString(@"Congratulations! Pairing is complete.", - @"Pairing waiting instruction"); - break; - } -} - -#pragma mark - UITextFieldDelegate - -- (void)textFieldDidBeginEditing:(UITextField *)textField { - self.flailGestureRecognizer.enabled = YES; -} - -- (void)textFieldDidEndEditing:(UITextField *)textField { - self.flailGestureRecognizer.enabled = NO; - - if (textField.text.length == 6) { - self.state = PairingStateReady; - } else if (PairingStateReady == self.state) { - self.state = PairingStateNeedsConfig; - } -} - -- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { - NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; - - if (newString.length > 6) { - return NO; - } else if (newString.length == 6) { - textField.text = newString; - [textField resignFirstResponder]; - return NO; - } else if (PairingStateReady == self.state) { - self.state = PairingStateNeedsConfig; - } - - return YES; -} - -- (BOOL)textFieldShouldReturn:(UITextField *)textField { - return YES; -} - -#pragma mark - Actions - -- (void)packetReceived:(MinimedPacket *)packet { - - BOOL handled = NO; - - if (packet && - PacketTypeSentry == packet.packetType && - [packet.address isEqualToString:[Config sharedInstance].pumpID]) - { - MessageBase *msg = [packet toMessage]; - if ([msg class] == [FindDeviceMessage class]) { - [self handleFindDevice:(FindDeviceMessage*)msg]; - handled = YES; - } - else if ([msg class] == [DeviceLinkMessage class]) { - [self handleDeviceLink:(DeviceLinkMessage*)msg]; - handled = YES; - } - else if ([msg class] == [PumpStatusMessage class]) { - [self handlePumpStatus:(PumpStatusMessage*)msg]; - handled = YES; - } - } - if (!handled) { - // Other random packet; ignore and start listening again. - [self performSelector:@selector(listenForPairing) withObject:nil afterDelay:0]; - } -} - -- (CmdBase *)makeCommandForAckAndListen:(uint8_t)sequence forMessageType:(uint8_t)messageType { - NSString *replyString = [NSString stringWithFormat:@"%02x%@%02x%02x%@00%02x000000", - PacketTypeSentry, - [Config sharedInstance].pumpID, - MESSAGE_TYPE_ACK, - sequence, - self.deviceIDTextField.text, - messageType - ]; - NSData *data = [NSData dataWithHexadecimalString:replyString]; - SendAndListenCmd *send = [[SendAndListenCmd alloc] init]; - send.sendChannel = 0; - send.timeoutMS = 180; - send.listenChannel = 2; - send.packet = [MinimedPacket encodeData:data]; - return send; -} - -- (void)runCommand:(CmdBase*) cmd { - // TODO: Upgrade to new api -// [self.device doCmd:cmd withCompletionHandler:^(CmdBase * _Nonnull cmd) { -// if (cmd.response) { -// [self handleResponse:cmd.response]; -// } -// }]; -} - -- (void)handleFindDevice:(FindDeviceMessage *)msg -{ - if (PairingStateStarted == self.state) { - self.state = PairingStateReceivedFindPacket; - } - - CmdBase *cmd = [self makeCommandForAckAndListen:msg.sequence forMessageType:(uint8_t)msg.messageType]; - - [self performSelector:@selector(runCommand:) withObject:cmd afterDelay:1]; - //[self runCommand:cmd]; -} - -- (void)handleDeviceLink:(DeviceLinkMessage *)msg -{ - if (PairingStateReceivedFindPacket == self.state) { - self.state = PairingStateReceivedLinkPacket; - } - - CmdBase *cmd = [self makeCommandForAckAndListen:msg.sequence forMessageType:(uint8_t)msg.messageType]; - [self performSelector:@selector(runCommand:) withObject:cmd afterDelay:1]; - //[self runCommand:cmd]; -} - -- (void)handlePumpStatus:(PumpStatusMessage *)msg { - if (PairingStateReceivedLinkPacket == self.state) { - self.state = PairingStateComplete; - } - CmdBase *cmd = [self makeCommandForAckAndListen:0 forMessageType:(uint8_t)msg.messageType]; - [self performSelector:@selector(runCommand:) withObject:cmd afterDelay:1]; - //[self runCommand:cmd]; -} - -- (void)closeKeyboard:(id)sender -{ - [self.view endEditing:YES]; -} - -- (IBAction)startPairing:(id)sender { - if (PairingStateReady == self.state) { - self.state = PairingStateStarted; - [self listenForPairing]; - } -} - -@end diff --git a/RileyLink/NSData+Conversion.m b/RileyLink/NSData+Conversion.m index f8c688975..b77eabe68 100644 --- a/RileyLink/NSData+Conversion.m +++ b/RileyLink/NSData+Conversion.m @@ -13,12 +13,12 @@ @implementation NSData (Conversion) - (NSString *)hexadecimalString { /* Returns hexadecimal string of NSData. Empty string if data is empty. */ - const unsigned char *dataBuffer = (const unsigned char *)[self bytes]; + const unsigned char *dataBuffer = (const unsigned char *)self.bytes; if (!dataBuffer) return [NSString string]; - NSUInteger dataLength = [self length]; + NSUInteger dataLength = self.length; NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)]; for (int i = 0; i < dataLength; ++i) @@ -32,7 +32,7 @@ + (NSData*)dataWithHexadecimalString: (NSString*)hexStr NSMutableData *data = [[NSMutableData alloc] init]; unsigned char whole_byte; char byte_chars[3] = {'\0','\0','\0'}; - for (int i = 0; i < ([hexStr length] / 2); i++) { + for (int i = 0; i < (hexStr.length / 2); i++) { byte_chars[0] = [hexStr characterAtIndex:i*2]; byte_chars[1] = [hexStr characterAtIndex:i*2+1]; whole_byte = strtol(byte_chars, NULL, 16); diff --git a/RileyLink/NSString+Hashes.h b/RileyLink/NSString+Hashes.h deleted file mode 100644 index 1da7986ec..000000000 --- a/RileyLink/NSString+Hashes.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// NSString+Hashes.h -// -// Created by Klaus-Peter Dudas on 26/07/2011. -// Copyright: Do whatever you want with this, i.e. Public Domain -// - -#import - -@interface NSString (Hashes) - -@property (nonatomic, readonly) NSString *md5; -@property (nonatomic, readonly) NSString *sha1; -@property (nonatomic, readonly) NSString *sha224; -@property (nonatomic, readonly) NSString *sha256; -@property (nonatomic, readonly) NSString *sha384; -@property (nonatomic, readonly) NSString *sha512; - -@end diff --git a/RileyLink/NSString+Hashes.m b/RileyLink/NSString+Hashes.m deleted file mode 100644 index 3cefdbf77..000000000 --- a/RileyLink/NSString+Hashes.m +++ /dev/null @@ -1,60 +0,0 @@ -// -// NSString+Hashes.m -// -// Created by Klaus-Peter Dudas on 26/07/2011. -// Copyright: Do whatever you want with this, i.e. Public Domain -// - -#import - -#import "NSString+Hashes.h" - -static inline NSString *NSStringCCHashFunction(unsigned char *(function)(const void *data, CC_LONG len, unsigned char *md), CC_LONG digestLength, NSString *string) -{ - NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; - uint8_t digest[digestLength]; - - function(data.bytes, (CC_LONG)data.length, digest); - - NSMutableString *output = [NSMutableString stringWithCapacity:digestLength * 2]; - - for (int i = 0; i < digestLength; i++) - { - [output appendFormat:@"%02x", digest[i]]; - } - - return output; -} - -@implementation NSString (Hashes) - -- (NSString *)md5 -{ - return NSStringCCHashFunction(CC_MD5, CC_MD5_DIGEST_LENGTH, self); -} - -- (NSString *)sha1 -{ - return NSStringCCHashFunction(CC_SHA1, CC_SHA1_DIGEST_LENGTH, self); -} - -- (NSString *)sha224 -{ - return NSStringCCHashFunction(CC_SHA224, CC_SHA224_DIGEST_LENGTH, self); -} - -- (NSString *)sha256 -{ - return NSStringCCHashFunction(CC_SHA256, CC_SHA256_DIGEST_LENGTH, self); -} - -- (NSString *)sha384 -{ - return NSStringCCHashFunction(CC_SHA384, CC_SHA384_DIGEST_LENGTH, self); -} -- (NSString *)sha512 -{ - return NSStringCCHashFunction(CC_SHA512, CC_SHA512_DIGEST_LENGTH, self); -} - -@end diff --git a/RileyLink/NightScoutBolus.h b/RileyLink/NightScoutBolus.h deleted file mode 100644 index 9f84aa3e9..000000000 --- a/RileyLink/NightScoutBolus.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// NightScoutBolus.h -// RileyLink -// -// Created by Pete Schwamb on 11/27/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import - -@interface NightScoutBolus : NSObject - -+ (NSArray*) process:(NSArray*)treatments; - -@end diff --git a/RileyLink/NightScoutBolus.m b/RileyLink/NightScoutBolus.m deleted file mode 100644 index 9420ea479..000000000 --- a/RileyLink/NightScoutBolus.m +++ /dev/null @@ -1,225 +0,0 @@ -// -// NightScoutBolus.m -// RileyLink -// -// Created by Pete Schwamb on 11/27/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// -// Based on https://github.com/openaps/oref0/blob/master/lib/bolus.js -// - -#import "NightScoutBolus.h" - -@interface NightScoutBolus () { - NSMutableArray *results; - NSMutableDictionary *state; - NSMutableArray *previous; - NSArray *treatments; - NSDateFormatter *dateFormatter; -} - -@end - - -@implementation NightScoutBolus - -- (instancetype)init -{ - self = [super init]; - if (self) { - results = [NSMutableArray array]; - state = [NSMutableDictionary dictionary]; - previous = [NSMutableArray array]; - dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; - } - return self; -} - -- (BOOL) inPrevious:(NSMutableDictionary *)ev { - for (NSMutableDictionary *elem in previous) { - if ([elem[@"timestamp"] isEqualToString:ev[@"timestamp"]] && - [ev[@"_type"] isEqualToString:elem[@"_type"]]) { - return YES; - } - } - return NO; -} - -- (NSArray*) withinMinutesFrom:(NSMutableDictionary*)origin tail:(NSArray*)tail minutes:(NSInteger)minutes { - NSInteger ms = minutes * 1000 * 60; - NSDate *ts = [dateFormatter dateFromString:origin[@"timestamp"]]; - NSMutableArray *candidates = [NSMutableArray array]; - for (NSDictionary *elem in tail) { - NSDate *dt = [dateFormatter dateFromString:elem[@"timestamp"]]; - if ([ts timeIntervalSinceDate:dt] < ms) { - [candidates addObject:elem]; - } - } - return candidates; -} - -- (void) bolus:(NSMutableDictionary*)ev remaining:(NSArray*)remaining { - if (!ev) { - NSLog(@"Error: XXX: bad event for bolus processing"); - return; - } - - if ([ev[@"_type"] isEqualToString:@"BolusWizardBolusEstimate"]) { - state[@"carbs"] = [ev[@"carb_input"] stringValue]; - state[@"ratio"] = [ev[@"carb_ratio"] stringValue]; - if ([ev[@"bg"] integerValue] > 0) { - state[@"bg"] = [ev[@"bg"] stringValue]; - state[@"glucose"] = [ev[@"bg"] stringValue]; - state[@"glucoseType"] = ev[@"_type"]; - } - state[@"wizard"] = ev; - state[@"timestamp"] = ev[@"timestamp"]; - state[@"created_at"] = ev[@"timestamp"]; - [previous addObject:ev]; - } - - if ([ev[@"_type"] isEqualToString:@"BolusNormal"]) { - state[@"duration"] = [ev[@"duration"] stringValue]; - if (ev[@"duration"] && [ev[@"duration"] integerValue] > 0) { - state[@"square"] = ev; - } else { - state[@"bolus"] = ev; - } - state[@"timestamp"] = ev[@"timestamp"]; - state[@"created_at"] = ev[@"timestamp"]; - [previous addObject:ev]; - } - - BOOL haveBoth = state[@"bolus"] && state[@"wizard"]; - - if (remaining.count > 0 && !haveBoth) { - // keep recursing - [self bolus:remaining[0] remaining:[remaining subarrayWithRange:NSMakeRange(1, remaining.count-1)]]; - return; - } else { - state[@"eventType"] = @""; - - float insulin = 0; - if (state[@"square"]) { - insulin += [state[@"square"][@"amount"] floatValue]; - } - if (state[@"bolus"]) { - insulin += [state[@"bolus"][@"amount"] floatValue]; - } - state[@"insulin"] = @(insulin); - - BOOL has_insulin = insulin > 0; - BOOL has_carbs = state[@"carbs"] && [state[@"carbs"] floatValue] > 0; - BOOL has_wizard = state[@"wizard"] ? YES : NO; - BOOL has_bolus = state[@"bolus"] ? YES : NO; - - if (state[@"square"] && has_bolus) { - [self annotate:@"DualWave bolus for", state[@"square"][@"duration"], @"minutes", nil]; - } else if (state[@"square"] && has_wizard) { - [self annotate:@"Square wave bolus for", state[@"square"][@"duration"], @"minutes", nil]; - } else if (state[@"square"]) { - [self annotate:@"Solo Square wave bolus for", state[@"square"][@"duration"], @"minutes", nil]; - [self annotate:@"No bolus wizard used.", nil]; - } else if (state[@"bolus"] && has_wizard) { - [self annotate:@"Normal bolus with wizard.", nil]; - } else if (state[@"bolus"]) { - [self annotate:@"Normal bolus (solo, no bolus wizard).", nil]; - } - - if (state[@"bolus"]) { - [self annotate:@"Programmed bolus", state[@"bolus"][@"programmed"], nil]; - [self annotate:@"Delivered bolus", state[@"bolus"][@"amount"], nil]; - int percent = [state[@"bolus"][@"amount"] floatValue] / [state[@"bolus"][@"programmed"] floatValue] * 100; - [self annotate:@"Percent delivered: ", [NSString stringWithFormat:@"%d%%", percent], nil]; - } - if (state[@"square"]) { - [self annotate:@"Programmed square", state[@"square"][@"programmed"], nil]; - [self annotate:@"Delivered square", state[@"square"][@"amount"], nil]; - int percent = [state[@"square"][@"amount"] floatValue] / [state[@"square"][@"programmed"] floatValue] * 100; - [self annotate:@"Success: ", [NSString stringWithFormat:@"%d%%", percent], nil]; - } - if (has_wizard) { - state[@"created_at"] = state[@"wizard"][@"timestamp"]; - [self annotate:@"Food estimate", state[@"wizard"][@"food_estimate"], nil]; - [self annotate:@"Correction estimate", state[@"wizard"][@"correction_estimate"], nil]; - [self annotate:@"Bolus estimate", state[@"wizard"][@"bolus_estimate"], nil]; - [self annotate:@"Target low", state[@"wizard"][@"bg_target_low"], nil]; - [self annotate:@"Target high", state[@"wizard"][@"bg_target_high"], nil]; - float delta = [state[@"wizard"][@"sensitivity"] floatValue] * [state[@"insulin"] floatValue] * -1; - [self annotate:@"Hypothetical glucose delta", [NSString stringWithFormat:@"%d", (int)delta], nil]; - if (state[@"bg"] && [state[@"bg"] integerValue] > 0) { - [self annotate:@"Glucose was:", state[@"bg"], nil]; - // TODO: annotate prediction - } - } - if (state[@"carbs"] && state[@"insulin"] && state[@"bg"]) { - state[@"eventType"] = @"Meal Bolus"; - } else { - if (has_carbs && !has_insulin) { - state[@"eventType"] = @"Carb Correction"; - } - if (!has_carbs && has_insulin) { - state[@"eventType"] = @"Correction Bolus"; - } - } - if (state[@"notes"] && [state[@"notes"] count] > 0) { - state[@"notes"] = [state[@"notes"] componentsJoinedByString:@"\n"]; - } - if (state[@"insulin"]) { - state[@"insulin"] = [state[@"insulin"] stringValue]; - } - - [results addObject:state]; - state = [NSMutableDictionary dictionary]; - } - -} - - - (void) annotate:(NSString *)firstStr, ... NS_REQUIRES_NIL_TERMINATION { - NSMutableArray *argArray = [NSMutableArray array]; - va_list args; - va_start(args, firstStr); - for (NSString *arg = firstStr; arg != nil; arg = va_arg(args, NSString*)) - { - [argArray addObject:arg]; - } - va_end(args); - NSString *msg = [argArray componentsJoinedByString:@" "]; - if (!state[@"notes"]) { - state[@"notes"] = [NSMutableArray array]; - } - [state[@"notes"] addObject:msg]; - } - -- (void) step:(NSMutableDictionary *)current withIndex:(NSInteger)index { - if ([self inPrevious:current]) { - return; - } - - if ([current[@"_type"] isEqualToString:@"BolusNormal"] || - [current[@"_type"] isEqualToString:@"BolusWizardBolusEstimate"]) { - NSArray *tail = [treatments subarrayWithRange:NSMakeRange(index+1, treatments.count-index-1)]; - tail = [self withinMinutesFrom:current tail:tail minutes:4]; - [self bolus:current remaining:tail]; - } else { - [results addObject:current]; - } - -} - -- (NSArray*) reduce:(NSArray*)newTreatments { - treatments = newTreatments; - for (int i=0; i - -@interface NightScoutPump : NSObject - -+ (NSArray*) process:(NSArray*)treatments; - -@end diff --git a/RileyLink/NightScoutPump.m b/RileyLink/NightScoutPump.m deleted file mode 100644 index b8707076f..000000000 --- a/RileyLink/NightScoutPump.m +++ /dev/null @@ -1,36 +0,0 @@ -// -// NightScoutPump.m -// RileyLink -// -// Created by Pete Schwamb on 11/27/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// -// Based on https://github.com/openaps/oref0/blob/master/lib/pump.js -// - - -#import "NightScoutPump.h" - -@implementation NightScoutPump - -- (NSArray*) translate:(NSArray*)treatments { - NSMutableArray *results = [NSMutableArray array]; - for (NSDictionary *entry in treatments) { - NSMutableDictionary *current = [entry mutableCopy]; - if ([current[@"_type"] isEqualToString:@"CalBGForPH"]) { - current[@"eventType"] = @""; - current[@"glucose"] = current[@"amount"]; - current[@"glucoseType"] = @"Finger"; - current[@"notes"] = @"Pump received finger stick."; - } - [results addObject:current]; - } - return results; -} - -+ (NSArray*) process:(NSArray*)treatments { - return [[[NightScoutPump alloc] init] translate: treatments]; -} - - -@end diff --git a/RileyLink/NightScoutUploader.h b/RileyLink/NightScoutUploader.h deleted file mode 100644 index 247430611..000000000 --- a/RileyLink/NightScoutUploader.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// NightScoutUploader.h -// GlucoseLink -// -// Created by Pete Schwamb on 5/23/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "MinimedPacket.h" - -@interface NightScoutUploader : NSObject - -- (void) reportJSON:(NSArray*)outgoingJSON toNightScoutEndpoint:(NSString*)endpoint - completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler; - -@property (nonatomic, strong) NSString *siteURL; -@property (nonatomic, strong) NSString *APISecret; - - -@end diff --git a/RileyLink/NightScoutUploader.m b/RileyLink/NightScoutUploader.m deleted file mode 100644 index 902824194..000000000 --- a/RileyLink/NightScoutUploader.m +++ /dev/null @@ -1,579 +0,0 @@ -// -// NightScoutUploader.m -// GlucoseLink -// -// Created by Pete Schwamb on 5/23/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// -// Based on code found in https://github.com/bewest/share2nightscout-bridge - -#import "NightScoutUploader.h" -#import "NSString+Hashes.h" -#import "MinimedPacket.h" -#import "PumpStatusMessage.h" -#import "ISO8601DateFormatter.h" -#import "MeterMessage.h" -#import "RileyLinkBLEManager.h" -#import "Config.h" -#import "NSData+Conversion.h" -#import "PumpState.h" -#import "PumpModel.h" -#import "PumpOps.h" -#import "HistoryPage.h" -#import "PumpHistoryEventBase.h" -#import "NSData+Conversion.h" -#import "NightScoutBolus.h" -#import "NightScoutPump.h" -#import "AppDelegate.h" - -#define RECORD_RAW_PACKETS NO - -typedef NS_ENUM(unsigned int, DexcomSensorError) { - DX_SENSOR_NOT_ACTIVE = 1, - DX_SENSOR_NOT_CALIBRATED = 5, - DX_BAD_RF = 12, -}; - - -@interface NightScoutUploader () { - BOOL fetchHistoryScheduled; - NSDate *lastHistoryAttempt; -} - -@property (strong, nonatomic) NSMutableArray *entries; -@property (strong, nonatomic) NSMutableArray *deviceStatuses; -@property (strong, nonatomic) NSMutableArray *treatmentsQueue; -@property (strong, nonatomic) ISO8601DateFormatter *dateFormatter; -@property (nonatomic, assign) NSInteger codingErrorCount; -@property (strong, nonatomic) NSString *pumpSerial; -@property (strong, nonatomic) NSData *lastSGV; -@property (strong, nonatomic) MeterMessage *lastMeterMessage; -@property (strong, nonatomic) NSTimer *pumpPollTimer; -@property (strong, nonatomic) RileyLinkBLEDevice *activeRileyLink; -@property (strong, nonatomic) NSTimer *getHistoryTimer; -@property (strong, nonatomic) NSString *pumpModel; -@property (strong, nonatomic) NSMutableSet *sentTreatments; - - -@end - - -@implementation NightScoutUploader - -static NSString *defaultNightscoutEntriesPath = @"/api/v1/entries.json"; -static NSString *defaultNightscoutTreatmentPath = @"/api/v1/treatments.json"; -static NSString *defaultNightscoutDeviceStatusPath = @"/api/v1/devicestatus.json"; - -- (instancetype)init -{ - self = [super init]; - if (self) { - _entries = [[NSMutableArray alloc] init]; - _sentTreatments = [NSMutableSet set]; - _treatmentsQueue = [[NSMutableArray alloc] init]; - _deviceStatuses = [[NSMutableArray alloc] init]; - _dateFormatter = [[ISO8601DateFormatter alloc] init]; - _dateFormatter.includeTime = YES; - _dateFormatter.useMillisecondPrecision = YES; - _dateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(packetReceived:) - name:RILEYLINK_EVENT_PACKET_RECEIVED - object:nil]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceConnected:) name:RILEYLINK_EVENT_DEVICE_CONNECTED object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceDisconnected:) name:RILEYLINK_EVENT_DEVICE_DISCONNECTED object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(rileyLinkAdded:) name:RILEYLINK_EVENT_DEVICE_ADDED object:nil]; - - [UIDevice currentDevice].batteryMonitoringEnabled = YES; - - lastHistoryAttempt = [NSDate date]; - self.getHistoryTimer = [NSTimer scheduledTimerWithTimeInterval:(5.0 * 60) target:self selector:@selector(timerTriggered:) userInfo:nil repeats:YES]; - - // This triggers one dump right away (in 10s).d - //[self performSelector:@selector(fetchHistory:) withObject:nil afterDelay:10]; - - // This is to just test decoding history - //[self performSelector:@selector(testDecodeHistory) withObject:nil afterDelay:1]; - - // Test storing MySentry packet: - //[self performSelector:@selector(testHandleMySentry) withObject:nil afterDelay:10]; - - } - return self; -} - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver: self]; -} - -#pragma mark - Testing - -- (void)testHandleMySentry { - NSMutableData *dataWithHeader = [[NSData dataWithHexadecimalString:@"0101"] mutableCopy]; - NSData *packet = [NSData dataWithHexadecimalString:@"a259705504e9401334001001050000000001d7040205e4000000000054000001240000000000000000dd"]; - packet = [MinimedPacket encodeData:packet]; - [dataWithHeader appendData:packet]; - MinimedPacket *mySentryPacket = [[MinimedPacket alloc] initWithData:dataWithHeader]; - [self handlePumpStatus:mySentryPacket fromDevice:nil withRSSI:1]; - [self flushAll]; -} - -- (void)testDecodeHistory { - NSData *page = [NSData dataWithHexadecimalString:@"010034003400000020424c05105b0018510c0510095000b44b500000140000000014965c113416c01038d01642d0164cd05056d0010014001400340018514c05105b0006440f6510285000b44b500000580000000058965c0b14a9c034bdc010dfd0010058005800040006444f65107b060040100510200e005b0015651265102d5000784b500000940000000094965c0e22d4c036dec0147ed03492d0010094009400000015655265107b0700401305102610000a7236633465103f0e3663546510c527ad7b0800401505102a13000afd0c443765103f1f0c44b76510c527ad5bfd1544170510005000b455503000000000000030965c08940dd022dfd0010030003000000016445705100af33b663765103f1e3b66776510c527ad7b000040000610000e00070000033305900000006e05900500b253fd090000033301432701f03d00990100003000c0000003010200000000000000000000000000000000000000007b0100400106100208007b020040040610080e007b0300400606100c10000aa216742866103f141674486610c527ad7b0400400a0610140b007b0500400c0610180a000a081e432c66903f211e430c6610c527ad5b0806440c06103d5100b44b503c008400000000c0960100c000c000000006444c06100a3f2a712f66103f072a71ef6610c527ad7b060040100610200e005b00194e106610145000784b500000400000000040965c088af9c03603d00100400040000000194e5066105b0001721166100a5000784b500000200000000020965c0e1c5fc02469c08a59d03663d00100200020001800017251661021001443120610030000003537433206107b060747120610200e00030003000339461206107b0700401306102610005b000c791406100c5000784b500000280000000028965c0b20c0c01c1ad02424d001002800280000000d795406107b0800401506102a1300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005751"]; - self.pumpModel = @"551"; - [self decodeHistoryPage:page]; -} - - -#pragma mark - Device updates - -- (void)deviceConnected:(NSNotification *)note -{ - self.activeRileyLink = [note object]; -} - -- (void)deviceDisconnected:(NSNotification *)note -{ - if (self.activeRileyLink == [note object]) { - self.activeRileyLink = nil; - } -} - -- (void)rileyLinkAdded:(NSNotification *)note -{ - RileyLinkBLEDevice *device = [note object]; - [device enableIdleListeningOnChannel:0]; -} - -- (void)timerTriggered:(id)sender { - - logMemUsage(); - - if ([lastHistoryAttempt timeIntervalSinceNow] < (- 5 * 60) && !fetchHistoryScheduled) { - NSLog(@"No fetchHistory for over five minutes. Triggering one"); - [self fetchHistory:nil]; - } - [self flushAll]; -} - - -- (void)packetReceived:(NSNotification*)notification { - NSDictionary *attrs = notification.userInfo; - MinimedPacket *packet = attrs[@"packet"]; - RileyLinkBLEDevice *device = notification.object; - [self addPacket:packet fromDevice:device]; - - //TODO: find some way to sleep for 4 mins to save on RL battery? -} - -#pragma mark - Polling - -- (void) fetchHistory:(id)sender { - lastHistoryAttempt = [NSDate date]; - - fetchHistoryScheduled = NO; - if (self.activeRileyLink && self.activeRileyLink.state != RileyLinkStateConnected) { - self.activeRileyLink = nil; - } - - if (self.activeRileyLink == nil) { - for (RileyLinkBLEDevice *device in [[RileyLinkBLEManager sharedManager] rileyLinkList]) { - if (device.state == RileyLinkStateConnected) { - self.activeRileyLink = device; - break; - } - } - } - - if (self.activeRileyLink == nil) { - NSLog(@"fetchHistory failed: No connected rileylinks to attempt to pull history with."); - return; - } - - NSLog(@"Using RileyLink \"%@\" to fetchHistory.", self.activeRileyLink.name); - - AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - PumpOps *pumpOps = [[PumpOps alloc] initWithPumpState:appDelegate.pump andDevice:self.activeRileyLink]; - - [pumpOps getHistoryPage:0 withHandler:^(NSDictionary * _Nonnull res) { - if (!res[@"error"]) { - NSData *page = res[@"pageData"]; - self.pumpModel = res[@"pumpModel"]; - NSLog(@"Avg RSSI for history dump: %@", res[@"avgRSSI"]); - NSLog(@"fetchHistory succeeded."); - [self decodeHistoryPage:page]; - } else { - NSLog(@"fetchHistory failed: %@", res[@"error"]); - } - [self flushAll]; - }]; -} - -#pragma mark - Decoding - -- (void) decodeHistoryPage:(NSData*)data { - NSLog(@"Got page: %@", [data hexadecimalString]); - - if (self.pumpModel == nil) { - NSLog(@"Cannot decode history page without knowing the pump model. pumpModel == nil!"); - return; - } - - PumpModel *m = [PumpModel find:self.pumpModel]; - HistoryPage *page = [[HistoryPage alloc] initWithData:data andPumpModel:m]; - - if (![page isCRCValid]) { - NSLog(@"Invalid CRC for history page %@", [data hexadecimalString]); - return; - } - - NSArray *events = [page decode]; - - NSMutableArray *jsonEvents = [NSMutableArray array]; - -// for (PumpHistoryEventBase *event in events) { -// NSLog(@"Event: %@", [event asJSON]); -// } -// return ; - - - // Processing code expects history in newest first order - NSEnumerator *enumerator = [events reverseObjectEnumerator]; - for (PumpHistoryEventBase *event in enumerator) { - [jsonEvents addObject:[event asJSON]]; - } - - NSArray *treatments = jsonEvents; - - treatments = [NightScoutPump process:treatments]; - treatments = [NightScoutBolus process:treatments]; - - for (NSMutableDictionary *treatment in treatments) { - NSLog(@"Treatment: %@", treatment); - - [self addTreatment:treatment fromModel:m]; - } -} - - -- (void) addTreatment:(NSMutableDictionary*)treatment fromModel:(PumpModel*)m { - treatment[@"enteredBy"] = [@"rileylink://medtronic/" stringByAppendingString:m.name]; - treatment[@"created_at"] = treatment[@"timestamp"]; - - if ([self.sentTreatments member:treatment]) { - NSLog(@"Already sent %@", treatment); - } else { - [self.treatmentsQueue addObject:treatment]; - } -} - -//var DIRECTIONS = { -//NONE: 0 -// , DoubleUp: 1 -// , SingleUp: 2 -// , FortyFiveUp: 3 -// , Flat: 4 -// , FortyFiveDown: 5 -// , SingleDown: 6 -// , DoubleDown: 7 -// , 'NOT COMPUTABLE': 8 -// , 'RATE OUT OF RANGE': 9 -//}; - - -- (NSString*)trendToDirection:(GlucoseTrend)trend { - switch (trend) { - case GLUCOSE_TREND_NONE: - return @""; - case GLUCOSE_TREND_UP: - return @"SingleUp"; - case GLUCOSE_TREND_DOUBLE_UP: - return @"DoubleUp"; - case GLUCOSE_TREND_DOWN: - return @"SingleDown"; - case GLUCOSE_TREND_DOUBLE_DOWN: - return @"DoubleDown"; - default: - return @"NOT COMPUTABLE"; - break; - } -} - -// Entries [ { sgv: 375, -// date: 1432421525000, -// dateString: '2015-05-23T22:52:05.000Z', -// trend: 1, -// direction: 'DoubleUp', -// device: 'share2', -// type: 'sgv' } ] - -- (void)addPacket:(MinimedPacket*)packet fromDevice:(RileyLinkBLEDevice*)device { - - if (![packet isValid]) { - return; - } - - if (RECORD_RAW_PACKETS) { - [self storeRawPacket:packet fromDevice:device]; - } - - if ([packet packetType] == PacketTypeSentry && - [packet messageType] == MESSAGE_TYPE_PUMP_STATUS && - [packet.address isEqualToString:[[Config sharedInstance] pumpID]]) { - // Make this RL the active one, for history dumping. - self.activeRileyLink = device; - [self handlePumpStatus:packet fromDevice:device withRSSI:packet.rssi]; - // Just got a MySentry packet; in 25s would be a good time to poll. - if (!fetchHistoryScheduled) { - [self performSelector:@selector(fetchHistory:) withObject:nil afterDelay:25]; - fetchHistoryScheduled = YES; - } - // TODO: send ack. also, we can probably wait less than 25s if we ack; the 25s - // above is mainly to avoid colliding with subsequent packets. - - } else if ([packet packetType] == PacketTypeMeter) { - [self handleMeterMessage:packet]; - } - - [self flushAll]; -} - -- (void) storeRawPacket:(MinimedPacket*)packet fromDevice:(RileyLinkBLEDevice*)device { - NSDate *now = [NSDate date]; - NSTimeInterval seconds = [now timeIntervalSince1970]; - NSNumber *epochTime = @(seconds * 1000); - - NSDictionary *entry = - @{@"date": epochTime, - @"dateString": [self.dateFormatter stringFromDate:now], - @"rfpacket": [packet.data hexadecimalString], - @"device": device.deviceURI, - @"rssi": @(packet.rssi), - @"type": @"rfpacket" - }; - [self.entries addObject:entry]; -} - -- (void) handlePumpStatus:(MinimedPacket*)packet fromDevice:(RileyLinkBLEDevice*)device withRSSI:(NSInteger)rssi { - PumpStatusMessage *msg = [[PumpStatusMessage alloc] initWithData:packet.data]; - - if ([packet.address isEqualToString:[[Config sharedInstance] pumpID]]) { - - NSDate *validTime = msg.sensorTime; - - NSInteger glucose = msg.glucose; - switch ([msg sensorStatus]) { - case SENSOR_STATUS_HIGH_BG: - glucose = 401; - break; - case SENSOR_STATUS_WEAK_SIGNAL: - glucose = DX_BAD_RF; - break; - case SENSOR_STATUS_METER_BG_NOW: - glucose = DX_SENSOR_NOT_CALIBRATED; - break; - case SENSOR_STATUS_LOST: - case SENSOR_STATUS_MISSING: - glucose = DX_SENSOR_NOT_ACTIVE; - validTime = msg.pumpTime; - break; - default: - break; - } - - NSNumber *epochTime = @([validTime timeIntervalSince1970] * 1000); - - NSMutableDictionary *status = [NSMutableDictionary dictionary]; - - status[@"device"] = device.deviceURI; - status[@"created_at"] = [self.dateFormatter stringFromDate:[NSDate date]]; - - // TODO: use battery monitoring to post updates if we're not hearing from pump? - UIDevice *uploaderDevice = [UIDevice currentDevice]; - if (uploaderDevice.isBatteryMonitoringEnabled) { - NSNumber *batteryPct = @((int)([[UIDevice currentDevice] batteryLevel] * 100)); - status[@"uploader"] = @{@"battery":batteryPct}; - } - - status[@"pump"] = @{ - @"clock": [self.dateFormatter stringFromDate:validTime], - @"iob": @{ - @"timestamp": [self.dateFormatter stringFromDate:validTime], - @"bolusiob": @(msg.activeInsulin), - }, - @"reservoir": @(msg.insulinRemaining), - @"battery": @{ - @"percent": @(msg.batteryPct) - } - }; - - if (msg.sensorStatus != SENSOR_STATUS_MISSING) { - status[@"sensor"] = @{ - @"sensorAge": @(msg.sensorAge), - @"sensorRemaining": @(msg.sensorRemaining), - @"sensorStatus": msg.sensorStatusString - }; - } - [self.deviceStatuses addObject:status]; - - // Do not store sgv values if sensor missing; we're likely just - // using MySentry to gather pump status. - if (msg.sensorStatus != SENSOR_STATUS_MISSING) { - NSDictionary *entry = - @{@"date": epochTime, - @"dateString": [self.dateFormatter stringFromDate:validTime], - @"sgv": @(glucose), - @"previousSGV": @(msg.previousGlucose), - @"direction": [self trendToDirection:msg.trend], - @"device": device.deviceURI, - @"rssi": @(rssi), - @"type": @"sgv" - }; - [self.entries addObject:entry]; - } - - - } else { - NSLog(@"Dropping mysentry packet for pump: %@", packet.address); - } -} - -- (void) handleMeterMessage:(MinimedPacket*)packet { - MeterMessage *msg = [[MeterMessage alloc] initWithData:packet.data]; - - if (msg.isAck) { - return; - } - - msg.dateReceived = [NSDate date]; - NSTimeInterval seconds = [msg.dateReceived timeIntervalSince1970]; - NSNumber *epochTime = @(seconds * 1000); - NSDictionary *entry = - @{@"date": epochTime, - @"dateString": [self.dateFormatter stringFromDate:msg.dateReceived], - @"mbg": @(msg.glucose), - @"device": @"Contour Next Link", - @"type": @"mbg" - }; - - // Skip duplicates - if (_lastMeterMessage && - [msg.dateReceived timeIntervalSinceDate:_lastMeterMessage.dateReceived] && - msg.glucose == _lastMeterMessage.glucose) { - entry = nil; - } else { - [self.entries addObject:entry]; - _lastMeterMessage = msg; - } -} - -#pragma mark - Uploading - -- (void) flushAll { - - NSArray *logEntries = [Log popLogEntries]; - if (logEntries.count > 0) { - NSDate *date = [NSDate date]; - NSTimeInterval seconds = [date timeIntervalSince1970]; - NSNumber *epochTime = @(seconds * 1000); - - NSDictionary *entry = - @{@"date": epochTime, - @"dateString": [self.dateFormatter stringFromDate:date], - @"entries": logEntries, - @"type": @"logs" - }; - [self.entries addObject:entry]; - } - - [self flushDeviceStatuses]; - [self flushEntries]; - [self flushTreatments]; -} - -- (void) flushDeviceStatuses { - - if (self.deviceStatuses.count == 0) { - return; - } - - NSArray *inFlightDeviceStatuses = self.deviceStatuses; - self.deviceStatuses = [[NSMutableArray alloc] init]; - [self reportJSON:inFlightDeviceStatuses toNightScoutEndpoint:defaultNightscoutDeviceStatusPath completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; - if (httpResponse.statusCode != 200) { - NSLog(@"Requeuing %d device statuses: %@", inFlightDeviceStatuses.count, error); - [self.deviceStatuses addObjectsFromArray:inFlightDeviceStatuses]; - } else { - //NSString *resp = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - //NSLog(@"Submitted %d device statuses to nightscout: %@", inFlightDeviceStatuses.count, resp); - } - }]; -} - -- (void) flushEntries { - - if (self.entries.count == 0) { - return; - } - - NSArray *inFlightEntries = self.entries; - self.entries = [[NSMutableArray alloc] init]; - [self reportJSON:inFlightEntries toNightScoutEndpoint:defaultNightscoutEntriesPath completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; - if (httpResponse.statusCode != 200) { - NSLog(@"Requeuing %d sgv entries: %@", inFlightEntries.count, error); - [self.entries addObjectsFromArray:inFlightEntries]; - } else { - //NSString *resp = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - //NSLog(@"Submitted %d entries to nightscout: %@", inFlightEntries.count, resp); - } - }]; -} - -- (void) flushTreatments { - - if (self.treatmentsQueue.count == 0) { - return; - } - - NSArray *inFlightTreatments = self.treatmentsQueue; - self.treatmentsQueue = [NSMutableArray array]; - [self reportJSON:inFlightTreatments toNightScoutEndpoint:defaultNightscoutTreatmentPath completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; - if (httpResponse.statusCode != 200) { - NSLog(@"Requeuing %d treatments: %@", inFlightTreatments.count, error); - [self.treatmentsQueue addObjectsFromArray:inFlightTreatments]; - } else { - //NSString *resp = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - [self.sentTreatments addObjectsFromArray:inFlightTreatments]; - //NSLog(@"Submitted %d treatments to nightscout: %@", inFlightTreatments.count, resp); - } - }]; -} - -- (void) reportJSON:(NSArray*)outgoingJSON toNightScoutEndpoint:(NSString*)endpoint -completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler -{ - NSURL *uploadURL = [NSURL URLWithString:endpoint - relativeToURL:[NSURL URLWithString:self.siteURL]]; - NSMutableURLRequest *request = [[NSURLRequest requestWithURL:uploadURL] mutableCopy]; - NSError *error; - NSData *sendData = [NSJSONSerialization dataWithJSONObject:outgoingJSON options:NSJSONWritingPrettyPrinted error:&error]; - //NSString *jsonPost = [[NSString alloc] initWithData:sendData encoding:NSUTF8StringEncoding]; - //NSLog(@"Posting to %@, %@", [uploadURL absoluteString], jsonPost); - [request setHTTPMethod:@"POST"]; - - [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; - [request setValue:[self.APISecret sha1] forHTTPHeaderField:@"api-secret"]; - - [request setHTTPBody: sendData]; - - [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:completionHandler] resume]; -} - -@end diff --git a/RileyLink/NightscoutUploadKit/BGCheckNightscoutTreatment.swift b/RileyLink/NightscoutUploadKit/BGCheckNightscoutTreatment.swift new file mode 100644 index 000000000..75247d044 --- /dev/null +++ b/RileyLink/NightscoutUploadKit/BGCheckNightscoutTreatment.swift @@ -0,0 +1,34 @@ +// +// BGCheckNightscoutTreatment.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BGCheckNightscoutTreatment: NightscoutTreatment { + + let glucose: Int + let glucoseType: GlucoseType + let units: Units + + init(timestamp: NSDate, enteredBy: String, glucose: Int, glucoseType: GlucoseType, units: Units) { + self.glucose = glucose + self.glucoseType = glucoseType + self.units = units + super.init(timestamp: timestamp, enteredBy: enteredBy) + } + + override public var dictionaryRepresentation: [String: AnyObject] { + var rval = super.dictionaryRepresentation + rval["eventType"] = "BG Check" + rval["glucose"] = glucose + rval["glucoseType"] = glucoseType.rawValue + rval["units"] = units.rawValue + return rval + } + + +} diff --git a/RileyLink/NightscoutUploadKit/BolusNightscoutTreatment.swift b/RileyLink/NightscoutUploadKit/BolusNightscoutTreatment.swift new file mode 100644 index 000000000..bd25e745e --- /dev/null +++ b/RileyLink/NightscoutUploadKit/BolusNightscoutTreatment.swift @@ -0,0 +1,54 @@ +// +// BolusNightscoutTreatment.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class BolusNightscoutTreatment: NightscoutTreatment { + + enum BolusType: String { + case Normal = "normal" + case Square = "square" + case DualWave = "dual" + } + + let bolusType: BolusType + let amount: Double + let programmed: Double + let unabsorbed: Double + let duration: Int + let carbs: Int + let ratio: Double + + init(timestamp: NSDate, enteredBy: String, bolusType: BolusType, amount: Double, programmed: Double, unabsorbed: Double, duration: Int, carbs: Int, ratio: Double) { + self.bolusType = bolusType + self.amount = amount + self.programmed = programmed + self.unabsorbed = unabsorbed + self.duration = duration + self.carbs = carbs + self.ratio = ratio + super.init(timestamp: timestamp, enteredBy: enteredBy) + } + + override public var dictionaryRepresentation: [String: AnyObject] { + var rval = super.dictionaryRepresentation + if carbs > 0 { + rval["eventType"] = "Meal Bolus" + rval["carbs"] = carbs + rval["ratio"] = ratio + } else { + rval["eventType"] = "Correction Bolus" + } + rval["type"] = bolusType.rawValue + rval["insulin"] = amount + rval["programmed"] = programmed + rval["unabsorbed"] = unabsorbed + rval["duration"] = duration + return rval + } +} diff --git a/RileyLink/NightscoutUploadKit/Extensions/StringCrypto.swift b/RileyLink/NightscoutUploadKit/Extensions/StringCrypto.swift new file mode 100644 index 000000000..9e325afc6 --- /dev/null +++ b/RileyLink/NightscoutUploadKit/Extensions/StringCrypto.swift @@ -0,0 +1,20 @@ +// +// StringCrypto.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + + +extension String { + func sha1() -> String { + let data = self.dataUsingEncoding(NSUTF8StringEncoding)! + var digest = [UInt8](count:Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0) + CC_SHA1(data.bytes, CC_LONG(data.length), &digest) + let hexBytes = digest.map { String(format: "%02hhx", $0) } + return hexBytes.joinWithSeparator("") + } +} diff --git a/RileyLink/NightscoutUploadKit/MealBolusNightscoutTreatment.swift b/RileyLink/NightscoutUploadKit/MealBolusNightscoutTreatment.swift new file mode 100644 index 000000000..ddd0cc61d --- /dev/null +++ b/RileyLink/NightscoutUploadKit/MealBolusNightscoutTreatment.swift @@ -0,0 +1,37 @@ +// +// MealBolusNightscoutTreatment.swift +// RileyLink +// +// Created by Pete Schwamb on 3/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class MealBolusNightscoutTreatment: NightscoutTreatment { + + let glucose: Int + let glucoseType: GlucoseType + let units: Units + let carbs: Int + let insulin: Double + + init(timestamp: NSDate, enteredBy: String, glucose: Int, glucoseType: GlucoseType, units: Units, carbs: Int, insulin: Double) { + self.glucose = glucose + self.glucoseType = glucoseType + self.units = units + self.insulin = insulin + self.carbs = carbs + super.init(timestamp: timestamp, enteredBy: enteredBy) + } + + override public var dictionaryRepresentation: [String: AnyObject] { + var rval = super.dictionaryRepresentation + rval["eventType"] = "Meal Bolus" + rval["glucose"] = glucose + rval["glucoseType"] = glucoseType.rawValue + rval["units"] = units.rawValue + return rval + } + +} diff --git a/RileyLink/NightscoutUploadKit/NightscoutPumpEvents.swift b/RileyLink/NightscoutUploadKit/NightscoutPumpEvents.swift new file mode 100644 index 000000000..454d7b1cd --- /dev/null +++ b/RileyLink/NightscoutUploadKit/NightscoutPumpEvents.swift @@ -0,0 +1,77 @@ +// +// NightscoutPumpEvents.swift +// RileyLink +// +// Created by Pete Schwamb on 3/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation +import MinimedKit + +class NightscoutPumpEvents: NSObject { + + class func translate(events: [PumpEvent], eventSource: String) -> [NightscoutTreatment] { + var results = [NightscoutTreatment]() + var lastBolusWizard: BolusWizardEstimatePumpEvent? + var lastTempBasal: TempBasalPumpEvent? + for event in events { + if let bgReceived = event as? BGReceivedPumpEvent { + if let date = TimeFormat.timestampAsLocalDate(bgReceived.timestamp) { + let entry = BGCheckNightscoutTreatment( + timestamp: date, + enteredBy: eventSource, + glucose: bgReceived.amount, + glucoseType: .Meter, + units: .MGDL) // TODO: can we tell this from the pump? + results.append(entry) + } + } + if let bolusNormal = event as? BolusNormalPumpEvent { + if let date = TimeFormat.timestampAsLocalDate(bolusNormal.timestamp) { + var carbs = 0 + var ratio = 0.0 + + if let wizard = lastBolusWizard where wizard.timestamp == bolusNormal.timestamp { + carbs = wizard.carbohydrates + ratio = wizard.carbRatio + } + let entry = BolusNightscoutTreatment( + timestamp: date, + enteredBy: eventSource, + bolusType: bolusNormal.duration > 0 ? .Square : .Normal, + amount: bolusNormal.amount, + programmed: bolusNormal.programmed, + unabsorbed: bolusNormal.unabsorbedInsulinTotal, + duration: bolusNormal.duration, + carbs: carbs, + ratio: ratio) + + results.append(entry) + } + } + if let bolusWizard = event as? BolusWizardEstimatePumpEvent { + lastBolusWizard = bolusWizard + } + if let tempBasal = event as? TempBasalPumpEvent { + lastTempBasal = tempBasal + } + if let tempBasalDuration = event as? TempBasalDurationPumpEvent, + tempBasal = lastTempBasal { + + if let date = TimeFormat.timestampAsLocalDate(tempBasal.timestamp) { + let absolute: Double? = tempBasal.rateType == .Absolute ? tempBasal.rate : nil + let entry = TempBasalNightscoutTreatment( + timestamp: date, + enteredBy: eventSource, + temp: tempBasal.rateType == .Absolute ? .Absolute : .Percentage, + rate: tempBasal.rate, absolute: absolute, duration: tempBasalDuration.duration) + + results.append(entry) + } + } + } + return results + } +} + diff --git a/RileyLink/NightscoutUploadKit/NightscoutTreatment.swift b/RileyLink/NightscoutUploadKit/NightscoutTreatment.swift new file mode 100644 index 000000000..e981fd11c --- /dev/null +++ b/RileyLink/NightscoutUploadKit/NightscoutTreatment.swift @@ -0,0 +1,37 @@ +// +// NightscoutTreatment.swift +// RileyLink +// +// Created by Pete Schwamb on 3/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import MinimedKit + +public class NightscoutTreatment : DictionaryRepresentable { + + enum GlucoseType: String { + case Meter + case Sensor + } + + public enum Units: String { + case MMOLL = "mmol/L" + case MGDL = "mg/dL" + } + + let timestamp: NSDate + let enteredBy: String + + init(timestamp: NSDate, enteredBy: String) { + self.timestamp = timestamp + self.enteredBy = enteredBy + } + + public var dictionaryRepresentation: [String: AnyObject] { + return [ + "timestamp": TimeFormat.timestampStrFromDate(timestamp), + "enteredBy": enteredBy, + ] + } +} diff --git a/RileyLink/NightscoutUploadKit/NightscoutUploader.swift b/RileyLink/NightscoutUploadKit/NightscoutUploader.swift new file mode 100644 index 000000000..b0a7ace56 --- /dev/null +++ b/RileyLink/NightscoutUploadKit/NightscoutUploader.swift @@ -0,0 +1,528 @@ +// +// NightScoutUploader.swift +// RileyLink +// +// Created by Pete Schwamb on 3/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import UIKit +import MinimedKit +import RileyLinkKit +import RileyLinkBLEKit + + +class NightScoutUploader: NSObject { + + enum DexcomSensorError: UInt8 { + case SensorNotActive = 1 + case SensorNotCalibrated = 5 + case BadRF = 12 + } + + var siteURL: String = "" + var APISecret: String = "" + + var fetchHistoryScheduled: Bool = false + var lastHistoryAttempt: NSDate? + var entries: [AnyObject] + var deviceStatuses: [AnyObject] + var treatmentsQueue: [AnyObject] + + var lastMeterMessageRxTime: NSDate? + var activeRileyLink: RileyLinkBLEDevice? + var getHistoryTimer: NSTimer? + + // TODO: since some treatments update, we should instead keep track of the time + // of the most recent non-mutating event, and send all events newer than that. + //var sentTreatments: [AnyObject] + var observingPumpEventsSince: NSDate + + let defaultNightscoutEntriesPath = "/api/v1/entries.json" + let defaultNightscoutTreatmentPath = "/api/v1/treatments.json" + let defaultNightscoutDeviceStatusPath = "/api/v1/devicestatus.json" + + override init() { + entries = [AnyObject]() + treatmentsQueue = [AnyObject]() + deviceStatuses = [AnyObject]() + + let calendar = NSCalendar.currentCalendar() + observingPumpEventsSince = calendar.dateByAddingUnit(.Day, value: -1, toDate: NSDate(), options: [])! + + super.init() + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NightScoutUploader.packetReceived(_:)), name: RILEYLINK_EVENT_PACKET_RECEIVED, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NightScoutUploader.deviceConnected(_:)), name: RILEYLINK_EVENT_DEVICE_CONNECTED, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NightScoutUploader.deviceDisconnected(_:)), name: RILEYLINK_EVENT_DEVICE_DISCONNECTED, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(NightScoutUploader.rileyLinkAdded(_:)), name: RILEYLINK_EVENT_DEVICE_ADDED, object: nil) + + UIDevice.currentDevice().batteryMonitoringEnabled = true + lastHistoryAttempt = nil + + getHistoryTimer = NSTimer.scheduledTimerWithTimeInterval(5.0 * 60, target:self, selector:#selector(NightScoutUploader.timerTriggered), userInfo:nil, repeats:true) + + // This triggers one history fetch right away (in 10s) + //performSelector(#selector(NightScoutUploader.fetchHistory), withObject: nil, afterDelay: 10) + + // This is to just test decoding history + //performSelector(Selector("testDecodeHistory"), withObject: nil, afterDelay: 1) + + // Test storing MySentry packet: + //[self performSelector:@selector(testHandleMySentry) withObject:nil afterDelay:10]; + } + + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + + // MARK: - Testing + + func testHandleMySentry() { + let data = NSData(hexadecimalString: "a259705504e9401334001001050000000001d7040205e4000000000054000001240000000000000000dd")! + let mySentryPacket = PumpMessage(rxData: data)! + handlePumpStatus(mySentryPacket, device:"testData", rssi:1) + flushAll() + } + + func testDecodeHistory() { + let pageData = NSData(hexadecimalString: "7b0100de080a101122007b0200c0160a102c1c007b0000c0000b1000160007000002be2a900000006e2a90050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de080b101122007b0200c0160b102c1c007b0000c0000c1000160007000002be2b900000006e2b90050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de080c10112200346418d3110c107b0200c0160c102c1c00343233db170c107b0000c0000d1000160007000002be2c900000006e2c90050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de080d101122007b0200c0160d102c1c007b0000c0000e1000160007000002be2d900000006e2d90050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de080e10112200063e033303c74f4e100c3e28d7100e1021001ce2150e1003000000202ce4350e101a000ae5150e101a0120e5150e107b0214c0160e102c1c00030001000112c0160e107b0000c0000f1000160007000001d32e900000006e2e90050000000000000001d301d3640000000000000000000000000000000000000000000000000000000000000000000000007b0100de080f10112200820108db150f1000a2ce8aa0810134e0150f1000a2ce8aa07d0134e0150f1000a2ce8aa0000000000000000000000000000000000000000000000000007b0200c0160f102c1c007b0000c000101000160007000002be2f900000006e2f90050000000000000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0810101122007b0200c01610102c1c000a5e36d03670103f0b36d0d67010c228060a5b0cd43670103f0b0cd4767010c228067b0000c000111000160007000002be30900000006e309005005d5b5e02000002be02be640000000000000000000000000000000000000000000000000000000000000000000000007b0100de0811101122000a600ada3171103f0c0ada117110c2280601002200220000001dea521110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e35")! + do { + let pumpModel = PumpModel.Model523 + let page = try HistoryPage(pageData: pageData, pumpModel: pumpModel) + let source = "testing/\(pumpModel)" + self.processPumpEvents(page.events, source: source, pumpModel: pumpModel) + } catch _ { + + } + } + + + // MARK: - Device updates + + func deviceConnected(note: NSNotification) + { + activeRileyLink = note.object as? RileyLinkBLEDevice + } + + func deviceDisconnected(note: NSNotification) + { + if activeRileyLink == (note.object as? RileyLinkBLEDevice) { + activeRileyLink = nil + } + } + + func rileyLinkAdded(note: NSNotification) + { + if let device = note.object as? RileyLinkBLEDevice { + device.enableIdleListeningOnChannel(0) + } + } + + func timerTriggered() { + logMemUsage() + + if lastHistoryAttempt == nil || lastHistoryAttempt!.timeIntervalSinceNow < (-5 * 60) && !fetchHistoryScheduled { + NSLog("No fetchHistory for over five minutes. Triggering one") + fetchHistory() + } + flushAll() + } + + + func packetReceived(note: NSNotification) { + let attrs = note.userInfo! + let packet = attrs["packet"] as! RFPacket + let device = note.object as! RileyLinkBLEDevice + + if let data = packet.data { + + if let msg = PumpMessage(rxData: data) { + handlePumpMessage(msg, device:device, rssi: Int(packet.rssi)) + //TODO: tell RL to sleep for 4 mins to save on RL battery? + + } else if let msg = MeterMessage(rxData: data) { + handleMeterMessage(msg) + } + + } + } + + // MARK: - Polling + + func fetchHistory() { + lastHistoryAttempt = NSDate() + + fetchHistoryScheduled = false + if let device = activeRileyLink where device.state != .Connected { + activeRileyLink = nil + } + + if (self.activeRileyLink == nil) { + for item in RileyLinkBLEManager.sharedManager().rileyLinkList { + if let device = item as? RileyLinkBLEDevice where device.state == .Connected { + activeRileyLink = device + break + } + } + } + + if let rl = activeRileyLink { + NSLog("Using RileyLink \"%@\" to fetchHistory.", rl.name!) + + let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate + let pumpOps = PumpOps(pumpState: appDelegate.pump, device:rl) + pumpOps.getHistoryEventsSinceDate(observingPumpEventsSince) { (response) -> Void in + switch response { + case .Success(let (events, pumpModel)): + NSLog("fetchHistory succeeded.") + let source = "rileylink://medtronic/\(pumpModel)" + self.processPumpEvents(events, source: source, pumpModel: pumpModel) + case .Failure(let error): + // TODO: Check for HistoryPage.Error.UnknownEventType, and let users submit + // back to us to discover new history events. + NSLog("History fetch failed: %@", String(error)) + } + } + } else { + NSLog("fetchHistory failed: No connected rileylinks to attempt to pull history with.") + } + } + + // MARK: - Decoding Treatments + + func processPumpEvents(events: [PumpEvent], source: String, pumpModel: PumpModel) { + + // Find valid event times + var validEventTimes = [NSDate]() + for event in events { + if event is TimestampedPumpEvent { + let timestamp = (event as! TimestampedPumpEvent).timestamp + if let date = TimeFormat.timestampAsLocalDate(timestamp) { + validEventTimes.append(date) + } + } + } + let newestEventTime = validEventTimes.last + + + // Find the oldest event that might still be updated. + var oldestUpdatingEventDate: NSDate? + let cal = NSCalendar.currentCalendar() + for event in events { + switch event { + case is BolusNormalPumpEvent: + let event = event as! BolusNormalPumpEvent + if let date = TimeFormat.timestampAsLocalDate(event.timestamp) { + let duration = NSDateComponents() + duration.minute = event.duration + let deliveryFinishDate = cal.dateByAddingComponents(duration, toDate: date, options: NSCalendarOptions(rawValue:0)) + if newestEventTime == nil || deliveryFinishDate?.compare(newestEventTime!) == .OrderedDescending { + // This event might still be updated. + oldestUpdatingEventDate = date + break + } + } + default: + continue + } + } + + if oldestUpdatingEventDate != nil { + observingPumpEventsSince = oldestUpdatingEventDate! + } else if newestEventTime != nil { + observingPumpEventsSince = newestEventTime! + } + NSLog("Updated fetch start time to %@", observingPumpEventsSince) + + for treatment in NightscoutPumpEvents.translate(events, eventSource: source) { + addTreatment(treatment, pumpModel:pumpModel) + } + self.flushAll() + } + + func addTreatment(treatment:NightscoutTreatment, pumpModel:PumpModel) { + var rep = treatment.dictionaryRepresentation + if rep["created_at"] == nil && rep["timestamp"] != nil { + rep["created_at"] = rep["timestamp"] + } + if rep["created_at"] == nil { + rep["created_at"] = TimeFormat.timestampStrFromDate(NSDate()) + } + treatmentsQueue.append(rep) + } + + +// - (NSString*)trendToDirection:(GlucoseTrend)trend { +// switch (trend) { +// case GLUCOSE_TREND_NONE: +// return @""; +// case GLUCOSE_TREND_UP: +// return @"SingleUp"; +// case GLUCOSE_TREND_DOUBLE_UP: +// return @"DoubleUp"; +// case GLUCOSE_TREND_DOWN: +// return @"SingleDown"; +// case GLUCOSE_TREND_DOUBLE_DOWN: +// return @"DoubleDown"; +// default: +// return @"NOT COMPUTABLE"; +// break; +// } +// } + + // Entries [ { sgv: 375, + // date: 1432421525000, + // dateString: '2015-05-23T22:52:05.000Z', + // trend: 1, + // direction: 'DoubleUp', + // device: 'share2', + // type: 'sgv' } ] + + func handlePumpMessage(msg: PumpMessage, device: RileyLinkBLEDevice, rssi: Int) { + + if (msg.packetType == .MySentry && + msg.messageType == .PumpStatus && + (msg.address.hexadecimalString == Config.sharedInstance().pumpID)) { + // Make this RL the active one, for history dumping. + activeRileyLink = device + handlePumpStatus(msg, device:device.deviceURI, rssi:rssi) + // Just got a MySentry packet; in 11s would be a good time to poll. + if !fetchHistoryScheduled { + performSelector(#selector(NightScoutUploader.fetchHistory), withObject:nil, afterDelay:11) + fetchHistoryScheduled = true + } + // TODO: send ack. also, we can probably wait less than 25s if we ack; the 25s + // above is mainly to avoid colliding with subsequent packets. + } + flushAll() + } + + func handlePumpStatus(msg: PumpMessage, device: String, rssi: Int) { + + let status: MySentryPumpStatusMessageBody = msg.messageBody as! MySentryPumpStatusMessageBody + + if msg.address.hexadecimalString == Config.sharedInstance().pumpID { + + enum DexcomSensorErrorType: Int { + case DX_SENSOR_NOT_ACTIVE = 1 + case DX_SENSOR_NOT_CALIBRATED = 5 + case DX_BAD_RF = 12 + } + + let glucose: Int = { + switch status.glucose { + case .Active(glucose: let glucose): + return glucose + case .HighBG: + return 401 + case .WeakSignal: + return DexcomSensorErrorType.DX_BAD_RF.rawValue + case .MeterBGNow, .CalError: + return DexcomSensorErrorType.DX_SENSOR_NOT_CALIBRATED.rawValue + case .Lost, .Missing, .Ended, .Unknown, .Off, .Warmup: + return DexcomSensorErrorType.DX_SENSOR_NOT_ACTIVE.rawValue + } + }() + + // Create deviceStatus record from this mysentry packet + + var nsStatus = [String: AnyObject]() + + nsStatus["device"] = device + nsStatus["created_at"] = TimeFormat.timestampStrFromDate(NSDate()) + + // TODO: use battery monitoring to post updates if we're not hearing from pump? + + let uploaderDevice = UIDevice.currentDevice() + + if uploaderDevice.batteryMonitoringEnabled { + nsStatus["uploader"] = ["battery":uploaderDevice.batteryLevel * 100] + } + + let pumpDate = TimeFormat.timestampStr(status.pumpDateComponents) + + nsStatus["pump"] = [ + "clock": pumpDate, + "iob": [ + "timestamp": pumpDate, + "bolusiob": status.iob, + ], + "reservoir": status.reservoirRemainingUnits, + "battery": [ + "percent": status.batteryRemainingPercent + ] + ] + + switch status.glucose { + case .Active(glucose: _): + nsStatus["sensor"] = [ + "sensorAge": status.sensorAgeHours, + "sensorRemaining": status.sensorRemainingHours, + ] + default: + nsStatus["sensorNotActive"] = true + } + deviceStatuses.append(nsStatus) + + + // Create SGV entry from this mysentry packet + var entry: [String: AnyObject] = [ + "sgv": glucose, + "device": device, + "rssi": rssi, + "type": "sgv" + ] + if let sensorDateComponents = status.glucoseDateComponents, + let sensorDate = TimeFormat.timestampAsLocalDate(sensorDateComponents) { + entry["date"] = sensorDate.timeIntervalSince1970 * 1000 + entry["dateString"] = TimeFormat.timestampStr(sensorDateComponents) + } + switch status.previousGlucose { + case .Active(glucose: let previousGlucose): + entry["previousSGV"] = previousGlucose + default: + entry["previousSGVNotActive"] = true + } + entry["direction"] = { + switch status.glucoseTrend { + case .Up: + return "SingleUp" + case .UpUp: + return "DoubleUp" + case .Down: + return "SingleDown" + case .DownDown: + return "DoubleDown" + case .Flat: + return "Flat" + } + }() + entries.append(entry) + } else { + NSLog("Dropping mysentry packet for pump: %@", msg.address.hexadecimalString); + } + } + + func handleMeterMessage(msg: MeterMessage) { + + // TODO: Should only accept meter messages from specified meter ids. + // Need to add an interface to allow user to specify linked meters. + + if msg.ackFlag { + return + } + + let date = NSDate() + let epochTime = date.timeIntervalSince1970 * 1000 + let entry = [ + "date": epochTime, + "dateString": TimeFormat.timestampStrFromDate(date), + "mbg": msg.glucose, + "device": "Contour Next Link", + "type": "mbg" + ] + + // Skip duplicates + if lastMeterMessageRxTime == nil || lastMeterMessageRxTime!.timeIntervalSinceNow < -3 * 60 { + entries.append(entry) + lastMeterMessageRxTime = NSDate() + } + } + + // MARK: - Uploading + + func flushAll() { + + let logEntries = Log.popLogEntries() + + if logEntries.count > 0 { + let date = NSDate() + let epochTime = date.timeIntervalSince1970 * 1000 + + let entry = [ + "date": epochTime, + "dateString": TimeFormat.timestampStrFromDate(date), + "entries": logEntries, + "type": "logs" + ] + entries.append(entry) + } + + flushDeviceStatuses() + flushEntries() + flushTreatments() + } + + func uploadToNS(json: [AnyObject], endpoint:String, completion: (String?) -> Void) { + if json.count == 0 { + completion(nil) + return + } + + if let uploadURL = NSURL(string: endpoint, relativeToURL: NSURL(string: siteURL)) { + let request = NSMutableURLRequest(URL: uploadURL) + do { + let sendData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions.PrettyPrinted) + request.HTTPMethod = "POST" + + request.setValue("application/json", forHTTPHeaderField:"Content-Type") + request.setValue("application/json", forHTTPHeaderField:"Accept") + request.setValue(self.APISecret.sha1(), forHTTPHeaderField:"api-secret") + request.HTTPBody = sendData + + let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in + let httpResponse = response as! NSHTTPURLResponse + if let error = error { + completion(error.description) + } else if httpResponse.statusCode != 200 { + completion(String(data: data!, encoding: NSUTF8StringEncoding)!) + } else { + completion(nil) + } + }) + task.resume() + } catch { + completion("Couldn't encode data to json.") + } + } else { + completion("Invalid URL: \(siteURL), \(endpoint)") + } + } + + func flushDeviceStatuses() { + let inFlight = deviceStatuses + deviceStatuses = [AnyObject]() + uploadToNS(inFlight, endpoint: defaultNightscoutDeviceStatusPath) { (error) in + if error != nil { + NSLog("Uploading device status to nightscout failed: %@", error!) + // Requeue + self.deviceStatuses.appendContentsOf(inFlight) + } + } + } + + func flushEntries() { + let inFlight = entries + entries = [AnyObject]() + uploadToNS(inFlight, endpoint: defaultNightscoutEntriesPath) { (error) in + if error != nil { + NSLog("Uploading nightscout entries failed: %@", error!) + // Requeue + self.entries.appendContentsOf(inFlight) + } + } + } + + func flushTreatments() { + let inFlight = treatmentsQueue + treatmentsQueue = [AnyObject]() + uploadToNS(inFlight, endpoint: defaultNightscoutTreatmentPath) { (error) in + if error != nil { + NSLog("Uploading nightscout treatment records failed: %@", error!) + // Requeue + self.treatmentsQueue.appendContentsOf(inFlight) + } + } + } +} diff --git a/RileyLink/NightscoutUploadKit/TempBasalNightscoutTreatment.swift b/RileyLink/NightscoutUploadKit/TempBasalNightscoutTreatment.swift new file mode 100644 index 000000000..9ab6b010a --- /dev/null +++ b/RileyLink/NightscoutUploadKit/TempBasalNightscoutTreatment.swift @@ -0,0 +1,44 @@ +// +// TempBasalNightscoutTreatment.swift +// RileyLink +// +// Created by Pete Schwamb on 4/18/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public class TempBasalNightscoutTreatment: NightscoutTreatment { + + enum RateType: String { + case Absolute = "absolute" + case Percentage = "percentage" + } + + + let rate: Double + let absolute: Double? + let temp: RateType + let duration: Int + + init(timestamp: NSDate, enteredBy: String, temp: RateType, rate: Double, absolute: Double?, duration: Int) { + self.rate = rate + self.absolute = absolute + self.temp = temp + self.duration = duration + + super.init(timestamp: timestamp, enteredBy: enteredBy) + } + + override public var dictionaryRepresentation: [String: AnyObject] { + var rval = super.dictionaryRepresentation + rval["eventType"] = "Temp Basal" + rval["temp"] = temp.rawValue + rval["rate"] = rate + if let absolute = absolute { + rval["absolute"] = absolute + } + rval["duration"] = duration + return rval + } +} diff --git a/RileyLink/NightscoutWebView.m b/RileyLink/NightscoutWebView.m index 68b523c0c..1eec8d397 100644 --- a/RileyLink/NightscoutWebView.m +++ b/RileyLink/NightscoutWebView.m @@ -26,16 +26,16 @@ - (void)viewDidLoad if (self.revealViewController != nil) { menuButton.target = self.revealViewController; - [menuButton setAction:@selector(revealToggle:)]; + menuButton.action = @selector(revealToggle:); [self.view addGestureRecognizer: self.revealViewController.panGestureRecognizer]; self.revealViewController.rearViewRevealWidth = 162; - if (![[Config sharedInstance] hasValidConfiguration]) { + if (![Config sharedInstance].hasValidConfiguration) { UINavigationController *configNav = [self.storyboard instantiateViewControllerWithIdentifier:@"configuration"]; - ConfigureViewController *configViewController = [configNav viewControllers][0]; + ConfigureViewController *configViewController = configNav.viewControllers[0]; [configViewController doInitialConfiguration]; - [self.revealViewController setFrontViewController:configNav]; + (self.revealViewController).frontViewController = configNav; } } @@ -43,7 +43,7 @@ - (void)viewDidLoad } - (void)loadPage { - NSURL *url = [NSURL URLWithString:[[Config sharedInstance] nightscoutURL]]; + NSURL *url = [NSURL URLWithString:[Config sharedInstance].nightscoutURL]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [_webView loadRequest:request]; } @@ -62,7 +62,7 @@ - (void)didReceiveMemoryWarning - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { [UIAlertView showWithTitle:@"Network Error" - message:[error localizedDescription] + message:error.localizedDescription cancelButtonTitle:@"OK" otherButtonTitles:@[@"Retry"] tapBlock:^(UIAlertView *alertView, NSInteger buttonIndex) { diff --git a/RileyLink/PacketGeneratorViewController.m b/RileyLink/PacketGeneratorViewController.m index 064bece50..aa326dc52 100644 --- a/RileyLink/PacketGeneratorViewController.m +++ b/RileyLink/PacketGeneratorViewController.m @@ -7,9 +7,8 @@ // #import "PacketGeneratorViewController.h" -#import "MinimedPacket.h" #import "NSData+Conversion.h" -#import "SendAndListenCmd.h" +#import "SendPacketCmd.h" @interface PacketGeneratorViewController () { int testPacketNum; @@ -40,7 +39,7 @@ - (void)viewDidLoad { } - (void)doneChangingChannel { - txChannel = [channelNumberTextField.text intValue]; + txChannel = (channelNumberTextField.text).intValue; [channelNumberTextField resignFirstResponder]; } @@ -64,16 +63,17 @@ - (void)incrementPacketNum { - (void)sendTestPacket { NSString *packetStr = [@"614C05E077" stringByAppendingFormat:@"%02x", testPacketNum]; NSData *data = [NSData dataWithHexadecimalString:packetStr]; - if (encodeDataSwitch.on) { - data = [MinimedPacket encodeData:data]; - } - packetData.text = [data hexadecimalString]; - SendAndListenCmd *cmd = [[SendAndListenCmd alloc] init]; +// if (encodeDataSwitch.on) { +// data = [MinimedPacket encodeData:data]; +// } + packetData.text = data.hexadecimalString; + SendPacketCmd *cmd = [[SendPacketCmd alloc] init]; cmd.sendChannel = txChannel; cmd.repeatCount = 0; cmd.msBetweenPackets = 0; - // TODO: Upgrade to new api - //[_device doCmd:cmd withCompletionHandler:nil]; + [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { + [session doCmd:cmd withTimeoutMs:1000]; + }]; } - (IBAction)sendPacketButtonPressed:(id)sender { diff --git a/RileyLink/PacketLogViewController.m b/RileyLink/PacketLogViewController.m index e4c761159..246d119c4 100644 --- a/RileyLink/PacketLogViewController.m +++ b/RileyLink/PacketLogViewController.m @@ -8,10 +8,11 @@ #import "PacketLogViewController.h" #import "PacketTableViewCell.h" -#import "MinimedPacket.h" +#import "RFPacket.h" #import "RileyLinkBLEManager.h" @interface PacketLogViewController () { + NSMutableArray *packets; } @end @@ -21,6 +22,8 @@ @implementation PacketLogViewController - (void)viewDidLoad { [super viewDidLoad]; + packets = [NSMutableArray array]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(packetReceived:) name:RILEYLINK_EVENT_PACKET_RECEIVED @@ -51,16 +54,16 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. - return self.device.packets.count; + return packets.count; } -- (MinimedPacket *)packetForIndex:(NSInteger) idx { - return self.device.packets[self.device.packets.count - idx - 1]; +- (RFPacket *)packetForIndex:(NSInteger) idx { + return packets[packets.count - idx - 1]; } - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { PacketTableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:@"packet" forIndexPath:indexPath]; - MinimedPacket *packet = [self packetForIndex:indexPath.row]; + RFPacket *packet = [self packetForIndex:indexPath.row]; cell.packet = packet; return cell; } diff --git a/RileyLink/PacketTableViewCell.h b/RileyLink/PacketTableViewCell.h index d5b717cb1..3b35129ff 100644 --- a/RileyLink/PacketTableViewCell.h +++ b/RileyLink/PacketTableViewCell.h @@ -7,10 +7,10 @@ // #import -#import "MinimedPacket.h" +#import "RFPacket.h" @interface PacketTableViewCell : UITableViewCell -@property (nonatomic, strong) MinimedPacket *packet; +@property (nonatomic, strong) RFPacket *packet; @end diff --git a/RileyLink/PacketTableViewCell.m b/RileyLink/PacketTableViewCell.m index 1747ab9a8..c9b126ff6 100644 --- a/RileyLink/PacketTableViewCell.m +++ b/RileyLink/PacketTableViewCell.m @@ -7,6 +7,8 @@ // #import "PacketTableViewCell.h" +#import "MinimedKit.h" +#import "NSData+Conversion.h" static NSDateFormatter *dateFormatter; static NSDateFormatter *timeFormatter; @@ -25,21 +27,21 @@ @implementation PacketTableViewCell + (void)initialize { dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setLocale:[NSLocale currentLocale]]; - [dateFormatter setDateStyle:NSDateFormatterShortStyle]; + dateFormatter.locale = [NSLocale currentLocale]; + dateFormatter.dateStyle = NSDateFormatterShortStyle; timeFormatter = [[NSDateFormatter alloc] init]; - [timeFormatter setLocale:[NSLocale currentLocale]]; - [timeFormatter setTimeStyle:NSDateFormatterShortStyle]; + timeFormatter.locale = [NSLocale currentLocale]; + timeFormatter.timeStyle = NSDateFormatterShortStyle; } - (void)awakeFromNib { // Initialization code } -- (void)setPacket:(MinimedPacket *)packet { +- (void)setPacket:(RFPacket *)packet { _packet = packet; - rawDataLabel.text = packet.hexadecimalString; + rawDataLabel.text = packet.data.hexadecimalString; dateLabel.text = [dateFormatter stringFromDate:packet.capturedAt]; timeLabel.text = [timeFormatter stringFromDate:packet.capturedAt]; rssiLabel.text = [NSString stringWithFormat:@"%d", packet.rssi]; diff --git a/RileyLink/PumpChatViewController.h b/RileyLink/PumpChatViewController.h deleted file mode 100644 index 849054777..000000000 --- a/RileyLink/PumpChatViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// PumpChatViewController.h -// RileyLink -// -// Created by Pete Schwamb on 8/8/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "RileyLinkBLEDevice.h" - -@interface PumpChatViewController : UIViewController - -@property (nonatomic, strong) RileyLinkBLEDevice *device; - -@end diff --git a/RileyLink/PumpChatViewController.m b/RileyLink/PumpChatViewController.m deleted file mode 100644 index 0c5ed65e0..000000000 --- a/RileyLink/PumpChatViewController.m +++ /dev/null @@ -1,109 +0,0 @@ -// -// PumpChatViewController.m -// RileyLink -// -// Created by Pete Schwamb on 8/8/15. -// Copyright (c) 2015 Pete Schwamb. All rights reserved. -// - -#import "PumpChatViewController.h" -#import "MessageBase.h" -#import "MinimedPacket.h" -#import "NSData+Conversion.h" -#import "Config.h" -#import "RileyLinkBLEManager.h" -#import "HistoryPage.h" -#import "PumpHistoryEventBase.h" -#import "SendAndListenCmd.h" -#import "AppDelegate.h" -#import "PumpOpsSynchronous.h" -#import "PumpOps.h" - -@interface PumpChatViewController () { - IBOutlet UITextView *output; - IBOutlet UILabel *batteryVoltage; - IBOutlet UILabel *pumpIdLabel; -} - -@property (nonatomic, strong) NSOperationQueue *pumpCommQueue; -@property (nonatomic, strong) PumpOps *pumpOps; - -@end - -@implementation PumpChatViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - pumpIdLabel.text = [NSString stringWithFormat:@"PumpID: %@", [[Config sharedInstance] pumpID]]; - - AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - _pumpOps = [[PumpOps alloc] initWithPumpState:appDelegate.pump andDevice:_device]; -} - - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -- (void)addOutputMessage:(NSString*)msg -{ - output.text = [output.text stringByAppendingFormat:@"%@\n", msg]; - NSLog(@"addOutputMessage: %@", msg); -} - - -- (IBAction)dumpHistoryButtonPressed:(id)sender { - [_pumpOps getHistoryPage:0 withHandler:^(NSDictionary * _Nonnull res) { - if (!res[@"error"]) { - NSData *page = res[@"pageData"]; - NSLog(@"Got page data: %@", [page hexadecimalString]); - [self decodeHistoryPage:page withModel:res[@"pumpModel"]]; - } else { - NSString *log = [NSString stringWithFormat:@"Dump of page 0 failed: %@", res[@"error"]]; - [self addOutputMessage:log]; - } - }]; -} - -- (void) decodeHistoryPage:(NSData*)data withModel:(NSString*)model { - - PumpModel *m = [PumpModel find:model]; - HistoryPage *page = [[HistoryPage alloc] initWithData:data andPumpModel:m]; - - NSArray *events = [page decode]; - - for (PumpHistoryEventBase *event in events) { - [self addOutputMessage:[NSString stringWithFormat:@"Event: %@", event]]; - NSLog(@"Event: %@", event); - } -} - -- (IBAction)pressDownButtonPressed:(id)sender { - [_pumpOps pressButton]; -} - -- (IBAction)queryPumpButtonPressed:(id)sender { - - [_pumpOps getPumpModel:^(NSString * _Nonnull model) { - if (model) { - [self addOutputMessage:[NSString stringWithFormat:@"Pump Model: %@", model]]; - } else { - [self addOutputMessage:@"Get pump model failed."]; - } - }]; - - [_pumpOps getBatteryVoltage:^(NSString * _Nonnull status, float value) { - [self addOutputMessage:[NSString stringWithFormat:@"Battery Level: %@, %0.02f volts", status, value]]; - }]; -} - -- (IBAction)tuneButtonPressed:(id)sender { - [_pumpOps tunePump:^(NSDictionary * _Nonnull res) { - [self addOutputMessage:[NSString stringWithFormat:@"Tuning results: %@", res]]; - }]; -} - - -@end diff --git a/RileyLink/PumpChatViewController.swift b/RileyLink/PumpChatViewController.swift new file mode 100644 index 000000000..0a8099692 --- /dev/null +++ b/RileyLink/PumpChatViewController.swift @@ -0,0 +1,99 @@ +// +// PumpChatViewController.swift +// RileyLink +// +// Created by Pete Schwamb on 3/12/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import UIKit +import MinimedKit +import RileyLinkKit +import RileyLinkBLEKit + + +class PumpChatViewController: UIViewController { + + @IBOutlet var output: UITextView! + @IBOutlet var batteryVoltage: UILabel! + @IBOutlet var pumpIdLabel: UILabel! + + var pumpOps: PumpOps! + var device: RileyLinkBLEDevice! + + override func viewDidLoad() { + super.viewDidLoad() + + pumpIdLabel.text = "PumpID: \(Config.sharedInstance().pumpID ?? "nil")" + + let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate + pumpOps = PumpOps(pumpState:appDelegate.pump, device:device) + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func addOutputMessage(msg: String) + { + output.text = output.text.stringByAppendingFormat("%@\n", msg) + NSLog("addOutputMessage: %@", msg) + } + + @IBAction func dumpHistoryButtonPressed(sender: UIButton) { + let calendar = NSCalendar.currentCalendar() + let oneDayAgo = calendar.dateByAddingUnit(.Day, value: -1, toDate: NSDate(), options: []) + pumpOps.getHistoryEventsSinceDate(oneDayAgo!) { (response) -> Void in + switch response { + case .Success(let (events, _)): + self.addOutputMessage(String(format:"Found %d events since %@", events.count, oneDayAgo!)) + for event in events { + self.addOutputMessage(String(format:"Event: %@", event.dictionaryRepresentation)) + NSLog("Event: %@", event.dictionaryRepresentation) + } + case .Failure(let error): + let errorMsg = String(format:"History fetch failed: %@", String(error)) + self.addOutputMessage(errorMsg) + } + } + } + + @IBAction func pressDownButtonPressed(sender: UIButton) { + pumpOps.pressButton() + } + + @IBAction func queryPumpButtonPressed(sender: UIButton) { + pumpOps.getPumpModel { (model) -> Void in + if let model = model { + self.addOutputMessage(String(format:"Pump Model: %@", model)) + } else { + self.addOutputMessage("Get pump model failed.") + } + } + + pumpOps.getBatteryVoltage { (results) -> Void in + if let results = results { + self.addOutputMessage(String(format:"Battery Level: %@, %0.02f volts", results.status, results.volts)) + } else { + self.addOutputMessage("Get battery voltage failed.") + } + } + } + + + @IBAction func tuneButtonPressed(sender: UIButton) { + pumpOps.tunePump { (result) -> Void in + switch result { + case .Success(let scanResults): + for trial in scanResults.trials { + self.addOutputMessage(String(format:"Trial: %0.02f - %d, %0.01f", trial.frequencyMHz, trial.successes, trial.avgRSSI)) + } + self.addOutputMessage(String(format:"Best Freq: %0.02f", scanResults.bestFrequency)) + case .Failure(let error): + let errorMsg = String(format:"Tune failed: %@", String(error)) + self.addOutputMessage(errorMsg) + } + } + } +} diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.h b/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.h deleted file mode 100644 index bfb796ace..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEAlarmClockReminder.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEAlarmClockReminder : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.m b/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.m deleted file mode 100644 index ee68822a7..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmClockReminder.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEAlarmClockReminder.m -// - -#import "PHEAlarmClockReminder.h" - -@implementation PHEAlarmClockReminder - -+ (int) eventTypeCode { - return 0x35; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmPump.h b/RileyLink/PumpHistoryEvents/PHEAlarmPump.h deleted file mode 100644 index c0d814c5b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmPump.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEAlarmPump.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEAlarmPump : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmPump.m b/RileyLink/PumpHistoryEvents/PHEAlarmPump.m deleted file mode 100644 index f4916e517..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmPump.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEAlarmPump.m -// - -#import "PHEAlarmPump.h" - -@implementation PHEAlarmPump - -+ (int) eventTypeCode { - return 0x06; -} - -- (int) length { - return 9; -} - -- (NSDateComponents*) timestamp { - return [self parseDateComponents:4]; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmSensor.h b/RileyLink/PumpHistoryEvents/PHEAlarmSensor.h deleted file mode 100644 index 04a5e24dc..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmSensor.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEAlarmSensor.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEAlarmSensor : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEAlarmSensor.m b/RileyLink/PumpHistoryEvents/PHEAlarmSensor.m deleted file mode 100644 index 7d8e804c9..000000000 --- a/RileyLink/PumpHistoryEvents/PHEAlarmSensor.m +++ /dev/null @@ -1,65 +0,0 @@ -// -// PHEAlarmSensor.m -// - -#import "PHEAlarmSensor.h" - -@implementation PHEAlarmSensor - -+ (int) eventTypeCode { - return 0x0b; -} - -- (int) length { - return 8; -} - -- (NSString*) alarmTypeStr { - NSString *str = @{ - @101: @"High Glucose", - @102: @"Low Glucose", - @104: @"Meter BG Now", - @105: @"Cal Reminder", - @106: @"Calibration Error", - @107: @"Sensor End", - @112: @"Weak Signal", - @113: @"Lost Sensor", - @114: @"High Glucose Predicted", - @115: @"Low Glucose Predicted" - }[[NSNumber numberWithInt:[self alarmType]]]; - if (str == nil) { - str = [NSString stringWithFormat:@"Unknown(0x%02x)", [self alarmType]]; - } - return str; -} - -- (uint8_t) alarmType { - return [self byteAt:1]; -} - -- (int) amount { - return (([self byteAt:7] & 0b10000000) << 1) + [self byteAt:2]; -} - -- (int) profileIndex { - return [self byteAt:1]; -} - -- (NSDateComponents*) timestamp { - return [self parseDateComponents:3]; -} - -- (NSDictionary*) asJSON { - NSMutableDictionary *base = [[super asJSON] mutableCopy]; - [base addEntriesFromDictionary:@{ - @"alarm_description": [self alarmTypeStr], - @"alarm_type": @([self alarmType]) - }]; - if ([self amount] > 0) { - base[@"amount"] = [NSNumber numberWithInt:[self alarmType]]; - } - return base; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.h b/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.h deleted file mode 100644 index e3d1d548f..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEBasalProfileStart.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEBasalProfileStart : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.m b/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.m deleted file mode 100644 index 312bb0d5f..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBasalProfileStart.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEBasalProfileStart.m -// - -#import "PHEBasalProfileStart.h" - -@implementation PHEBasalProfileStart - -+ (int) eventTypeCode { - return 0x7b; -} - - -- (int) length { - return 10; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBattery.h b/RileyLink/PumpHistoryEvents/PHEBattery.h deleted file mode 100644 index cba0fbd35..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBattery.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEBattery.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEBattery : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBattery.m b/RileyLink/PumpHistoryEvents/PHEBattery.m deleted file mode 100644 index 9f56a3ce0..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBattery.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEBattery.m -// - -#import "PHEBattery.h" - -@implementation PHEBattery - -+ (int) eventTypeCode { - return 0x1a; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBgReceived.h b/RileyLink/PumpHistoryEvents/PHEBgReceived.h deleted file mode 100644 index 7f6aca34a..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBgReceived.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// PHEBgReceived.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEBgReceived : PumpHistoryEventBase - -- (int) bloodGlucose; - -- (nonnull NSString*) meterId; - -- (nonnull NSDateComponents*) timestamp; - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBgReceived.m b/RileyLink/PumpHistoryEvents/PHEBgReceived.m deleted file mode 100644 index f0382b5e6..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBgReceived.m +++ /dev/null @@ -1,31 +0,0 @@ -// -// PHEBgReceived.m -// - -#import "PHEBgReceived.h" -#import "NSData+Conversion.h" - -@implementation PHEBgReceived - -+ (int) eventTypeCode { - return 0x3f; -} - -- (int) length { - return 10; -} - -- (int) bloodGlucose { - return ([self byteAt:1] << 3) + ([self byteAt:4] >> 5); -} - -- (NSString*) meterId { - return [[self.data subdataWithRange:NSMakeRange(7, 3)] hexadecimalString]; -} - -- (NSDateComponents*) timestamp { - return [self parseDateComponents:2]; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBolusNormal.h b/RileyLink/PumpHistoryEvents/PHEBolusNormal.h deleted file mode 100644 index 5d77c601e..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBolusNormal.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEBolusNormal.h -// - -#import -#import "PumpHistoryEventBase.h" -#import "PHEUnabsorbedInsulin.h" - -@interface PHEBolusNormal : PumpHistoryEventBase - -@property (nonatomic, readonly) double amount; -@property (nonatomic, readonly) double programmed_amount; -@property (nonatomic, readonly) double unabsorbed_insulin_total; -@property (nonatomic, readonly) NSInteger duration; -@property (nonatomic, readonly) NSString *type; -@property (nonatomic, strong) PHEUnabsorbedInsulin *unabsorbedInsulinRecord; - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBolusNormal.m b/RileyLink/PumpHistoryEvents/PHEBolusNormal.m deleted file mode 100644 index fadabdd1a..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBolusNormal.m +++ /dev/null @@ -1,83 +0,0 @@ -// -// PHEBolusNormal.m -// - -#import "PHEBolusNormal.h" - -@implementation PHEBolusNormal - -+ (int) eventTypeCode { - return 0x01; -} - -- (instancetype)initWithData:(NSData*)data andPumpModel:(PumpModel*)model -{ - self = [super initWithData:data andPumpModel:model]; - if (self) { - if (data.length >= self.length) { - if (model.larger) { - _amount = [self insulinDecodeWithBytesA:[self byteAt:3] andB:[self byteAt:4]]; - _programmed_amount = [self insulinDecodeWithBytesA:[self byteAt:1] andB:[self byteAt:2]]; - _unabsorbed_insulin_total = [self insulinDecodeWithBytesA:[self byteAt:5] andB:[self byteAt:6]]; - _duration = [self byteAt:7] * 30; - } else { - _amount = [self byteAt:2] / 10.0; - _programmed_amount = [self byteAt:1] / 10.0; - _duration = [self byteAt:3] * 30; - } - _type = _duration > 0 ? @"square" : @"normal"; - - } - } - return self; -} - -- (double) insulinDecodeWithBytesA:(uint8_t)a andB:(uint8_t)b { - return ((a << 8) + b) / 40.0; -} - - -- (int) length { - if (self.pumpModel.larger) { - return 13; - } else { - return 9; - } -} - -- (NSDateComponents*) timestamp { - if (self.pumpModel.larger) { - return [self parseDateComponents:8]; - } else { - return [self parseDateComponents:4]; - } -} - -- (NSString*) description { - return [NSString stringWithFormat:@"%@ - %@ amount:%f programmed:%f unabsorbed:%f duration:%ld", - self.typeName, self.timestampStr, self.amount, self.programmed_amount, self.unabsorbed_insulin_total, (long)self.duration]; -} - -- (NSDictionary*) asJSON { - NSMutableDictionary *base = [[super asJSON] mutableCopy]; - [base addEntriesFromDictionary:@{ - @"amount": @(_amount), - @"programmed": @(_programmed_amount), - @"type": _type - }]; - - if (_unabsorbed_insulin_total > 0) { - base[@"unabsorbed"] = @(_unabsorbed_insulin_total); - } - if (_duration > 0) { - base[@"duration"] = @(_duration); - } - if (_unabsorbedInsulinRecord) { - base[@"appended"] = [_unabsorbedInsulinRecord asJSON]; - } - return base; -} - - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.h b/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.h deleted file mode 100644 index 9ddb01942..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEBolusWizardBolusEstimate.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEBolusWizardBolusEstimate : PumpHistoryEventBase - -@property (nonatomic, readonly) int carbohydrates; -@property (nonatomic, readonly) int bloodGlucose; -@property (nonatomic, readonly) double foodEstimate; -@property (nonatomic, readonly) double correctionEstimate; -@property (nonatomic, readonly) double bolusEstimate; -@property (nonatomic, readonly) double unabsorbedInsulinTotal; -@property (nonatomic, readonly) int bgTargetLow; -@property (nonatomic, readonly) int bgTargetHigh; -@property (nonatomic, readonly) int insulinSensitivity; -@property (nonatomic, readonly) double carbRatio; - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.m b/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.m deleted file mode 100644 index e5122e134..000000000 --- a/RileyLink/PumpHistoryEvents/PHEBolusWizardBolusEstimate.m +++ /dev/null @@ -1,82 +0,0 @@ -// -// PHEBolusWizardBolusEstimate.m -// - -#import "PHEBolusWizardBolusEstimate.h" - -@implementation PHEBolusWizardBolusEstimate - -+ (int) eventTypeCode { - return 0x5b; -} - -- (instancetype)initWithData:(NSData*)data andPumpModel:(PumpModel*)model -{ - self = [super initWithData:data andPumpModel:model]; - if (self) { - if (data.length >= self.length) { - if (model.larger) { - _carbohydrates = (([self byteAt:8] & 0xc) << 6) + [self byteAt:7]; - _bloodGlucose = (([self byteAt:8] & 0x3) << 8) + [self byteAt:1]; - _foodEstimate = [self insulinDecodeByteA:[self byteAt:14] byteB:[self byteAt:15]]; - _correctionEstimate = ((([self byteAt:16] & 0b111000) << 5) + [self byteAt:13]) / 40.0; - _bolusEstimate = [self insulinDecodeByteA:[self byteAt:19] byteB:[self byteAt:20]]; - _unabsorbedInsulinTotal = [self insulinDecodeByteA:[self byteAt:17] byteB:[self byteAt:18]]; - _bgTargetLow = [self byteAt:12]; - _bgTargetHigh = [self byteAt:21]; - _insulinSensitivity = [self byteAt:11]; - _carbRatio = (([self byteAt:9] & 0x7) << 8) + [self byteAt:10] / 10.0; - } else { - _carbohydrates = [self byteAt:7]; - _bloodGlucose = (([self byteAt:8] & 0x3) << 8) + [self byteAt:1]; - _foodEstimate = [self byteAt:13]/10.0; - _correctionEstimate = (([self byteAt:14] << 8) + [self byteAt:12]) / 10.0; - _bolusEstimate = [self byteAt:18]/10.0; - _unabsorbedInsulinTotal = [self byteAt:16]/10.0; - _bgTargetLow = [self byteAt:11]; - _bgTargetHigh = [self byteAt:19]; - _insulinSensitivity = [self byteAt:10]; - _carbRatio = [self byteAt:9]; - } - } - } - return self; -} - -- (double) insulinDecodeByteA:(uint8_t)a byteB:(uint8_t)b { - return ((a << 8) + b) / 40.0; -} - -- (int) length { - if (self.pumpModel.larger) { - return 22; - } else { - return 20; - } -} - - -- (NSDictionary*) asJSON { - NSMutableDictionary *base = [[super asJSON] mutableCopy]; - [base addEntriesFromDictionary:@{ - @"bg_target_high": @(self.bgTargetHigh), - @"correction_estimate": @(self.correctionEstimate), - @"unabsorbed_insulin_total": @(self.unabsorbedInsulinTotal), - @"bolus_estimate": @(self.bolusEstimate), - @"carb_ratio": @(self.carbRatio), - @"food_estimate": @(self.foodEstimate), - @"bg_target_low": @(self.bgTargetLow), - @"sensitivity": @(self.insulinSensitivity), - }]; - if (self.bloodGlucose > 0) { - base[@"bg"] = @(self.bloodGlucose); - } - if (self.carbohydrates > 0) { - base[@"carb_input"] = @(self.carbohydrates); - } - - return base; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHECalBGForPH.h b/RileyLink/PumpHistoryEvents/PHECalBGForPH.h deleted file mode 100644 index bd7367cbd..000000000 --- a/RileyLink/PumpHistoryEvents/PHECalBGForPH.h +++ /dev/null @@ -1,12 +0,0 @@ -// -// PHECalBGForPH.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHECalBGForPH : PumpHistoryEventBase - -- (int) amount; - -@end diff --git a/RileyLink/PumpHistoryEvents/PHECalBGForPH.m b/RileyLink/PumpHistoryEvents/PHECalBGForPH.m deleted file mode 100644 index 00613721b..000000000 --- a/RileyLink/PumpHistoryEvents/PHECalBGForPH.m +++ /dev/null @@ -1,29 +0,0 @@ -// -// PHECalBGForPH.m -// - -#import "PHECalBGForPH.h" - -@implementation PHECalBGForPH - -+ (int) eventTypeCode { - return 0x0a; -} - -- (int) amount { - return (([self byteAt:6] & 0b10000000) << 1) + [self byteAt:1]; -} - -- (int) length { - return 7; -} - -- (NSDictionary*) asJSON { - NSMutableDictionary *base = [[super asJSON] mutableCopy]; - if ([self amount] > 0) { - base[@"amount"] = [NSNumber numberWithInt:[self amount]]; - } - return base; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.h deleted file mode 100644 index b83c3f694..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeAlarmClockEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeAlarmClockEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.m deleted file mode 100644 index 48b5b2e89..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeAlarmClockEnable.m -// - -#import "PHEChangeAlarmClockEnable.h" - -@implementation PHEChangeAlarmClockEnable - -+ (int) eventTypeCode { - return 0x61; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.h b/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.h deleted file mode 100644 index b4a0ed8db..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeAlarmClockTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeAlarmClockTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.m b/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.m deleted file mode 100644 index 8a1a22dc3..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmClockTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeAlarmClockTime.m -// - -#import "PHEChangeAlarmClockTime.h" - -@implementation PHEChangeAlarmClockTime - -+ (int) eventTypeCode { - return 0x32; -} - - -- (int) length { - return 14; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.h b/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.h deleted file mode 100644 index 6dc6364ba..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeAlarmNotifyMode.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeAlarmNotifyMode : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.m b/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.m deleted file mode 100644 index 57758f8d1..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAlarmNotifyMode.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeAlarmNotifyMode.m -// - -#import "PHEChangeAlarmNotifyMode.h" - -@implementation PHEChangeAlarmNotifyMode - -+ (int) eventTypeCode { - return 0x63; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.h b/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.h deleted file mode 100644 index c0342ab35..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeAudioBolus.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeAudioBolus : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.m b/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.m deleted file mode 100644 index 912690d04..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeAudioBolus.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeAudioBolus.m -// - -#import "PHEChangeAudioBolus.h" - -@implementation PHEChangeAudioBolus - -+ (int) eventTypeCode { - return 0x5f; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.h deleted file mode 100644 index 0d7ac29fc..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBGReminderEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBGReminderEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.m deleted file mode 100644 index dede17166..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBGReminderEnable.m -// - -#import "PHEChangeBGReminderEnable.h" - -@implementation PHEChangeBGReminderEnable - -+ (int) eventTypeCode { - return 0x60; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.h b/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.h deleted file mode 100644 index 5ee42b4b7..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBGReminderOffset.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBGReminderOffset : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.m b/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.m deleted file mode 100644 index ab1ef57f2..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBGReminderOffset.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBGReminderOffset.m -// - -#import "PHEChangeBGReminderOffset.h" - -@implementation PHEChangeBGReminderOffset - -+ (int) eventTypeCode { - return 0x31; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.h b/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.h deleted file mode 100644 index 41dfa2fd9..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBasalProfile.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBasalProfile : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.m b/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.m deleted file mode 100644 index 2464b18e4..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfile.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBasalProfile.m -// - -#import "PHEChangeBasalProfile.h" - -@implementation PHEChangeBasalProfile - -+ (int) eventTypeCode { - return 0x09; -} - - -- (int) length { - return 152; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.h b/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.h deleted file mode 100644 index 9a675c57b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBasalProfilePattern.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBasalProfilePattern : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.m b/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.m deleted file mode 100644 index 153c1914d..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBasalProfilePattern.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBasalProfilePattern.m -// - -#import "PHEChangeBasalProfilePattern.h" - -@implementation PHEChangeBasalProfilePattern - -+ (int) eventTypeCode { - return 0x08; -} - - -- (int) length { - return 152; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.h deleted file mode 100644 index 4cfc656a3..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBolusReminderEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBolusReminderEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.m deleted file mode 100644 index 50d0be966..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBolusReminderEnable.m -// - -#import "PHEChangeBolusReminderEnable.h" - -@implementation PHEChangeBolusReminderEnable - -+ (int) eventTypeCode { - return 0x66; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.h b/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.h deleted file mode 100644 index f8c6f4d97..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBolusReminderTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBolusReminderTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.m b/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.m deleted file mode 100644 index 791996cc8..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusReminderTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBolusReminderTime.m -// - -#import "PHEChangeBolusReminderTime.h" - -@implementation PHEChangeBolusReminderTime - -+ (int) eventTypeCode { - return 0x67; -} - - -- (int) length { - return 9; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.h b/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.h deleted file mode 100644 index 84aca71c8..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBolusScrollStepSize.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBolusScrollStepSize : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.m b/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.m deleted file mode 100644 index 78ba3f0f7..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusScrollStepSize.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBolusScrollStepSize.m -// - -#import "PHEChangeBolusScrollStepSize.h" - -@implementation PHEChangeBolusScrollStepSize - -+ (int) eventTypeCode { - return 0x57; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.h b/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.h deleted file mode 100644 index 57af8154d..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeBolusWizardSetup.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeBolusWizardSetup : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.m b/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.m deleted file mode 100644 index c809f3384..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeBolusWizardSetup.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeBolusWizardSetup.m -// - -#import "PHEChangeBolusWizardSetup.h" - -@implementation PHEChangeBolusWizardSetup - -+ (int) eventTypeCode { - return 0x5a; -} - - -- (int) length { - return 144; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.h deleted file mode 100644 index 71de9537b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeCaptureEventEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeCaptureEventEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.m deleted file mode 100644 index b51ac5964..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeCaptureEventEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeCaptureEventEnable.m -// - -#import "PHEChangeCaptureEventEnable.h" - -@implementation PHEChangeCaptureEventEnable - -+ (int) eventTypeCode { - return 0x83; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.h b/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.h deleted file mode 100644 index 7d03a70b7..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeCarbUnits.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeCarbUnits : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.m b/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.m deleted file mode 100644 index 68d8ec150..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeCarbUnits.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeCarbUnits.m -// - -#import "PHEChangeCarbUnits.h" - -@implementation PHEChangeCarbUnits - -+ (int) eventTypeCode { - return 0x6f; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.h deleted file mode 100644 index 2eeba42b1..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeChildBlockEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeChildBlockEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.m deleted file mode 100644 index eb1e04a2f..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeChildBlockEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeChildBlockEnable.m -// - -#import "PHEChangeChildBlockEnable.h" - -@implementation PHEChangeChildBlockEnable - -+ (int) eventTypeCode { - return 0x23; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.h b/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.h deleted file mode 100644 index 8a89c143c..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeMaxBolus.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeMaxBolus : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.m b/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.m deleted file mode 100644 index 9349035f0..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeMaxBolus.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeMaxBolus.m -// - -#import "PHEChangeMaxBolus.h" - -@implementation PHEChangeMaxBolus - -+ (int) eventTypeCode { - return 0x24; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.h b/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.h deleted file mode 100644 index a015db9bc..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// PHEChangeOtherDeviceID.h -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PumpHistoryEventBase.h" - -@interface PHEChangeOtherDeviceID : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.m b/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.m deleted file mode 100644 index f5a985cd0..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeOtherDeviceID.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEChangeOtherDeviceID.m -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PHEChangeOtherDeviceID.h" - -@implementation PHEChangeOtherDeviceID - -+ (int) eventTypeCode { - return 0x7d; -} - -- (int) length { - return 37; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.h b/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.h deleted file mode 100644 index d02f1c276..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeParadigmLinkID.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeParadigmLinkID : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.m b/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.m deleted file mode 100644 index e8fd5958b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeParadigmLinkID.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeParadigmLinkID.m -// - -#import "PHEChangeParadigmLinkID.h" - -@implementation PHEChangeParadigmLinkID - -+ (int) eventTypeCode { - return 0x3c; -} - - -- (int) length { - return 21; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.h b/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.h deleted file mode 100644 index 3200825ed..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeReservoirWarningTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeReservoirWarningTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.m b/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.m deleted file mode 100644 index aff023344..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeReservoirWarningTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeReservoirWarningTime.m -// - -#import "PHEChangeReservoirWarningTime.h" - -@implementation PHEChangeReservoirWarningTime - -+ (int) eventTypeCode { - return 0x65; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.h b/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.h deleted file mode 100644 index e507f09c4..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeSensorRateOfChangeAlertSetup.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeSensorRateOfChangeAlertSetup : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.m b/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.m deleted file mode 100644 index a3c6dedfa..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeSensorRateOfChangeAlertSetup.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeSensorRateOfChangeAlertSetup.m -// - -#import "PHEChangeSensorRateOfChangeAlertSetup.h" - -@implementation PHEChangeSensorRateOfChangeAlertSetup - -+ (int) eventTypeCode { - return 0x56; -} - - -- (int) length { - return 12; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.h b/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.h deleted file mode 100644 index 4aee6ad32..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeSensorSetup2.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeSensorSetup2 : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.m b/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.m deleted file mode 100644 index b05e03ff1..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeSensorSetup2.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEChangeSensorSetup2.m -// - -#import "PHEChangeSensorSetup2.h" - -@implementation PHEChangeSensorSetup2 - -+ (int) eventTypeCode { - return 0x50; -} - - -- (int) length { - if (self.pumpModel.hasLowSuspend) { - return 41; - } else { - return 37; - } -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.h b/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.h deleted file mode 100644 index f6ab53c13..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeTempBasalPercent.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeTempBasalPercent : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.m b/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.m deleted file mode 100644 index 01476dc20..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTempBasalPercent.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeTempBasalPercent.m -// - -#import "PHEChangeTempBasalPercent.h" - -@implementation PHEChangeTempBasalPercent - -+ (int) eventTypeCode { - return 0x33; -} - - -- (int) length { - return 15; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTime.h b/RileyLink/PumpHistoryEvents/PHEChangeTime.h deleted file mode 100644 index e7115d177..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTime.m b/RileyLink/PumpHistoryEvents/PHEChangeTime.m deleted file mode 100644 index 8975bbbb5..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeTime.m -// - -#import "PHEChangeTime.h" - -@implementation PHEChangeTime - -+ (int) eventTypeCode { - return 0x17; -} - - -- (int) length { - return 14; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.h b/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.h deleted file mode 100644 index 1737e36b9..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeTimeFormat.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeTimeFormat : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.m b/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.m deleted file mode 100644 index baa77a97a..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeTimeFormat.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeTimeFormat.m -// - -#import "PHEChangeTimeFormat.h" - -@implementation PHEChangeTimeFormat - -+ (int) eventTypeCode { - return 0x64; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.h b/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.h deleted file mode 100644 index c4654fb76..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeVariableBolus.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeVariableBolus : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.m b/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.m deleted file mode 100644 index a008b2042..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeVariableBolus.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeVariableBolus.m -// - -#import "PHEChangeVariableBolus.h" - -@implementation PHEChangeVariableBolus - -+ (int) eventTypeCode { - return 0x5e; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.h b/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.h deleted file mode 100644 index 81c79bede..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEChangeWatchdogEnable.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEChangeWatchdogEnable : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.m b/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.m deleted file mode 100644 index e5c98cf53..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogEnable.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEChangeWatchdogEnable.m -// - -#import "PHEChangeWatchdogEnable.h" - -@implementation PHEChangeWatchdogEnable - -+ (int) eventTypeCode { - return 0x7c; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.h b/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.h deleted file mode 100644 index f688afddd..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// PHEChangeWatchdogMarriageProfile.h -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PumpHistoryEventBase.h" - -@interface PHEChangeWatchdogMarriageProfile : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.m b/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.m deleted file mode 100644 index b898a455a..000000000 --- a/RileyLink/PumpHistoryEvents/PHEChangeWatchdogMarriageProfile.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// PHEChangeWatchdogMarriageProfile.m -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PHEChangeWatchdogMarriageProfile.h" - -@implementation PHEChangeWatchdogMarriageProfile - -+ (int) eventTypeCode { - return 0x81; -} - -- (int) length { - return 12; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEClearAlarm.h b/RileyLink/PumpHistoryEvents/PHEClearAlarm.h deleted file mode 100644 index 787fbba32..000000000 --- a/RileyLink/PumpHistoryEvents/PHEClearAlarm.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEClearAlarm.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEClearAlarm : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEClearAlarm.m b/RileyLink/PumpHistoryEvents/PHEClearAlarm.m deleted file mode 100644 index fbd9c2115..000000000 --- a/RileyLink/PumpHistoryEvents/PHEClearAlarm.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEClearAlarm.m -// - -#import "PHEClearAlarm.h" - -@implementation PHEClearAlarm - -+ (int) eventTypeCode { - return 0x0c; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.h b/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.h deleted file mode 100644 index abfc1c4a5..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEDeleteAlarmClockTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEDeleteAlarmClockTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.m b/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.m deleted file mode 100644 index ef8110711..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteAlarmClockTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEDeleteAlarmClockTime.m -// - -#import "PHEDeleteAlarmClockTime.h" - -@implementation PHEDeleteAlarmClockTime - -+ (int) eventTypeCode { - return 0x6a; -} - - -- (int) length { - return 14; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.h b/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.h deleted file mode 100644 index 4a77a07da..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEDeleteBolusReminderTime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEDeleteBolusReminderTime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.m b/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.m deleted file mode 100644 index a4df01255..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteBolusReminderTime.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEDeleteBolusReminderTime.m -// - -#import "PHEDeleteBolusReminderTime.h" - -@implementation PHEDeleteBolusReminderTime - -+ (int) eventTypeCode { - return 0x68; -} - - -- (int) length { - return 9; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.h b/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.h deleted file mode 100644 index 0e167fd68..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// PHEDeleteOtherDeviceID.h -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PumpHistoryEventBase.h" - -@interface PHEDeleteOtherDeviceID : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.m b/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.m deleted file mode 100644 index 42b30045b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEDeleteOtherDeviceID.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEDeleteOtherDeviceID.m -// RileyLink -// -// Created by Pete Schwamb on 1/3/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PHEDeleteOtherDeviceID.h" - -@implementation PHEDeleteOtherDeviceID - -+ (int) eventTypeCode { - return 0x82; -} - -- (int) length { - return 12; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.h b/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.h deleted file mode 100644 index d5b38f8fb..000000000 --- a/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEEnableDisableRemote.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEEnableDisableRemote : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.m b/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.m deleted file mode 100644 index 4321f4466..000000000 --- a/RileyLink/PumpHistoryEvents/PHEEnableDisableRemote.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEEnableDisableRemote.m -// - -#import "PHEEnableDisableRemote.h" - -@implementation PHEEnableDisableRemote - -+ (int) eventTypeCode { - return 0x26; -} - - -- (int) length { - return 21; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.h b/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.h deleted file mode 100644 index fa12d1298..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEJournalEntryExerciseMarker.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEJournalEntryExerciseMarker : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.m b/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.m deleted file mode 100644 index dbfa015a2..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryExerciseMarker.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEJournalEntryExerciseMarker.m -// - -#import "PHEJournalEntryExerciseMarker.h" - -@implementation PHEJournalEntryExerciseMarker - -+ (int) eventTypeCode { - return 0x41; -} - - -- (int) length { - return 8; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.h b/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.h deleted file mode 100644 index 2ad9641bd..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEJournalEntryPumpLowBattery.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEJournalEntryPumpLowBattery : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.m b/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.m deleted file mode 100644 index bff6915fc..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowBattery.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEJournalEntryPumpLowBattery.m -// - -#import "PHEJournalEntryPumpLowBattery.h" - -@implementation PHEJournalEntryPumpLowBattery - -+ (int) eventTypeCode { - return 0x19; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.h b/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.h deleted file mode 100644 index c864ffddf..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEJournalEntryPumpLowReservoir.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEJournalEntryPumpLowReservoir : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.m b/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.m deleted file mode 100644 index c969e2505..000000000 --- a/RileyLink/PumpHistoryEvents/PHEJournalEntryPumpLowReservoir.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEJournalEntryPumpLowReservoir.m -// - -#import "PHEJournalEntryPumpLowReservoir.h" - -@implementation PHEJournalEntryPumpLowReservoir - -+ (int) eventTypeCode { - return 0x34; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.h b/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.h deleted file mode 100644 index c0bc8c869..000000000 --- a/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEModel522ResultTotals.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEModel522ResultTotals : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.m b/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.m deleted file mode 100644 index e01facb81..000000000 --- a/RileyLink/PumpHistoryEvents/PHEModel522ResultTotals.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEModel522ResultTotals.m -// - -#import "PHEModel522ResultTotals.h" - -@implementation PHEModel522ResultTotals - -+ (int) eventTypeCode { - return 0x6d; -} - - -- (int) length { - return 44; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEPrime.h b/RileyLink/PumpHistoryEvents/PHEPrime.h deleted file mode 100644 index bd45ca76f..000000000 --- a/RileyLink/PumpHistoryEvents/PHEPrime.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEPrime.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEPrime : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEPrime.m b/RileyLink/PumpHistoryEvents/PHEPrime.m deleted file mode 100644 index e192250da..000000000 --- a/RileyLink/PumpHistoryEvents/PHEPrime.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEPrime.m -// - -#import "PHEPrime.h" - -@implementation PHEPrime - -+ (int) eventTypeCode { - return 0x03; -} - - -- (int) length { - return 10; -} - -- (nullable NSDateComponents*) timestamp { - return [self parseDateComponents:5]; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.h b/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.h deleted file mode 100644 index 9c50acce6..000000000 --- a/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEResultDailyTotal.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEResultDailyTotal : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.m b/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.m deleted file mode 100644 index 6079e7369..000000000 --- a/RileyLink/PumpHistoryEvents/PHEResultDailyTotal.m +++ /dev/null @@ -1,44 +0,0 @@ -// -// PHEResultDailyTotal.m -// - -#import "PHEResultDailyTotal.h" - -@implementation PHEResultDailyTotal - -+ (int) eventTypeCode { - return 0x07; -} - - -- (int) length { - if (self.pumpModel.larger) { - return 10; - } else { - return 7; - } -} - -//- (NSDateComponents*) validDate { -// [self parseDate2Byte:5]; -//} - -- (NSDateComponents*) timestamp { - NSDateComponents *c = [self parseDate2Byte:5]; - - NSCalendar *cal = [NSCalendar currentCalendar]; - [cal setTimeZone:[NSTimeZone localTimeZone]]; - [cal setLocale:[NSLocale currentLocale]]; - NSDate *date = [cal dateFromComponents:c]; - - NSDateComponents *dayComponent = [[NSDateComponents alloc] init]; - dayComponent.day = 1; - - NSDate *nextDate = [cal dateByAddingComponents:dayComponent toDate:date options:0]; - - unsigned flags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; - return [cal components:flags fromDate:nextDate]; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEResume.h b/RileyLink/PumpHistoryEvents/PHEResume.h deleted file mode 100644 index 265750ce6..000000000 --- a/RileyLink/PumpHistoryEvents/PHEResume.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEResume.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEResume : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEResume.m b/RileyLink/PumpHistoryEvents/PHEResume.m deleted file mode 100644 index 55c5ab46b..000000000 --- a/RileyLink/PumpHistoryEvents/PHEResume.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHEResume.m -// - -#import "PHEResume.h" - -@implementation PHEResume - -+ (int) eventTypeCode { - return 0x1f; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHERewind.h b/RileyLink/PumpHistoryEvents/PHERewind.h deleted file mode 100644 index 01d1bb7b2..000000000 --- a/RileyLink/PumpHistoryEvents/PHERewind.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHERewind.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHERewind : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHERewind.m b/RileyLink/PumpHistoryEvents/PHERewind.m deleted file mode 100644 index 8e1194d42..000000000 --- a/RileyLink/PumpHistoryEvents/PHERewind.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHERewind.m -// - -#import "PHERewind.h" - -@implementation PHERewind - -+ (int) eventTypeCode { - return 0x21; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHESara6E.h b/RileyLink/PumpHistoryEvents/PHESara6E.h deleted file mode 100644 index 30757a6aa..000000000 --- a/RileyLink/PumpHistoryEvents/PHESara6E.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHESara6E.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHESara6E : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHESara6E.m b/RileyLink/PumpHistoryEvents/PHESara6E.m deleted file mode 100644 index 4a1e53a02..000000000 --- a/RileyLink/PumpHistoryEvents/PHESara6E.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHESara6E.m -// - -#import "PHESara6E.h" - -@implementation PHESara6E - -+ (int) eventTypeCode { - return 0x6e; -} - - -- (int) length { - return 52; -} - -- (NSDateComponents*) timestamp { - return [self parseDate2Byte:1]; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHESuspend.h b/RileyLink/PumpHistoryEvents/PHESuspend.h deleted file mode 100644 index 937bf8b7c..000000000 --- a/RileyLink/PumpHistoryEvents/PHESuspend.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHESuspend.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHESuspend : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHESuspend.m b/RileyLink/PumpHistoryEvents/PHESuspend.m deleted file mode 100644 index 2c9e58d63..000000000 --- a/RileyLink/PumpHistoryEvents/PHESuspend.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// PHESuspend.m -// - -#import "PHESuspend.h" - -@implementation PHESuspend - -+ (int) eventTypeCode { - return 0x1e; -} - - -- (int) length { - return 7; -} - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.h b/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.h deleted file mode 100644 index 454ace34e..000000000 --- a/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// PHEUnabsorbedInsulin.h -// - -#import -#import "PumpHistoryEventBase.h" - -@interface PHEUnabsorbedInsulin : PumpHistoryEventBase - -@end diff --git a/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.m b/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.m deleted file mode 100644 index c13d5dc8d..000000000 --- a/RileyLink/PumpHistoryEvents/PHEUnabsorbedInsulin.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// PHEUnabsorbedInsulin.m -// - -#import "PHEUnabsorbedInsulin.h" - -@implementation PHEUnabsorbedInsulin - -+ (int) eventTypeCode { - return 0x5c; -} - -- (int) length { - return MAX([self byteAt:1], 2); -} - -- (nullable NSDateComponents*) timestamp { - return nil; -} - - -@end diff --git a/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.h b/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.h deleted file mode 100644 index a26b0afca..000000000 --- a/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// PumpHistoryEventBase.h -// RileyLink -// -// Created by Pete Schwamb on 11/18/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "PumpModel.h" - -@interface PumpHistoryEventBase : NSObject - -@property (nonatomic, nonnull, readonly, strong) NSData *data; -@property (nonatomic, nullable, readonly, strong) PumpModel *pumpModel; - -- (nonnull instancetype)initWithData:(nonnull NSData *)data andPumpModel:(nullable PumpModel *)model; - -+ (int) eventTypeCode; - -- (int) length; -- (uint8_t)byteAt:(NSInteger)index; -- (nonnull NSDateComponents*) parseDateComponents:(NSInteger)offset; -- (nonnull NSDateComponents*) parseDate2Byte:(NSInteger)offset; -- (nullable NSDateComponents*) timestamp; -- (nonnull NSString*) timestampStr; -- (nonnull NSDictionary*) asJSON; -- (nonnull NSString*) typeName; - -@end diff --git a/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.m b/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.m deleted file mode 100644 index 7cfef7997..000000000 --- a/RileyLink/PumpHistoryEvents/PumpHistoryEventBase.m +++ /dev/null @@ -1,115 +0,0 @@ -// -// PumpHistoryEventBase.m -// RileyLink -// -// Created by Pete Schwamb on 11/18/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "PumpHistoryEventBase.h" -#import "NSData+Conversion.h" -#import "ISO8601DateFormatter.h" - -@interface PumpHistoryEventBase () - -@property (strong, nonatomic) ISO8601DateFormatter *dateFormatter; - -@end - -@implementation PumpHistoryEventBase - -- (instancetype)initWithData:(NSData*)data andPumpModel:(PumpModel*)model -{ - self = [super init]; - if (self) { - _dateFormatter = [[ISO8601DateFormatter alloc] init]; - _dateFormatter.includeTime = YES; - _dateFormatter.useMillisecondPrecision = NO; - _dateFormatter.timeZoneSeparator = ':'; - _dateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; - - _data = data; - _pumpModel = model; - if (_data.length > self.length) { - _data = [_data subdataWithRange:NSMakeRange(0, [self length])]; - } - } - return self; -} - -- (int) length { - [NSException raise:@"Invalid Message" format:@"PumpHistoryEventBase does not implement length."]; - return 0; -} - -+ (int) eventTypeCode { - [NSException raise:@"Invalid Message" format:@"PumpHistoryEventBase does not implement eventTypeCode."]; - return 0; -} - -- (uint8_t)byteAt:(NSInteger)index { - if (_data && index < [_data length]) { - return ((uint8_t*)[_data bytes])[index]; - } else { - return 0; - } -} - -- (NSDateComponents*) parseDateComponents:(NSInteger)offset { - NSDateComponents *comps = [[NSDateComponents alloc] init]; - [comps setSecond:[self byteAt:offset] & 0x3f]; - [comps setMinute:[self byteAt:offset+1] & 0x3f]; - [comps setHour:[self byteAt:offset+2] & 0x1f]; - [comps setDay:[self byteAt:offset+3] & 0x1f]; - [comps setMonth:([self byteAt:offset] >>4 & 0xc) + ([self byteAt:offset+1] >> 6)]; - [comps setYear:2000 + ([self byteAt:offset+4] & 0b1111111)]; - return comps; -} - -- (NSDateComponents*) parseDate2Byte:(NSInteger)offset { - NSDateComponents *comps = [[NSDateComponents alloc] init]; - [comps setDay:[self byteAt:offset] & 0x1f]; - [comps setMonth:(([self byteAt:offset] & 0xe0) >> 4) + (([self byteAt:offset+1] & 0x80) >> 7)]; - [comps setYear:2000 + ([self byteAt:offset+1] & 0b1111111)]; - return comps; -} - -- (nullable NSDateComponents*) timestamp { - return [self parseDateComponents:2]; -} - -- (NSString*) timestampStr { - NSCalendar *cal = [NSCalendar currentCalendar]; - [cal setTimeZone:[NSTimeZone localTimeZone]]; - [cal setLocale:[NSLocale currentLocale]]; - NSDateComponents *c = [self timestamp]; - if (c == nil) { - return @""; - } - NSDate *date = [cal dateFromComponents:c]; - - return [self.dateFormatter stringFromDate:date timeZone:cal.timeZone]; -} - -- (NSString*) description { - return [NSString stringWithFormat:@"%@ - %@", self.typeName, self.timestampStr]; -} - -- (NSString*) typeName { - NSString *fullName = NSStringFromClass(self.class); - if ([fullName hasPrefix:@"PHE"]) { - return [fullName substringFromIndex:3]; - } - return fullName; -} - -- (NSDictionary*) asJSON { - return @{ - @"_type": [self typeName], - @"_raw": [self.data hexadecimalString], - @"timestamp": self.timestampStr, - @"description": self.description - }; -} - -@end diff --git a/RileyLink/PumpModel.h b/RileyLink/PumpModel.h deleted file mode 100644 index c821c3e64..000000000 --- a/RileyLink/PumpModel.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// PumpModels.h -// RileyLink -// -// Created by Pete Schwamb on 11/19/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import - -@interface PumpModel : NSObject - -@property (nonatomic, readonly) BOOL larger; -@property (nonatomic, readonly) BOOL hasLowSuspend; -@property (nonatomic, readonly) NSInteger strokesPerUnit; -@property (nonatomic, readonly, strong) NSString *name; - -+ (PumpModel*) find:(NSString*)number; - - - -@end diff --git a/RileyLink/PumpModel.m b/RileyLink/PumpModel.m deleted file mode 100644 index 10cb1b7a3..000000000 --- a/RileyLink/PumpModel.m +++ /dev/null @@ -1,87 +0,0 @@ -// -// PumpModels.m -// RileyLink -// -// Created by Pete Schwamb on 11/19/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "PumpModel.h" - -@interface PumpModel () { - NSDictionary *settings; -} - -@end - - -@implementation PumpModel - - -+ (PumpModel*) find:(NSString*)number { - NSDictionary *base = @{ - @"larger": @NO, - @"hasLowSuspend": @NO, - @"strokePerUnit": @10 - }; - - NSDictionary *m523 = @{ - @"larger": @YES, - @"hasLowSuspend": @NO, - @"strokePerUnit": @40 - }; - - NSDictionary *m551 = @{ - @"larger": @YES, - @"hasLowSuspend": @YES, - @"strokePerUnit": @40 - }; - - - - NSDictionary *settings = @{ - @"508": base, - @"511": base, - @"512": base, - @"515": base, - @"522": base, - @"722": base, - @"523": m523, - @"723": m523, - @"530": m523, - @"730": m523, - @"540": m523, - @"740": m523, - @"551": m551, - @"554": m551, - @"751": m551, - @"754": m551 - }[number]; - - return [[PumpModel alloc] initWithSettings:settings andName:number]; -} - -- (instancetype)initWithSettings:(NSDictionary*)newSettings andName:(NSString*)name -{ - self = [super init]; - if (self) { - settings = newSettings; - _name = name; - } - return self; -} - - -- (BOOL) larger { - return [settings[@"larger"] boolValue]; -} - -- (BOOL) hasLowSuspend { - return [settings[@"hasLowSuspend"] boolValue]; -} - -- (NSInteger) strokesPerUnit { - return [settings[@"strokesPerUnit"] integerValue]; -} - -@end diff --git a/RileyLink/PumpOps.h b/RileyLink/PumpOps.h deleted file mode 100644 index 4d2224eb0..000000000 --- a/RileyLink/PumpOps.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// PumpOps.h -// RileyLink -// -// Created by Pete Schwamb on 1/29/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import -#import "PumpState.h" -#import "RileyLinkBLEDevice.h" - -@interface PumpOps : NSObject - -- (nonnull instancetype)initWithPumpState:(nonnull PumpState *)pump andDevice:(nonnull RileyLinkBLEDevice *)device NS_DESIGNATED_INITIALIZER; - -- (void) pressButton; -- (void) getPumpModel:(void (^ _Nullable)(NSString* _Nonnull))completionHandler; -- (void) getBatteryVoltage:(void (^ _Nullable)(NSString * _Nonnull, float))completionHandler; -- (void) getHistoryPage:(NSInteger)page withHandler:(void (^ _Nullable)(NSDictionary * _Nonnull))completionHandler; -- (void) tunePump:(void (^ _Nullable)(NSDictionary * _Nonnull))completionHandler; - -@property (readonly, strong, nonatomic, nonnull) PumpState *pump; -@property (readonly, strong, nonatomic, nonnull) RileyLinkBLEDevice *device; - -@end diff --git a/RileyLink/PumpOps.m b/RileyLink/PumpOps.m deleted file mode 100644 index 219b6f8c3..000000000 --- a/RileyLink/PumpOps.m +++ /dev/null @@ -1,91 +0,0 @@ -// -// PumpOps.m -// RileyLink -// -// Created by Pete Schwamb on 1/29/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PumpOps.h" -#import "PumpOpsSynchronous.h" - -@interface PumpOps () - -@property (nonatomic) UIBackgroundTaskIdentifier historyTask; - -@end - -@implementation PumpOps - -- (nonnull instancetype)initWithPumpState:(nonnull PumpState *)a_pump andDevice:(nonnull RileyLinkBLEDevice *)a_device { - self = [super init]; - if (self) { - _pump = a_pump; - _device = a_device; - } - return self; -} - - -- (instancetype)init NS_UNAVAILABLE -{ - return nil; -} - -- (void) pressButton { - [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { - PumpOpsSynchronous *ops = [[PumpOpsSynchronous alloc] initWithPump:_pump andSession:session]; - [ops pressButton]; - }]; -} - -- (void) getPumpModel:(void (^ _Nullable)(NSString* _Nonnull))completionHandler { - [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { - PumpOpsSynchronous *ops = [[PumpOpsSynchronous alloc] initWithPump:_pump andSession:session]; - NSString *model = [ops getPumpModel]; - dispatch_async(dispatch_get_main_queue(),^{ - completionHandler(model); - }); - }]; -} - -- (void) getBatteryVoltage:(void (^ _Nullable)(NSString * _Nonnull, float))completionHandler { - [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { - PumpOpsSynchronous *ops = [[PumpOpsSynchronous alloc] initWithPump:_pump andSession:session]; - NSDictionary *results = [ops getBatteryVoltage]; - dispatch_async(dispatch_get_main_queue(),^{ - completionHandler(results[@"status"], [results[@"value"] floatValue]); - }); - }]; -} - -- (void) getHistoryPage:(NSInteger)page withHandler:(void (^ _Nullable)(NSDictionary * _Nonnull))completionHandler { - self.historyTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ - NSLog(@"History fetching task expired.") - [[UIApplication sharedApplication] endBackgroundTask:self.historyTask]; - } ]; - NSLog(@"History fetching task started."); - [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { - PumpOpsSynchronous *ops = [[PumpOpsSynchronous alloc] initWithPump:_pump andSession:session]; - NSDictionary *res = [ops getHistoryPage:0]; - dispatch_async(dispatch_get_main_queue(),^{ - completionHandler(res); - [[UIApplication sharedApplication] endBackgroundTask:self.historyTask]; - NSLog(@"History fetching task completed normally.") - }); - }]; - - -} - -- (void) tunePump:(void (^ _Nullable)(NSDictionary * _Nonnull))completionHandler { - [_device runSession:^(RileyLinkCmdSession * _Nonnull session) { - PumpOpsSynchronous *ops = [[PumpOpsSynchronous alloc] initWithPump:_pump andSession:session]; - NSDictionary *res = [ops scanForPump]; - dispatch_async(dispatch_get_main_queue(),^{ - completionHandler(res); - }); - }]; -} - -@end diff --git a/RileyLink/PumpOpsSynchronous.h b/RileyLink/PumpOpsSynchronous.h deleted file mode 100644 index 6ef10235c..000000000 --- a/RileyLink/PumpOpsSynchronous.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// PumpOpsSynchronous.h -// RileyLink -// -// Created by Pete Schwamb on 1/29/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import -#import "PumpState.h" - -@interface PumpOpsSynchronous : NSObject - -- (nonnull instancetype)initWithPump:(nonnull PumpState *)pump andSession:(nonnull RileyLinkCmdSession *)session NS_DESIGNATED_INITIALIZER; - -@property (readonly, strong, nonatomic, nonnull) PumpState *pump; -@property (readonly, strong, nonatomic, nonnull) RileyLinkCmdSession *session; - -- (BOOL) wakeup:(uint8_t)duration; -- (void) pressButton; -- (NSString* _Nullable) getPumpModel; -- (NSDictionary* _Nonnull) getBatteryVoltage; -- (NSDictionary* _Nonnull) getHistoryPage:(uint8_t)pageNum; -- (NSDictionary* _Nonnull) scanForPump; - -@end diff --git a/RileyLink/PumpOpsSynchronous.m b/RileyLink/PumpOpsSynchronous.m deleted file mode 100644 index 319df6eb3..000000000 --- a/RileyLink/PumpOpsSynchronous.m +++ /dev/null @@ -1,382 +0,0 @@ -// -// PumpOpsSynchronous.m -// RileyLink -// -// Created by Pete Schwamb on 1/29/16. -// Copyright © 2016 Pete Schwamb. All rights reserved. -// - -#import "PumpOpsSynchronous.h" -#import "NSData+Conversion.h" -#import "SendPacketCmd.h" -#import "SendAndListenCmd.h" -#import "MinimedPacket.h" -#import "MessageBase.h" -#import "UpdateRegisterCmd.h" - -#define STANDARD_PUMP_RESPONSE_WINDOW 180 -#define EXPECTED_MAX_BLE_LATENCY_MS 1500 - - -@implementation PumpOpsSynchronous - -- (nonnull instancetype)initWithPump:(nonnull PumpState *)a_pump andSession:(nonnull RileyLinkCmdSession *)a_session { - - self = [super init]; - if (self) { - _session = a_session; - _pump = a_pump; - } - return self; - -} - -- (instancetype)init NS_UNAVAILABLE -{ - return nil; -} - -- (MessageBase *)msgType:(unsigned char)t withArgs:(NSString *)args { - NSString *packetStr = [NSString stringWithFormat:@"%02x%@%02x%@", PacketTypeCarelink, _pump.pumpId, t, args]; - NSData *data = [NSData dataWithHexadecimalString:packetStr]; - - return [[MessageBase alloc] initWithData:data]; -} - -- (MessageBase *)powerMessage -{ - return [self powerMessageWithArgs:@"00"]; -} - -- (MessageBase *)powerMessageWithArgs:(NSString *)args -{ - return [self msgType:MESSAGE_TYPE_POWER withArgs:args]; -} - -- (MessageBase *)buttonPressMessage -{ - return [self buttonPressMessageWithArgs:@"00"]; -} - -- (MessageBase *)buttonPressMessageWithArgs:(NSString *)args -{ - return [self msgType:MESSAGE_TYPE_BUTTON_PRESS withArgs:args]; -} - -- (MessageBase *)batteryStatusMessage -{ - NSString *packetStr = [NSString stringWithFormat:@"%02x%@%02x00", PacketTypeCarelink, _pump.pumpId, MESSAGE_TYPE_GET_BATTERY]; - NSData *data = [NSData dataWithHexadecimalString:packetStr]; - - return [[MessageBase alloc] initWithData:data]; -} - - -- (MinimedPacket*) sendAndListen:(NSData*)msg - timeoutMS:(uint16_t)timeoutMS - repeat:(uint8_t)repeat - msBetweenPackets:(uint8_t)msBetweenPackets - retryCount:(uint8_t)retryCount { - SendAndListenCmd *cmd = [[SendAndListenCmd alloc] init]; - cmd.packet = [MinimedPacket encodeData:msg]; - cmd.timeoutMS = timeoutMS; - cmd.repeatCount = repeat; - cmd.msBetweenPackets = msBetweenPackets; - cmd.retryCount = retryCount; - cmd.listenChannel = 0; - MinimedPacket *rxPacket = nil; - NSInteger totalTimeout = repeat * msBetweenPackets + timeoutMS + EXPECTED_MAX_BLE_LATENCY_MS; - NSData *response = [_session doCmd:cmd withTimeoutMs:totalTimeout]; - if (response && response.length > 2) { - rxPacket = [[MinimedPacket alloc] initWithData:response]; - } - return rxPacket; -} - -- (MinimedPacket*) sendAndListen:(NSData*)msg { - return [self sendAndListen:msg - timeoutMS:STANDARD_PUMP_RESPONSE_WINDOW - repeat:0 - msBetweenPackets:0 - retryCount:3]; -} - -- (BOOL) wakeIfNeeded { - return [self wakeup:1]; -} - -- (void) pressButton { - - if ([self wakeIfNeeded]) { - - MinimedPacket *response = [self sendAndListen:[[self buttonPressMessage] data]]; - - if (response && response.messageType == MESSAGE_TYPE_ACK) { - NSLog(@"Pump acknowledged button press (no args)!"); - } else { - NSLog(@"Pump did not acknowledge button press (no args)"); - return; - } - - NSString *args = @"0104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; - - response = [self sendAndListen:[[self buttonPressMessageWithArgs:args] data]]; - - if (response && response.messageType == MESSAGE_TYPE_ACK) { - NSLog(@"Pump acknowledged button press (with args)!"); - } else { - NSLog(@"Pump did not acknowledge button press (with args)"); - return; - } - - } -} - -- (MessageBase *)modelQueryMessage -{ - NSString *packetStr = [NSString stringWithFormat:@"%02x%@%02x00", PacketTypeCarelink, _pump.pumpId, MESSAGE_TYPE_GET_PUMP_MODEL]; - NSData *data = [NSData dataWithHexadecimalString:packetStr]; - - return [[MessageBase alloc] initWithData:data]; -} - -- (NSString*) getPumpModel { - if ([self wakeIfNeeded]) { - MinimedPacket *response = [self sendAndListen:[[self modelQueryMessage] data]]; - - NSLog(@"*********** getPumpModel: %@", [response hexadecimalString]); - - if (response && response.messageType == MESSAGE_TYPE_GET_PUMP_MODEL) { - return [NSString stringWithCString:&[response.data bytes][7] - encoding:NSASCIIStringEncoding]; - } - } - return nil; -} - -- (NSDictionary*) getBatteryVoltage { - - NSString *rvalStatus = @"Unknown"; - float rvalValue = 0.0; - - if ([self wakeIfNeeded]) { - - MinimedPacket *response = [self sendAndListen:[[self batteryStatusMessage] data]]; - - if (response && response.valid && response.messageType == MESSAGE_TYPE_GET_BATTERY) { - unsigned char *data = (unsigned char *)[response.data bytes] + 6; - - NSInteger volts = (((int)data[1]) << 8) + data[2]; - rvalStatus = data[0] ? @"Low" : @"Normal"; - rvalValue = volts/100.0; - } - } - - return @{@"status": rvalStatus, @"value": @(rvalValue)}; -} - -- (NSData*)parseFramesIntoHistoryPage:(NSArray*)packets { - NSMutableData *data = [NSMutableData data]; - - NSRange r = NSMakeRange(6, 64); - for (NSData *frame in packets) { - if (frame.length < 70) { - NSLog(@"Bad frame length in history: %@", [frame hexadecimalString]); - return nil; - } - [data appendData:[frame subdataWithRange:r]]; - } - return data; -} - - -- (NSDictionary*) scanForPump { - - - NSMutableArray *scanResults = [NSMutableArray array]; - NSMutableArray *rssi = [NSMutableArray array]; - NSArray *frequencies = @[@916.55, @916.60, @916.65, @916.70, @916.75, @916.80]; - - [self wakeIfNeeded]; - NSInteger totalSuccesses = 0; - - for (NSNumber *freq in frequencies) { - [self setBaseFrequency:[freq floatValue]]; - NSInteger successCount = 0; - int avgRSSI = 0; - int tries = 3; - for (int i=0; i bestResult) { - bestResult = [result intValue]; - bestIndex = i; - } - } - NSMutableDictionary *rval = [NSMutableDictionary dictionary]; - rval[@"frequencies"] = frequencies; - rval[@"scanResults"] = scanResults; - rval[@"avgRSSI"] = rssi; - - if (totalSuccesses > 0) { - rval[@"bestFreq"] = frequencies[bestIndex]; - NSLog(@"Scanning found best results at %@MHz (RSSI: %@)", frequencies[bestIndex], rssi[bestIndex]); - } else { - rval[@"error"] = @"Pump did not respond on any of the attempted frequencies."; - } - [self setBaseFrequency:[frequencies[bestIndex] floatValue]]; - - NSLog(@"Frequency scan results: %@", rval); - - return rval; -} - -- (BOOL) wakeup:(uint8_t) durationMinutes { - - if ([_pump isAwake]) { - return YES; - } - - MinimedPacket *response = [self sendAndListen:[[self powerMessage] data] - timeoutMS:15000 - repeat:200 - msBetweenPackets:0 - retryCount:0]; - - if (response && response.messageType == MESSAGE_TYPE_ACK) { - NSLog(@"Pump acknowledged wakeup!"); - } else { - return NO; - } - - NSString *msg = [NSString stringWithFormat:@"0201%02x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", durationMinutes]; - - response = [self sendAndListen:[[self powerMessageWithArgs:msg] data] - timeoutMS:STANDARD_PUMP_RESPONSE_WINDOW - repeat:0 - msBetweenPackets:0 - retryCount:3]; - - - if (response && response.messageType == MESSAGE_TYPE_ACK) { - NSLog(@"Power on for %d minutes", durationMinutes); - _pump.awakeUntil = [NSDate dateWithTimeIntervalSinceNow:durationMinutes*60]; - } else { - return NO; - } - return YES; -} - -- (void)updateRegister:(uint8_t)addr toValue:(uint8_t)value { - UpdateRegisterCmd *cmd = [[UpdateRegisterCmd alloc] init]; - cmd.addr = addr; - cmd.value = value; - [_session doCmd:cmd withTimeoutMs:EXPECTED_MAX_BLE_LATENCY_MS]; -} - -- (void)setBaseFrequency:(float)freqMhz { - uint32_t val = (freqMhz * 1000000)/(RILEYLINK_FREQ_XTAL/pow(2.0,16.0)); - - [self updateRegister:CC111X_REG_FREQ0 toValue:val & 0xff]; - [self updateRegister:CC111X_REG_FREQ1 toValue:(val >> 8) & 0xff]; - [self updateRegister:CC111X_REG_FREQ2 toValue:(val >> 16) & 0xff]; - NSLog(@"Set frequency to %f", freqMhz); -} - -- (NSDictionary*) getHistoryPage:(uint8_t)pageNum { - float rssiSum = 0; - int rssiCount = 0; - - NSMutableDictionary *responseDict = [NSMutableDictionary dictionary]; - NSMutableArray *responses = [NSMutableArray array]; - - [self wakeIfNeeded]; - - NSString *pumpModel = [self getPumpModel]; - - if (!pumpModel) { - NSDictionary *tuneResults = [self scanForPump]; - if (tuneResults[@"error"]) { - responseDict[@"error"] = @"Could not find pump, even after scanning."; - } - // Try again to get pump model, after scanning/tuning - pumpModel = [self getPumpModel]; - } - - if (!pumpModel) { - responseDict[@"error"] = @"get model failed"; - return responseDict; - } else { - responseDict[@"pumpModel"] = pumpModel; - } - - MinimedPacket *response; - response = [self sendAndListen:[[self msgType:MESSAGE_TYPE_READ_HISTORY withArgs:@"00"] data]]; - - if (response && response.isValid && response.messageType == MESSAGE_TYPE_ACK) { - rssiSum += response.rssi; - rssiCount += 1; - NSLog(@"Pump acked dump msg (0x80)") - } else { - NSLog(@"Missing response to initial read history command"); - responseDict[@"error"] = @"Missing response to initial read history command"; - return responseDict; - } - - NSString *dumpHistArgs = [NSString stringWithFormat:@"01%02x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", pageNum]; - - response = [self sendAndListen:[[self msgType:MESSAGE_TYPE_READ_HISTORY withArgs:dumpHistArgs] data]]; - - if (response && response.isValid && response.messageType == MESSAGE_TYPE_READ_HISTORY) { - rssiSum += response.rssi; - rssiCount += 1; - [responses addObject:response.data]; - } else { - NSLog(@"Read history with args command failed"); - responseDict[@"error"] = @"Read history with args command failed"; - return responseDict; - } - - // Send 15 acks, and expect 15 more dumps - for (int i=0; i<15; i++) { - - response = [self sendAndListen:[[self msgType:MESSAGE_TYPE_ACK withArgs:@"00"] data]]; - - if (response && response.isValid && response.messageType == MESSAGE_TYPE_READ_HISTORY) { - rssiSum += response.rssi; - rssiCount += 1; - [responses addObject:response.data]; - } else { - NSLog(@"Read history segment %d with args command failed", i); - responseDict[@"error"] = @"Read history with args command failed"; - return responseDict; - } - responseDict[@"pageData"] = [self parseFramesIntoHistoryPage:responses]; - } - - if (rssiCount > 0) { - responseDict[@"avgRSSI"] = @((int)(rssiSum / rssiCount)); - } - - // Last ack packet doesn't need a response - SendPacketCmd *cmd = [[SendPacketCmd alloc] init]; - cmd.packet = [MinimedPacket encodeData:[[self msgType:MESSAGE_TYPE_ACK withArgs:@"00"] data]]; - [_session doCmd:cmd withTimeoutMs:EXPECTED_MAX_BLE_LATENCY_MS]; - return responseDict; -} - -@end diff --git a/RileyLink/PumpState.h b/RileyLink/PumpState.h deleted file mode 100644 index 4b2865dfc..000000000 --- a/RileyLink/PumpState.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// PumpState.h -// RileyLink -// -// Created by Pete Schwamb on 10/6/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import -#import "RileyLinkBLEDevice.h" - -@interface PumpState : NSObject - -- (nonnull instancetype)initWithPumpId:(nonnull NSString *)pumpId NS_DESIGNATED_INITIALIZER; - -- (BOOL) isAwake; - -@property (strong, nonatomic, nonnull) NSString *pumpId; -@property (strong, nonatomic, nonnull) NSDate *lastHistoryDump; -@property (strong, nonatomic, nonnull) NSDate *awakeUntil; - -@end diff --git a/RileyLink/PumpState.m b/RileyLink/PumpState.m deleted file mode 100644 index 838231e72..000000000 --- a/RileyLink/PumpState.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// PumpState.m -// RileyLink -// -// Created by Pete Schwamb on 10/6/15. -// Copyright © 2015 Pete Schwamb. All rights reserved. -// - -#import "PumpState.h" -#import "NSData+Conversion.h" -#import "SendPacketCmd.h" -#import "SendAndListenCmd.h" -#import "RileyLinkBLEDevice.h" -#import "MinimedPacket.h" -#import "MessageBase.h" -#import "UpdateRegisterCmd.h" - -@implementation PumpState - -- (nonnull instancetype)initWithPumpId:(nonnull NSString *)a_pumpId { - self = [super init]; - if (self) { - _pumpId = a_pumpId; - } - return self; -} - -- (instancetype)init NS_UNAVAILABLE -{ - return nil; -} - -- (BOOL) isAwake { - return (_awakeUntil != nil && [_awakeUntil timeIntervalSinceNow] > 0); -} - - -@end diff --git a/RileyLink/PumpStatusMessage.h b/RileyLink/PumpStatusMessage.h deleted file mode 100644 index 477dca4fd..000000000 --- a/RileyLink/PumpStatusMessage.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// GlucoseSensorMessage.h -// GlucoseLink -// -// Created by Pete Schwamb on 8/14/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import -#import "MessageBase.h" - -typedef NS_ENUM(unsigned int, SensorStatus) { - SENSOR_STATUS_MISSING, - SENSOR_STATUS_METER_BG_NOW, - SENSOR_STATUS_WEAK_SIGNAL, - SENSOR_STATUS_WARMUP, - SENSOR_STATUS_LOST, - SENSOR_STATUS_HIGH_BG, - SENSOR_STATUS_OK, - SENSOR_STATUS_UNKNOWN -}; - -typedef NS_ENUM(unsigned int, GlucoseTrend) { - GLUCOSE_TREND_NONE = 0b000, - GLUCOSE_TREND_UP = 0b001, - GLUCOSE_TREND_DOUBLE_UP = 0b010, - GLUCOSE_TREND_DOWN = 0b011, - GLUCOSE_TREND_DOUBLE_DOWN = 0b100, -}; - - -@interface PumpStatusMessage : MessageBase - -@property (nonatomic, readonly) NSInteger glucose; -@property (nonatomic, readonly) NSInteger previousGlucose; -@property (nonatomic, readonly, copy) NSDate *sensorTime; -@property (nonatomic, readonly) GlucoseTrend trend; -@property (nonatomic, readonly) double activeInsulin; -@property (nonatomic, readonly) SensorStatus sensorStatus; -@property (nonatomic, readonly) NSString* sensorStatusString; -@property (nonatomic, readonly) NSInteger sensorAge; -@property (nonatomic, readonly) NSInteger sensorRemaining; -@property (nonatomic, readonly) NSInteger batteryPct; -@property (nonatomic, readonly) double insulinRemaining; -@property (nonatomic, readonly) NSDate* nextCal; -@property (nonatomic, readonly) NSDate* pumpTime; - -@end diff --git a/RileyLink/PumpStatusMessage.m b/RileyLink/PumpStatusMessage.m deleted file mode 100644 index 10fc9b6fa..000000000 --- a/RileyLink/PumpStatusMessage.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// GlucoseSensorMessage.m -// GlucoseLink -// -// Created by Pete Schwamb on 8/14/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import "PumpStatusMessage.h" - - -@interface PumpStatusMessage () - -@end - -@implementation PumpStatusMessage - -- (NSDictionary*) bitBlocks { - return @{@"sequence": @[@1, @7], - @"trend": @[@12, @3], - @"pump_hour": @[@19, @5], - @"pump_minute": @[@26, @6], - @"pump_second": @[@34, @6], - @"pump_year": @[@40, @8], - @"pump_month": @[@52, @4], - @"pump_day": @[@59, @5], - @"bg_h": @[@72, @8], - @"prev_bg_h": @[@80, @8], - @"insulin_remaining": @[@101,@11], - @"batt": @[@116,@4], - @"sensor_age": @[@144,@8], - @"sensor_remaining": @[@152,@8], - @"next_cal_hour": @[@160,@8], // ff at sensor end, 00 at sensor off - @"next_cal_minute": @[@168,@8], - @"active_ins": @[@181, @11], - @"prev_bg_l": @[@198, @1], - @"bg_l": @[@199, @1], - @"sensor_hour": @[@227, @5], - @"sensor_minute": @[@234, @6], - @"sensor_year": @[@248, @8], - @"sensor_month": @[@260, @4], - @"sensor_day": @[@267, @5], - }; -} - -- (NSDate*) nextCal { - NSInteger hour = [self getBits:@"next_cal_hour"]; - NSInteger minute = [self getBits:@"next_cal_minute"]; - - NSDate *pumpDate = [self pumpTime]; - - return [[NSCalendar currentCalendar] nextDateAfterDate:pumpDate matchingHour:hour minute:minute second:0 options:NSCalendarMatchNextTime]; -} - -- (NSInteger) sensorAge { - return [self getBits:@"sensor_age"]; -} - -- (NSInteger) sensorRemaining { - return [self getBits:@"sensor_remaining"]; -} - -- (NSInteger) batteryPct { - return [self getBits:@"batt"] / 4.0 * 100; -} - -- (SensorStatus) sensorStatus { - NSInteger bgH = [self getBits:@"bg_h"]; - switch (bgH) { - case 0: - return SENSOR_STATUS_MISSING; - case 1: - return SENSOR_STATUS_METER_BG_NOW; - case 2: - return SENSOR_STATUS_WEAK_SIGNAL; - case 4: - return SENSOR_STATUS_WARMUP; - case 7: - return SENSOR_STATUS_HIGH_BG; - case 10: - return SENSOR_STATUS_LOST; - } - if (bgH > 10) { - return SENSOR_STATUS_OK; - } else { - return SENSOR_STATUS_UNKNOWN; - } -} - -- (NSString*) sensorStatusString { - switch ([self sensorStatus]) { - case SENSOR_STATUS_MISSING: - return @"Sensor Missing"; - case SENSOR_STATUS_METER_BG_NOW: - return @"Meter BG Now"; - case SENSOR_STATUS_WEAK_SIGNAL: - return @"Weak Signal"; - case SENSOR_STATUS_WARMUP: - return @"Warmup"; - case SENSOR_STATUS_HIGH_BG: - return @"High BG"; - case SENSOR_STATUS_LOST: - return @"Sensor Lost"; - case SENSOR_STATUS_OK: - return @"Sensor OK"; - case SENSOR_STATUS_UNKNOWN: - default: - return @"Sensor Status Unknown"; - } -} - -- (GlucoseTrend) trend { - return (GlucoseTrend)[self getBits:@"trend"]; -} - -- (NSInteger) glucose { - if ([self sensorStatus] == SENSOR_STATUS_OK) { - return ([self getBits:@"bg_h"] << 1) + [self getBits:@"bg_l"]; - } else { - return 0; - } -} - -- (NSInteger) previousGlucose { - if ([self sensorStatus] == SENSOR_STATUS_OK) { - return ([self getBits:@"prev_bg_h"] << 1) + [self getBits:@"prev_bg_l"]; - } else { - return 0; - } -} - -- (double) activeInsulin { - return [self getBits:@"active_ins"] * 0.025; -} - -- (double) insulinRemaining { - return [self getBits:@"insulin_remaining"] / 10.0; -} - -- (NSDate*) pumpTime { - NSCalendar *calendar = [NSCalendar currentCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; - [components setYear:[self getBits:@"pump_year"]+2000]; - [components setMonth:[self getBits:@"pump_month"]]; - [components setDay:[self getBits:@"pump_day"]]; - [components setHour:[self getBits:@"pump_hour"]]; - [components setMinute:[self getBits:@"pump_minute"]]; - [components setSecond:0]; - return [calendar dateFromComponents:components]; -} - - -- (NSDate*) sensorTime { - NSCalendar *calendar = [NSCalendar currentCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; - [components setYear:[self getBits:@"sensor_year"]+2000]; - [components setMonth:[self getBits:@"sensor_month"]]; - [components setDay:[self getBits:@"sensor_day"]]; - [components setHour:[self getBits:@"sensor_hour"]]; - [components setMinute:[self getBits:@"sensor_minute"]]; - [components setSecond:0]; - return [calendar dateFromComponents:components]; -} - -@end diff --git a/RileyLink/RileyLink-Bridging-Header.h b/RileyLink/RileyLink-Bridging-Header.h new file mode 100644 index 000000000..65b734fcf --- /dev/null +++ b/RileyLink/RileyLink-Bridging-Header.h @@ -0,0 +1,8 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "Config.h" +#import "Log.h" +#import +#import "NSData+Conversion.h" diff --git a/RileyLink/RileyLink-Info.plist b/RileyLink/RileyLink-Info.plist index b88770f25..0fcec1bd9 100644 --- a/RileyLink/RileyLink-Info.plist +++ b/RileyLink/RileyLink-Info.plist @@ -19,11 +19,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1.4 + 0.2.0 CFBundleSignature ???? CFBundleVersion - 0.1.4 + $(CURRENT_PROJECT_VERSION) LSApplicationCategoryType LSRequiresIPhoneOS diff --git a/RileyLink/RileyLink-Prefix.pch b/RileyLink/RileyLink-Prefix.pch deleted file mode 100644 index 775604ba3..000000000 --- a/RileyLink/RileyLink-Prefix.pch +++ /dev/null @@ -1,19 +0,0 @@ -// -// Prefix header -// -// The contents of this file are implicitly included at the beginning of every source file. -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iOS SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import - #import -#endif - -#import "Log.h" \ No newline at end of file diff --git a/RileyLink/RileyLinkDeviceViewController.m b/RileyLink/RileyLinkDeviceViewController.m index 51a9dfce9..467e68654 100644 --- a/RileyLink/RileyLinkDeviceViewController.m +++ b/RileyLink/RileyLinkDeviceViewController.m @@ -6,11 +6,11 @@ // Copyright (c) 2015 Pete Schwamb. All rights reserved. // +@import RileyLinkBLEKit; + #import "RileyLinkDeviceViewController.h" #import "PacketLogViewController.h" -#import "PumpChatViewController.h" #import "PacketGeneratorViewController.h" -#import "RileyLinkBLEManager.h" @interface RileyLinkDeviceViewController () { IBOutlet UILabel *deviceIDLabel; @@ -43,7 +43,7 @@ - (void)viewDidLoad { [self updateNameView]; - autoConnectSwitch.on = [self.rlRecord.autoConnect boolValue]; + autoConnectSwitch.on = (self.rlRecord.autoConnect).boolValue; } -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { diff --git a/RileyLink/RileyLinkListTableViewController.m b/RileyLink/RileyLinkListTableViewController.m index 3af888467..2051be628 100644 --- a/RileyLink/RileyLinkListTableViewController.m +++ b/RileyLink/RileyLinkListTableViewController.m @@ -6,13 +6,13 @@ // Copyright (c) 2015 Pete Schwamb. All rights reserved. // +@import RileyLinkBLEKit; + #import "RileyLinkListTableViewController.h" #import "SWRevealViewController.h" -#import "RileyLinkBLEManager.h" #import "RileyLinkTableViewCell.h" -#import "RileyLinkBLEDevice.h" -#import "AppDelegate.h" #import "RileyLinkDeviceViewController.h" +#import "RileyLink-Swift.h" @interface RileyLinkListTableViewController () { NSMutableArray *rileyLinkRecords; @@ -28,7 +28,7 @@ @implementation RileyLinkListTableViewController - (void)viewDidLoad { [super viewDidLoad]; - AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; + AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; self.managedObjectContext = appDelegate.managedObjectContext; [[NSNotificationCenter defaultCenter] addObserver:self @@ -46,7 +46,7 @@ - (void)viewDidLoad { if (self.revealViewController != nil) { menuButton.target = self.revealViewController; - [menuButton setAction:@selector(revealToggle:)]; + menuButton.action = @selector(revealToggle:); [self.view addGestureRecognizer: self.revealViewController.panGestureRecognizer]; } @@ -76,7 +76,7 @@ - (void)dealloc - (void)processVisibleDevices { devicesById = [NSMutableDictionary dictionary]; - for (RileyLinkBLEDevice *device in [[RileyLinkBLEManager sharedManager] rileyLinkList]) { + for (RileyLinkBLEDevice *device in [RileyLinkBLEManager sharedManager].rileyLinkList) { devicesById[device.peripheralId] = device; RileyLinkRecord *existingRecord = recordsById[device.peripheralId]; @@ -114,10 +114,10 @@ - (void)loadRecordsFromDB { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"firstSeenAt" ascending:YES]; - [fetchRequest setSortDescriptors:@[sortDescriptor1]]; + fetchRequest.sortDescriptors = @[sortDescriptor1]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"RileyLinkRecord" inManagedObjectContext:self.managedObjectContext]; - [fetchRequest setEntity:entity]; + fetchRequest.entity = entity; NSError *error; NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; for (RileyLinkRecord *record in fetchedObjects) { @@ -142,14 +142,14 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. - return [rileyLinkRecords count]; + return rileyLinkRecords.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { RileyLinkTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"rileylink" forIndexPath:indexPath]; RileyLinkRecord *record = rileyLinkRecords[indexPath.row]; cell.name = record.name; - cell.autoConnect = [record.autoConnect boolValue]; + cell.autoConnect = (record.autoConnect).boolValue; RileyLinkBLEDevice *device = devicesById[record.peripheralId]; if (device) { @@ -200,8 +200,8 @@ - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *) // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - RileyLinkDeviceViewController *controller = [segue destinationViewController]; - NSIndexPath *ip = [self.tableView indexPathForSelectedRow]; + RileyLinkDeviceViewController *controller = segue.destinationViewController; + NSIndexPath *ip = (self.tableView).indexPathForSelectedRow; RileyLinkRecord *record = rileyLinkRecords[ip.row]; controller.rlRecord = record; controller.rlDevice = devicesById[record.peripheralId]; diff --git a/RileyLink/RileyLinkTableViewCell.m b/RileyLink/RileyLinkTableViewCell.m index c214e6cd8..07af5e106 100644 --- a/RileyLink/RileyLinkTableViewCell.m +++ b/RileyLink/RileyLinkTableViewCell.m @@ -26,7 +26,7 @@ - (void)setName:(NSString *)name { - (void)setRSSI:(NSNumber *)RSSI { _RSSI = RSSI; - rssiLabel.text = [RSSI stringValue]; + rssiLabel.text = RSSI.stringValue; } - (void)setAutoConnect:(BOOL)autoConnect { diff --git a/RileyLink/SWRevealViewController.h b/RileyLink/SWRevealViewController.h index 345dfaa00..1ad3fc02a 100755 --- a/RileyLink/SWRevealViewController.h +++ b/RileyLink/SWRevealViewController.h @@ -187,7 +187,7 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType) /* Basic API */ // Object instance init and rear view setting -- (id)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController; +- (instancetype)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController NS_DESIGNATED_INITIALIZER; // Rear view controller, can be nil if not used @property (nonatomic) UIViewController *rearViewController; @@ -227,13 +227,13 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType) // By default, the panGestureRecognizer is added to the view containing the front controller view. To keep this default behavior // you still need to call this method, just don't add it to any of your views. The default setup allows you to dissable // user interactions on your controller views without affecting the recognizer. -- (UIPanGestureRecognizer*)panGestureRecognizer; +@property (NS_NONATOMIC_IOSONLY, readonly, strong) UIPanGestureRecognizer *panGestureRecognizer; // The following method will provide a tapGestureRecognizer suitable to be added to any view on the frontController // for concealing the rear views. By default no tap recognizer is created or added to any view, however if you call this method after // the controller's view has been loaded the recognizer is added to the reveal controller's front container view. // Thus, you can disable user interactions on your frontViewController view without affecting the tap recognizer. -- (UITapGestureRecognizer*)tapGestureRecognizer; +@property (NS_NONATOMIC_IOSONLY, readonly, strong) UITapGestureRecognizer *tapGestureRecognizer; /* The following properties are provided for further customization, they are set to default values on initialization, you do not generally have to set them */ @@ -318,14 +318,14 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType) #pragma mark - SWRevealViewControllerDelegate Protocol -typedef enum +typedef NS_ENUM(unsigned int, SWRevealControllerOperation) { SWRevealControllerOperationNone, SWRevealControllerOperationReplaceRearController, SWRevealControllerOperationReplaceFrontController, SWRevealControllerOperationReplaceRightController, -} SWRevealControllerOperation; +}; @protocol SWRevealViewControllerDelegate @@ -390,7 +390,7 @@ typedef enum // A category of UIViewController to let childViewControllers easily access their parent SWRevealViewController @interface UIViewController(SWRevealViewController) -- (SWRevealViewController*)revealViewController; +@property (NS_NONATOMIC_IOSONLY, readonly, strong) SWRevealViewController *revealViewController; @end diff --git a/RileyLink/SWRevealViewController.m b/RileyLink/SWRevealViewController.m index aff2a163b..756b162ab 100755 --- a/RileyLink/SWRevealViewController.m +++ b/RileyLink/SWRevealViewController.m @@ -37,8 +37,8 @@ static CGFloat statusBarAdjustment( UIView* view ) { CGFloat adjustment = 0.0f; UIApplication *app = [UIApplication sharedApplication]; - CGRect viewFrame = [view convertRect:view.bounds toView:[app keyWindow]]; - CGRect statusBarFrame = [app statusBarFrame]; + CGRect viewFrame = [view convertRect:view.bounds toView:app.keyWindow]; + CGRect statusBarFrame = app.statusBarFrame; if ( CGRectIntersectsRect(viewFrame, statusBarFrame) ) adjustment = fminf(statusBarFrame.size.width, statusBarFrame.size.height); @@ -82,7 +82,7 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 } -- (id)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller +- (instancetype)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller { self = [super initWithFrame:frame]; if ( self ) @@ -103,7 +103,7 @@ - (id)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller - (void)reloadShadow { CALayer *frontViewLayer = _frontView.layer; - frontViewLayer.shadowColor = [_c.frontViewShadowColor CGColor]; + frontViewLayer.shadowColor = (_c.frontViewShadowColor).CGColor; frontViewLayer.shadowOpacity = _c.frontViewShadowOpacity; frontViewLayer.shadowOffset = _c.frontViewShadowOffset; frontViewLayer.shadowRadius = _c.frontViewShadowRadius; @@ -374,7 +374,7 @@ @implementation SWContextTransitionObject } -- (id)initWithRevealController:(SWRevealViewController*)revealVC containerView:(UIView*)view fromVC:(UIViewController*)fromVC +- (instancetype)initWithRevealController:(SWRevealViewController*)revealVC containerView:(UIView*)view fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC completion:(void (^)(void))completion { self = [super init]; @@ -493,7 +493,7 @@ @implementation SWDefaultAnimationController } -- (id)initWithDuration:(NSTimeInterval)duration +- (instancetype)initWithDuration:(NSTimeInterval)duration { self = [super init]; if ( self ) @@ -609,7 +609,7 @@ @implementation SWRevealViewController #pragma mark - Init -- (id)initWithCoder:(NSCoder *)aDecoder +- (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if ( self ) @@ -620,13 +620,13 @@ - (id)initWithCoder:(NSCoder *)aDecoder } -- (id)init +- (instancetype)init { return [self initWithRearViewController:nil frontViewController:nil]; } -- (id)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController; +- (instancetype)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController; { self = [super init]; if ( self ) @@ -708,16 +708,16 @@ - (void)loadView // On iOS7 the applicationFrame does not return the whole screen. This is possibly a bug. // As a workaround we use the screen bounds, this still works on iOS6, any zero based frame would work anyway! - CGRect frame = [[UIScreen mainScreen] bounds]; + CGRect frame = [UIScreen mainScreen].bounds; // create a custom content view for the controller _contentView = [[SWRevealView alloc] initWithFrame:frame controller:self]; // set the content view to resize along with its superview - [_contentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; + _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; // set the content view to clip its bounds if requested - [_contentView setClipsToBounds:_clipsViewsToBounds]; + _contentView.clipsToBounds = _clipsViewsToBounds; // set our contentView to the controllers view self.view = _contentView; @@ -928,7 +928,7 @@ - (UITapGestureRecognizer*)tapGestureRecognizer - (void)setClipsViewsToBounds:(BOOL)clipsViewsToBounds { _clipsViewsToBounds = clipsViewsToBounds; - [_contentView setClipsToBounds:clipsViewsToBounds]; + _contentView.clipsToBounds = clipsViewsToBounds; } @@ -961,7 +961,7 @@ - (void)_restoreUserInteraction { // we use the stored userInteraction state just in case a developer decided // to have our view interaction disabled beforehand - [_contentView setUserInteractionEnabled:_userInteractionStore]; + _contentView.userInteractionEnabled = _userInteractionStore; [_contentView setDisableLayout:NO]; } @@ -1087,7 +1087,7 @@ - (void)_dequeue if ( _animationQueue.count > 0 ) { - void (^block)(void) = [_animationQueue lastObject]; + void (^block)(void) = _animationQueue.lastObject; block(); } } @@ -1719,7 +1719,7 @@ + (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)ide if (sb) { vc = (SWRevealViewController*)[sb instantiateViewControllerWithIdentifier:@"SWRevealViewController"]; - vc.restorationIdentifier = [identifierComponents lastObject]; + vc.restorationIdentifier = identifierComponents.lastObject; vc.restorationClass = [SWRevealViewController class]; } return vc; @@ -1791,11 +1791,11 @@ - (void)decodeRestorableStateWithCoder:(NSCoder *)coder _clipsViewsToBounds = [coder decodeBoolForKey:@"_clipsViewsToBounds"]; _extendsPointInsideHit = [coder decodeBoolForKey:@"_extendsPointInsideHit"]; - [self setRearViewController:[coder decodeObjectForKey:@"_rearViewController"]]; - [self setFrontViewController:[coder decodeObjectForKey:@"_frontViewController"]]; - [self setRightViewController:[coder decodeObjectForKey:@"_rightViewController"]]; + self.rearViewController = [coder decodeObjectForKey:@"_rearViewController"]; + self.frontViewController = [coder decodeObjectForKey:@"_frontViewController"]; + self.rightViewController = [coder decodeObjectForKey:@"_rightViewController"]; - [self setFrontViewPosition:[coder decodeIntForKey: @"_frontViewPosition"]]; + self.frontViewPosition = [coder decodeIntForKey: @"_frontViewPosition"]; [super decodeRestorableStateWithCoder:coder]; } @@ -1818,7 +1818,7 @@ - (SWRevealViewController*)revealViewController { UIViewController *parent = self; Class revealClass = [SWRevealViewController class]; - while ( nil != (parent = [parent parentViewController]) && ![parent isKindOfClass:revealClass] ) {} + while ( nil != (parent = parent.parentViewController) && ![parent isKindOfClass:revealClass] ) {} return (id)parent; } diff --git a/RileyLink/Storyboard.storyboard b/RileyLink/Storyboard.storyboard index 6ef05eff5..f5fc0d9b4 100644 --- a/RileyLink/Storyboard.storyboard +++ b/RileyLink/Storyboard.storyboard @@ -1,8 +1,8 @@ - + - + @@ -659,7 +659,7 @@ - + @@ -729,7 +729,7 @@ - + @@ -742,7 +742,7 @@ - + @@ -757,9 +757,9 @@ - - + @@ -814,7 +814,7 @@ - + diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h index fbd8619ee..c7ab484ef 100644 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.h @@ -10,6 +10,6 @@ #import "UIScrollView+TPKeyboardAvoidingAdditions.h" @interface TPKeyboardAvoidingCollectionView : UICollectionView -- (BOOL)focusNextTextField; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL focusNextTextField; - (void)scrollToActiveTextField; @end diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m index 253b02255..01ef95688 100644 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingCollectionView.m @@ -22,13 +22,13 @@ - (void)setup { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil]; } --(id)initWithFrame:(CGRect)frame { +-(instancetype)initWithFrame:(CGRect)frame { if ( !(self = [super initWithFrame:frame]) ) return nil; [self setup]; return self; } -- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout { +- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout { if ( !(self = [super initWithFrame:frame collectionViewLayout:layout]) ) return nil; [self setup]; return self; @@ -46,7 +46,7 @@ -(void)dealloc { } -(void)setFrame:(CGRect)frame { - [super setFrame:frame]; + super.frame = frame; [self TPKeyboardAvoiding_updateContentInset]; } @@ -56,7 +56,7 @@ -(void)setContentSize:(CGSize)contentSize { // cause weird infinte scrolling and locking bug return; } - [super setContentSize:contentSize]; + super.contentSize = contentSize; [self TPKeyboardAvoiding_updateContentInset]; } diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h index 6947992cb..2a8e73f18 100755 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.h @@ -11,6 +11,6 @@ @interface TPKeyboardAvoidingScrollView : UIScrollView - (void)contentSizeToFit; -- (BOOL)focusNextTextField; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL focusNextTextField; - (void)scrollToActiveTextField; @end diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m index 81f753ac3..3391f532a 100644 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingScrollView.m @@ -22,7 +22,7 @@ - (void)setup { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil]; } --(id)initWithFrame:(CGRect)frame { +-(instancetype)initWithFrame:(CGRect)frame { if ( !(self = [super initWithFrame:frame]) ) return nil; [self setup]; return self; @@ -40,12 +40,12 @@ -(void)dealloc { } -(void)setFrame:(CGRect)frame { - [super setFrame:frame]; + super.frame = frame; [self TPKeyboardAvoiding_updateContentInset]; } -(void)setContentSize:(CGSize)contentSize { - [super setContentSize:contentSize]; + super.contentSize = contentSize; [self TPKeyboardAvoiding_updateFromContentSizeChange]; } diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h index 7e05a0e1c..e63c8298d 100644 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.h @@ -10,6 +10,6 @@ #import "UIScrollView+TPKeyboardAvoidingAdditions.h" @interface TPKeyboardAvoidingTableView : UITableView -- (BOOL)focusNextTextField; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL focusNextTextField; - (void)scrollToActiveTextField; @end diff --git a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m index cc652de04..90c0df52f 100644 --- a/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m +++ b/RileyLink/TPKeyboardAvoiding/TPKeyboardAvoidingTableView.m @@ -24,13 +24,13 @@ - (void)setup { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(scrollToActiveTextField) name:UITextFieldTextDidBeginEditingNotification object:nil]; } --(id)initWithFrame:(CGRect)frame { +-(instancetype)initWithFrame:(CGRect)frame { if ( !(self = [super initWithFrame:frame]) ) return nil; [self setup]; return self; } --(id)initWithFrame:(CGRect)frame style:(UITableViewStyle)withStyle { +-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)withStyle { if ( !(self = [super initWithFrame:frame style:withStyle]) ) return nil; [self setup]; return self; @@ -59,14 +59,14 @@ -(BOOL)hasAutomaticKeyboardAvoidingBehaviour { } -(void)setFrame:(CGRect)frame { - [super setFrame:frame]; + super.frame = frame; if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) return; [self TPKeyboardAvoiding_updateContentInset]; } -(void)setContentSize:(CGSize)contentSize { if ( [self hasAutomaticKeyboardAvoidingBehaviour] ) { - [super setContentSize:contentSize]; + super.contentSize = contentSize; return; } if (CGSizeEqualToSize(contentSize, self.contentSize)) { @@ -74,7 +74,7 @@ -(void)setContentSize:(CGSize)contentSize { // this cause table view to scroll to top on contentInset changes return; } - [super setContentSize:contentSize]; + super.contentSize = contentSize; [self TPKeyboardAvoiding_updateContentInset]; } diff --git a/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h b/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h index 80b9b1090..2e6f87b42 100644 --- a/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h +++ b/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.h @@ -9,7 +9,7 @@ #import @interface UIScrollView (TPKeyboardAvoidingAdditions) -- (BOOL)TPKeyboardAvoiding_focusNextTextField; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL TPKeyboardAvoiding_focusNextTextField; - (void)TPKeyboardAvoiding_scrollToActiveTextField; - (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification; @@ -18,5 +18,5 @@ - (void)TPKeyboardAvoiding_updateFromContentSizeChange; - (void)TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView:(UIView*)view; - (UIView*)TPKeyboardAvoiding_findFirstResponderBeneathView:(UIView*)view; --(CGSize)TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames; +@property (NS_NONATOMIC_IOSONLY, readonly) CGSize TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames; @end diff --git a/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m b/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m index df3b329c9..e3cfadb76 100644 --- a/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m +++ b/RileyLink/TPKeyboardAvoiding/UIScrollView+TPKeyboardAvoidingAdditions.m @@ -43,7 +43,7 @@ - (TPKeyboardAvoidingState*)keyboardAvoidingState { } - (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification { - CGRect keyboardRect = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; + CGRect keyboardRect = [self convertRect:[notification.userInfo[_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; if (CGRectIsEmpty(keyboardRect)) { return; } @@ -79,8 +79,8 @@ - (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification { // Shrink view's inset by the keyboard's height, and scroll to show the text field/view being edited [UIView beginAnimations:nil context:NULL]; - [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]]; - [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]]; + [UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]]; + [UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]]; self.contentInset = [self TPKeyboardAvoiding_contentInsetForKeyboard]; @@ -97,7 +97,7 @@ - (void)TPKeyboardAvoiding_keyboardWillShow:(NSNotification*)notification { } - (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification { - CGRect keyboardRect = [self convertRect:[[[notification userInfo] objectForKey:_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; + CGRect keyboardRect = [self convertRect:[notification.userInfo[_UIKeyboardFrameEndUserInfoKey] CGRectValue] fromView:nil]; if (CGRectIsEmpty(keyboardRect)) { return; } @@ -113,8 +113,8 @@ - (void)TPKeyboardAvoiding_keyboardWillHide:(NSNotification*)notification { // Restore dimensions to prior size [UIView beginAnimations:nil context:NULL]; - [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]]; - [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]]; + [UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]]; + [UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue]]; if ( [self isKindOfClass:[TPKeyboardAvoidingScrollView class]] ) { self.contentSize = state.priorContentSize; @@ -316,8 +316,8 @@ -(CGFloat)TPKeyboardAvoiding_idealOffsetForView:(UIView *)view withViewingAreaHe - (void)TPKeyboardAvoiding_initializeView:(UIView*)view { if ( [view isKindOfClass:[UITextField class]] && ((UITextField*)view).returnKeyType == UIReturnKeyDefault - && (![(UITextField*)view delegate] || [(UITextField*)view delegate] == (id)self) ) { - [(UITextField*)view setDelegate:(id)self]; + && (!((UITextField*)view).delegate || ((UITextField*)view).delegate == (id)self) ) { + ((UITextField*)view).delegate = (id)self; UIView *otherView = [self TPKeyboardAvoiding_findNextInputViewAfterView:view beneathView:self]; if ( otherView ) { diff --git a/RileyLink/main.m b/RileyLink/main.m deleted file mode 100644 index 0628714c5..000000000 --- a/RileyLink/main.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// main.m -// GlucoseLink -// -// Created by Pete Schwamb on 7/31/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. -// - -#import - -#import "AppDelegate.h" - -int main(int argc, char * argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/RileyLink/CmdBase.h b/RileyLinkBLEKit/CmdBase.h similarity index 85% rename from RileyLink/CmdBase.h rename to RileyLinkBLEKit/CmdBase.h index 15ebfda78..fd81d1311 100644 --- a/RileyLink/CmdBase.h +++ b/RileyLinkBLEKit/CmdBase.h @@ -6,7 +6,7 @@ // Copyright © 2015 Pete Schwamb. All rights reserved. // -#import +@import Foundation; #define RILEYLINK_CMD_GET_STATE 1 #define RILEYLINK_CMD_GET_VERSION 2 @@ -18,7 +18,7 @@ @interface CmdBase : NSObject -- (NSData*)data; +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSData *data; @property (nonatomic, strong) NSData *response; diff --git a/RileyLink/CmdBase.m b/RileyLinkBLEKit/CmdBase.m similarity index 100% rename from RileyLink/CmdBase.m rename to RileyLinkBLEKit/CmdBase.m diff --git a/RileyLink/GetPacketCmd.h b/RileyLinkBLEKit/GetPacketCmd.h similarity index 72% rename from RileyLink/GetPacketCmd.h rename to RileyLinkBLEKit/GetPacketCmd.h index 8a0060adf..284efa8c4 100644 --- a/RileyLink/GetPacketCmd.h +++ b/RileyLinkBLEKit/GetPacketCmd.h @@ -6,11 +6,11 @@ // Copyright © 2016 Pete Schwamb. All rights reserved. // -#import -#import "CmdBase.h" +@import Foundation; +#import "ReceivingPacketCmd.h" -@interface GetPacketCmd : CmdBase +@interface GetPacketCmd : ReceivingPacketCmd @property (nonatomic, assign) uint8_t listenChannel; @property (nonatomic, assign) uint16_t timeoutMS; diff --git a/RileyLink/GetPacketCmd.m b/RileyLinkBLEKit/GetPacketCmd.m similarity index 53% rename from RileyLink/GetPacketCmd.m rename to RileyLinkBLEKit/GetPacketCmd.m index 4629c1fbf..5a01bf858 100644 --- a/RileyLink/GetPacketCmd.m +++ b/RileyLinkBLEKit/GetPacketCmd.m @@ -8,16 +8,18 @@ #import "GetPacketCmd.h" -@implementation GetPacketCmd +@implementation GetPacketCmd - (NSData*)data { - uint8_t cmd[4]; + uint8_t cmd[6]; cmd[0] = RILEYLINK_CMD_GET_PACKET; cmd[1] = _listenChannel; - cmd[2] = _timeoutMS >> 8; - cmd[3] = _timeoutMS & 0xff; + cmd[2] = _timeoutMS >> 24; + cmd[3] = (_timeoutMS >> 16) & 0xff; + cmd[4] = (_timeoutMS >> 8) & 0xff; + cmd[5] = _timeoutMS & 0xff; - return [NSData dataWithBytes:cmd length:4]; + return [NSData dataWithBytes:cmd length:6]; } @end diff --git a/RileyLink/GetVersionCmd.h b/RileyLinkBLEKit/GetVersionCmd.h similarity index 100% rename from RileyLink/GetVersionCmd.h rename to RileyLinkBLEKit/GetVersionCmd.h diff --git a/RileyLink/GetVersionCmd.m b/RileyLinkBLEKit/GetVersionCmd.m similarity index 100% rename from RileyLink/GetVersionCmd.m rename to RileyLinkBLEKit/GetVersionCmd.m diff --git a/RileyLinkBLEKit/Info.plist b/RileyLinkBLEKit/Info.plist new file mode 100644 index 000000000..6019f05bf --- /dev/null +++ b/RileyLinkBLEKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/RileyLinkBLEKit/RFPacket.h b/RileyLinkBLEKit/RFPacket.h new file mode 100644 index 000000000..2300bca7d --- /dev/null +++ b/RileyLinkBLEKit/RFPacket.h @@ -0,0 +1,24 @@ +// +// RFPacket.h +// RileyLink +// +// Created by Pete Schwamb on 2/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +@import Foundation; + +@interface RFPacket : NSObject + +- (nonnull instancetype)initWithData:(nonnull NSData*)data NS_DESIGNATED_INITIALIZER; +- (nullable instancetype)initWithRFSPYResponse:(nonnull NSData*)data NS_DESIGNATED_INITIALIZER; + +- (nonnull NSData*)encodedData; + +@property (nonatomic, nullable, strong) NSData *data; +@property (nonatomic, nullable, strong) NSDate *capturedAt; +@property (nonatomic, assign) int rssi; +@property (nonatomic, assign) int packetNumber; + + +@end diff --git a/RileyLink/MinimedPacket.m b/RileyLinkBLEKit/RFPacket.m similarity index 54% rename from RileyLink/MinimedPacket.m rename to RileyLinkBLEKit/RFPacket.m index f2820e966..7f4a16197 100644 --- a/RileyLink/MinimedPacket.m +++ b/RileyLinkBLEKit/RFPacket.m @@ -1,41 +1,47 @@ // -// MinimedPacket.m -// GlucoseLink +// RFPacket.m +// RileyLink // -// Created by Pete Schwamb on 8/5/14. -// Copyright (c) 2014 Pete Schwamb. All rights reserved. +// Created by Pete Schwamb on 2/28/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. // -#import "MinimedPacket.h" -#import "NSData+Conversion.h" -#import "CRC8.h" -#import "PumpStatusMessage.h" -#import "DeviceLinkMessage.h" -#import "FindDeviceMessage.h" -#import "MeterMessage.h" +#import "RFPacket.h" +@implementation RFPacket -@interface MinimedPacket () +static const unsigned char crcTable[256] = { 0x0, 0x9B, 0xAD, 0x36, 0xC1, 0x5A, 0x6C, 0xF7, 0x19, 0x82, 0xB4, 0x2F, 0xD8, 0x43, 0x75, 0xEE, 0x32, 0xA9, 0x9F, 0x4, 0xF3, 0x68, 0x5E, 0xC5, 0x2B, 0xB0, 0x86, 0x1D, 0xEA, 0x71, 0x47, 0xDC, 0x64, 0xFF, 0xC9, 0x52, 0xA5, 0x3E, 0x8, 0x93, 0x7D, 0xE6, 0xD0, 0x4B, 0xBC, 0x27, 0x11, 0x8A, 0x56, 0xCD, 0xFB, 0x60, 0x97, 0xC, 0x3A, 0xA1, 0x4F, 0xD4, 0xE2, 0x79, 0x8E, 0x15, 0x23, 0xB8, 0xC8, 0x53, 0x65, 0xFE, 0x9, 0x92, 0xA4, 0x3F, 0xD1, 0x4A, 0x7C, 0xE7, 0x10, 0x8B, 0xBD, 0x26, 0xFA, 0x61, 0x57, 0xCC, 0x3B, 0xA0, 0x96, 0xD, 0xE3, 0x78, 0x4E, 0xD5, 0x22, 0xB9, 0x8F, 0x14, 0xAC, 0x37, 0x1, 0x9A, 0x6D, 0xF6, 0xC0, 0x5B, 0xB5, 0x2E, 0x18, 0x83, 0x74, 0xEF, 0xD9, 0x42, 0x9E, 0x5, 0x33, 0xA8, 0x5F, 0xC4, 0xF2, 0x69, 0x87, 0x1C, 0x2A, 0xB1, 0x46, 0xDD, 0xEB, 0x70, 0xB, 0x90, 0xA6, 0x3D, 0xCA, 0x51, 0x67, 0xFC, 0x12, 0x89, 0xBF, 0x24, 0xD3, 0x48, 0x7E, 0xE5, 0x39, 0xA2, 0x94, 0xF, 0xF8, 0x63, 0x55, 0xCE, 0x20, 0xBB, 0x8D, 0x16, 0xE1, 0x7A, 0x4C, 0xD7, 0x6F, 0xF4, 0xC2, 0x59, 0xAE, 0x35, 0x3, 0x98, 0x76, 0xED, 0xDB, 0x40, 0xB7, 0x2C, 0x1A, 0x81, 0x5D, 0xC6, 0xF0, 0x6B, 0x9C, 0x7, 0x31, 0xAA, 0x44, 0xDF, 0xE9, 0x72, 0x85, 0x1E, 0x28, 0xB3, 0xC3, 0x58, 0x6E, 0xF5, 0x2, 0x99, 0xAF, 0x34, 0xDA, 0x41, 0x77, 0xEC, 0x1B, 0x80, 0xB6, 0x2D, 0xF1, 0x6A, 0x5C, 0xC7, 0x30, 0xAB, 0x9D, 0x6, 0xE8, 0x73, 0x45, 0xDE, 0x29, 0xB2, 0x84, 0x1F, 0xA7, 0x3C, 0xA, 0x91, 0x66, 0xFD, 0xCB, 0x50, 0xBE, 0x25, 0x13, 0x88, 0x7F, 0xE4, 0xD2, 0x49, 0x95, 0xE, 0x38, 0xA3, 0x54, 0xCF, 0xF9, 0x62, 0x8C, 0x17, 0x21, 0xBA, 0x4D, 0xD6, 0xE0, 0x7B }; -@property (nonatomic, assign) NSInteger codingErrorCount; -@end - -@implementation MinimedPacket - -+ (void)initialize { ++ (uint8_t) computeCRC8:(NSData*)data { + uint8_t crc = 0; + const uint8_t *pdata = data.bytes; + unsigned long nbytes = data.length; + /* loop over the buffer data */ + while (nbytes-- > 0) { + crc = crcTable[(crc ^ *pdata++) & 0xff]; + } + return crc; } - (instancetype)init NS_UNAVAILABLE { - return nil; + return nil; +} + +- (instancetype)initWithData:(NSData*)data { + self = [super init]; + if (self) { + _data = data; + } + return self; } -- (instancetype)initWithData:(NSData*)data + +- (instancetype)initWithRFSPYResponse:(NSData*)data { self = [super init]; if (self) { - _codingErrorCount = 0; if (data.length > 0) { unsigned char rssiDec = ((const unsigned char*)[data bytes])[0]; unsigned char rssiOffset = 73; @@ -48,7 +54,7 @@ - (instancetype)initWithData:(NSData*)data if (data.length > 1) { self.packetNumber = ((const unsigned char*)[data bytes])[1]; } - + if (data.length > 2) { _data = [self decodeRF:[data subdataWithRange:NSMakeRange(2, data.length - 2)]]; } @@ -56,24 +62,12 @@ - (instancetype)initWithData:(NSData*)data return self; } - -- (BOOL) crcValid { - if (_data.length < 2) { - return NO; - } - uint8_t packetCrc = ((uint8_t*)[_data bytes])[_data.length-1]; - uint8_t crc = [CRC8 compute:[_data subdataWithRange:NSMakeRange(0, _data.length-1)]]; - return crc == packetCrc; -} - -- (BOOL) isValid { - return _data.length > 0 && [self crcValid]; -} - -+ (NSData*)encodeData:(NSData*)data { +- (NSData*)encodedData { NSMutableData *outData = [NSMutableData data]; - NSMutableData *dataPlusCrc = [data mutableCopy]; - unsigned char crc = [CRC8 compute:data]; + // TODO; we should be able to avoid this copy by accessing the CRC + // in the loop below when i == data.length + NSMutableData *dataPlusCrc = [_data mutableCopy]; + unsigned char crc = [RFPacket computeCRC8:_data]; [dataPlusCrc appendBytes:&crc length:1]; char codes[16] = {21,49,50,35,52,37,38,22,26,25,42,11,44,13,14,28}; const unsigned char *inBytes = [dataPlusCrc bytes]; @@ -103,6 +97,8 @@ + (NSData*)encodeData:(NSData*)data { return outData; } + + - (NSData*)decodeRF:(NSData*) rawData { // Converted from ruby using: CODE_SYMBOLS.each{|k,v| puts "@#{Integer("0b"+k)}: @#{Integer("0x"+v)},"};nil NSDictionary *codes = @{@21: @0, @@ -136,7 +132,7 @@ - (NSData*)decodeRF:(NSData*) rawData { unsigned char decoded = ([hiNibble integerValue] << 4) + [loNibble integerValue]; [output appendBytes:&decoded length:1]; } else { - _codingErrorCount += 1; + return nil; } availBits -= 12; x = x & (0xffff >> (16-availBits)); @@ -145,46 +141,5 @@ - (NSData*)decodeRF:(NSData*) rawData { return output; } -- (NSString*) hexadecimalString { - return [_data hexadecimalString]; -} - -- (unsigned char)byteAt:(NSInteger)index { - if (_data && index < [_data length]) { - return ((unsigned char*)[_data bytes])[index]; - } else { - return 0; - } -} - -- (PacketType) packetType { - return [self byteAt:0]; -} - -- (MessageType) messageType { - return [self byteAt:4]; -} - -- (NSString*) address { - return [NSString stringWithFormat:@"%02x%02x%02x", [self byteAt:1], [self byteAt:2], [self byteAt:3]]; -} - -- (MessageBase*)toMessage { - if (self.packetType == PacketTypeSentry) { - switch (self.messageType) { - case MESSAGE_TYPE_PUMP_STATUS: - return [[PumpStatusMessage alloc] initWithData:_data]; - case MESSAGE_TYPE_DEVICE_LINK: - return [[DeviceLinkMessage alloc] initWithData:_data]; - case MESSAGE_TYPE_FIND_DEVICE: - return [[FindDeviceMessage alloc] initWithData:_data]; - } - } else if (self.packetType == PacketTypeMeter) { - return [[MeterMessage alloc] initWithData:_data]; - } - return nil; -} - - @end diff --git a/RileyLinkBLEKit/ReceivingPacketCmd.h b/RileyLinkBLEKit/ReceivingPacketCmd.h new file mode 100644 index 000000000..cfc55dd86 --- /dev/null +++ b/RileyLinkBLEKit/ReceivingPacketCmd.h @@ -0,0 +1,17 @@ +// +// ReceivingPacketCmd.h +// RileyLink +// +// Created by Pete Schwamb on 3/3/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +@import Foundation; +#import "CmdBase.h" +#import "RFPacket.h" + +@interface ReceivingPacketCmd : CmdBase + +@property (nonatomic, strong) RFPacket *receivedPacket; + +@end diff --git a/RileyLinkBLEKit/ReceivingPacketCmd.m b/RileyLinkBLEKit/ReceivingPacketCmd.m new file mode 100644 index 000000000..beb14ac03 --- /dev/null +++ b/RileyLinkBLEKit/ReceivingPacketCmd.m @@ -0,0 +1,20 @@ +// +// ReceivingPacketCmd.m +// RileyLink +// +// Created by Pete Schwamb on 3/3/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +#import "ReceivingPacketCmd.h" + +@implementation ReceivingPacketCmd + +- (RFPacket*) receivedPacket { + if (_receivedPacket == nil && self.response != nil) { + _receivedPacket = [[RFPacket alloc] initWithRFSPYResponse:self.response]; + } + return _receivedPacket; +} + +@end diff --git a/RileyLink/RileyLinkBLEDevice.h b/RileyLinkBLEKit/RileyLinkBLEDevice.h similarity index 71% rename from RileyLink/RileyLinkBLEDevice.h rename to RileyLinkBLEKit/RileyLinkBLEDevice.h index acdca409f..da1cbac29 100644 --- a/RileyLink/RileyLinkBLEDevice.h +++ b/RileyLinkBLEKit/RileyLinkBLEDevice.h @@ -22,6 +22,13 @@ typedef NS_ENUM(NSUInteger, SubgRfspyError) { SubgRfspyErrorZeroData = 0xcc }; +typedef NS_ENUM(NSUInteger, SubgRfspyVersionState) { + SubgRfspyVersionStateUnknown = 0, + SubgRfspyVersionStateUpToDate, + SubgRfspyVersionStateOutOfDate, + SubgRfspyVersionStateInvalid +}; + #define ERROR_RX_TIMEOUT 0xaa #define ERROR_CMD_INTERRUPTED 0xbb @@ -45,7 +52,12 @@ typedef NS_ENUM(NSUInteger, SubgRfspyError) { @interface RileyLinkCmdSession : NSObject -- (nonnull NSData *) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS; +/** + Runs a command synchronously. I.E. this method will not return until the command + finishes, or times out. Returns NO if the command timed out. The command's response + is set if the command did not time out. + */ +- (BOOL) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS; @end @interface RileyLinkBLEDevice : NSObject @@ -55,12 +67,18 @@ typedef NS_ENUM(NSUInteger, SubgRfspyError) { @property (nonatomic, nonnull, readonly) NSString * peripheralId; @property (nonatomic, nonnull, readonly, retain) CBPeripheral * peripheral; -@property (nonatomic, nonnull, readonly, copy) NSArray *packets; - @property (nonatomic, readonly) RileyLinkState state; @property (nonatomic, readonly, copy, nonnull) NSString * deviceURI; +@property (nonatomic, readonly, nullable) NSString *firmwareVersion; + +@property (nonatomic, readonly) SubgRfspyVersionState firmwareState; + +@property (nonatomic, readonly, nullable) NSDate *lastIdle; + +@property (nonatomic) BOOL timerTickEnabled; + /** Initializes the device with a specified peripheral @@ -70,11 +88,12 @@ typedef NS_ENUM(NSUInteger, SubgRfspyError) { */ - (nonnull instancetype)initWithPeripheral:(nonnull CBPeripheral *)peripheral NS_DESIGNATED_INITIALIZER; -- (void) didDisconnect:(nullable NSError*)error; +- (void) connectionStateDidChange:(nullable NSError *)error; - (void) runSession:(void (^ _Nonnull)(RileyLinkCmdSession* _Nonnull))proc; - (void) setCustomName:(nonnull NSString*)customName; - (void) enableIdleListeningOnChannel:(uint8_t)channel; - (void) disableIdleListening; +- (void) assertIdleListening; @end diff --git a/RileyLink/RileyLinkBLEDevice.m b/RileyLinkBLEKit/RileyLinkBLEDevice.m similarity index 77% rename from RileyLink/RileyLinkBLEDevice.m rename to RileyLinkBLEKit/RileyLinkBLEDevice.m index 7773fadf3..67aa95737 100644 --- a/RileyLink/RileyLinkBLEDevice.m +++ b/RileyLinkBLEKit/RileyLinkBLEDevice.m @@ -6,14 +6,13 @@ // Copyright (c) 2015 Pete Schwamb. All rights reserved. // -#import "MinimedPacket.h" #import "RileyLinkBLEDevice.h" #import "RileyLinkBLEManager.h" #import "NSData+Conversion.h" #import "SendAndListenCmd.h" #import "GetPacketCmd.h" #import "GetVersionCmd.h" -#import "UIAlertView+Blocks.h" +#import "RFPacket.h" // See impl at bottom of file. @@ -32,6 +31,7 @@ @interface RileyLinkBLEDevice () { NSData *endOfResponseMarker; BOOL idleListeningEnabled; uint8_t idleListenChannel; + uint16_t _idleTimeout; BOOL fetchingResponse; CmdBase *currentCommand; BOOL runningIdle; @@ -51,6 +51,8 @@ @interface RileyLinkBLEDevice () { @implementation RileyLinkBLEDevice @synthesize peripheral = _peripheral; +@synthesize lastIdle = _lastIdle; +@synthesize firmwareVersion = _firmwareVersion; - (instancetype)initWithPeripheral:(CBPeripheral *)peripheral { @@ -63,6 +65,9 @@ - (instancetype)initWithPeripheral:(CBPeripheral *)peripheral cmdDispatchGroup = dispatch_group_create(); idleDetectDispatchGroup = dispatch_group_create(); + _idleTimeout = 60 * 1000; + _timerTickEnabled = YES; + incomingPackets = [NSMutableArray array]; inBuf = [NSMutableData data]; @@ -93,34 +98,42 @@ - (NSString *)peripheralId return self.peripheral.identifier.UUIDString; } -- (NSArray*) packets { - return [NSArray arrayWithArray:incomingPackets]; +- (void)setTimerTickEnabled:(BOOL)timerTickEnabled +{ + _timerTickEnabled = timerTickEnabled; + + if (timerTickCharacteristic != nil && + timerTickCharacteristic.isNotifying != timerTickEnabled && + self.peripheral.state == CBPeripheralStateConnected) + { + [self.peripheral setNotifyValue:_timerTickEnabled + forCharacteristic:timerTickCharacteristic]; + } } - (void) runSession:(void (^ _Nonnull)(RileyLinkCmdSession* _Nonnull))proc { dispatch_group_enter(idleDetectDispatchGroup); RileyLinkCmdSession *session = [[RileyLinkCmdSession alloc] init]; session.device = self; - runningSession = YES; dispatch_async(_serialDispatchQueue, ^{ + runningSession = YES; NSLog(@"Running dispatched RL comms task"); proc(session); NSLog(@"Finished running dispatched RL comms task"); + runningSession = NO; dispatch_group_leave(idleDetectDispatchGroup); }); dispatch_group_notify(idleDetectDispatchGroup, dispatch_get_main_queue(), ^{ NSLog(@"idleDetectDispatchGroup empty"); - runningSession = NO; - if (!runningIdle) { - [self onIdle]; - } + [self assertIdleListening]; }); } -- (nonnull NSData *) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS { +- (BOOL) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS { dispatch_group_enter(cmdDispatchGroup); + BOOL timedOut = NO; currentCommand = cmd; [self issueCommand:cmd]; dispatch_time_t timeoutAt = dispatch_time(DISPATCH_TIME_NOW, timeoutMS * NSEC_PER_MSEC); @@ -129,8 +142,9 @@ - (nonnull NSData *) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeou [self.peripheral readValueForCharacteristic:dataCharacteristic]; dispatch_group_leave(cmdDispatchGroup); currentCommand = nil; + timedOut = YES; } - return cmd.response; + return !timedOut; } - (void) issueCommand:(nonnull CmdBase*)cmd { @@ -141,7 +155,7 @@ - (void) issueCommand:(nonnull CmdBase*)cmd { NSLog(@"Writing command to data characteristic: %@", [cmd.data hexadecimalString]); // 255 is the real limit (buf limit in bgscript), but we set the limit at 220, as we need room for escaping special chars. if (cmd.data.length > 220) { - NSLog(@"********** Warning: packet too large: %d bytes ************", cmd.data.length); + NSLog(@"********** Warning: packet too large: %zd bytes ************", cmd.data.length); } else { uint8_t count = cmd.data.length; NSMutableData *outBuf = [NSMutableData dataWithBytes:&count length:1]; @@ -177,7 +191,20 @@ - (RileyLinkState) state { return rval; } -- (void) didDisconnect:(NSError*)error { +- (void)connectionStateDidChange:(NSError *)error +{ + switch (self.peripheral.state) { + case CBPeripheralStateConnected: + [self assertIdleListening]; + break; + case CBPeripheralStateDisconnected: + runningIdle = NO; + runningSession = NO; + break; + case CBPeripheralStateConnecting: + case CBPeripheralStateDisconnecting: + break; + } } - (void)setCharacteristicsFromService:(CBService *)service { @@ -191,7 +218,7 @@ - (void)setCharacteristicsFromService:(CBService *)service { } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:RILEYLINK_CUSTOM_NAME_UUID]]) { customNameCharacteristic = characteristic; } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:RILEYLINK_TIMER_TICK_UUID]]) { - [self.peripheral setNotifyValue:YES forCharacteristic:characteristic]; + [self.peripheral setNotifyValue:_timerTickEnabled forCharacteristic:characteristic]; timerTickCharacteristic = characteristic; } } @@ -239,50 +266,75 @@ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForServi - (void)checkVersion { [self runSession:^(RileyLinkCmdSession * _Nonnull s) { GetVersionCmd *cmd = [[GetVersionCmd alloc] init]; - // We run two commands here, to flush out responses to any old commands - [s doCmd:cmd withTimeoutMs:1000]; - NSData *response = [s doCmd:cmd withTimeoutMs:1000]; NSString *foundVersion; BOOL versionOK = NO; - if (response && response.length > 0) { - foundVersion = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding]; + // We run two commands here, to flush out responses to any old commands + [s doCmd:cmd withTimeoutMs:1000]; + if ([s doCmd:cmd withTimeoutMs:1000]) { + foundVersion = [[NSString alloc] initWithData:cmd.response encoding:NSUTF8StringEncoding]; NSLog(@"Got version: %@", foundVersion); - NSRange range = [foundVersion rangeOfString:@"subg_rfspy"]; - if (range.location == 0 && foundVersion.length > 11) { - NSString *numberPart = [foundVersion substringFromIndex:11]; - NSArray *versionComponents = [numberPart componentsSeparatedByString:@"."]; - if (versionComponents.count > 1) { - NSInteger major = [versionComponents[0] integerValue]; - NSInteger minor = [versionComponents[1] integerValue]; - if (major == 0 && minor > 4) { - versionOK = YES; - } - } + + switch ([self firmwareStateForVersionString:foundVersion]) { + case SubgRfspyVersionStateUnknown: + case SubgRfspyVersionStateInvalid: + NSLog(@"Unable to parse version... expecting 0.x, found %@", foundVersion); + break; + case SubgRfspyVersionStateUpToDate: + versionOK = YES; + break; + case SubgRfspyVersionStateOutOfDate: + NSLog(@"The firmware version on this RileyLink is out of date. Found version\"%@\". Please use subg_rfspy version 0.7 or newer.", foundVersion); + break; } + + _firmwareVersion = foundVersion; + } else { + NSLog(@"Unable to retrieve version from RileyLink. Get version command timed out."); } + if (versionOK) { ready = YES; dispatch_async(dispatch_get_main_queue(),^{ [[NSNotificationCenter defaultCenter] postNotificationName:RILEYLINK_EVENT_DEVICE_READY object:self]; }); - } else { - dispatch_async(dispatch_get_main_queue(),^{ - NSString *msg; - if (foundVersion != nil) { - msg = [NSString stringWithFormat:@"The firmware version on this RileyLink is out of date. Found version\"%@\". Please use subg_rfspy version 0.5 or newer.", foundVersion]; - } else { - msg = @"Communication issue with RileyLink. Please power cycle the RileyLink and try again."; - } - [UIAlertView showWithTitle:@"Firmware version check failed." - message:msg - cancelButtonTitle:@"OK" - otherButtonTitles:nil - tapBlock:nil]; - }); } }]; } +- (SubgRfspyVersionState)firmwareStateForVersionString:(NSString *)firmwareVersion +{ + if (firmwareVersion == nil) { + return SubgRfspyVersionStateUnknown; + } + + NSRange range = [firmwareVersion rangeOfString:@"subg_rfspy"]; + + if (range.location == 0 && firmwareVersion.length > 11) { + NSString *numberPart = [firmwareVersion substringFromIndex:11]; + NSArray *versionComponents = [numberPart componentsSeparatedByString:@"."]; + + if (versionComponents.count > 1) { + NSInteger major = [versionComponents[0] integerValue]; + NSInteger minor = [versionComponents[1] integerValue]; + + if (major <= 0 && minor < 7) { + return SubgRfspyVersionStateOutOfDate; + } else { + return SubgRfspyVersionStateUpToDate; + } + } else { + return SubgRfspyVersionStateInvalid; + } + } else { + return SubgRfspyVersionStateInvalid; + } +} + +- (SubgRfspyVersionState)firmwareState +{ + return [self firmwareStateForVersionString:_firmwareVersion]; +} + - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if (error) { NSLog(@"Error updating %@: %@", characteristic, error); @@ -292,20 +344,19 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(C if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:RILEYLINK_DATA_UUID]]) { [self dataReceivedFromRL:characteristic.value]; - fetchingResponse = NO; } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:RILEYLINK_RESPONSE_COUNT_UUID]]) { if (!haveResponseCount) { // The first time we get a notice on this is just from connecting. haveResponseCount = YES; [self checkVersion]; } else { - const unsigned char responseCount = ((const unsigned char*)[characteristic.value bytes])[0]; + const unsigned char responseCount = ((const unsigned char*)(characteristic.value).bytes)[0]; NSLog(@"Updated response count: %d", responseCount); - fetchingResponse = YES; [peripheral readValueForCharacteristic:dataCharacteristic]; } } else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:RILEYLINK_TIMER_TICK_UUID]]) { - const unsigned char timerTick = ((const unsigned char*)[characteristic.value bytes])[0]; + const unsigned char timerTick = ((const unsigned char*)(characteristic.value).bytes)[0]; + [self assertIdleListening]; NSLog(@"Updated timer tick: %d", timerTick); } } @@ -356,7 +407,7 @@ - (void)dataReceivedFromRL:(NSData*) data { currentCommand = nil; dispatch_group_leave(cmdDispatchGroup); } else { - NSLog(@"Received data but no outstanding command!") + NSLog(@"Received data but no outstanding command!"); inBuf.length = 0; } } else { @@ -412,37 +463,48 @@ - (void) onIdle { NSLog(@"Starting idle RX"); GetPacketCmd *cmd = [[GetPacketCmd alloc] init]; cmd.listenChannel = idleListenChannel; - cmd.timeoutMS = 60 * 1000; + cmd.timeoutMS = _idleTimeout; [self issueCommand:cmd]; + + _lastIdle = [NSDate date]; } } - (void) enableIdleListeningOnChannel:(uint8_t)channel { idleListeningEnabled = YES; idleListenChannel = channel; - if (!runningIdle && !runningSession) { - [self onIdle]; - } + + [self assertIdleListening]; } - (void) disableIdleListening { idleListeningEnabled = NO; + runningIdle = NO; +} + +- (void) assertIdleListening { + if (idleListeningEnabled && !runningSession) { + NSTimeInterval resetIdleAfterInterval = 2.0 * (float)_idleTimeout / 1000.0; + + if (!runningIdle || ([NSDate dateWithTimeIntervalSinceNow:-resetIdleAfterInterval] > _lastIdle)) { + [self onIdle]; + } + } } - (void) handleIdleListenerResponse:(NSData *)response { if (response.length > 3) { // This is a response to our idle listen command - MinimedPacket *packet = [[MinimedPacket alloc] initWithData:response]; + RFPacket *packet = [[RFPacket alloc] initWithRFSPYResponse:response]; packet.capturedAt = [NSDate date]; - [incomingPackets addObject:packet]; - NSLog(@"Read packet (%d): %@", packet.rssi, packet.data.hexadecimalString); + NSLog(@"Read packet (%d): %zd bytes", packet.rssi, packet.data.length); NSDictionary *attrs = @{ @"packet": packet, @"peripheral": self.peripheral, }; [[NSNotificationCenter defaultCenter] postNotificationName:RILEYLINK_EVENT_PACKET_RECEIVED object:self userInfo:attrs]; } else if (response.length > 0) { - uint8_t errorCode = ((uint8_t*)[response bytes])[0]; + uint8_t errorCode = ((uint8_t*)response.bytes)[0]; switch (errorCode) { case SubgRfspyErrorRxTimeout: NSLog(@"Idle rx timeout"); @@ -465,7 +527,7 @@ - (void) handleIdleListenerResponse:(NSData *)response { @end @implementation RileyLinkCmdSession -- (nonnull NSData *) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS { +- (BOOL) doCmd:(nonnull CmdBase*)cmd withTimeoutMs:(NSInteger)timeoutMS { return [_device doCmd:cmd withTimeoutMs:timeoutMS]; } @end diff --git a/RileyLinkBLEKit/RileyLinkBLEKit.h b/RileyLinkBLEKit/RileyLinkBLEKit.h new file mode 100644 index 000000000..64ce668ea --- /dev/null +++ b/RileyLinkBLEKit/RileyLinkBLEKit.h @@ -0,0 +1,23 @@ +// +// RileyLinkBLEKit.h +// RileyLinkBLEKit +// +// Created by Nathan Racklyeft on 4/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +#import + +//! Project version number for RileyLinkBLEKit. +FOUNDATION_EXPORT double RileyLinkBLEKitVersionNumber; + +//! Project version string for RileyLinkBLEKit. +FOUNDATION_EXPORT const unsigned char RileyLinkBLEKitVersionString[]; + +#import +#import +#import +#import +#import +#import +#import diff --git a/RileyLink/RileyLinkBLEManager.h b/RileyLinkBLEKit/RileyLinkBLEManager.h similarity index 96% rename from RileyLink/RileyLinkBLEManager.h rename to RileyLinkBLEKit/RileyLinkBLEManager.h index 32eb15042..91f7fe85f 100644 --- a/RileyLink/RileyLinkBLEManager.h +++ b/RileyLinkBLEKit/RileyLinkBLEManager.h @@ -6,8 +6,8 @@ // Copyright (c) 2014 Pete Schwamb. All rights reserved. // -#import -#import "RileyLinkBLEDevice.h" +@import CoreBluetooth; +@import Foundation; #define RILEYLINK_EVENT_LIST_UPDATED @"RILEYLINK_EVENT_LIST_UPDATED" #define RILEYLINK_EVENT_PACKET_RECEIVED @"RILEYLINK_EVENT_PACKET_RECEIVED" diff --git a/RileyLink/RileyLinkBLEManager.m b/RileyLinkBLEKit/RileyLinkBLEManager.m similarity index 93% rename from RileyLink/RileyLinkBLEManager.m rename to RileyLinkBLEKit/RileyLinkBLEManager.m index 47eb39a31..fea63ff64 100644 --- a/RileyLink/RileyLinkBLEManager.m +++ b/RileyLinkBLEKit/RileyLinkBLEManager.m @@ -38,7 +38,7 @@ + (NSArray *)UUIDsFromUUIDStrings:(NSArray *)UUIDStrings return [NSArray arrayWithArray:UUIDs]; } -+ (instancetype)sharedManager { ++ (RileyLinkBLEManager*)sharedManager { static RileyLinkBLEManager *sharedMyRileyLink = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -79,7 +79,12 @@ - (RileyLinkBLEDevice *)addPeripheralToDeviceList:(CBPeripheral *)peripheral RSS } if ([self.autoConnectIds containsObject:d.peripheralId]) { - [self connectPeripheral:d.peripheral]; + if (peripheral.state == CBPeripheralStateConnected) { + [self centralManager:_centralManager + didConnectPeripheral:peripheral]; + } else { + [self connectPeripheral:d.peripheral]; + } } return d; @@ -143,7 +148,7 @@ - (void)disconnectPeripheral:(CBPeripheral *)peripheral } - (void)attemptReconnectForDisconnectedDevices { - for (RileyLinkBLEDevice *device in [self rileyLinkList]) { + for (RileyLinkBLEDevice *device in self.rileyLinkList) { CBPeripheral *peripheral = device.peripheral; if (peripheral.state == CBPeripheralStateDisconnected && [self.autoConnectIds containsObject:device.peripheralId]) { @@ -190,7 +195,10 @@ - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeri - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"Failed to connect to peripheral: %@", error); - + + RileyLinkBLEDevice *device = _devicesById[peripheral.identifier.UUIDString]; + [device connectionStateDidChange:error]; + [self attemptReconnectForDisconnectedDevices]; } @@ -201,7 +209,9 @@ - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPerip excludingAttributes:peripheral.services]]; RileyLinkBLEDevice *device = _devicesById[peripheral.identifier.UUIDString]; - + + [device connectionStateDidChange:nil]; + NSDictionary *attrs = @{@"peripheral": peripheral}; [[NSNotificationCenter defaultCenter] postNotificationName:RILEYLINK_EVENT_DEVICE_CONNECTED object:device userInfo:attrs]; @@ -217,7 +227,7 @@ - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPe attrs[@"peripheral"] = peripheral; RileyLinkBLEDevice *device = _devicesById[peripheral.identifier.UUIDString]; - [device didDisconnect:error]; + [device connectionStateDidChange:error]; if (error) { attrs[@"error"] = error; diff --git a/RileyLink/SendAndListenCmd.h b/RileyLinkBLEKit/SendAndListenCmd.h similarity index 77% rename from RileyLink/SendAndListenCmd.h rename to RileyLinkBLEKit/SendAndListenCmd.h index afa902bbf..1a9263f8a 100644 --- a/RileyLink/SendAndListenCmd.h +++ b/RileyLinkBLEKit/SendAndListenCmd.h @@ -6,12 +6,13 @@ // Copyright (c) 2015 Pete Schwamb. All rights reserved. // -#import -#import "CmdBase.h" +@import Foundation; +#import "ReceivingPacketCmd.h" +#import "RFPacket.h" -@interface SendAndListenCmd : CmdBase +@interface SendAndListenCmd : ReceivingPacketCmd -@property (nonatomic, strong) NSData *packet; +@property (nonatomic, strong) RFPacket *packet; @property (nonatomic, assign) uint8_t sendChannel; // In general, 0 = meter, cgm. 2 = pump @property (nonatomic, assign) uint8_t repeatCount; // 0 = no repeat, i.e. only one packet. 1 repeat = 2 packets sent total. @property (nonatomic, assign) uint8_t msBetweenPackets; diff --git a/RileyLink/SendAndListenCmd.m b/RileyLinkBLEKit/SendAndListenCmd.m similarity index 71% rename from RileyLink/SendAndListenCmd.m rename to RileyLinkBLEKit/SendAndListenCmd.m index 75e29a37a..76b5e422b 100644 --- a/RileyLink/SendAndListenCmd.m +++ b/RileyLinkBLEKit/SendAndListenCmd.m @@ -12,18 +12,20 @@ @implementation SendAndListenCmd - (NSData*)data { - uint8_t cmd[8]; + uint8_t cmd[10]; cmd[0] = RILEYLINK_CMD_SEND_AND_LISTEN; cmd[1] = _sendChannel; cmd[2] = _repeatCount; cmd[3] = _msBetweenPackets; cmd[4] = _listenChannel; - cmd[5] = _timeoutMS >> 8; - cmd[6] = _timeoutMS & 0xff; - cmd[7] = _retryCount; + cmd[5] = _timeoutMS >> 24; + cmd[6] = (_timeoutMS >> 16) & 0xff; + cmd[7] = (_timeoutMS >> 8) & 0xff; + cmd[8] = _timeoutMS & 0xff; + cmd[9] = _retryCount; - NSMutableData *serialized = [NSMutableData dataWithBytes:cmd length:8]; - [serialized appendData:_packet]; + NSMutableData *serialized = [NSMutableData dataWithBytes:cmd length:10]; + [serialized appendData:[_packet encodedData]]; uint8_t nullTerminator = 0; [serialized appendBytes:&nullTerminator length:1]; return serialized; diff --git a/RileyLink/SendPacketCmd.h b/RileyLinkBLEKit/SendPacketCmd.h similarity index 84% rename from RileyLink/SendPacketCmd.h rename to RileyLinkBLEKit/SendPacketCmd.h index 0577cbf3d..c5d50e830 100644 --- a/RileyLink/SendPacketCmd.h +++ b/RileyLinkBLEKit/SendPacketCmd.h @@ -6,12 +6,13 @@ // Copyright © 2015 Pete Schwamb. All rights reserved. // -#import +@import Foundation; #import "CmdBase.h" +#import "RFPacket.h" @interface SendPacketCmd : CmdBase -@property (nonatomic, strong) NSData *packet; +@property (nonatomic, strong) RFPacket *packet; @property (nonatomic, assign) uint8_t sendChannel; // In general, 0 = meter, cgm. 2 = pump @property (nonatomic, assign) uint8_t repeatCount; // 0 = no repeat, i.e. only one packet. 1 repeat = 2 packets sent total. @property (nonatomic, assign) uint8_t msBetweenPackets; diff --git a/RileyLink/SendPacketCmd.m b/RileyLinkBLEKit/SendPacketCmd.m similarity index 91% rename from RileyLink/SendPacketCmd.m rename to RileyLinkBLEKit/SendPacketCmd.m index fe5d165eb..f33057143 100644 --- a/RileyLink/SendPacketCmd.m +++ b/RileyLinkBLEKit/SendPacketCmd.m @@ -18,7 +18,7 @@ - (NSData*)data { cmd[3] = _msBetweenPackets; NSMutableData *serialized = [NSMutableData dataWithBytes:cmd length:4]; - [serialized appendData:_packet]; + [serialized appendData:[_packet encodedData]]; uint8_t nullTerminator = 0; [serialized appendBytes:&nullTerminator length:1]; return serialized; diff --git a/RileyLink/UpdateRegisterCmd.h b/RileyLinkBLEKit/UpdateRegisterCmd.h similarity index 100% rename from RileyLink/UpdateRegisterCmd.h rename to RileyLinkBLEKit/UpdateRegisterCmd.h diff --git a/RileyLink/UpdateRegisterCmd.m b/RileyLinkBLEKit/UpdateRegisterCmd.m similarity index 100% rename from RileyLink/UpdateRegisterCmd.m rename to RileyLinkBLEKit/UpdateRegisterCmd.m diff --git a/RileyLinkBLEKitTests/Info.plist b/RileyLinkBLEKitTests/Info.plist new file mode 100644 index 000000000..9c88642be --- /dev/null +++ b/RileyLinkBLEKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/RileyLinkBLEKitTests/RileyLinkBLEKitTests.m b/RileyLinkBLEKitTests/RileyLinkBLEKitTests.m new file mode 100644 index 000000000..8b4f228a2 --- /dev/null +++ b/RileyLinkBLEKitTests/RileyLinkBLEKitTests.m @@ -0,0 +1,44 @@ +// +// RileyLinkBLEKitTests.m +// RileyLinkBLEKitTests +// +// Created by Nathan Racklyeft on 4/8/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +#import +#import "RileyLinkBLEDevice.h" + +@interface RileyLinkBLEDevice (_Private) + +- (SubgRfspyVersionState)firmwareStateForVersionString:(NSString *)firmwareVersion; + +@end + +@interface RileyLinkBLEKitTests : XCTestCase + +@end + +@implementation RileyLinkBLEKitTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testVersionParsing { + id peripheral = nil; + + RileyLinkBLEDevice *device = [[RileyLinkBLEDevice alloc] initWithPeripheral:peripheral]; + + SubgRfspyVersionState state = [device firmwareStateForVersionString:@"subg_rfspy 0.8"]; + + XCTAssertEqual(SubgRfspyVersionStateUpToDate, state); +} + +@end diff --git a/RileyLinkKit/Either.swift b/RileyLinkKit/Either.swift new file mode 100644 index 000000000..b8f3c7537 --- /dev/null +++ b/RileyLinkKit/Either.swift @@ -0,0 +1,14 @@ +// +// Either.swift +// RileyLink +// +// Created by Pete Schwamb on 3/19/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + +public enum Either { + case Success(T1) + case Failure(T2) +} \ No newline at end of file diff --git a/RileyLinkKit/Info.plist b/RileyLinkKit/Info.plist new file mode 100644 index 000000000..6019f05bf --- /dev/null +++ b/RileyLinkKit/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/RileyLinkKit/NSTimeInterval.swift b/RileyLinkKit/NSTimeInterval.swift new file mode 100644 index 000000000..ae5d8b240 --- /dev/null +++ b/RileyLinkKit/NSTimeInterval.swift @@ -0,0 +1,28 @@ +// +// NSTimeInterval.swift +// RileyLink +// +// Created by Nathan Racklyeft on 4/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation + + +extension NSTimeInterval { + init(minutes: Double) { + self.init(minutes * 60) + } + + init(hours: Double) { + self.init(minutes: hours * 60) + } + + var minutes: Double { + return self / 60.0 + } + + var hours: Double { + return minutes / 60.0 + } +} diff --git a/RileyLinkKit/PumpOps.swift b/RileyLinkKit/PumpOps.swift new file mode 100644 index 000000000..1834edac6 --- /dev/null +++ b/RileyLinkKit/PumpOps.swift @@ -0,0 +1,168 @@ +// +// PumpOps.swift +// RileyLink +// +// Created by Pete Schwamb on 3/14/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation +import MinimedKit +import RileyLinkBLEKit + + +public class PumpOps { + + public let pumpState: PumpState + public let device: RileyLinkBLEDevice + + public init(pumpState: PumpState, device: RileyLinkBLEDevice) { + self.pumpState = pumpState + self.device = device + } + + public func pressButton() { + device.runSession { (session) -> Void in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + let message = PumpMessage(packetType: .Carelink, address: self.pumpState.pumpID, messageType: .ButtonPress, messageBody: ButtonPressCarelinkMessageBody(buttonType: .Down)) + do { + try ops.runCommandWithArguments(message) + } catch { } + } + } + + public func getPumpModel(completion: (String?) -> Void) { + device.runSession { (session) -> Void in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + let model = try? ops.getPumpModelNumber() + + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(model) + }) + } + } + + public func getBatteryVoltage(completion: (GetBatteryCarelinkMessageBody?) -> Void) { + device.runSession { (session) -> Void in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + let response: GetBatteryCarelinkMessageBody? = try? ops.getMessageBodyWithType(.GetBattery) + + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(response) + }) + } + } + + public func getHistoryEventsSinceDate(startDate: NSDate, completion: (Either<(events: [PumpEvent], pumpModel: PumpModel), ErrorType>) -> Void) { + device.runSession { (session) -> Void in + NSLog("History fetching task started.") + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + do { + let (events, pumpModel) = try ops.getHistoryEventsSinceDate(startDate) + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(.Success(events: events, pumpModel: pumpModel)) + }) + } catch let error { + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(.Failure(error)) + }) + } + } + } + + /** + Sets a bolus + + *Note: Use at your own risk!* + + This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. + + - parameter units: The number of units to deliver + - parameter completion: A closure called after the command is complete. This closure takes a single argument: + - error: An error describing why the command failed + */ + public func setNormalBolus(units: Double, completion: (error: ErrorType?) -> Void) { + device.runSession { (session) in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + + + do { + let pumpModel = try ops.getPumpModel() + + let message = PumpMessage(packetType: .Carelink, address: self.pumpState.pumpID, messageType: .Bolus, messageBody: BolusCarelinkMessageBody(units: units, strokesPerUnit: pumpModel.strokesPerUnit)) + + try ops.runCommandWithArguments(message) + + completion(error: nil) + } catch let error { + completion(error: error) + } + } + } + + /** + Changes the current temporary basal rate + + This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. + + - parameter unitsPerHour: The new basal rate, in Units per hour + - parameter duration: The duration of the rate + - parameter completion: A closure called after the command is complete. This closure takes a single Result argument: + - Success(messageBody): The pump message body describing the new basal rate + - Failure(error): An error describing why the command failed + */ + public func setTempBasal(unitsPerHour: Double, duration: NSTimeInterval, completion: (Either) -> Void) { + device.runSession { (session) in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + + do { + let response = try ops.setTempBasal(unitsPerHour, duration: duration) + completion(.Success(response)) + } catch let error { + completion(.Failure(error)) + } + } + } + + /** + Changes the pump's clock to the specified date components + + This operation is performed asynchronously and the completion will be executed on an arbitrary background queue. + + - parameter generator: A closure which returns the desired date components. An exeception is raised if the date components are not valid. + - parameter completion: A closure called after the command is complete. This closure takes a single argument: + - error: An error describing why the command failed + */ + public func setTime(generator: () -> NSDateComponents, completion: (error: ErrorType?) -> Void) { + device.runSession { (session) in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + + do { + try ops.changeTime { + PumpMessage(packetType: .Carelink, address: self.pumpState.pumpID, messageType: .ChangeTime, messageBody: ChangeTimeCarelinkMessageBody(dateComponents: generator())!) + } + completion(error: nil) + } catch let error { + completion(error: error) + } + } + } + + // TODO: Internal scope + public func tunePump(completion: (Either) -> Void) { + device.runSession { (session) -> Void in + let ops = PumpOpsSynchronous(pumpState: self.pumpState, session: session) + do { + let response = try ops.scanForPump() + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(.Success(response)) + }) + } catch let error { + dispatch_async(dispatch_get_main_queue(), { () -> Void in + completion(.Failure(error)) + }) + } + } + } + +} diff --git a/RileyLinkKit/PumpOpsSynchronous.swift b/RileyLinkKit/PumpOpsSynchronous.swift new file mode 100644 index 000000000..8eed35bd8 --- /dev/null +++ b/RileyLinkKit/PumpOpsSynchronous.swift @@ -0,0 +1,337 @@ +// +// PumpOpsSynchronous.swift +// RileyLink +// +// Created by Pete Schwamb on 3/12/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation +import MinimedKit +import RileyLinkBLEKit + + +public enum PumpCommsError: ErrorType { + case RFCommsFailure(String) + case UnknownPumpModel + case RileyLinkTimeout + case UnknownResponse(String) +} + + +class PumpOpsSynchronous { + + private static let standardPumpResponseWindow: UInt16 = 180 + private let expectedMaxBLELatencyMS = 1500 + + let pump: PumpState + let session: RileyLinkCmdSession + + init(pumpState: PumpState, session: RileyLinkCmdSession) { + self.pump = pumpState + self.session = session + } + + private func makePumpMessage(messageType: MessageType, body: MessageBody = CarelinkShortMessageBody()) -> PumpMessage { + return PumpMessage(packetType: .Carelink, address: pump.pumpID, messageType: messageType, messageBody: body) + } + + private func sendAndListen(msg: PumpMessage, timeoutMS: UInt16 = standardPumpResponseWindow, repeatCount: UInt8 = 0, msBetweenPackets: UInt8 = 0, retryCount: UInt8 = 3) throws -> PumpMessage { + let cmd = SendAndListenCmd() + cmd.packet = RFPacket(data: msg.txData) + cmd.timeoutMS = timeoutMS + cmd.repeatCount = repeatCount + cmd.msBetweenPackets = msBetweenPackets + cmd.retryCount = retryCount + cmd.listenChannel = 0 + + let totalTimeout = Int(retryCount) * Int(msBetweenPackets) + Int(timeoutMS) + expectedMaxBLELatencyMS + + guard session.doCmd(cmd, withTimeoutMs: totalTimeout) else { + throw PumpCommsError.RileyLinkTimeout + } + + guard let data = cmd.receivedPacket.data, message = PumpMessage(rxData: data) where message.address == msg.address else { + throw PumpCommsError.UnknownResponse("Sent \(msg.txData) and received \(cmd.receivedPacket.data ?? NSData())") + } + + return message + } + + private func wakeup(duration: NSTimeInterval = NSTimeInterval(minutes: 1)) throws { + guard !pump.isAwake else { + return + } + + let shortPowerMessage = makePumpMessage(.PowerOn) + let shortResponse = try sendAndListen(shortPowerMessage, timeoutMS: 15000, repeatCount: 200, msBetweenPackets: 0, retryCount: 0) + + guard shortResponse.messageType == .PumpAck else { + throw PumpCommsError.UnknownResponse("Wakeup shortResponse: \(shortResponse.txData)") + } + NSLog("Pump acknowledged wakeup!") + + let longPowerMessage = makePumpMessage(.PowerOn, body: PowerOnCarelinkMessageBody(duration: duration)) + let longResponse = try sendAndListen(longPowerMessage) + + guard longResponse.messageType == .PumpAck else { + throw PumpCommsError.UnknownResponse("Wakeup longResponse: \(longResponse.txData)") + } + + NSLog("Power on for %.0f minutes", duration.minutes) + pump.awakeUntil = NSDate(timeIntervalSinceNow: duration) + } + + internal func runCommandWithArguments(msg: PumpMessage, responseMessageType: MessageType = .PumpAck) throws -> PumpMessage { + try wakeup() + + let shortMsg = makePumpMessage(msg.messageType) + let shortResponse = try sendAndListen(shortMsg) + + guard shortResponse.messageType == .PumpAck else { + throw PumpCommsError.UnknownResponse(String(shortResponse.txData)) + } + + let response = try sendAndListen(msg) + + guard response.messageType == responseMessageType else { + throw PumpCommsError.UnknownResponse(String(response.txData)) + } + + return response + } + + internal func getPumpModelNumber() throws -> String { + let body: GetPumpModelCarelinkMessageBody = try getMessageBodyWithType(.GetPumpModel) + return body.model + } + + internal func getPumpModel() throws -> PumpModel { + guard let pumpModel = try (pump.pumpModel ?? PumpModel(rawValue: getPumpModelNumber())) else { + throw PumpCommsError.UnknownPumpModel + } + + return pumpModel + } + + internal func getMessageBodyWithType(messageType: MessageType) throws -> T { + try wakeup() + + let msg = makePumpMessage(messageType) + let response = try sendAndListen(msg) + + guard response.messageType == messageType, let body = response.messageBody as? T else { + throw PumpCommsError.UnknownResponse(String(response.txData)) + } + return body + } + + internal func setTempBasal(unitsPerHour: Double, duration: NSTimeInterval) throws -> ReadTempBasalCarelinkMessageBody { + + try wakeup() + var lastError: ErrorType? + + let changeMessage = PumpMessage(packetType: .Carelink, address: pump.pumpID, messageType: .ChangeTempBasal, messageBody: ChangeTempBasalCarelinkMessageBody(unitsPerHour: unitsPerHour, duration: duration)) + + for attempt in 0..<3 { + do { + try sendAndListen(makePumpMessage(changeMessage.messageType)) + + do { + try sendAndListen(changeMessage, retryCount: 0) + } catch { + // The pump does not ACK a temp basal. We'll check manually below if it was successful. + } + + let response: ReadTempBasalCarelinkMessageBody = try getMessageBodyWithType(.ReadTempBasal) + + if response.timeRemaining == duration && response.rateType == .Absolute { + return response + } else { + lastError = PumpCommsError.RFCommsFailure("Could not verify TempBasal on attempt \(attempt)") + } + } catch let error { + lastError = error + } + } + + throw lastError! + } + + internal func changeTime(messageGenerator: () -> PumpMessage) throws { + try wakeup() + + let shortResponse = try sendAndListen(makePumpMessage(.ChangeTime)) + + guard shortResponse.messageType == .PumpAck else { + throw PumpCommsError.UnknownResponse("changeTime shortResponse: \(shortResponse.txData)") + } + + let response = try sendAndListen(messageGenerator()) + + guard response.messageType == .PumpAck else { + throw PumpCommsError.UnknownResponse("changeTime response: \(response.txData)") + } + } + + private func updateRegister(addr: UInt8, value: UInt8) throws { + let cmd = UpdateRegisterCmd() + cmd.addr = addr; + cmd.value = value; + if !session.doCmd(cmd, withTimeoutMs: expectedMaxBLELatencyMS) { + throw PumpCommsError.RileyLinkTimeout + } + } + + private func setBaseFrequency(freqMhz: Double) throws { + let val = Int((freqMhz * 1000000)/(Double(RILEYLINK_FREQ_XTAL)/pow(2.0,16.0))) + + try updateRegister(UInt8(CC111X_REG_FREQ0), value:UInt8(val & 0xff)) + try updateRegister(UInt8(CC111X_REG_FREQ1), value:UInt8((val >> 8) & 0xff)) + try updateRegister(UInt8(CC111X_REG_FREQ2), value:UInt8((val >> 16) & 0xff)) + NSLog("Set frequency to %f", freqMhz) + } + + internal func scanForPump() throws -> FrequencyScanResults { + + let frequencies = [916.55, 916.60, 916.65, 916.70, 916.75, 916.80] + var results = FrequencyScanResults() + + do { + try wakeup() + } catch { + // Continue anyway + } + + for freq in frequencies { + let tries = 3 + var trial = FrequencyTrial() + trial.frequencyMHz = freq + try setBaseFrequency(freq) + var sumRSSI = 0 + for _ in 1...tries { + let msg = makePumpMessage(.GetPumpModel) + let cmd = SendAndListenCmd() + cmd.packet = RFPacket(data: msg.txData) + cmd.timeoutMS = self.dynamicType.standardPumpResponseWindow + if session.doCmd(cmd, withTimeoutMs: expectedMaxBLELatencyMS) { + if let data = cmd.receivedPacket.data, + let response = PumpMessage(rxData: data) where response.messageType == .GetPumpModel { + sumRSSI += Int(cmd.receivedPacket.rssi) + trial.successes += 1 + } + } else { + throw PumpCommsError.RileyLinkTimeout + } + trial.tries += 1 + } + // Mark each failure as a -99 rssi, so we can use highest rssi as best freq + sumRSSI += -99 * (trial.tries - trial.successes) + trial.avgRSSI = Double(sumRSSI) / Double(trial.tries) + results.trials.append(trial) + } + let sortedTrials = results.trials.sort({ (a, b) -> Bool in + return a.avgRSSI > b.avgRSSI + }) + if sortedTrials.first!.successes > 0 { + results.bestFrequency = sortedTrials.first!.frequencyMHz + try setBaseFrequency(results.bestFrequency) + } else { + throw PumpCommsError.RFCommsFailure("No pump responses during scan") + } + + return results + } + + internal func getHistoryEventsSinceDate(startDate: NSDate) throws -> ([PumpEvent], PumpModel) { + + do { + try wakeup() + } catch _ as PumpCommsError { + try scanForPump() + } + + let pumpModel = try getPumpModel() + + var pageNum = 0 + var events = [PumpEvent]() + while pageNum < 16 { + NSLog("Fetching page %d", pageNum) + let pageData = try getHistoryPage(pageNum) + + NSLog("Fetched page %d: %@", pageNum, pageData) + let page = try HistoryPage(pageData: pageData, pumpModel: pumpModel) + var eventIdxBeforeStartDate = -1 + for (reverseIndex, event) in page.events.reverse().enumerate() { + if event is TimestampedPumpEvent { + let event = event as! TimestampedPumpEvent + if let date = TimeFormat.timestampAsLocalDate(event.timestamp) { + if date.compare(startDate) == .OrderedAscending { + NSLog("Found event (%@) before startDate(%@)", date, startDate); + eventIdxBeforeStartDate = page.events.count - reverseIndex + break + } + } + } + } + if eventIdxBeforeStartDate >= 0 { + let slice = page.events[eventIdxBeforeStartDate..<(page.events.count)] + events.insertContentsOf(slice, at: 0) + break + } + events.insertContentsOf(page.events, at: 0) + pageNum += 1 + } + return (events, pumpModel) + } + + private func getHistoryPage(pageNum: Int) throws -> NSData { + let frameData = NSMutableData() + + let msg = makePumpMessage(.GetHistoryPage, body: GetHistoryPageCarelinkMessageBody(pageNum: pageNum)) + + guard let firstResponse = try? runCommandWithArguments(msg, responseMessageType: .GetHistoryPage) else { + throw PumpCommsError.RFCommsFailure("Pump not responding to GetHistory command") + } + + var expectedFrameNum = 1 + var curResp = firstResponse.messageBody as! GetHistoryPageCarelinkMessageBody + + while(expectedFrameNum == curResp.frameNumber) { + frameData.appendData(curResp.frame) + expectedFrameNum += 1 + let msg = makePumpMessage(.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 == .GetHistoryPage else { + throw PumpCommsError.RFCommsFailure("Bad packet type or message type. Possible interference.") + } + curResp = resp.messageBody as! GetHistoryPageCarelinkMessageBody + } else { + let cmd = SendPacketCmd() + cmd.packet = RFPacket(data: msg.txData) + session.doCmd(cmd, withTimeoutMs: expectedMaxBLELatencyMS) + break + } + } + + guard frameData.length == 1024 else { + throw PumpCommsError.RFCommsFailure("Short history page: " + String(frameData.length) + " bytes. Expected 1024") + } + return frameData + } +} + +public struct FrequencyTrial { + public var tries: Int = 0 + public var successes: Int = 0 + public var avgRSSI: Double = -99 + public var frequencyMHz: Double = 0 +} + +public struct FrequencyScanResults { + public var trials = [FrequencyTrial]() + public var bestFrequency: Double = 0 +} diff --git a/RileyLinkKit/PumpState.swift b/RileyLinkKit/PumpState.swift new file mode 100644 index 000000000..15e5398e7 --- /dev/null +++ b/RileyLinkKit/PumpState.swift @@ -0,0 +1,74 @@ +// +// PumpState.swift +// RileyLink +// +// Created by Nathan Racklyeft on 4/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation +import MinimedKit + + +public class PumpState { + + /// Posted when values of the properties of the PumpState object have changed. + /// The `userInfo` dictionary contains the following keys: `PropertyKey` and `ValueChangeOldKey` + public static let ValuesDidChangeNotification = "com.rileylink.RileyLinkKit.PumpState.ValuesDidChangeNotification" + + /// The key for a string value naming the object property whose value changed + public static let PropertyKey = "com.rileylink.RileyLinkKit.PumpState.PropertyKey" + + /// The key for the previous value of the object property whose value changed. + /// If the value type does not conform to AnyObject, a raw representation will be provided instead. + public static let ValueChangeOldKey = "com.rileylink.RileyLinkKit.PumpState.ValueChangeOldKey" + + public let pumpID: String + + public var timeZone: NSTimeZone = NSTimeZone.defaultTimeZone() { + didSet { + postChangeNotificationForKey("timeZone", oldValue: oldValue) + } + } + + public var pumpModel: PumpModel? { + didSet { + postChangeNotificationForKey("pumpModel", oldValue: oldValue?.rawValue) + } + } + + public var lastHistoryDump: NSDate? { + didSet { + postChangeNotificationForKey("lastHistoryDump", oldValue: oldValue) + } + } + + public var awakeUntil: NSDate? { + didSet { + postChangeNotificationForKey("awakeUntil", oldValue: awakeUntil) + } + } + + public init(pumpID: String) { + self.pumpID = pumpID + } + + public var isAwake: Bool { + return awakeUntil?.timeIntervalSinceNow > 0 + } + + private func postChangeNotificationForKey(key: String, oldValue: AnyObject?) { + var userInfo: [String: AnyObject] = [ + self.dynamicType.PropertyKey: key + ] + + if let oldValue = oldValue { + userInfo[self.dynamicType.ValueChangeOldKey] = oldValue + } + + NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.ValuesDidChangeNotification, + object: self, + userInfo: userInfo + ) + } +} diff --git a/RileyLinkKit/RileyLinkDevice.swift b/RileyLinkKit/RileyLinkDevice.swift new file mode 100644 index 000000000..da9fb296a --- /dev/null +++ b/RileyLinkKit/RileyLinkDevice.swift @@ -0,0 +1,126 @@ +// +// RileyLinkDevice.swift +// Naterade +// +// Created by Nathan Racklyeft on 4/10/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation +import CoreBluetooth +import MinimedKit +import RileyLinkBLEKit + + +public class RileyLinkDevice { + + enum Error: ErrorType { + case ConfigurationError + } + + public static let DidReceiveIdleMessageNotification = "com.rileylink.RileyLinkKit.RileyLinkDeviceDidReceiveIdleMessageNotification" + + public static let IdleMessageDataKey = "com.rileylink.RileyLinkKit.RileyLinkDeviceIdleMessageData" + + public internal(set) var pumpState: PumpState? + + public var lastIdle: NSDate? { + return device.lastIdle + } + + public private(set) var lastTuned: NSDate? + + public private(set) var radioFrequency: Double? + + public var firmwareVersion: String? { + return device.firmwareVersion + } + + public var name: String? { + return device.name + } + + public var RSSI: Int? { + return device.RSSI?.integerValue + } + + public var peripheral: CBPeripheral { + return device.peripheral + } + + internal init(BLEDevice: RileyLinkBLEDevice, pumpState: PumpState?) { + self.device = BLEDevice + self.pumpState = pumpState + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(receivedDeviceNotification(_:)), name: nil, object: BLEDevice) + } + + // MARK: - Device commands + + public func assertIdleListening() { + device.assertIdleListening() + } + + public func syncPumpTime(resultHandler: (ErrorType?) -> Void) { + if let ops = ops { + ops.setTime({ () -> NSDateComponents in + let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)! + return calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: NSDate()) + }, + completion: { (error) in + if error == nil { + ops.pumpState.timeZone = NSTimeZone.defaultTimeZone() + } + + resultHandler(error) + } + ) + } else { + resultHandler(Error.ConfigurationError) + } + } + + public func tunePumpWithResultHandler(resultHandler: (Either) -> Void) { + if let ops = ops { + ops.tunePump { (result) in + switch result { + case .Success(let scanResults): + self.lastTuned = NSDate() + self.radioFrequency = scanResults.bestFrequency + case .Failure: + break + } + + resultHandler(result) + } + } else { + resultHandler(.Failure(Error.ConfigurationError)) + } + } + + public var ops: PumpOps? { + if let pumpState = pumpState { + return PumpOps(pumpState: pumpState, device: device) + } else { + return nil + } + } + + // MARK: - + + internal var device: RileyLinkBLEDevice + + @objc private func receivedDeviceNotification(note: NSNotification) { + switch note.name { + case RILEYLINK_EVENT_PACKET_RECEIVED: + if let packet = note.userInfo?["packet"] as? RFPacket, pumpID = pumpState?.pumpID, data = packet.data, message = PumpMessage(rxData: data) where message.address.hexadecimalString == pumpID { + NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.DidReceiveIdleMessageNotification, object: self, userInfo: [self.dynamicType.IdleMessageDataKey: data]) + } + case RILEYLINK_EVENT_DEVICE_CONNECTED: + device.enableIdleListeningOnChannel(0) + default: + break + } + } + +} diff --git a/RileyLinkKit/RileyLinkDeviceManager.swift b/RileyLinkKit/RileyLinkDeviceManager.swift new file mode 100644 index 000000000..ca617c776 --- /dev/null +++ b/RileyLinkKit/RileyLinkDeviceManager.swift @@ -0,0 +1,106 @@ +// +// RileyLinkDeviceManager.swift +// RileyLink +// +// Created by Nathan Racklyeft on 4/10/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import Foundation +import RileyLinkBLEKit + + +public class RileyLinkDeviceManager { + + public static let DidDiscoverDeviceNotification = "com.rileylink.RileyLinkKit.DidDiscoverDeviceNotification" + + public static let ConnectionStateDidChangeNotification = "com.rileylink.RileyLinkKit.ConnectionStateDidChangeNotification" + + public static let RileyLinkDeviceKey = "com.rileylink.RileyLinkKit.RileyLinkDevice" + + public var pumpState: PumpState? { + didSet { + for device in _devices { + device.pumpState = pumpState + } + } + } + + public init(pumpState: PumpState?, autoConnectIDs: Set) { + self.pumpState = pumpState + + BLEManager.autoConnectIds = autoConnectIDs + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(discoveredBLEDevice(_:)), name: RILEYLINK_EVENT_LIST_UPDATED, object: BLEManager) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(connectionStateDidChange(_:)), name: RILEYLINK_EVENT_DEVICE_CONNECTED, object: BLEManager) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(connectionStateDidChange(_:)), name: RILEYLINK_EVENT_DEVICE_DISCONNECTED, object: BLEManager) + } + + public var deviceScanningEnabled: Bool { + get { + return BLEManager.scanningEnabled + } + set { + BLEManager.scanningEnabled = newValue + } + } + + public var timerTickEnabled = true { + didSet { + for device in _devices { + device.device.timerTickEnabled = timerTickEnabled + } + } + } + + private var _devices: [RileyLinkDevice] = [] + + public var devices: [RileyLinkDevice] { + return _devices + } + + public var firstConnectedDevice: RileyLinkDevice? { + if let index = _devices.indexOf({ $0.peripheral.state == .Connected }) { + return _devices[index] + } else { + return nil + } + } + + public func connectDevice(device: RileyLinkDevice) { + BLEManager.connectPeripheral(device.peripheral) + } + + public func disconnectDevice(device: RileyLinkDevice) { + BLEManager.disconnectPeripheral(device.peripheral) + } + + private let BLEManager = RileyLinkBLEManager() + + // MARK: - RileyLinkBLEManager + + @objc private func discoveredBLEDevice(note: NSNotification) { + if let BLEDevice = note.userInfo?["device"] as? RileyLinkBLEDevice { + BLEDevice.timerTickEnabled = timerTickEnabled + + let device = RileyLinkDevice(BLEDevice: BLEDevice, pumpState: pumpState) + + _devices.append(device) + + NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.DidDiscoverDeviceNotification, object: self, userInfo: [self.dynamicType.RileyLinkDeviceKey: device]) + + } + } + + @objc private func connectionStateDidChange(note: NSNotification) { + if let BLEDevice = note.object as? RileyLinkBLEDevice, + index = _devices.indexOf({ $0.peripheral == BLEDevice.peripheral }) { + let device = _devices[index] + + NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.ConnectionStateDidChangeNotification, object: self, userInfo: [self.dynamicType.RileyLinkDeviceKey: device]) + } + } + +} \ No newline at end of file diff --git a/RileyLinkKit/RileyLinkKit.h b/RileyLinkKit/RileyLinkKit.h new file mode 100644 index 000000000..c46804f33 --- /dev/null +++ b/RileyLinkKit/RileyLinkKit.h @@ -0,0 +1,19 @@ +// +// RileyLinkKit.h +// RileyLinkKit +// +// Created by Nathan Racklyeft on 4/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +#import + +//! Project version number for RileyLinkKit. +FOUNDATION_EXPORT double RileyLinkKitVersionNumber; + +//! Project version string for RileyLinkKit. +FOUNDATION_EXPORT const unsigned char RileyLinkKitVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/RileyLinkKitTests/Info.plist b/RileyLinkKitTests/Info.plist new file mode 100644 index 000000000..9c88642be --- /dev/null +++ b/RileyLinkKitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.2.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/RileyLinkKitTests/RileyLinkKitTests.swift b/RileyLinkKitTests/RileyLinkKitTests.swift new file mode 100644 index 000000000..37d7a1b0e --- /dev/null +++ b/RileyLinkKitTests/RileyLinkKitTests.swift @@ -0,0 +1,24 @@ +// +// RileyLinkKitTests.swift +// RileyLinkKitTests +// +// Created by Nathan Racklyeft on 4/9/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import RileyLinkKit + +class RileyLinkKitTests: 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() + } + +} diff --git a/RileyLinkTests/NightscoutPumpEventsTests.swift b/RileyLinkTests/NightscoutPumpEventsTests.swift new file mode 100644 index 000000000..c0ec2e992 --- /dev/null +++ b/RileyLinkTests/NightscoutPumpEventsTests.swift @@ -0,0 +1,54 @@ +// +// NightscoutPumpEventsTests.swift +// RileyLink +// +// Created by Pete Schwamb on 3/18/16. +// Copyright © 2016 Pete Schwamb. All rights reserved. +// + +import XCTest +@testable import MinimedKit +@testable import RileyLink + +class NightscoutPumpEventsTests: 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 testBgCheckFromMeter() { + let events: [PumpEvent] = [ + BGReceivedPumpEvent(availableData: NSData(hexadecimalString: "3f2122938d7510c527ad")!, + pumpModel: PumpModel.Model523)! + ] + let treatments = NightscoutPumpEvents.translate(events, eventSource: "testing") + XCTAssertEqual(1, treatments.count) + let bgCheck = treatments[0] as! BGCheckNightscoutTreatment + XCTAssertEqual(bgCheck.glucose, 268) + XCTAssertEqual(bgCheck.glucoseType, NightscoutTreatment.GlucoseType.Meter) + XCTAssertEqual(bgCheck.enteredBy, "testing") + XCTAssertEqual(bgCheck.units, NightscoutTreatment.Units.MGDL) + } + + func testStandaloneBolus() { + let events: [PumpEvent] = [ + BolusNormalPumpEvent(availableData: NSData(hexadecimalString: "010080008000240009a24a1510")!, + pumpModel: PumpModel.Model551)! + ] + let treatments = NightscoutPumpEvents.translate(events, eventSource: "testing") + XCTAssertEqual(1, treatments.count) + let bolus = treatments[0] as! BolusNightscoutTreatment + XCTAssertEqual(bolus.amount, 3.2) + XCTAssertEqual(bolus.bolusType, BolusNightscoutTreatment.BolusType.Normal) + XCTAssertEqual(bolus.duration, 0) + XCTAssertEqual(bolus.programmed, 3.2) + XCTAssertEqual(bolus.unabsorbed, 0.9) + } + +} diff --git a/RileyLinkTests/RileyLinkTests-Info.plist b/RileyLinkTests/RileyLinkTests-Info.plist index 169b6f710..62565e967 100644 --- a/RileyLinkTests/RileyLinkTests-Info.plist +++ b/RileyLinkTests/RileyLinkTests-Info.plist @@ -13,10 +13,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.0 + 0.2.0 CFBundleSignature ???? CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) diff --git a/RileyLinkTests/RileyLinkTests.m b/RileyLinkTests/RileyLinkTests.m index 9a48b7960..37fb70388 100644 --- a/RileyLinkTests/RileyLinkTests.m +++ b/RileyLinkTests/RileyLinkTests.m @@ -1,6 +1,6 @@ // -// GlucoseLinkTests.m -// GlucoseLinkTests +// RileyLinkTests.m +// RileyLinkTests // // Created by Pete Schwamb on 7/31/14. // Copyright (c) 2014 Pete Schwamb. All rights reserved. @@ -8,11 +8,11 @@ #import -@interface GlucoseLinkTests : XCTestCase +@interface RileyLinkTests : XCTestCase @end -@implementation GlucoseLinkTests +@implementation RileyLinkTests - (void)setUp { @@ -28,7 +28,7 @@ - (void)tearDown - (void)testExample { - XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); + XCTAssertTrue(YES); } @end diff --git a/sync_version.rb b/sync_version.rb deleted file mode 100755 index c21d39002..000000000 --- a/sync_version.rb +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env ruby - -plist_path = File.absolute_path("RileyLink/RileyLink-Info.plist") - -canonical_version = `defaults read #{plist_path} CFBundleShortVersionString`.chomp - -bundle_version = `defaults read #{plist_path} CFBundleVersion`.chomp -if bundle_version != canonical_version - puts "Updating CFBundleVersion to #{canonical_version}" - `defaults write #{plist_path} CFBundleVersion -string "#{canonical_version}"` -end - -podspec_text = File.open("RileyLink.podspec",:encoding => "UTF-8").read - -match_data = podspec_text.match(/s.version.*=.*\"([\d\.]*)\"/) - -if match_data - podspec_version = match_data[1] - if podspec_version != canonical_version - puts "Updating version in RileyLink.podspec to #{canonical_version}" - `sed -i -e 's/s\.version.*=.*$/s.version = \"#{canonical_version}\"/' RileyLink.podspec` - end -else - puts "Could not find s.version in podspec!" - exit -1 -end