Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ Carthage
#

Pods/

Carthage/
.gitmodules
541 changes: 532 additions & 9 deletions CGMBLEKit.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
80 changes: 80 additions & 0 deletions CGMBLEKit.xcodeproj/xcshareddata/xcschemes/CGMBLEKitUI.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1000"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "43A8EC51210D0A7400A81379"
BuildableName = "CGMBLEKitUI.framework"
BlueprintName = "CGMBLEKitUI"
ReferencedContainer = "container:CGMBLEKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "43A8EC51210D0A7400A81379"
BuildableName = "CGMBLEKitUI.framework"
BlueprintName = "CGMBLEKitUI"
ReferencedContainer = "container:CGMBLEKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "43A8EC51210D0A7400A81379"
BuildableName = "CGMBLEKitUI.framework"
BlueprintName = "CGMBLEKitUI"
ReferencedContainer = "container:CGMBLEKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
37 changes: 37 additions & 0 deletions CGMBLEKit/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* CGM display title */
"Dexcom G5" = "Dexcom G5";

/* CGM display title */
"Dexcom G6" = "Dexcom G6";

/* Error description for unreliable state */
"Glucose data is unavailable" = "Glucose data is unavailable";

"Low Battery" = "Low Battery";

/* Describes a functioning transmitter */
"OK" = "OK";

/* Timeout error description */
"Peripheral did not respond in time" = "Peripheral did not respond in time";

/* Not ready error description */
"Peripheral isnʼt connected" = "Peripheral isnʼt connected";

/* The description of sensor calibration state when sensor calibration is ok. */
"Sensor calibration is OK" = "Sensor calibration is OK";

/* The description of sensor calibration state when raw value is unknown. (1: missing data details) */
"Sensor is in unknown state %1$d" = "Sensor is in unknown state %1$d";

/* The description of sensor calibration state when sensor sensor is stopped. */
"Sensor is stopped" = "Sensor is stopped";

/* The description of sensor calibration state when sensor sensor is warming up. */
"Sensor is warming up" = "Sensor is warming up";

/* The description of sensor calibration state when sensor needs calibration. */
"Sensor needs calibration" = "Sensor needs calibration";

/* Error description */
"Unknown characteristic" = "Unknown characteristic";
68 changes: 68 additions & 0 deletions CGMBLEKit/Glucose+SensorDisplayable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// GlucoseRxMessage.swift
// Loop
//
// Created by Nathan Racklyeft on 5/30/16.
// Copyright © 2016 Nathan Racklyeft. All rights reserved.
//

import Foundation
import LoopKit


extension Glucose: SensorDisplayable {
public var isStateValid: Bool {
return state == .known(.ok) && status == .ok
}

public var stateDescription: String {
var messages = [String]()

switch state {
case .known(.ok):
break // Suppress the "OK" message
default:
messages.append(state.localizedDescription)
}

switch self.status {
case .ok:
if messages.isEmpty {
messages.append(status.localizedDescription)
} else {
break // Suppress the "OK" message
}
case .lowBattery, .unknown:
messages.append(status.localizedDescription)
}

return messages.joined(separator: ". ")
}

public var trendType: GlucoseTrend? {
guard trend < Int(Int8.max) else {
return nil
}

switch trend {
case let x where x <= -30:
return .downDownDown
case let x where x <= -20:
return .downDown
case let x where x <= -10:
return .down
case let x where x < 10:
return .flat
case let x where x < 20:
return .up
case let x where x < 30:
return .upUp
default:
return .upUpUp
}
}

public var isLocal: Bool {
return true
}
}
11 changes: 11 additions & 0 deletions CGMBLEKit/Glucose.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public struct Glucose {
self.glucoseMessage = glucoseMessage
self.timeMessage = timeMessage
self.status = TransmitterStatus(rawValue: status)
self.activationDate = activationDate

sessionStartDate = activationDate.addingTimeInterval(TimeInterval(timeMessage.sessionStartTime))
readDate = activationDate.addingTimeInterval(TimeInterval(glucoseMessage.timestamp))
Expand All @@ -52,6 +53,7 @@ public struct Glucose {
// MARK: - Transmitter Info
public let transmitterID: String
public let status: TransmitterStatus
public let activationDate: Date
public let sessionStartDate: Date

// MARK: - Glucose Info
Expand Down Expand Up @@ -80,6 +82,15 @@ public struct Glucose {
return Int(glucoseMessage.trend)
}

public var trendRate: HKQuantity? {
guard glucoseMessage.trend < Int8.max && glucoseMessage.trend > Int8.min else {
return nil
}

let unit = HKUnit.milligramsPerDeciliterPerMinute
return HKQuantity(unit: unit, doubleValue: Double(glucoseMessage.trend) / 10)
}

// An identifier for this reading thatʼs consistent between backfill/live data
public var syncIdentifier: String {
return "\(transmitterID) \(glucoseMessage.timestamp)"
Expand Down
8 changes: 8 additions & 0 deletions CGMBLEKit/OSLog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ extension OSLog {
log(message, type: .info, args)
}

func `default`(_ message: StaticString, _ args: CVarArg...) {
log(message, type: .default, args)
}

func error(_ message: StaticString, _ args: CVarArg...) {
log(message, type: .error, args)
}
Expand All @@ -35,6 +39,10 @@ extension OSLog {
os_log(message, log: self, type: type, args[0], args[1])
case 3:
os_log(message, log: self, type: type, args[0], args[1], args[2])
case 4:
os_log(message, log: self, type: type, args[0], args[1], args[2], args[3])
case 5:
os_log(message, log: self, type: type, args[0], args[1], args[2], args[3], args[4])
default:
os_log(message, log: self, type: type, args)
}
Expand Down
6 changes: 3 additions & 3 deletions CGMBLEKit/PeripheralManagerError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ extension PeripheralManagerError: LocalizedError {
case .cbPeripheralError(let error):
return error.localizedDescription
case .notReady:
return NSLocalizedString("Peripheral isnʼt connected", comment: "Not ready error description")
return LocalizedString("Peripheral isnʼt connected", comment: "Not ready error description")
case .timeout:
return NSLocalizedString("Peripheral did not respond in time", comment: "Timeout error description")
return LocalizedString("Peripheral did not respond in time", comment: "Timeout error description")
case .unknownCharacteristic:
return NSLocalizedString("Unknown characteristic", comment: "Error description")
return LocalizedString("Unknown characteristic", comment: "Error description")
}
}

Expand Down
14 changes: 11 additions & 3 deletions CGMBLEKit/Transmitter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public final class Transmitter: BluetoothManagerDelegate {
/// The initial activation date of the transmitter
private var activationDate: Date?

/// The last-seen time message
/// The last-observed time message
private var lastTimeMessage: TransmitterTimeRxMessage? {
didSet {
if let time = lastTimeMessage {
Expand All @@ -79,6 +79,9 @@ public final class Transmitter: BluetoothManagerDelegate {
}
}

/// The last-observed calibration message
private var lastCalibrationMessage: CalibrationDataRxMessage?

/// The backfill data buffer
private var backfillBuffer: GlucoseBackfillFrameBuffer?

Expand Down Expand Up @@ -236,13 +239,12 @@ public final class Transmitter: BluetoothManagerDelegate {
let activationDate = activationDate
{
delegateQueue.async {
self.delegate?.transmitter(self, didRead: Glucose(transmitterID: self.id.id, glucoseMessage: glucoseMessage, timeMessage: timeMessage, activationDate: activationDate))
self.delegate?.transmitter(self, didRead: Glucose(transmitterID: self.id.id, glucoseMessage: glucoseMessage, timeMessage: timeMessage, calibrationMessage: self.lastCalibrationMessage, activationDate: activationDate))
}
}
case .transmitterTimeRx?:
if let timeMessage = TransmitterTimeRxMessage(data: response) {
self.lastTimeMessage = timeMessage
return
}
case .glucoseBackfillRx?:
guard let backfillMessage = GlucoseBackfillRxMessage(data: response) else {
Expand Down Expand Up @@ -287,6 +289,12 @@ public final class Transmitter: BluetoothManagerDelegate {
delegateQueue.async {
self.delegate?.transmitter(self, didReadBackfill: glucose)
}
case .calibrationDataRx?:
guard let calibrationDataMessage = CalibrationDataRxMessage(data: response) else {
break
}

lastCalibrationMessage = calibrationDataMessage
case .none:
delegateQueue.async {
self.delegate?.transmitter(self, didReadUnknownData: response)
Expand Down
Loading