Libre2 direct connectivity, just prepared, not tested at all

This commit is contained in:
Johan Degraeve 2020-08-30 09:45:31 +02:00
parent 46c0aea3ec
commit ef8f6ebbb5
19 changed files with 688 additions and 12 deletions

View File

@ -30,6 +30,13 @@
F808D2D2240329E80084B5DB /* Bubble+BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F808D2D1240329E70084B5DB /* Bubble+BluetoothPeripheral.swift */; };
F80D915C24F06A40006840B5 /* PreLibre2.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D915B24F06A40006840B5 /* PreLibre2.swift */; };
F80D916024F45EB3006840B5 /* LibreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D915F24F45EB2006840B5 /* LibreError.swift */; };
F80D916424F5B3DE006840B5 /* Libre2+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916224F5B3DE006840B5 /* Libre2+CoreDataProperties.swift */; };
F80D916524F5B3DE006840B5 /* Libre2+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916324F5B3DE006840B5 /* Libre2+CoreDataClass.swift */; };
F80D916824F7086D006840B5 /* Libre2BluetoothPeripheralViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916724F7086D006840B5 /* Libre2BluetoothPeripheralViewModel.swift */; };
F80D916B24F82913006840B5 /* CGMLibre2Transmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916A24F82913006840B5 /* CGMLibre2Transmitter.swift */; };
F80D916D24F82A17006840B5 /* CGMLibre2TransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916C24F82A17006840B5 /* CGMLibre2TransmitterDelegate.swift */; };
F80D917024F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D916F24F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift */; };
F80D917224FA9CD5006840B5 /* BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80D917124FA9CD5006840B5 /* BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift */; };
F80ED2EC236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2E9236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift */; };
F80ED2ED236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2EA236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift */; };
F80ED2EE236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2EB236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift */; };
@ -486,6 +493,14 @@
F808D2D1240329E70084B5DB /* Bubble+BluetoothPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bubble+BluetoothPeripheral.swift"; sourceTree = "<group>"; };
F80D915B24F06A40006840B5 /* PreLibre2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreLibre2.swift; sourceTree = "<group>"; };
F80D915F24F45EB2006840B5 /* LibreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreError.swift; sourceTree = "<group>"; };
F80D916124F5AA62006840B5 /* xdrip v12.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v12.xcdatamodel"; sourceTree = "<group>"; };
F80D916224F5B3DE006840B5 /* Libre2+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Libre2+CoreDataProperties.swift"; sourceTree = "<group>"; };
F80D916324F5B3DE006840B5 /* Libre2+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Libre2+CoreDataClass.swift"; sourceTree = "<group>"; };
F80D916724F7086D006840B5 /* Libre2BluetoothPeripheralViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Libre2BluetoothPeripheralViewModel.swift; sourceTree = "<group>"; };
F80D916A24F82913006840B5 /* CGMLibre2Transmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMLibre2Transmitter.swift; sourceTree = "<group>"; };
F80D916C24F82A17006840B5 /* CGMLibre2TransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMLibre2TransmitterDelegate.swift; sourceTree = "<group>"; };
F80D916F24F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Libre2+BluetoothPeripheral.swift"; sourceTree = "<group>"; };
F80D917124FA9CD5006840B5 /* BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift"; sourceTree = "<group>"; };
F80ED2E9236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackBluetoothSettingsViewModel.swift; sourceTree = "<group>"; };
F80ED2EA236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackGeneralSettingsViewModel.swift; sourceTree = "<group>"; };
F80ED2EB236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackWiFiSettingsViewModel.swift; sourceTree = "<group>"; };
@ -1122,6 +1137,7 @@
F808D2C3240323750084B5DB /* Libre */ = {
isa = PBXGroup;
children = (
F80D916624F70840006840B5 /* Libre2 */,
F816E11F24392D27009EE65B /* Droplet */,
F816E1112438A72C009EE65B /* BlueReader */,
F816E10124367389009EE65B /* GNSENtry */,
@ -1143,6 +1159,7 @@
F808D2CF240329D40084B5DB /* Libre */ = {
isa = PBXGroup;
children = (
F80D916E24F85C5A006840B5 /* Libre2 */,
F816E114243919ED009EE65B /* Droplet */,
F816E1062437E58E009EE65B /* BlueReader */,
F816E0FC24367338009EE65B /* GNSEntry */,
@ -1161,6 +1178,31 @@
path = Bubble;
sourceTree = "<group>";
};
F80D916624F70840006840B5 /* Libre2 */ = {
isa = PBXGroup;
children = (
F80D916724F7086D006840B5 /* Libre2BluetoothPeripheralViewModel.swift */,
);
path = Libre2;
sourceTree = "<group>";
};
F80D916924F828D5006840B5 /* Libre2 */ = {
isa = PBXGroup;
children = (
F80D916A24F82913006840B5 /* CGMLibre2Transmitter.swift */,
F80D916C24F82A17006840B5 /* CGMLibre2TransmitterDelegate.swift */,
);
path = Libre2;
sourceTree = "<group>";
};
F80D916E24F85C5A006840B5 /* Libre2 */ = {
isa = PBXGroup;
children = (
F80D916F24F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift */,
);
path = Libre2;
sourceTree = "<group>";
};
F80ED2E8236F68D90005C035 /* M5StackSettingsViewModels */ = {
isa = PBXGroup;
children = (
@ -1358,6 +1400,7 @@
F8297F44238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift */,
F816E12D2439E06E009EE65B /* BluetoothPeripheralManager+CGMDexcomG4TransmitterDelegate.swift */,
F825286D2443C1000067AF77 /* BluetoothPeripheralManager+CGMG6TransmitterDelegate.swift */,
F80D917124FA9CD5006840B5 /* BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift */,
);
path = BluetoothPeripheral;
sourceTree = "<group>";
@ -2007,6 +2050,8 @@
F816E11B2439243B009EE65B /* Droplet+CoreDataProperties.swift */,
F816E0F624367137009EE65B /* GNSEntry+CoreDataClass.swift */,
F816E0F424367131009EE65B /* GNSEntry+CoreDataProperties.swift */,
F80D916324F5B3DE006840B5 /* Libre2+CoreDataClass.swift */,
F80D916224F5B3DE006840B5 /* Libre2+CoreDataProperties.swift */,
F804870A2336D90200EBDDB7 /* M5Stack+CoreDataClass.swift */,
F804870B2336D90200EBDDB7 /* M5Stack+CoreDataProperties.swift */,
F8C97851242AA70C00A09483 /* MiaoMiao+CoreDataClass.swift */,
@ -2177,6 +2222,7 @@
F8F971D623A5915900C3F17D /* Libre */ = {
isa = PBXGroup;
children = (
F80D916924F828D5006840B5 /* Libre2 */,
F8F971D723A5915900C3F17D /* Droplet */,
F8F971D923A5915900C3F17D /* BlueReader */,
F8F971DB23A5915900C3F17D /* GNSEntry */,
@ -2661,6 +2707,7 @@
F8B3A84A227F090E004BA588 /* SettingsViewGeneralSettingsViewModel.swift in Sources */,
F83098FE23AD3F84005741DF /* UITabBarController.swift in Sources */,
F816E11A243923B2009EE65B /* Droplet+CoreDataClass.swift in Sources */,
F80D916D24F82A17006840B5 /* CGMLibre2TransmitterDelegate.swift in Sources */,
F816E1102437ED21009EE65B /* BluetoothPeripheralManager+CGMBlueReaderTransmitterDelegate.swift in Sources */,
F8B3A85B2280CCD1004BA588 /* AlertSettingsViewController.swift in Sources */,
F8F9722E23A5915900C3F17D /* M5StackTransmitterOpCode.swift in Sources */,
@ -2684,6 +2731,7 @@
F8DF765323E34F4500063910 /* DexcomG5+CoreDataClass.swift in Sources */,
F8F9720F23A5915900C3F17D /* NSData+CRC.swift in Sources */,
F8A1585722EDB754007F5B5D /* ConstantsCoreData.swift in Sources */,
F80D917224FA9CD5006840B5 /* BluetoothPeripheralManager+CGMLibre2TransmitterDelegate.swift in Sources */,
F821CF9022AB1068005C1E43 /* DatePickerViewData.swift in Sources */,
F8F9722623A5915900C3F17D /* BluconTransmitterOpCode.swift in Sources */,
F8025E4E21ED450300ECF0C0 /* Double.swift in Sources */,
@ -2700,6 +2748,7 @@
F8AF11FC24B27A6D00AE5BA2 /* LibreOOPWebServerResponse.swift in Sources */,
F8F9723123A5915900C3F17D /* M5StackAuthenticateTXMessage.swift in Sources */,
F8F9721223A5915900C3F17D /* FirmwareVersionTxMessage.swift in Sources */,
F80D916824F7086D006840B5 /* Libre2BluetoothPeripheralViewModel.swift in Sources */,
F867E2612252ADAB000FD265 /* Calibration+CoreDataProperties.swift in Sources */,
F8025E6B21F7CD7600ECF0C0 /* UIStoryboard.swift in Sources */,
F830991D23C2909E005741DF /* Watlaa+CoreDataProperties.swift in Sources */,
@ -2727,6 +2776,7 @@
F80859292364D61B00F3829D /* UserDefaults+charts.swift in Sources */,
F8B3A7B2226A0878004BA588 /* TextsAlerts.swift in Sources */,
F8297F46238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift in Sources */,
F80D917024F85C7A006840B5 /* Libre2+BluetoothPeripheral.swift in Sources */,
F8F9721423A5915900C3F17D /* AuthChallengeRxMessage.swift in Sources */,
F8025E5421EE8D2100ECF0C0 /* Libre1Calibrator.swift in Sources */,
F81FA00A228F53680028C70F /* TextsHomeView.swift in Sources */,
@ -2850,6 +2900,7 @@
F8F9720823A5915900C3F17D /* BatteryStatusTxMessage.swift in Sources */,
F8F9721C23A5915900C3F17D /* LibreOOPResponse.swift in Sources */,
F81F9FFC2288C7530028C70F /* NewAlertSettingsViewController.swift in Sources */,
F80D916524F5B3DE006840B5 /* Libre2+CoreDataClass.swift in Sources */,
F898EDF2234A8A0500BFB79B /* UInt8.swift in Sources */,
F8DF766423E781C100063910 /* BLEPeripheralAccessor.swift in Sources */,
F816E12124392D40009EE65B /* DropletBluetoothPeripheralViewModel.swift in Sources */,
@ -2908,7 +2959,9 @@
F816E11E24392690009EE65B /* BluetoothPeripheralManager+CGMDropletTransmitterDelegate.swift in Sources */,
F821CF6B229FC22D005C1E43 /* Endpoint.swift in Sources */,
F821CF58229BF43A005C1E43 /* AlertManager.swift in Sources */,
F80D916B24F82913006840B5 /* CGMLibre2Transmitter.swift in Sources */,
F8297F59238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift in Sources */,
F80D916424F5B3DE006840B5 /* Libre2+CoreDataProperties.swift in Sources */,
F898EDEC233F549100BFB79B /* UIBarButtonItem.swift in Sources */,
F816E0E42432A4FA009EE65B /* CGMBluconTransmitterDelegate.swift in Sources */,
F8A389CF232AE2EA0010F405 /* M5StackSettingsViewController.swift in Sources */,
@ -3402,6 +3455,7 @@
F8AC429F21B31F160078C348 /* xdrip.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
F80D916124F5AA62006840B5 /* xdrip v12.xcdatamodel */,
F8DF765123E34E6A00063910 /* xdrip v11.xcdatamodel */,
F8DF764E23DCF64F00063910 /* xdrip v10.xcdatamodel */,
F830991523C28E79005741DF /* xdrip v9.xcdatamodel */,
@ -3414,7 +3468,7 @@
F85C4A93233632EC00D6A86F /* xdrip v2.xcdatamodel */,
F8AC42A021B31F160078C348 /* xdrip.xcdatamodel */,
);
currentVersion = F8DF765123E34E6A00063910 /* xdrip v11.xcdatamodel */;
currentVersion = F80D916124F5AA62006840B5 /* xdrip v12.xcdatamodel */;
path = xdrip.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;

View File

@ -0,0 +1,15 @@
import Foundation
extension Libre2: BluetoothPeripheral {
func bluetoothPeripheralType() -> BluetoothPeripheralType {
return .Libre2Type
}
func overrideNeedsOOPWeb() -> Bool {
// for Libre 2 we decrypt the data, so the data will be processed as Libre 1, means user can choose to use oop web or not for defining slope parameters
return true
}
}

View File

@ -42,6 +42,9 @@ enum BluetoothPeripheralType: String, CaseIterable {
/// watlaa master
case WatlaaType = "Watlaa"
/// Libre 2
case Libre2Type = "Libre2"
/// - returns: the BluetoothPeripheralViewModel. If nil then there's no specific settings for the tpe of bluetoothPeripheral
func viewModel() -> BluetoothPeripheralViewModel? {
@ -84,6 +87,9 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .DexcomG6Type:
return DexcomG6BluetoothPeripheralViewModel()
case .Libre2Type:
return Libre2BluetoothPeripheralViewModel()
}
}
@ -149,6 +155,10 @@ enum BluetoothPeripheralType: String, CaseIterable {
return DexcomG4(address: address, name: name, alias: nil, nsManagedObjectContext: nsManagedObjectContext)
case .Libre2Type:
return Libre2(address: address, name: name, alias: nil, nsManagedObjectContext: nsManagedObjectContext)
}
}
@ -161,7 +171,7 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .M5StackType, .M5StickCType:
return .M5Stack
case .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type, .WatlaaType:
case .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type, .WatlaaType, .Libre2Type:
return .CGM
}
@ -173,7 +183,7 @@ enum BluetoothPeripheralType: String, CaseIterable {
switch self {
case .M5StackType, .M5StickCType, .WatlaaType, .BubbleType, .MiaoMiaoType, .GNSentryType, .BlueReaderType, .DropletType:
case .M5StackType, .M5StickCType, .WatlaaType, .BubbleType, .MiaoMiaoType, .GNSentryType, .BlueReaderType, .DropletType, .Libre2Type:
return false
case .DexcomG5Type, .BluconType, .DexcomG4Type, .DexcomG6Type:
@ -223,7 +233,7 @@ enum BluetoothPeripheralType: String, CaseIterable {
}
return nil
case .M5StackType, .M5StickCType, .WatlaaType, .BubbleType, .MiaoMiaoType, .GNSentryType, .BlueReaderType, .DropletType:
case .M5StackType, .M5StickCType, .WatlaaType, .BubbleType, .MiaoMiaoType, .GNSentryType, .BlueReaderType, .DropletType, .Libre2Type:
// no transmitter id means no validation to do
return nil
@ -253,6 +263,10 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .BubbleType, .MiaoMiaoType:
return true
case .Libre2Type:
// oop web can still be used for Libre2 because in the end the data received is Libre 1 format, we can use oop web to get slope parameters
return true
}
@ -268,7 +282,10 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .BubbleType, .MiaoMiaoType, .WatlaaType, .BluconType, .BlueReaderType, .DropletType , .GNSentryType:
return true
case .Libre2Type:
return true
}
}

View File

@ -73,6 +73,9 @@ enum CGMTransmitterType:String, CaseIterable {
/// watlaa
case watlaa = "Watlaa"
/// Libre2
case Libre2 = "Libre2"
/// what sensorType does this CGMTransmitter type support
func sensorType() -> CGMSensorType {
@ -81,7 +84,7 @@ enum CGMTransmitterType:String, CaseIterable {
case .dexcomG4, .dexcomG5, .dexcomG6 :
return .Dexcom
case .miaomiao, .Bubble, .GNSentry, .Droplet1, .blueReader, .watlaa, .Blucon :
case .miaomiao, .Bubble, .GNSentry, .Droplet1, .blueReader, .watlaa, .Blucon, .Libre2:
return .Libre
}
@ -120,6 +123,10 @@ enum CGMTransmitterType:String, CaseIterable {
case .watlaa:
return false
case .Libre2:
return true
}
}
@ -133,7 +140,7 @@ enum CGMTransmitterType:String, CaseIterable {
case .dexcomG4, .dexcomG5, .dexcomG6, .GNSentry, .Droplet1, .blueReader, .watlaa:
return true
case .miaomiao, .Bubble, .Blucon:
case .miaomiao, .Bubble, .Blucon, .Libre2:
return true
@ -171,6 +178,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .watlaa:
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelWatlaa
case .Libre2:
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelLibre2
}
}
@ -202,6 +212,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .watlaa:
return "%"
case .Libre2:
return "%"
}
}

View File

@ -0,0 +1,112 @@
import Foundation
import os
import CoreBluetooth
class CGMLibre2Transmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: - properties
/// service to be discovered
let CBUUID_Service_Libre2: String = "C97433F0-BE8F-4DC8-B6F0-5343E6100EB4"
/// receive characteristic
let CBUUID_ReceiveCharacteristic_Libre2: String = "c97433f1-be8f-4dc8-b6f0-5343e6100eb4"
/// write characteristic
let CBUUID_WriteCharacteristic_Libre2: String = "c97433f2-be8f-4dc8-b6f0-5343e6100eb4"
/// will be used to pass back bluetooth and cgm related events
private(set) weak var cgmTransmitterDelegate: CGMTransmitterDelegate?
/// CGMLibre2TransmitterDelegate
public weak var cGMLibre2TransmitterDelegate: CGMLibre2TransmitterDelegate?
/// is nonFixed enabled for the transmitter or not
private var nonFixedSlopeEnabled: Bool
/// for trace
private let log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryCGMLibre2)
/// used as parameter in call to cgmTransmitterDelegate.cgmTransmitterInfoReceived, when there's no glucosedata to send
var emptyArray: [GlucoseData] = []
// MARK: - Initialization
/// - parameters:
/// - address: if already connected before, then give here the address that was received during previous connect, if not give nil
/// - name : if already connected before, then give here the name that was received during previous connect, if not give nil
/// - bluetoothTransmitterDelegate : a bluetoothTransmitterDelegate
/// - cGMLibre2TransmitterDelegate : a CGMLibre2TransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMLibre2TransmitterDelegate : CGMLibre2TransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate, nonFixedSlopeEnabled: Bool?) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "abbott")
if let address = address {
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address, name: name)
}
// assign CGMTransmitterDelegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
// assign cGMLibre2TransmitterDelegate
self.cGMLibre2TransmitterDelegate = cGMLibre2TransmitterDelegate
// initialize nonFixedSlopeEnabled
self.nonFixedSlopeEnabled = nonFixedSlopeEnabled ?? false
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Libre2)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Libre2, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Libre2, bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
// MARK: - overriden BluetoothTransmitter functions
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
trace("in peripheral didUpdateValueFor", log: log, category: ConstantsLog.categoryCGMLibre2, 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, category: ConstantsLog.categoryCGMLibre2, type: .error)
return
}
} else {
trace(" value is nil, no further processing", log: log, category: ConstantsLog.categoryCGMLibre2, type: .error)
}
}
// MARK: CGMTransmitter protocol functions
func setNonFixedSlopeEnabled(enabled: Bool) {
nonFixedSlopeEnabled = enabled
}
/// this transmitter does not support oopWeb
func setWebOOPEnabled(enabled: Bool) {
}
func setWebOOPSite(oopWebSite: String) {}
func setWebOOPToken(oopWebToken: String) {}
func cgmTransmitterType() -> CGMTransmitterType {
return .Libre2
}
func isWebOOPEnabled() -> Bool {
return false
}
func isNonFixedSlopeEnabled() -> Bool {
return nonFixedSlopeEnabled
}
func requestNewReading() {
// not supported for blucon
}
}

View File

@ -0,0 +1,5 @@
import Foundation
protocol CGMLibre2TransmitterDelegate: AnyObject {
}

View File

@ -10,6 +10,7 @@ enum ConstantsDefaultAlertLevels {
static let defaultBatteryAlertLevelDroplet = 20
static let defaultBatteryAlertLevelBlueReader = 20
static let defaultBatteryAlertLevelWatlaa = 20
static let defaultBatteryAlertLevelLibre2 = 20
// blood glucose level alert values in mgdl
static let veryHigh = 250

View File

@ -43,6 +43,9 @@ enum ConstantsLog {
/// Blucon
static let categoryBlucon = "Blucon "
/// Libre2
static let categoryCGMLibre2 = "Libre2 "
/// core data manager
static let categoryCoreDataManager = "CoreDataManager "
@ -132,5 +135,6 @@ enum ConstantsLog {
/// trace
static let categoryTraceSettingsViewModel = "TraceSettingsViewModel"
}

View File

@ -61,6 +61,9 @@ extension BLEPeripheral {
// a BLEPeripheral should only have one of dexcomG5, watlaa, m5Stack, ...
@NSManaged public var dexcomG4: DexcomG4?
// a BLEPeripheral should only have one of dexcomG5, watlaa, m5Stack, ...
@NSManaged public var libre2: Libre2?
/// sensorSerialNumber of last sensor that was read
@NSManaged public var sensorSerialNumber: String?

View File

@ -0,0 +1,41 @@
import Foundation
import CoreData
public class Libre2: NSManagedObject {
// sensorState, not stored in coreData, will only be available after having received it from the Libre2
public var sensorState: LibreSensorState = .unknown
/// create Libre2
/// - parameters:
init(address: String, name: String, alias: String?, nsManagedObjectContext:NSManagedObjectContext) {
let entity = NSEntityDescription.entity(forEntityName: "Libre2", in: nsManagedObjectContext)!
super.init(entity: entity, insertInto: nsManagedObjectContext)
blePeripheral = BLEPeripheral(address: address, name: name, alias: nil, nsManagedObjectContext: nsManagedObjectContext)
}
/// create Libre2
/// - parameters:
init(address: String, name: String, alias: String?, timeStampLastBgReading: Date?, sensorSerialNumber: String?, webOOPEnabled: Bool, nsManagedObjectContext:NSManagedObjectContext) {
let entity = NSEntityDescription.entity(forEntityName: "Libre2", in: nsManagedObjectContext)!
super.init(entity: entity, insertInto: nsManagedObjectContext)
self.timeStampLastBgReading = timeStampLastBgReading
blePeripheral = BLEPeripheral(address: address, name: name, alias: nil, nsManagedObjectContext: nsManagedObjectContext)
blePeripheral.webOOPEnabled = webOOPEnabled
}
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
super.init(entity: entity, insertInto: context)
}
}

View File

@ -0,0 +1,16 @@
import Foundation
import CoreData
extension Libre2 {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Libre2> {
return NSFetchRequest<Libre2>(entityName: "Libre2")
}
// blePeripheral is required to conform to protocol BluetoothPeripheral
@NSManaged public var blePeripheral: BLEPeripheral
/// timestamp of last reading read with this transmitter
@NSManaged public var timeStampLastBgReading: Date?
}

View File

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>xdrip v11.xcdatamodel</string>
<string>xdrip v12.xcdatamodel</string>
</dict>
</plist>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19C57" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19G73" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AlertEntry" representedClassName=".AlertEntry" syncable="YES">
<attribute name="alertkind" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="start" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>

View File

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19G73" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AlertEntry" representedClassName=".AlertEntry" syncable="YES">
<attribute name="alertkind" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="start" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="value" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="alertType" maxCount="1" deletionRule="No Action" destinationEntity="AlertType" inverseName="alertEntries" inverseEntity="AlertType"/>
</entity>
<entity name="AlertType" representedClassName=".AlertType" syncable="YES">
<attribute name="enabled" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String"/>
<attribute name="overridemute" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="snooze" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="snoozeperiod" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="soundname" optional="YES" attributeType="String"/>
<attribute name="vibrate" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="alertEntries" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AlertEntry" inverseName="alertType" inverseEntity="AlertEntry"/>
</entity>
<entity name="BgReading" representedClassName=".BgReading" syncable="YES">
<attribute name="a" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="ageAdjustedRawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="b" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="c" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="calculatedValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="calculatedValueSlope" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="calibrationFlag" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="deviceName" optional="YES" attributeType="String"/>
<attribute name="filteredCalculatedValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="filteredData" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="hideSlope" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="id" attributeType="String"/>
<attribute name="ra" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="rawData" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="rb" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="rc" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="timeStamp" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="calibration" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Calibration" inverseName="bgreadings" inverseEntity="Calibration"/>
<relationship name="sensor" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Sensor" inverseName="readings" inverseEntity="Sensor"/>
</entity>
<entity name="BLEPeripheral" representedClassName=".BLEPeripheral" syncable="YES">
<attribute name="address" attributeType="String"/>
<attribute name="alias" optional="YES" attributeType="String"/>
<attribute name="lastConnectionStatusChangeTimeStamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="name" attributeType="String"/>
<attribute name="nonFixedSlopeEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="parameterUpdateNeededAtNextConnect" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sensorSerialNumber" optional="YES" attributeType="String"/>
<attribute name="shouldconnect" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="transmitterId" optional="YES" attributeType="String"/>
<attribute name="webOOPEnabled" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="blucon" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Blucon" inverseName="blePeripheral" inverseEntity="Blucon"/>
<relationship name="blueReader" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BlueReader" inverseName="blePeripheral" inverseEntity="BlueReader"/>
<relationship name="bubble" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Bubble" inverseName="blePeripheral" inverseEntity="Bubble"/>
<relationship name="dexcomG4" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DexcomG4" inverseName="blePeripheral" inverseEntity="DexcomG4"/>
<relationship name="dexcomG5" optional="YES" maxCount="1" deletionRule="Deny" destinationEntity="DexcomG5" inverseName="blePeripheral" inverseEntity="DexcomG5"/>
<relationship name="droplet" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Droplet" inverseName="blePeripheral" inverseEntity="Droplet"/>
<relationship name="gNSEntry" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="GNSEntry" inverseName="blePeripheral" inverseEntity="GNSEntry"/>
<relationship name="libre2" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Libre2" inverseName="blePeripheral" inverseEntity="Libre2"/>
<relationship name="m5Stack" optional="YES" maxCount="1" deletionRule="Deny" destinationEntity="M5Stack" inverseName="blePeripheral" inverseEntity="M5Stack"/>
<relationship name="miaoMiao" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MiaoMiao" inverseName="blePeripheral" inverseEntity="MiaoMiao"/>
<relationship name="watlaa" optional="YES" maxCount="1" deletionRule="Deny" destinationEntity="Watlaa" inverseName="blePeripheral" inverseEntity="Watlaa"/>
</entity>
<entity name="Blucon" representedClassName=".Blucon" syncable="YES">
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="blucon" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="BlueReader" representedClassName=".BlueReader" syncable="YES">
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="blueReader" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="Bubble" representedClassName=".Bubble" syncable="YES">
<attribute name="firmware" optional="YES" attributeType="String"/>
<attribute name="hardware" optional="YES" attributeType="String"/>
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="bubble" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="Calibration" representedClassName=".Calibration" syncable="YES">
<attribute name="adjustedRawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="bg" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="deviceName" optional="YES" attributeType="String"/>
<attribute name="distanceFromEstimate" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="estimateRawAtTimeOfCalibration" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="String"/>
<attribute name="intercept" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="possibleBad" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="rawTimeStamp" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="rawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="sensorConfidence" attributeType="Double" usesScalarValueType="YES"/>
<attribute name="slope" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="slopeConfidence" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="timeStamp" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="bgreadings" toMany="YES" deletionRule="Deny" destinationEntity="BgReading" inverseName="calibration" inverseEntity="BgReading"/>
<relationship name="sensor" maxCount="1" deletionRule="Nullify" destinationEntity="Sensor" inverseName="calibrations" inverseEntity="Sensor"/>
</entity>
<entity name="DexcomG4" representedClassName=".DexcomG4" syncable="YES">
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="dexcomG4" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="DexcomG5" representedClassName=".DexcomG5" syncable="YES">
<attribute name="batteryResist" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="batteryRuntime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="batteryStatus" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="batteryTemperature" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
<attribute name="isDexcomG6" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lastResetTimeStamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="voltageA" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="voltageB" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="blePeripheral" maxCount="1" deletionRule="Cascade" destinationEntity="BLEPeripheral" inverseName="dexcomG5" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="Droplet" representedClassName=".Droplet" syncable="YES">
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="droplet" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="GNSEntry" representedClassName=".GNSEntry" syncable="YES">
<attribute name="bootLoader" optional="YES" attributeType="String"/>
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
<attribute name="serialNumber" optional="YES" attributeType="String"/>
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="gNSEntry" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="Libre2" representedClassName=".Libre2" syncable="YES">
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="libre2" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="M5Stack" representedClassName=".M5Stack" syncable="YES">
<attribute name="backGroundColor" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="blepassword" optional="YES" attributeType="String"/>
<attribute name="brightness" optional="YES" attributeType="Integer 16" defaultValueString="100" usesScalarValueType="YES"/>
<attribute name="connectToWiFi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isM5StickC" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="rotation" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="textcolor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="blePeripheral" maxCount="1" deletionRule="Cascade" destinationEntity="BLEPeripheral" inverseName="m5Stack" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="MiaoMiao" representedClassName=".MiaoMiao" syncable="YES">
<attribute name="firmware" optional="YES" attributeType="String"/>
<attribute name="hardware" optional="YES" attributeType="String"/>
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BLEPeripheral" inverseName="miaoMiao" inverseEntity="BLEPeripheral"/>
</entity>
<entity name="Sensor" representedClassName=".Sensor" syncable="YES">
<attribute name="endDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="id" attributeType="String"/>
<attribute name="startDate" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="uploadedToNS" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="calibrations" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Calibration" inverseName="sensor" inverseEntity="Calibration"/>
<relationship name="readings" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="BgReading" inverseName="sensor" inverseEntity="BgReading"/>
</entity>
<entity name="Watlaa" representedClassName=".Watlaa" syncable="YES">
<attribute name="firmware" optional="YES" attributeType="String"/>
<attribute name="hardware" optional="YES" attributeType="String"/>
<attribute name="timeStampLastBgReading" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="blePeripheral" maxCount="1" deletionRule="Cascade" destinationEntity="BLEPeripheral" inverseName="watlaa" inverseEntity="BLEPeripheral"/>
</entity>
<elements>
<element name="AlertEntry" positionX="-648" positionY="189" width="128" height="105"/>
<element name="AlertType" positionX="-657" positionY="180" width="128" height="165"/>
<element name="BgReading" positionX="-285.87109375" positionY="31.9921875" width="128" height="330"/>
<element name="BLEPeripheral" positionX="-630" positionY="216" width="128" height="358"/>
<element name="Blucon" positionX="-657" positionY="189" width="128" height="73"/>
<element name="BlueReader" positionX="-639" positionY="207" width="128" height="58"/>
<element name="Bubble" positionX="-657" positionY="189" width="128" height="103"/>
<element name="Calibration" positionX="-859.21484375" positionY="46.21484375" width="128" height="285"/>
<element name="DexcomG4" positionX="-621" positionY="225" width="128" height="58"/>
<element name="DexcomG5" positionX="-648" positionY="198" width="128" height="193"/>
<element name="Droplet" positionX="-630" positionY="216" width="128" height="58"/>
<element name="GNSEntry" positionX="-648" positionY="198" width="128" height="118"/>
<element name="M5Stack" positionX="-657" positionY="180" width="128" height="163"/>
<element name="MiaoMiao" positionX="-657" positionY="189" width="128" height="103"/>
<element name="Sensor" positionX="-603.0859375" positionY="482.2890625" width="128" height="133"/>
<element name="Watlaa" positionX="-639" positionY="207" width="128" height="103"/>
<element name="Libre2" positionX="-648" positionY="198" width="128" height="73"/>
</elements>
</model>

View File

@ -0,0 +1,5 @@
import Foundation
extension BluetoothPeripheralManager: CGMLibre2TransmitterDelegate {
}

View File

@ -278,6 +278,34 @@ class BluetoothPeripheralManager: NSObject {
}
case .Libre2Type:
if let libre2 = blePeripheral.libre2 {
// add it to the list of bluetoothPeripherals
let index = insertInBluetoothPeripherals(bluetoothPeripheral: libre2)
if libre2.blePeripheral.shouldconnect {
// create an instance of CGMDropletTransmitter, CGMDropletTransmitter will automatically try to connect to the Bubble with the address that is stored in bubble
// add it to the array of bluetoothTransmitters
bluetoothTransmitters.insert(CGMLibre2Transmitter(address: libre2.blePeripheral.address, name: libre2.blePeripheral.name, bluetoothTransmitterDelegate: self, cGMLibre2TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate, nonFixedSlopeEnabled: libre2.blePeripheral.nonFixedSlopeEnabled), at: index)
// if Libre2Type is of type CGM, then assign the address to currentCgmTransmitterAddress, there shouldn't be any other bluetoothPeripherals of type .CGM with shouldconnect = true
if bluetoothPeripheralType.category() == .CGM {
currentCgmTransmitterAddress = blePeripheral.address
}
} else {
// bluetoothTransmitters array (which shoul dhave the same number of elements as bluetoothPeripherals) needs to have an empty row for the transmitter
bluetoothTransmitters.insert(nil, at: index)
}
}
case .DropletType:
if let droplet = blePeripheral.droplet {
@ -458,7 +486,7 @@ class BluetoothPeripheralManager: NSObject {
// no need to send reading to watlaa in master mode
break
case .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type:
case .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type, .Libre2Type:
// cgm's don't receive reading, they send it
break
@ -653,6 +681,22 @@ class BluetoothPeripheralManager: NSObject {
}
}
case .Libre2Type:
if let libre2 = bluetoothPeripheral as? Libre2 {
if let cgmTransmitterDelegate = cgmTransmitterDelegate {
newTransmitter = CGMLibre2Transmitter(address: libre2.blePeripheral.address, name: libre2.blePeripheral.name, bluetoothTransmitterDelegate: self, cGMLibre2TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate, nonFixedSlopeEnabled: libre2.blePeripheral.nonFixedSlopeEnabled)
} else {
trace("in getBluetoothTransmitter, case Libre2 but cgmTransmitterDelegate is nil, looks like a coding error ", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
}
}
}
@ -733,6 +777,11 @@ class BluetoothPeripheralManager: NSObject {
return .DexcomG4Type
}
case .Libre2Type:
if bluetoothTransmitter is CGMLibre2Transmitter {
return .Libre2Type
}
}
}
@ -828,7 +877,15 @@ class BluetoothPeripheralManager: NSObject {
}
return CGMG4xDripTransmitter(address: nil, name: nil, transmitterID: transmitterId, bluetoothTransmitterDelegate: self, cGMDexcomG4TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate)
case .Libre2Type:
guard let cgmTransmitterDelegate = cgmTransmitterDelegate else {
fatalError("in createNewTransmitter, Libre2Type, cgmTransmitterDelegate is nil")
}
return CGMLibre2Transmitter(address: nil, name: nil, bluetoothTransmitterDelegate: self, cGMLibre2TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate, nonFixedSlopeEnabled: nil)
}
}
@ -1072,7 +1129,7 @@ class BluetoothPeripheralManager: NSObject {
bluetoothPeripheral.blePeripheral.parameterUpdateNeededAtNextConnect = true
}
case .WatlaaType, .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type:
case .WatlaaType, .DexcomG5Type, .BubbleType, .MiaoMiaoType, .BluconType, .GNSentryType, .BlueReaderType, .DropletType, .DexcomG4Type, .DexcomG6Type, .Libre2Type:
// oop website and oop web token need to be checked
switch keyPathEnum {

View File

@ -441,6 +441,13 @@ class Trace {
traceInfo.appendStringAndNewLine(" batteryLevel : " + watlaa.watlaaBatteryLevel.description)
}
case .Libre2Type:
if let libre2 = blePeripheral.libre2 {
traceInfo.appendStringAndNewLine(" type = " + bluetoothPeripheralType.rawValue)
}
}
}

View File

@ -0,0 +1,154 @@
import UIKit
class Libre2BluetoothPeripheralViewModel {
/// settings specific for Libre2
private enum Settings: Int, CaseIterable {
/// battery level
case batteryLevel = 0
}
/// Libre2 settings willb be in section 0 + numberOfGeneralSections
private let sectionNumberForLibre2SpecificSettings = 0
/// reference to bluetoothPeripheralManager
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging?
/// reference to the tableView
private weak var tableView: UITableView?
/// reference to BluetoothPeripheralViewController that will own this Libre2BluetoothPeripheralViewModel - needed to present stuff etc
private weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
/// temporary reference to bluetoothPerpipheral, will be set in configure function.
private var bluetoothPeripheral: BluetoothPeripheral?
/// it's the bluetoothPeripheral as M5Stack
private var libre2: Libre2? {
get {
return bluetoothPeripheral as? Libre2
}
}
// MARK: - deinit
deinit {
// when closing the viewModel, and if there's still a bluetoothTransmitter existing, then reset the specific delegate to BluetoothPeripheralManager
guard let bluetoothPeripheralManager = bluetoothPeripheralManager else {return}
guard let libre2 = libre2 else {return}
guard let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: libre2, createANewOneIfNecesssary: false) else {return}
guard let cGMLibre2BluetoothTransmitter = blueToothTransmitter as? CGMLibre2Transmitter else {return}
cGMLibre2BluetoothTransmitter.cGMLibre2TransmitterDelegate = bluetoothPeripheralManager as! BluetoothPeripheralManager
}
}
// MARK: - conform to BluetoothPeripheralViewModel
extension Libre2BluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, onLibreSensorTypeReceived: ((LibreSensorType) -> ())?) {
// this type of transmitter does not receive libre sensor types, so the closure onLibreSensorTypeReceived does not need to be stored
self.bluetoothPeripheralManager = bluetoothPeripheralManager
self.tableView = tableView
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
self.bluetoothPeripheral = bluetoothPeripheral
if let bluetoothPeripheral = bluetoothPeripheral {
if let droplet = bluetoothPeripheral as? Libre2 {
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: droplet, createANewOneIfNecesssary: false), let cGMLibre2Transmitter = blueToothTransmitter as? CGMLibre2Transmitter {
// set CGMLibre2Transmitter delegate to self.
cGMLibre2Transmitter.cGMLibre2TransmitterDelegate = self
}
} else {
fatalError("in Libre2BluetoothPeripheralViewModel, configure. bluetoothPeripheral is not Libre2")
}
}
}
func screenTitle() -> String {
return BluetoothPeripheralType.Libre2Type.rawValue
}
func sectionTitle(forSection section: Int) -> String {
return BluetoothPeripheralType.Libre2Type.rawValue
}
func update(cell: UITableViewCell, forRow rawValue: Int, forSection section: Int, for bluetoothPeripheral: BluetoothPeripheral) {
// verify that bluetoothPeripheral is a Libre2
guard let Libre2 = bluetoothPeripheral as? Libre2 else {
fatalError("Libre2BluetoothPeripheralViewModel update, bluetoothPeripheral is not Libre2")
}
// default value for accessoryView is nil
cell.accessoryView = nil
guard let setting = Settings(rawValue: rawValue) else { fatalError("Libre2BluetoothPeripheralViewModel update, unexpected setting") }
switch setting {
case .batteryLevel:
cell.textLabel?.text = Texts_BluetoothPeripheralsView.batteryLevel
// not yet supported, can we get the battery level for Libre 2 ?
cell.detailTextLabel?.text = ""
cell.accessoryType = .none
}
}
func userDidSelectRow(withSettingRawValue rawValue: Int, forSection section: Int, for bluetoothPeripheral: BluetoothPeripheral, bluetoothPeripheralManager: BluetoothPeripheralManaging) -> SettingsSelectedRowAction {
guard let setting = Settings(rawValue: rawValue) else { fatalError("Libre2BluetoothPeripheralViewModel userDidSelectRow, unexpected setting") }
switch setting {
case .batteryLevel:
return .nothing
}
}
func numberOfSettings(inSection section: Int) -> Int {
return Settings.allCases.count
}
func numberOfSections() -> Int {
// for the moment only one specific section for DexcomG5
return 1
}
}
// MARK: - conform to CGMDropletTransmitterDelegate
extension Libre2BluetoothPeripheralViewModel: CGMLibre2TransmitterDelegate {
}

View File

@ -951,7 +951,7 @@ final class RootViewController: UIViewController {
return DexcomCalibrator()
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1, .blueReader, .watlaa:
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1, .blueReader, .watlaa, .Libre2:
if cgmTransmitter.isWebOOPEnabled() && !UserDefaults.standard.overrideWebOOPCalibration {