Droplet-1
This commit is contained in:
parent
705fa98b8b
commit
032425f733
|
@ -181,6 +181,7 @@
|
|||
F8BDD455221DEF22006EAB84 /* SettingsViews.strings in Resources */ = {isa = PBXBuildFile; fileRef = F8BDD457221DEF22006EAB84 /* SettingsViews.strings */; };
|
||||
F8C5EBE522F297F000563B5F /* SensorSerialNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5EBE422F297EF00563B5F /* SensorSerialNumber.swift */; };
|
||||
F8C5EBE722F38F0E00563B5F /* Trace.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5EBE622F38F0E00563B5F /* Trace.swift */; };
|
||||
F8C5EBEA22F49AC700563B5F /* CGMDroplet1Transmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5EBE922F49AC700563B5F /* CGMDroplet1Transmitter.swift */; };
|
||||
F8E3C3AB21FE17B700907A04 /* StringProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3C3AA21FE17B700907A04 /* StringProtocol.swift */; };
|
||||
F8E3C3AD21FE551C00907A04 /* DexcomCalibrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3C3AC21FE551C00907A04 /* DexcomCalibrator.swift */; };
|
||||
F8EA6C8221B723BC0082976B /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8EA6C8121B723BC0082976B /* Date.swift */; };
|
||||
|
@ -481,6 +482,7 @@
|
|||
F8BDD458221DEF24006EAB84 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/SettingsViews.strings; sourceTree = "<group>"; };
|
||||
F8C5EBE422F297EF00563B5F /* SensorSerialNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SensorSerialNumber.swift; sourceTree = "<group>"; };
|
||||
F8C5EBE622F38F0E00563B5F /* Trace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Trace.swift; sourceTree = "<group>"; };
|
||||
F8C5EBE922F49AC700563B5F /* CGMDroplet1Transmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMDroplet1Transmitter.swift; sourceTree = "<group>"; };
|
||||
F8E3C3AA21FE17B700907A04 /* StringProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringProtocol.swift; sourceTree = "<group>"; };
|
||||
F8E3C3AC21FE551C00907A04 /* DexcomCalibrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomCalibrator.swift; sourceTree = "<group>"; };
|
||||
F8EA6C8121B723BC0082976B /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
|
||||
|
@ -825,6 +827,7 @@
|
|||
F8A54AEC22D9156600934E7A /* Libre */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8C5EBE822F49AB300563B5F /* Droplet */,
|
||||
EE9947E622EEDD0700DCB876 /* Bubble */,
|
||||
F8A54AFB22D9179100934E7A /* Utilities */,
|
||||
F8A54AED22D9156600934E7A /* GNSEntry */,
|
||||
|
@ -1085,6 +1088,14 @@
|
|||
path = Texts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F8C5EBE822F49AB300563B5F /* Droplet */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8C5EBE922F49AC700563B5F /* CGMDroplet1Transmitter.swift */,
|
||||
);
|
||||
path = Droplet;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F8EA6C7D21B70DEA0082976B /* Constants */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1355,6 +1366,7 @@
|
|||
F8B3A7FA2278E0E8004BA588 /* SettingsViewModelProtocol.swift in Sources */,
|
||||
F85DC2F521CFE3D400B9F74A /* BgReading+CoreDataClass.swift in Sources */,
|
||||
F8A54AEA22D911BA00934E7A /* PairRequestTxMessage.swift in Sources */,
|
||||
F8C5EBEA22F49AC700563B5F /* CGMDroplet1Transmitter.swift in Sources */,
|
||||
F821CF56229BF43A005C1E43 /* AlertKind.swift in Sources */,
|
||||
F85DC2ED21CFE2F500B9F74A /* BgReading+CoreDataProperties.swift in Sources */,
|
||||
F8A54AE422D911BA00934E7A /* NSData+CRC.swift in Sources */,
|
||||
|
|
|
@ -7,6 +7,7 @@ enum ConstantsDefaultAlertLevels {
|
|||
static let defaultBatteryAlertLevelBubble = 20
|
||||
static let defaultBatteryAlertLevelGNSEntry = 20
|
||||
static let defaultBatteryAlertLevelBlucon = 20
|
||||
static let defaultBatteryAlertLevelDroplet = 20
|
||||
|
||||
// blood glucose level alert values in mgdl
|
||||
static let veryHigh = 250
|
||||
|
|
|
@ -48,5 +48,7 @@ enum ConstantsLog {
|
|||
static let categorySettingsViewHealthKitSettingsViewModel = "categorySettingsViewHealthKitSettingsViewModel"
|
||||
/// dexcom share upload manager
|
||||
static let categoryDexcomShareUploadManager = "categoryDexcomShareUploadManager"
|
||||
/// droplet 1
|
||||
static let categoryCGMDroplet1 = "categoryCGMDroplet1"
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
/// Bubble
|
||||
case Bubble = "Bubble"
|
||||
|
||||
/// Droplet
|
||||
case Droplet1 = "Droplet-1"
|
||||
|
||||
/// does the transmitter need a transmitter id ?
|
||||
///
|
||||
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
|
||||
|
@ -87,6 +90,10 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
|
||||
case .Blucon:
|
||||
return true
|
||||
|
||||
case .Droplet1:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +120,10 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
|
||||
case .Blucon:
|
||||
return true
|
||||
|
||||
case .Droplet1:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,12 +153,13 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
}
|
||||
return nil
|
||||
|
||||
case .miaomiao, .GNSentry, .Bubble:
|
||||
case .miaomiao, .GNSentry, .Bubble, .Droplet1:
|
||||
return nil
|
||||
|
||||
case .Blucon:
|
||||
// todo: validate transmitter id for blucon
|
||||
return nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,6 +185,9 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .Blucon:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelBlucon
|
||||
|
||||
case .Droplet1:
|
||||
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelDroplet
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +195,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
///
|
||||
/// for this type of devices, there's no need to give an option in the UI to manually start scanning.
|
||||
func startScanningAfterInit() -> Bool {
|
||||
|
||||
switch self {
|
||||
|
||||
case .dexcomG4:
|
||||
|
@ -196,6 +212,10 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
|
||||
case .Blucon:
|
||||
return true
|
||||
|
||||
case .Droplet1:
|
||||
return false
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,6 +223,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
///
|
||||
/// to be used for UI stuff
|
||||
func batteryUnit() -> String {
|
||||
|
||||
switch self {
|
||||
|
||||
case .dexcomG4:
|
||||
|
@ -211,7 +232,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return "voltA"
|
||||
|
||||
case .miaomiao, .Bubble:
|
||||
case .miaomiao, .Bubble, .Droplet1:
|
||||
return "%"
|
||||
|
||||
case .GNSentry:
|
||||
|
@ -226,6 +247,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
///
|
||||
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
|
||||
func resetPossible() -> Bool {
|
||||
|
||||
switch self {
|
||||
|
||||
case .dexcomG4:
|
||||
|
@ -234,7 +256,7 @@ enum CGMTransmitterType:String, CaseIterable {
|
|||
case .dexcomG5, .dexcomG6:
|
||||
return true
|
||||
|
||||
case .miaomiao, .Bubble:
|
||||
case .miaomiao, .Bubble, .Droplet1:
|
||||
return false
|
||||
|
||||
case .GNSentry:
|
||||
|
|
|
@ -3,6 +3,7 @@ import CoreBluetooth
|
|||
import os
|
||||
|
||||
class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
/// service to be discovered
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
import Foundation
|
||||
import os
|
||||
import CoreBluetooth
|
||||
|
||||
class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
/// service to be discovered
|
||||
let CBUUID_Service_Droplet: String = "C97433F0-BE8F-4DC8-B6F0-5343E6100EB4"
|
||||
|
||||
/// receive characteristic
|
||||
let CBUUID_ReceiveCharacteristic_Droplet: String = "c97433f1-be8f-4dc8-b6f0-5343e6100eb4"
|
||||
|
||||
/// write characteristic
|
||||
let CBUUID_WriteCharacteristic_Droplet: String = "c97433f2-be8f-4dc8-b6f0-5343e6100eb4"
|
||||
|
||||
/// will be used to pass back bluetooth and cgm related events
|
||||
private(set) weak var cgmTransmitterDelegate: CGMTransmitterDelegate?
|
||||
|
||||
/// for trace
|
||||
private let log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryCGMDroplet1)
|
||||
|
||||
/// used as parameter in call to cgmTransmitterDelegate.cgmTransmitterInfoReceived, when there's no glucosedata to send
|
||||
var emptyArray: [RawGlucoseData] = []
|
||||
|
||||
// MARK: - Initialization
|
||||
/// - parameters:
|
||||
/// - address: if already connected before, then give here the address that was received during previous connect, if not give nil
|
||||
init(address:String?, delegate:CGMTransmitterDelegate) {
|
||||
|
||||
// assign addressname and name or expected devicename
|
||||
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "limitter")
|
||||
if let address = address {
|
||||
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address)
|
||||
}
|
||||
|
||||
// assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Droplet)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Droplet, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Droplet, startScanningAfterInit: CGMTransmitterType.Droplet1.startScanningAfterInit())
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
trace("in peripheral didUpdateValueFor", log: log, type: .info)
|
||||
|
||||
if let value = characteristic.value {
|
||||
|
||||
guard let valueAsString = String(bytes: value, encoding: .utf8) else {
|
||||
trace(" failed to convert value to string", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
trace(" value = %{public}@", log: log, type: .info, valueAsString)
|
||||
|
||||
//find indexes of " "
|
||||
var indexesOfSplitter = valueAsString.indexes(of: " ")
|
||||
|
||||
// length of indexesOfSplitter should be minimum 3 (there should be minimum 3 spaces)
|
||||
guard indexesOfSplitter.count >= 3 else {
|
||||
trace(" there's less than 3 spaces", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// get first field
|
||||
let firstField = String(valueAsString[valueAsString.startIndex..<indexesOfSplitter[0]])
|
||||
|
||||
// if firstfield equals "000000" or "000999" then sensor detection failure - inform delegate and return
|
||||
guard firstField != "000000" && firstField != "000999" else {
|
||||
cgmTransmitterDelegate?.sensorNotDetected()
|
||||
return
|
||||
}
|
||||
|
||||
// first field : first digits are rawvalue, to be multiplied with 100, last two digits are sensor type indicator, 10=L1, 20=L2, 30=US 14 day, 40=Lpro/h
|
||||
let rawValueAsString = firstField[0..<(firstField.count - 2)] + "00"
|
||||
let sensorTypeIndicator = firstField[(firstField.count - 2)..<firstField.count]
|
||||
trace(" sensor type indicator = %{public}@", log: log, type: .info, rawValueAsString, sensorTypeIndicator)
|
||||
|
||||
// convert rawValueAsString to double and stop if this fails
|
||||
guard let rawValueAsDouble = rawValueAsString.toDouble() else {
|
||||
trace(" failed to convert rawValueAsString to double", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// third field is battery percentage, stop if convert to Int fails
|
||||
guard let batteryPercentage = Int(String(valueAsString[valueAsString.index(after: indexesOfSplitter[1])..<indexesOfSplitter[2]])) else {
|
||||
trace(" failed to convert batteryPercentage field to Int", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// fourth field is sensor time in minutes, stop if convert to Int fails
|
||||
guard let sensorTimeInMinutes = Int(String(valueAsString[valueAsString.index(after: indexesOfSplitter[2])..<valueAsString.endIndex])) else {
|
||||
trace(" failed to convert sensorTimeInMinutes field to Int", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// send to delegate
|
||||
var glucoseDataArray = [RawGlucoseData(timeStamp: Date(), glucoseLevelRaw: rawValueAsDouble)]
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &glucoseDataArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: batteryPercentage), sensorState: nil, sensorTimeInMinutes: sensorTimeInMinutes * 10, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
} else {
|
||||
trace(" value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
||||
/// to ask pairing - empty function because Bubble doesn't need pairing
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func initiatePairing() {}
|
||||
|
||||
/// to ask transmitter reset - empty function because Bubble doesn't support reset
|
||||
///
|
||||
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
|
||||
func reset(requested:Bool) {}
|
||||
|
||||
}
|
|
@ -18,6 +18,10 @@ func debuglogging(_ logtext:String) {
|
|||
/// - args : optional list of parameters that will be used. MAXIMUM 10 !
|
||||
func trace(_ message: StaticString, log:OSLog, type:OSLogType, _ args: CVarArg...) {
|
||||
|
||||
/*let message1 = message.description.replacingOccurrences(of: "{public}", with: "%").replacingOccurrences(of: "{private}", with: "%")
|
||||
let toprint = String(format: message1, "test")
|
||||
debuglogging("toprint = " + toprint)*/
|
||||
|
||||
switch args.count {
|
||||
|
||||
case 0:
|
||||
|
|
|
@ -609,6 +609,10 @@ final class RootViewController: UIViewController {
|
|||
calibrator = Libre1Calibrator()
|
||||
}
|
||||
|
||||
case .Droplet1:
|
||||
cgmTransmitter = CGMDroplet1Transmitter(address: UserDefaults.standard.bluetoothDeviceAddress, delegate: self)
|
||||
calibrator = Libre1Calibrator()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue