resolve merge conflicts

This commit is contained in:
Johan Degraeve 2020-01-19 21:24:16 +01:00
commit fe2b988b7c
30 changed files with 1120 additions and 64 deletions

BIN
Default-568h@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -61,6 +61,16 @@
F8297F5A238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F58238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift */; };
F83098FE23AD3F84005741DF /* UITabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83098FD23AD3F84005741DF /* UITabBarController.swift */; };
F830990523B94ED7005741DF /* TimeScheduleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830990423B94ED7005741DF /* TimeScheduleViewController.swift */; };
F830991C23C2909E005741DF /* Watlaa+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830991A23C2909E005741DF /* Watlaa+CoreDataClass.swift */; };
F830991D23C2909E005741DF /* Watlaa+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830991B23C2909E005741DF /* Watlaa+CoreDataProperties.swift */; };
F830992023C291E2005741DF /* WatlaaBluetoothTransmitterMaster.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830991F23C291E2005741DF /* WatlaaBluetoothTransmitterMaster.swift */; };
F830992323C291EE005741DF /* Watlaa+BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992223C291EE005741DF /* Watlaa+BluetoothPeripheral.swift */; };
F830992623C32251005741DF /* WatlaaMasterBluetoothPeripheralViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992523C32251005741DF /* WatlaaMasterBluetoothPeripheralViewModel.swift */; };
F830992823C32A13005741DF /* TextsWatlaaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992723C32A13005741DF /* TextsWatlaaView.swift */; };
F830992A23C32A98005741DF /* WatlaaView.strings in Resources */ = {isa = PBXBuildFile; fileRef = F830992923C32A98005741DF /* WatlaaView.strings */; };
F830992C23C694F4005741DF /* WatlaaAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992B23C694F4005741DF /* WatlaaAccessor.swift */; };
F830992E23C7D756005741DF /* WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992D23C7D756005741DF /* WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift */; };
F830993023C928E0005741DF /* WatlaaBluetoothTransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F830992F23C928E0005741DF /* WatlaaBluetoothTransmitterDelegate.swift */; };
F856CE5B22EDC8E50083E436 /* ConstantsBluetoothPairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = F856CE5A22EDC8E50083E436 /* ConstantsBluetoothPairing.swift */; };
F85DC2ED21CFE2F500B9F74A /* BgReading+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2E721CFE2F500B9F74A /* BgReading+CoreDataProperties.swift */; };
F85DC2EF21CFE2F500B9F74A /* Sensor+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2E921CFE2F500B9F74A /* Sensor+CoreDataProperties.swift */; };
@ -180,6 +190,7 @@
F8BECB05235CE5D80060DAE1 /* GlucoseChartManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8BECB04235CE5D80060DAE1 /* GlucoseChartManager.swift */; };
F8BECB12235CEA9B0060DAE1 /* TimeInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8BECB11235CEA9B0060DAE1 /* TimeInterval.swift */; };
F8C5EBE722F38F0E00563B5F /* Trace.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8C5EBE622F38F0E00563B5F /* Trace.swift */; };
F8E3A2A323D4E7E200E5E98A /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F8E3A2A223D4E7E200E5E98A /* Default-568h@2x.png */; };
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 */; };
@ -311,6 +322,17 @@
F83098FD23AD3F84005741DF /* UITabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITabBarController.swift; sourceTree = "<group>"; };
F830990323B3928E005741DF /* xdrip v8.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v8.xcdatamodel"; sourceTree = "<group>"; };
F830990423B94ED7005741DF /* TimeScheduleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeScheduleViewController.swift; sourceTree = "<group>"; };
F830991523C28E79005741DF /* xdrip v9.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v9.xcdatamodel"; sourceTree = "<group>"; };
F830991A23C2909E005741DF /* Watlaa+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Watlaa+CoreDataClass.swift"; sourceTree = "<group>"; };
F830991B23C2909E005741DF /* Watlaa+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Watlaa+CoreDataProperties.swift"; sourceTree = "<group>"; };
F830991F23C291E2005741DF /* WatlaaBluetoothTransmitterMaster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WatlaaBluetoothTransmitterMaster.swift; sourceTree = "<group>"; };
F830992223C291EE005741DF /* Watlaa+BluetoothPeripheral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Watlaa+BluetoothPeripheral.swift"; sourceTree = "<group>"; };
F830992523C32251005741DF /* WatlaaMasterBluetoothPeripheralViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatlaaMasterBluetoothPeripheralViewModel.swift; sourceTree = "<group>"; };
F830992723C32A13005741DF /* TextsWatlaaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextsWatlaaView.swift; sourceTree = "<group>"; };
F830992923C32A98005741DF /* WatlaaView.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = WatlaaView.strings; sourceTree = "<group>"; };
F830992B23C694F4005741DF /* WatlaaAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatlaaAccessor.swift; sourceTree = "<group>"; };
F830992D23C7D756005741DF /* WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift"; sourceTree = "<group>"; };
F830992F23C928E0005741DF /* WatlaaBluetoothTransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatlaaBluetoothTransmitterDelegate.swift; sourceTree = "<group>"; };
F846CDD523046BAC00DCF016 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/SettingsViews.strings"; sourceTree = "<group>"; };
F846CDD623046BAE00DCF016 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/SettingsViews.strings; sourceTree = "<group>"; };
F856CE5A22EDC8E50083E436 /* ConstantsBluetoothPairing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsBluetoothPairing.swift; sourceTree = "<group>"; };
@ -575,6 +597,7 @@
F8C5EBE622F38F0E00563B5F /* Trace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Trace.swift; sourceTree = "<group>"; };
F8C5EBED22F5A52400563B5F /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Common.strings"; sourceTree = "<group>"; };
F8C5EBEE22F5A52800563B5F /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Common.strings; sourceTree = "<group>"; };
F8E3A2A223D4E7E200E5E98A /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; 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>"; };
@ -883,6 +906,32 @@
path = BluetoothPeripheralViewController;
sourceTree = "<group>";
};
F830991E23C291E2005741DF /* watlaa */ = {
isa = PBXGroup;
children = (
F830991F23C291E2005741DF /* WatlaaBluetoothTransmitterMaster.swift */,
F830992D23C7D756005741DF /* WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift */,
F830992F23C928E0005741DF /* WatlaaBluetoothTransmitterDelegate.swift */,
);
path = watlaa;
sourceTree = "<group>";
};
F830992123C291EE005741DF /* watlaa */ = {
isa = PBXGroup;
children = (
F830992223C291EE005741DF /* Watlaa+BluetoothPeripheral.swift */,
);
path = watlaa;
sourceTree = "<group>";
};
F830992423C32226005741DF /* watlaa */ = {
isa = PBXGroup;
children = (
F830992523C32251005741DF /* WatlaaMasterBluetoothPeripheralViewModel.swift */,
);
path = watlaa;
sourceTree = "<group>";
};
F85DC29B21CFCEB800B9F74A /* Recovered References */ = {
isa = PBXGroup;
children = (
@ -926,6 +975,7 @@
F8BDD457221DEF22006EAB84 /* SettingsViews.strings */,
F8B48A9A22B2FA66009BCC01 /* SpeakReading.strings */,
F869188F23A155100065B607 /* BluetoothPeripheralView.strings */,
F830992923C32A98005741DF /* WatlaaView.strings */,
);
path = Storyboards;
sourceTree = "<group>";
@ -961,6 +1011,7 @@
F8AC425121ADEBD60078C348 = {
isa = PBXGroup;
children = (
F8E3A2A223D4E7E200E5E98A /* Default-568h@2x.png */,
F8AC425B21ADEBD60078C348 /* Products */,
F8AC425C21ADEBD60078C348 /* xdrip */,
F85DC29B21CFCEB800B9F74A /* Recovered References */,
@ -1065,6 +1116,7 @@
F8B3A819227DEC92004BA588 /* README.md */,
F8B3A815227DEC91004BA588 /* SensorsAccessor.swift */,
F8F6226F233AA3B200BE8796 /* M5StackAccessor.swift */,
F830992B23C694F4005741DF /* WatlaaAccessor.swift */,
);
path = accessors;
sourceTree = "<group>";
@ -1178,6 +1230,7 @@
F8BDD451221DEAB1006EAB84 /* TextsSettingsView.swift */,
F8B48A9322B2A705009BCC01 /* TextsSpeakReading.swift */,
F869188B23A044340065B607 /* TextsM5StackView.swift */,
F830992723C32A13005741DF /* TextsWatlaaView.swift */,
);
path = Texts;
sourceTree = "<group>";
@ -1243,6 +1296,8 @@
F8EA6CA421B9A25B0082976B /* classes */ = {
isa = PBXGroup;
children = (
F830991A23C2909E005741DF /* Watlaa+CoreDataClass.swift */,
F830991B23C2909E005741DF /* Watlaa+CoreDataProperties.swift */,
F8B3A79122635A25004BA588 /* AlertEntry+CoreDataClass.swift */,
F8B3A79222635A25004BA588 /* AlertEntry+CoreDataProperties.swift */,
F8B3A78C22622953004BA588 /* AlertType+CoreDataClass.swift */,
@ -1274,6 +1329,7 @@
F8F971AD23A5914C00C3F17D /* BluetoothPeripheral */ = {
isa = PBXGroup;
children = (
F830992123C291EE005741DF /* watlaa */,
F8F971AE23A5914C00C3F17D /* CGM */,
F8F971AF23A5914C00C3F17D /* M5 */,
F8F971B323A5914C00C3F17D /* Generic */,
@ -1326,6 +1382,7 @@
F8F971B923A5915900C3F17D /* BluetoothTransmitter */ = {
isa = PBXGroup;
children = (
F830991E23C291E2005741DF /* watlaa */,
F8F971BA23A5915900C3F17D /* CGM */,
F8F971F523A5915900C3F17D /* M5Stack */,
F8F971FF23A5915900C3F17D /* Generic */,
@ -1500,10 +1557,10 @@
isa = PBXGroup;
children = (
F8F971F623A5915900C3F17D /* M5StackBluetoothTransmitter.swift */,
F8F971FE23A5915900C3F17D /* M5StackBluetoothTransmitterDelegate.swift */,
F8F971FB23A5915900C3F17D /* M5StackMessages */,
F8F971F723A5915900C3F17D /* M5StackTransmitterOpCode.swift */,
F8F971F823A5915900C3F17D /* Utilities */,
F8F971FB23A5915900C3F17D /* M5StackMessages */,
F8F971FE23A5915900C3F17D /* M5StackBluetoothTransmitterDelegate.swift */,
);
path = M5Stack;
sourceTree = "<group>";
@ -1538,6 +1595,7 @@
F8F9723623A5928D00C3F17D /* Models */ = {
isa = PBXGroup;
children = (
F830992423C32226005741DF /* watlaa */,
F8F9723A23A5934300C3F17D /* M5StickC */,
F8F9723723A5928D00C3F17D /* M5Stack */,
);
@ -1645,6 +1703,8 @@
F869189023A155100065B607 /* BluetoothPeripheralView.strings in Resources */,
F8BDD442221C9D0D006EAB84 /* Common.strings in Resources */,
F8AC426A21ADEBD70078C348 /* LaunchScreen.storyboard in Resources */,
F8E3A2A323D4E7E200E5E98A /* Default-568h@2x.png in Resources */,
F830992A23C32A98005741DF /* WatlaaView.strings in Resources */,
F8BDD438221A0349006EAB84 /* Localizable.strings in Resources */,
F8B3A786225D4473004BA588 /* NightScoutTestResult.strings in Resources */,
F8B48AA022B2FA7B009BCC01 /* HomeView.strings in Resources */,
@ -1783,6 +1843,7 @@
F8F9721223A5915900C3F17D /* FirmwareVersionTxMessage.swift in Sources */,
F867E2612252ADAB000FD265 /* Calibration+CoreDataProperties.swift in Sources */,
F8025E6B21F7CD7600ECF0C0 /* UIStoryboard.swift in Sources */,
F830991D23C2909E005741DF /* Watlaa+CoreDataProperties.swift in Sources */,
F8F9721623A5915900C3F17D /* CGMG4xDripTransmitter.swift in Sources */,
F821CF8122A5C814005C1E43 /* RepeatingTimer.swift in Sources */,
F8F9722223A5915900C3F17D /* CRC.swift in Sources */,
@ -1802,6 +1863,7 @@
F8B3A7B2226A0878004BA588 /* TextsAlerts.swift in Sources */,
F8297F46238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift in Sources */,
F8F9721423A5915900C3F17D /* AuthChallengeRxMessage.swift in Sources */,
F830992623C32251005741DF /* WatlaaMasterBluetoothPeripheralViewModel.swift in Sources */,
F8025E5421EE8D2100ECF0C0 /* Libre1Calibrator.swift in Sources */,
F81FA00A228F53680028C70F /* TextsHomeView.swift in Sources */,
F8E3C3AD21FE551C00907A04 /* DexcomCalibrator.swift in Sources */,
@ -1813,8 +1875,11 @@
F8A1585522EDB706007F5B5D /* ConstantsCalibrationAlgorithms.swift in Sources */,
F897AAF92200F2D200CDDD10 /* CBPeripheralState.swift in Sources */,
F8F971B623A5914D00C3F17D /* M5Stack+BluetoothPeripheral.swift in Sources */,
F830992323C291EE005741DF /* Watlaa+BluetoothPeripheral.swift in Sources */,
F821CF57229BF43A005C1E43 /* SnoozeParameters.swift in Sources */,
F830992823C32A13005741DF /* TextsWatlaaView.swift in Sources */,
F8B3A79722635A25004BA588 /* AlertEntry+CoreDataProperties.swift in Sources */,
F830992023C291E2005741DF /* WatlaaBluetoothTransmitterMaster.swift in Sources */,
F8F971B723A5914D00C3F17D /* BluetoothPeripheralType.swift in Sources */,
F80610C4222D4E4D00D8F236 /* ActionClosureable-extension.swift in Sources */,
F8B3A835227F08AC004BA588 /* PickerViewController.swift in Sources */,
@ -1836,6 +1901,7 @@
F8F9722523A5915900C3F17D /* LibreRawGlucoseData.swift in Sources */,
F8B3A830227F085A004BA588 /* SettingsTableViewCell.swift in Sources */,
F8F62270233AA3B200BE8796 /* M5StackAccessor.swift in Sources */,
F830991C23C2909E005741DF /* Watlaa+CoreDataClass.swift in Sources */,
F8A1586122EDB844007F5B5D /* ConstantsNotifications.swift in Sources */,
F8F9720423A5915900C3F17D /* TransmitterVersionTxMessage.swift in Sources */,
F8F9720323A5915900C3F17D /* CGMG5Transmitter.swift in Sources */,
@ -1867,6 +1933,7 @@
F8A1586722EDB8BF007F5B5D /* ConstantsHomeView.swift in Sources */,
F8A1585922EDB7C6007F5B5D /* ConstantsDefaultAlertLevels.swift in Sources */,
F8A54AAD22D6859200934E7A /* SlopeParameters.swift in Sources */,
F830993023C928E0005741DF /* WatlaaBluetoothTransmitterDelegate.swift in Sources */,
F8B3A783225D37F2004BA588 /* TextsNightScoutTestResult.swift in Sources */,
F8025C0A21D94FD700ECF0C0 /* CBManagerState.swift in Sources */,
F8F9722723A5915900C3F17D /* CGMBluconTransmitter.swift in Sources */,
@ -1874,6 +1941,7 @@
F8F9721823A5915900C3F17D /* CGMBlueReaderTransmitter.swift in Sources */,
F8A1586D22EDB9BE007F5B5D /* ConstantsDexcomFollower.swift in Sources */,
F8F9720923A5915900C3F17D /* AESCrypt.m in Sources */,
F830992E23C7D756005741DF /* WatlaaBluetoothTransmitterMaster+CGMTransmitter.swift in Sources */,
F80ED2ED236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift in Sources */,
F8B3A850227F26F8004BA588 /* AlertTypesSettingsViewController.swift in Sources */,
F8B3A808227A2933004BA588 /* SettingsSelectedRowAction.swift in Sources */,
@ -1905,6 +1973,7 @@
F8B3A84C227F090E004BA588 /* SettingsViewController.swift in Sources */,
F8EEDD5222FECE3800D2D610 /* ConstantsLibreOOP.swift in Sources */,
F8F9720B23A5915900C3F17D /* SensorDataRxMessage.swift in Sources */,
F830992C23C694F4005741DF /* WatlaaAccessor.swift in Sources */,
F8AC426021ADEBD60078C348 /* RootViewController.swift in Sources */,
F8B3A78B225D473D004BA588 /* UIAlertController.swift in Sources */,
F8F9720E23A5915900C3F17D /* AuthRequestRxMessage.swift in Sources */,
@ -2430,6 +2499,7 @@
F8AC429F21B31F160078C348 /* xdrip.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
F830991523C28E79005741DF /* xdrip v9.xcdatamodel */,
F830990323B3928E005741DF /* xdrip v8.xcdatamodel */,
F8F9724523A699CE00C3F17D /* xdrip v7.xcdatamodel */,
F8EBB030239701DA0058B0D4 /* xdrip v6.xcdatamodel */,
@ -2439,7 +2509,7 @@
F85C4A93233632EC00D6A86F /* xdrip v2.xcdatamodel */,
F8AC42A021B31F160078C348 /* xdrip.xcdatamodel */,
);
currentVersion = F830990323B3928E005741DF /* xdrip v8.xcdatamodel */;
currentVersion = F830991523C28E79005741DF /* xdrip v9.xcdatamodel */;
path = xdrip.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;

View File

@ -6,6 +6,9 @@ enum BluetoothPeripheralCategory: String, CaseIterable {
/// this is the category for M5Stack ad M5StickC
case M5Stack = "M5Stack"
/// category for watlaa, master and follower
case watlaa = "watlaa"
/// gets list of categories in array of strings, user will see those strings when selecting a category
static func listOfCategories() -> [String] {

View File

@ -13,6 +13,9 @@ enum BluetoothPeripheralType: String, CaseIterable {
/// M5StickC
case M5StickCType = "M5StickC"
/// watlaa master
case watlaaMaster = "Watlaa master"
/// - returns: the BluetoothPeripheralViewModel
func viewModel() -> BluetoothPeripheralViewModel {
@ -24,6 +27,8 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .M5StickCType:
return M5StickCBluetoothPeripheralViewModel()
case .watlaaMaster:
return WatlaaMasterBluetoothPeripheralViewModel()
}
}
@ -47,6 +52,12 @@ enum BluetoothPeripheralType: String, CaseIterable {
return newM5StickC
case .watlaaMaster:
let newWatlaa = Watlaa(address: address, name: name, alias: nil, nsManagedObjectContext: nsManagedObjectContext)
return newWatlaa
}
@ -61,6 +72,10 @@ enum BluetoothPeripheralType: String, CaseIterable {
case .M5StickCType:
return .M5Stack
case .watlaaMaster:
return .watlaa
}
}

View File

@ -0,0 +1,50 @@
import Foundation
extension Watlaa: BluetoothPeripheral {
func getDeviceName() -> String {
return name
}
func bluetoothPeripheralType() -> BluetoothPeripheralType {
return .watlaaMaster
}
func getAddress() -> String {
return address
}
func getAlias() -> String? {
return alias
}
func setAlias(_ value: String?) {
alias = value
}
func dontTryToConnectToThisBluetoothPeripheral() {
shouldconnect = false
}
func alwaysTryToConnectToThisBluetoothPeripheral() {
shouldconnect = true
}
func shouldXdripTryToConnectToThisBluetoothPeripheral() -> Bool {
return shouldconnect
}
func parameterUpdateNotNeededAtNextConnect() {
parameterUpdateNeeded = false
}
func parameterUpdateNeededAtNextConnect() {
parameterUpdateNeeded = true
}
func isParameterUpdateNeededAtNextConnect() -> Bool {
return parameterUpdateNeeded
}
}

View File

@ -6,7 +6,7 @@ import CoreBluetooth
/// Most of the functions are already defined by BlueToothTransmitter.swift - so most of these functions don't need re-implementation in CGMTransmitter classes that conform to this protocol.
///
/// An exception is for example initiatePairing, which is implemented in CGMG5Transmitter.swift, because that transmitter needs to send a message to the transmitter that will cause the app to request the user to accept the pairing
protocol CGMTransmitter {
protocol CGMTransmitter:AnyObject {
/// get device address, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
///
@ -85,6 +85,9 @@ enum CGMTransmitterType:String, CaseIterable {
/// BlueReader
case blueReader = "BlueReader"
/// watlaa
case watlaa = "Watlaa (under development)"
/// 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
@ -112,6 +115,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return false
case .watlaa:
return false
}
}
@ -145,6 +151,8 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return false
case .watlaa:
return false
}
}
@ -177,6 +185,10 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return false
case .watlaa:
return false
}
}
@ -216,6 +228,8 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return nil
case .watlaa:
return nil
}
}
@ -247,6 +261,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelBlueReader
case .watlaa:
return ConstantsDefaultAlertLevels.defaultBatteryAlertLevelWatlaa
}
}
@ -278,6 +295,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return false
case .watlaa:
return false
}
}
@ -306,6 +326,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return "%"
case .watlaa:
return "%"
}
}
@ -334,6 +357,9 @@ enum CGMTransmitterType:String, CaseIterable {
case .blueReader:
return false
case .watlaa:
return false
}
}
}

View File

@ -48,6 +48,10 @@ protocol CGMTransmitterDelegate:AnyObject {
/// to pass some text error message, delegate can decide to show to user, log, ...
func error(message: String)
/// temporary function till all cgm transmitters have moved to bluetooth tab. - this function returns the currently assigned cgmTransmiter
func getCGMTransmitter() -> CGMTransmitter?
}

View File

@ -25,9 +25,6 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
// used in parsing packet
private var timeStampLastBgReading:Date
// counts number of times resend was requested due to crc error
private var resendPacketCounter:Int = 0
/// used when processing Bubble data packet
private var startDate:Date
// receive buffer for bubble packets
@ -241,7 +238,6 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
private func resetRxBuffer() {
rxBuffer = Data()
startDate = Date()
resendPacketCounter = 0
}
/// this transmitter supports oopWeb

View File

@ -98,9 +98,9 @@ class LibreDataParser {
/// - completionHandler : will be called when glucose data is read with as parameter the timestamp of the last reading. Goal is that caller an set timeStampLastBgReading to the new value
///
/// parameter values that are not known, simply ignore them, if they are not known then they are probably not important, or they've already been passed to the delegate before.
public static func libreDataProcessor(sensorSerialNumber: String?, webOOPEnabled: Bool, oopWebSite: String, oopWebToken: String, libreData: Data, cgmTransmitterDelegate : CGMTransmitterDelegate?, transmitterBatteryInfo:TransmitterBatteryInfo?, firmware: String?, hardware: String?, hardwareSerialNumber: String?, bootloader:String?, timeStampLastBgReading: Date, completionHandler:@escaping ((_ timeStampLastBgReading: Date) -> ())) {
public static func libreDataProcessor(sensorSerialNumber: String?, webOOPEnabled: Bool, oopWebSite: String?, oopWebToken: String?, libreData: Data, cgmTransmitterDelegate : CGMTransmitterDelegate?, transmitterBatteryInfo:TransmitterBatteryInfo?, firmware: String?, hardware: String?, hardwareSerialNumber: String?, bootloader:String?, timeStampLastBgReading: Date, completionHandler:@escaping ((_ timeStampLastBgReading: Date) -> ())) {
if let sensorSerialNumber = sensorSerialNumber, webOOPEnabled {
if let sensorSerialNumber = sensorSerialNumber, let oopWebSite = oopWebSite, let oopWebToken = oopWebToken, webOOPEnabled {
LibreOOPClient.handleLibreData(libreData: libreData, timeStampLastBgReading: timeStampLastBgReading, serialNumber: sensorSerialNumber, oopWebSite: oopWebSite, oopWebToken: oopWebToken) {
(result) in
handleGlucoseData(result: result, cgmTransmitterDelegate: cgmTransmitterDelegate, transmitterBatteryInfo: transmitterBatteryInfo, firmware: firmware, hardware: hardware, hardwareSerialNumber: hardwareSerialNumber, bootloader: bootloader, sensorSerialNumber: sensorSerialNumber, completionHandler: completionHandler)

View File

@ -154,7 +154,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
centralManager.cancelPeripheralConnection(peripheral)
}
}
}
/// stops scanning
@ -237,6 +237,11 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
return false
}
}
/// calls peripheral?.readValue(for: characteristic)
func readValueForCharacteristic(for characteristic: CBCharacteristic) {
peripheral?.readValue(for: characteristic)
}
/// will write to characteristicToWriteTo
/// - returns: true if writeValue was successfully called, doesn't necessarily mean data is successvully written to peripheral
@ -357,6 +362,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
timeStampLastStatusUpdate = Date()
trace("connected to peripheral with name %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'")
@ -369,6 +375,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
timeStampLastStatusUpdate = Date()
if let error = error {
@ -382,6 +389,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
timeStampLastStatusUpdate = Date()
trace("in centralManagerDidUpdateState, for peripheral with name %{public}@, new state is %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'", "\(central.state.toString())")
@ -402,6 +410,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
timeStampLastStatusUpdate = Date()
trace(" didDisconnect peripheral with name %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info , deviceName ?? "'unknown'")
@ -434,9 +443,11 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
timeStampLastStatusUpdate = Date()
trace("didDiscoverServices for peripheral with name %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'")
if let error = error {
trace(" didDiscoverServices error: %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .error , "\(error.localizedDescription)")
}
@ -452,6 +463,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
timeStampLastStatusUpdate = Date()
trace("didDiscoverCharacteristicsFor for peripheral with name %{public}@, for service with uuid %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'", String(describing:service.uuid))
@ -479,6 +491,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
timeStampLastStatusUpdate = Date()
if let error = error {
@ -489,6 +502,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
timeStampLastStatusUpdate = Date()
if let error = error {
@ -498,6 +512,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
timeStampLastStatusUpdate = Date()
if let error = error {

View File

@ -269,17 +269,6 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
// MARK: - overriden BluetoothTransmitter functions
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
if deviceAddress == nil {
/// this bluetoothTransmitter is created to start scanning for a new, unknown M5Stack, so start scanning
_ = startScanning()
}
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
@ -412,7 +401,6 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
trace(" value length should be minimum 2", log: log, category: ConstantsLog.categoryM5StackBluetoothTransmitter, type: .error)
return
}
let receivedBatteryLevel = Int(value[1])

View File

@ -0,0 +1,11 @@
import Foundation
protocol WatlaaBluetoothTransmitterDelegate: BluetoothTransmitterDelegate {
/// will be called if WatlaaBluetoothTransmitter is connected and ready to receive data, as soon as this is received, xdrip can request for example battery level
func isReadyToReceiveData(watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster)
/// Watlaa is sending batteryLevel
func receivedBattery(level: Int, watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster)
}

View File

@ -0,0 +1,21 @@
import Foundation
extension WatlaaBluetoothTransmitterMaster: CGMTransmitter {
func initiatePairing() {
// no pairing needed for watlaa
}
func reset(requested: Bool) {
// no reset need for watlaa
}
func setWebOOPEnabled(enabled: Bool) {
// no web oop for watlaa as sensorid detection not supported
}
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {
// no web oop for watlaa as sensorid detection not supported
}
}

View File

@ -0,0 +1,322 @@
import Foundation
import os
import CoreBluetooth
final class WatlaaBluetoothTransmitterMaster: BluetoothTransmitter {
// MARK: UUID's
/// Glucose Data Service UUID
let CBUUID_Data_Service = "00001010-1212-EFDE-0137-875F45AC0113"
/// Battery Service UUID
let CBUUID_Battery_Service = "0000180F-0000-1000-8000-00805F9B34FB"
/// Current Time Service UUID
let CBUUID_CurrentTime_Service = "00002A2B-0000-1000-8000-00805F9B34FB"
/// characteristic uuids (created them in an enum as there's a lot of them, it's easy to switch through the list)
private enum CBUUID_Characteristic_UUID:String, CustomStringConvertible, CaseIterable {
/// Raw data characteristic
case CBUUID_RawData_Characteristic = "00001011-1212-EFDE-0137-875F45AC0113"
/// Bridge connection status characteristic
case CBUUID_BridgeConnectionStatus_Characteristic = "00001012-1212-EFDE-0137-875F45AC0113"
/// Last BG raw value characteristic
case CBUUID_LastBGRawValue_Characteristic = "00001013-1212-EFDE-0137-875F45AC0113"
/// Calibration characteristic
case CBUUID_Calibration_Characteristic = "00001014-1212-EFDE-0137-875F45AC0113"
/// Glucose unit characteristic
case CBUUID_GlucoseUnit_Characteristic = "00001015-1212-EFDE-0137-875F45AC0113"
/// Alerts settings characteristic
case CBUUID_AlertSettings_Characteristic = "00001016-1212-EFDE-0137-875F45AC0113"
/// Battery level characteristic
case CBUUID_BatteryLevel_Characteristic = "00002A19-0000-1000-8000-00805F9B34FB"
/// Current time characteristic
case CBUUID_CurrentTime_Characteristic = "00002A2B-0000-1000-8000-00805F9B34FB"
/// for logging, returns a readable name for the characteristic
var description: String {
switch self {
case .CBUUID_RawData_Characteristic:
return "RawData"
case .CBUUID_BridgeConnectionStatus_Characteristic:
return "BridgeConnectionStatus"
case .CBUUID_LastBGRawValue_Characteristic:
return "LastBGRawValue"
case .CBUUID_Calibration_Characteristic:
return "Calibration"
case .CBUUID_GlucoseUnit_Characteristic:
return "GlucoseUnit"
case .CBUUID_AlertSettings_Characteristic:
return "AlertSettings"
case .CBUUID_BatteryLevel_Characteristic:
return "BatteryLevel"
case .CBUUID_CurrentTime_Characteristic:
return "CurrentTime"
}
}
}
// MARK: Other private properties
/// for trace
private let log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryWatlaa)
/// will be used to pass back bluetooth and cgm related events
private weak var cgmTransmitterDelegate:CGMTransmitterDelegate?
/// receive buffer for bubble packets
private var rxBuffer:Data
/// used when processing Bubble data packet
private var startDate:Date
// used in parsing packet
private var timeStampLastBgReading:Date
/// battery level Characteristic, needed to be able to read value
private var batteryLevelCharacteric: CBCharacteristic?
// MARK: - public functions
/// - 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
init(address:String?, name: String?, cgmTransmitterDelegate:CGMTransmitterDelegate?, bluetoothTransmitterDelegate: WatlaaBluetoothTransmitterDelegate, bluetoothPeripheralType: BluetoothPeripheralType) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "watlaa")
if let address = address {
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address, name: name)
}
// initialize rxbuffer
rxBuffer = Data()
startDate = Date()
//assign CGMTransmitterDelegate
self.cgmTransmitterDelegate = cgmTransmitterDelegate
//initialize timeStampLastBgReading
timeStampLastBgReading = Date(timeIntervalSince1970: 0)
// initialize - CBUUID_Receive_Authentication.rawValue and CBUUID_Write_Control.rawValue will not be used in the superclass
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Data_Service), CBUUID(string: CBUUID_Battery_Service), CBUUID(string: CBUUID_CurrentTime_Service)], CBUUID_ReceiveCharacteristic: CBUUID_Characteristic_UUID.CBUUID_RawData_Characteristic.rawValue, CBUUID_WriteCharacteristic: CBUUID_Characteristic_UUID.CBUUID_Calibration_Characteristic.rawValue, startScanningAfterInit: false, bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
/// read battery level
public func readBatteryLevel() {
if let batteryLevelCharacteric = batteryLevelCharacteric {
readValueForCharacteristic(for: batteryLevelCharacteric)
}
}
// MARK: - private functions
/// reset rxBuffer, reset startDate, stop packetRxMonitorTimer, set resendPacketCounter to 0
private func resetRxBuffer() {
rxBuffer = Data()
startDate = Date()
}
/// creates CBUUID_Characteristic_UUID for the characteristicUUID
private func receivedCharacteristicUUIDToCharacteristic(characteristicUUID:String) -> CBUUID_Characteristic_UUID? {
// using enum to make sure no new characteristics are forgotten in case new are added in the future
for characteristic_UUID in CBUUID_Characteristic_UUID.allCases {
switch characteristic_UUID {
case .CBUUID_RawData_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_RawData_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_RawData_Characteristic
}
case .CBUUID_BridgeConnectionStatus_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_BridgeConnectionStatus_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_BridgeConnectionStatus_Characteristic
}
case .CBUUID_LastBGRawValue_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_LastBGRawValue_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_LastBGRawValue_Characteristic
}
case .CBUUID_Calibration_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_Calibration_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_Calibration_Characteristic
}
case .CBUUID_GlucoseUnit_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_GlucoseUnit_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_GlucoseUnit_Characteristic
}
case .CBUUID_AlertSettings_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_AlertSettings_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_AlertSettings_Characteristic
}
case .CBUUID_BatteryLevel_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_BatteryLevel_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_BatteryLevel_Characteristic
}
case .CBUUID_CurrentTime_Characteristic:
if CBUUID_Characteristic_UUID.CBUUID_CurrentTime_Characteristic.rawValue.containsIgnoringCase(find: characteristicUUID) {
return CBUUID_Characteristic_UUID.CBUUID_CurrentTime_Characteristic
}
}
}
return nil
}
private func handleUpdateValueFor_RawData_Characteristic(value: Data) {
rxBuffer.append(value)
if rxBuffer.count >= 344 {
if (Crc.LibreCrc(data: &rxBuffer, headerOffset: 0)) {
// setting webOOPEnabled to false, as we don't have the sensor serial number
LibreDataParser.libreDataProcessor(sensorSerialNumber: nil, webOOPEnabled: false, oopWebSite: nil, oopWebToken: nil, libreData: (rxBuffer.subdata(in: 0..<(344 + 0))), cgmTransmitterDelegate: cgmTransmitterDelegate, transmitterBatteryInfo: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, timeStampLastBgReading: timeStampLastBgReading, completionHandler: {(timeStampLastBgReading:Date) in
self.timeStampLastBgReading = timeStampLastBgReading
})
//reset the buffer
resetRxBuffer()
}
}
}
private func handleUpdateValueFor_BridgeConnectionStatus_Characteristic(value: Data) {
}
private func handleUpdateValueFor_LastBGRawValue_Characteristic(value: Data) {
}
private func handleUpdateValueFor_Calibration_Characteristic(value: Data) {
}
private func handleUpdateValueFor_GlucoseUnit_Characteristic(value: Data) {
}
private func handleUpdateValueFor_AlertSettings_Characteristic(value: Data) {
}
private func handleUpdateValueFor_BatteryLevel_Characteristic(value: Data) {
guard value.count >= 1 else {
trace(" value length should be minimum 1", log: log, category: ConstantsLog.categoryWatlaa, type: .error)
return
}
// Watlaa is sending batteryLevel, which is in the first byte
let receivedBatteryLevel = Int(value[0])
(fixedBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.receivedBattery(level: receivedBatteryLevel, watlaaBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.receivedBattery(level: receivedBatteryLevel, watlaaBluetoothTransmitter: self)
}
private func handleUpdateValueFor_CurrentTime_Characteristic(value: Data) {
}
// MARK: - BluetoothTransmitter overriden functions
override func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
super.peripheral(peripheral, didDiscoverCharacteristicsFor: service, error: error)
//need to store some of the characteristics to be able to write to them
if let characteristics = service.characteristics {
for characteristic in characteristics {
if (characteristic.uuid == CBUUID(string: CBUUID_Characteristic_UUID.CBUUID_BatteryLevel_Characteristic.rawValue)) {
trace(" found batteryLevelCharacteristic", log: log, category: ConstantsLog.categoryWatlaa, type: .info)
batteryLevelCharacteric = characteristic
}
}
}
// here all characteristics should be known, we can call isReadyToReceiveData
(fixedBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.isReadyToReceiveData(watlaaBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.isReadyToReceiveData(watlaaBluetoothTransmitter: self)
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
// find the CBUUID_Characteristic_UUID
guard let receivedCharacteristic = receivedCharacteristicUUIDToCharacteristic(characteristicUUID: characteristic.uuid.uuidString) else {
trace("in peripheralDidUpdateValueFor, unknown characteristic received with uuid = %{public}@", log: log, category: ConstantsLog.categoryWatlaa, type: .error, characteristic.uuid.uuidString)
return
}
trace("in peripheralDidUpdateValueFor, characteristic uuid = %{public}@", log: log, category: ConstantsLog.categoryWatlaa, type: .info, receivedCharacteristic.description)
guard let value = characteristic.value else {return}
debuglogging("Received value from Watlaa : " + value.hexEncodedString())
switch receivedCharacteristic {
case .CBUUID_RawData_Characteristic:
handleUpdateValueFor_RawData_Characteristic(value: value)
case .CBUUID_BridgeConnectionStatus_Characteristic:
handleUpdateValueFor_BridgeConnectionStatus_Characteristic(value: value)
case .CBUUID_LastBGRawValue_Characteristic:
handleUpdateValueFor_LastBGRawValue_Characteristic(value: value)
case .CBUUID_Calibration_Characteristic:
handleUpdateValueFor_Calibration_Characteristic(value: value)
case .CBUUID_GlucoseUnit_Characteristic:
handleUpdateValueFor_GlucoseUnit_Characteristic(value: value)
case .CBUUID_AlertSettings_Characteristic:
handleUpdateValueFor_AlertSettings_Characteristic(value: value)
case .CBUUID_BatteryLevel_Characteristic:
handleUpdateValueFor_BatteryLevel_Characteristic(value: value)
case .CBUUID_CurrentTime_Characteristic:
handleUpdateValueFor_CurrentTime_Characteristic(value: value)
}
}
}

View File

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

View File

@ -34,6 +34,9 @@ enum ConstantsLog {
/// G5
static let categoryCGMG5 = "CGMG5 "
/// watlaa
static let categoryWatlaa = "Watlaa"
/// GNSEntry
static let categoryCGMGNSEntry = "CGMGNSEntry "
@ -61,6 +64,9 @@ enum ConstantsLog {
/// application data for M5Stack
static let categoryApplicationDataM5Stacks = "ApplicationDataM5Stacks "
/// application data for M5Stack
static let categoryApplicationDataWatlaa = "ApplicationDataWatlaa"
/// application for for M5StackName
static let categoryApplicationDataM5StackNames = "ApplicationDataM5StackNames "

View File

@ -0,0 +1,45 @@
import Foundation
import os
import CoreData
class WatlaaAccessor {
// MARK: - Properties
/// CoreDataManager to use
private let coreDataManager:CoreDataManager
/// for logging
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryApplicationDataWatlaa)
// MARK: - initializer
init(coreDataManager:CoreDataManager) {
self.coreDataManager = coreDataManager
}
// MARK: Public functions
/// gets all Watlaa instances from coredata
func getWatlaas() -> [Watlaa] {
// create fetchRequest to get watlaa's as Watlaa classes
let watlaaFetchRequest: NSFetchRequest<Watlaa> = Watlaa.fetchRequest()
// fetch the Watlaa's
var watlaaArray = [Watlaa]()
coreDataManager.mainManagedObjectContext.performAndWait {
do {
// Execute Fetch Request
watlaaArray = try watlaaFetchRequest.execute()
} catch {
let fetchError = error as NSError
trace("in getWatlaas, Unable to Execute Watlaas Fetch Request : %{public}@", log: self.log, category: ConstantsLog.categoryWatlaa, type: .error, fetchError.localizedDescription)
}
}
return watlaaArray
}
}

View File

@ -42,6 +42,9 @@ public class M5Stack: NSManagedObject {
// this is creation of an M5Stack, not M5Stick, set isM5StickC to false
self.isM5StickC = false
// by default, don't connect to WiFi
self.connectToWiFi = false
}
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {

View File

@ -0,0 +1,32 @@
import Foundation
import CoreData
public class Watlaa: NSManagedObject {
/// explanation, see function parameterUpdateNotNeededAtNextConnect in protocol BluetoothPeripheral
public var parameterUpdateNeeded: Bool = false
/// battery level , not stored in coredata,
public var batteryLevel: Int?
/// create Watlaa, shouldconnect default value = true
/// - parameters:
/// - rotation is internally stored as Int32, actual value should always be between 0 and 360 so UInt16 as parameter is sufficient.
init(address: String, name: String, alias: String?, nsManagedObjectContext:NSManagedObjectContext) {
let entity = NSEntityDescription.entity(forEntityName: "Watlaa", in: nsManagedObjectContext)!
super.init(entity: entity, insertInto: nsManagedObjectContext)
self.address = address
self.name = name
self.shouldconnect = true
self.alias = alias
}
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 Watlaa {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Watlaa> {
return NSFetchRequest<Watlaa>(entityName: "Watlaa")
}
@NSManaged public var address: String
@NSManaged public var name: String
@NSManaged public var shouldconnect: Bool
@NSManaged public var alias: String?
}

View File

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

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15702" systemVersion="19C57" 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="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="M5Stack" representedClassName=".M5Stack" syncable="YES">
<attribute name="address" attributeType="String"/>
<attribute name="alias" optional="YES" attributeType="String"/>
<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="name" attributeType="String"/>
<attribute name="rotation" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="shouldconnect" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="textcolor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
</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"/>
<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="address" attributeType="String"/>
<attribute name="alias" optional="YES" attributeType="String"/>
<attribute name="name" attributeType="String"/>
<attribute name="shouldconnect" attributeType="Boolean" usesScalarValueType="YES"/>
</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="Calibration" positionX="-859.21484375" positionY="46.21484375" width="128" height="285"/>
<element name="M5Stack" positionX="-657" positionY="180" width="128" height="208"/>
<element name="Sensor" positionX="-603.0859375" positionY="482.2890625" width="128" height="120"/>
<element name="Watlaa" positionX="-639" positionY="207" width="128" height="103"/>
</elements>
</model>

View File

@ -28,6 +28,9 @@ class BluetoothPeripheralManager: NSObject {
/// reference to BgReadingsAccessor
private var bgReadingsAccessor: BgReadingsAccessor
/// reference to watlaaAccessor
private var watlaaAccessor: WatlaaAccessor
/// if scan is called, and a connection is successfully made to a new device, then a new M5Stack must be created, and this function will be called. It is owned by the UIViewController that calls the scan function
private var callBackAfterDiscoveringDevice: ((BluetoothPeripheral) -> Void)?
@ -36,45 +39,102 @@ class BluetoothPeripheralManager: NSObject {
/// to solve problem that sometemes UserDefaults key value changes is triggered twice for just one change
private let keyValueObserverTimeKeeper:KeyValueObserverTimeKeeper = KeyValueObserverTimeKeeper()
/// will be used to pass back bluetooth and cgm related events, probably temporary ?
private(set) weak var cgmTransmitterDelegate:CGMTransmitterDelegate?
/// when xdrip connects to a BluetoothTransmitter that is also CGMTransmitter, then we'll call this function with the BluetoothTransmitter as argument. This is to let the cgmTransmitterDelegate know what is the CGMTransmitter
private var onCGMTransmitterCreation: (CGMTransmitter?) -> ()
// MARK: - initializer
init(coreDataManager: CoreDataManager) {
/// - parameters:
/// - onCGMTransmitterCreation : to be called when cgmtransmitter is created
init(coreDataManager: CoreDataManager, cgmTransmitterDelegate: CGMTransmitterDelegate, onCGMTransmitterCreation: @escaping (CGMTransmitter?) -> ()) {
// initialize properties
self.coreDataManager = coreDataManager
self.m5StackAccessor = M5StackAccessor(coreDataManager: coreDataManager)
self.bgReadingsAccessor = BgReadingsAccessor(coreDataManager: coreDataManager)
self.watlaaAccessor = WatlaaAccessor(coreDataManager: coreDataManager)
self.cgmTransmitterDelegate = cgmTransmitterDelegate
self.onCGMTransmitterCreation = onCGMTransmitterCreation
super.init()
// initialize m5Stacks
let m5Stacks = m5StackAccessor.getM5Stacks()
for m5Stack in m5Stacks {
// need to initialize all types of bluetoothperipheral
// using enum here to make sure future types are not forgotten
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
// add it to the list of bluetoothPeripherals
bluetoothPeripherals.append(m5Stack)
if m5Stack.shouldconnect {
switch bluetoothPeripheralType {
case .M5StickCType:
// no seperate handling needed for M5StickC because M5StickC is stored in coredata as M5Stack objecct, so it will be handled when going through case M5StackType
break
// create an instance of M5StackBluetoothTransmitter, M5StackBluetoothTransmitter will automatically try to connect to the M5Stack with the address that is stored in m5Stack
// add it to the array of bluetoothTransmitters
bluetoothTransmitters.append(M5StackBluetoothTransmitter(address: m5Stack.address, name: m5Stack.name, delegate: self, blePassword: m5Stack.blepassword, bluetoothPeripheralType: m5Stack.isM5StickC ? .M5StickCType : .M5StackType))
case .M5StackType:
} else {
// initialize m5Stacks
let m5Stacks = m5StackAccessor.getM5Stacks()
for m5Stack in m5Stacks {
// add it to the list of bluetoothPeripherals
bluetoothPeripherals.append(m5Stack)
if m5Stack.shouldconnect {
// create an instance of M5StackBluetoothTransmitter, M5StackBluetoothTransmitter will automatically try to connect to the M5Stack with the address that is stored in m5Stack
// add it to the array of bluetoothTransmitters
bluetoothTransmitters.append(M5StackBluetoothTransmitter(address: m5Stack.address, name: m5Stack.name, delegate: self, blePassword: m5Stack.blepassword, bluetoothPeripheralType: m5Stack.isM5StickC ? .M5StickCType : .M5StackType))
} else {
// shouldn't connect, so don't create an instance of M5StackBluetoothTransmitter
// but append a nil element
bluetoothTransmitters.append(nil)
}
// each time the app launches, we will send the parameters to all BluetoothPeripherals
m5Stack.parameterUpdateNeededAtNextConnect()
}
// shouldn't connect, so don't create an instance of M5StackBluetoothTransmitter
// but append a nil element
bluetoothTransmitters.append(nil)
case .watlaaMaster:
// initialize watlaa's
let watlaas = watlaaAccessor.getWatlaas()
for watlaa in watlaas {
// add it to the list of bluetoothPeripherals
bluetoothPeripherals.append(watlaa)
if watlaa.shouldconnect {
// create an instance of WatlaaBluetoothTransmitter, WatlaaBluetoothTransmitter will automatically try to connect to the watlaa with the address that is stored in watlaa
// add it to the array of bluetoothTransmitters
bluetoothTransmitters.append(WatlaaBluetoothTransmitterMaster(address: watlaa.address, name: watlaa.name, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, bluetoothPeripheralType: .watlaaMaster))
} else {
// shouldn't connect, so don't create an instance of M5StackBluetoothTransmitter
// but append a nil element
bluetoothTransmitters.append(nil)
}
// each time the app launches, we will send the parameters to all BluetoothPeripherals
watlaa.parameterUpdateNeededAtNextConnect()
}
}
// each time the app launches, we will send the parameters to all BluetoothPeripherals
m5Stack.parameterUpdateNeededAtNextConnect()
}
// when user changes M5Stack related settings, then the transmitter need to get that info
// when user changes any of the buetooth peripheral related settings, that need to be sent to the transmitter
addObservers()
}
@ -120,6 +180,10 @@ class BluetoothPeripheralManager: NSObject {
_ = m5StackBluetoothTransmitter.writeBgReadingInfo(bgReading: bgReadingToSend[0])
}
case .watlaaMaster:
// no need to send reading to watlaa in master mode
break
}
}
@ -129,6 +193,22 @@ class BluetoothPeripheralManager: NSObject {
// MARK: - private functions
/// check if transmitter in bluetoothTransmitters with index, is the cgmtransmitter currently assigned to delegate, if so set cgmtransmitter at delegate to nil - This should be temporary till cgm transmitters have moved to bluetooth tab
private func setCGMTransmitterToNilAtDelegate(withIndexInBluetoothTransmitters index: Int) {
if let cgmTransmitter = cgmTransmitterDelegate?.getCGMTransmitter() as? BluetoothTransmitter, let transmitterBeingDeleted = bluetoothTransmitters[index] {
if cgmTransmitter.getAddress() == transmitterBeingDeleted.getAddress() {
// so the cgmTransmitter is actually being deleted, so we need to also assign cgmTransmitterDelegate to nil to make sure there's no more reference to it
onCGMTransmitterCreation(nil)
}
}
}
/// when user changes M5Stack related settings, then the transmitter need to get that info, add observers
private func addObservers() {
@ -143,7 +223,6 @@ class BluetoothPeripheralManager: NSObject {
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutUrl.rawValue, options: .new, context: nil)
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutAPIKey.rawValue, options: .new, context: nil)
}
/// disconnect from bluetoothPeripheral - and don't reconnect - set shouldconnect to false
@ -157,7 +236,7 @@ class BluetoothPeripheralManager: NSObject {
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false) {
bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
_ = bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
}
@ -175,6 +254,10 @@ class BluetoothPeripheralManager: NSObject {
return M5StackBluetoothTransmitter(address: nil, name: nil, delegate: self, blePassword: UserDefaults.standard.m5StackBlePassword, bluetoothPeripheralType: type)
case .watlaaMaster:
return WatlaaBluetoothTransmitterMaster(address: nil, name: nil, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, bluetoothPeripheralType: type)
}
}
@ -192,6 +275,12 @@ class BluetoothPeripheralManager: NSObject {
return bluetoothTransmitter.bluetoothPeripheralType
}
case .watlaaMaster:
if bluetoothTransmitter is WatlaaBluetoothTransmitterMaster {
return .watlaaMaster
}
}
}
@ -297,6 +386,9 @@ class BluetoothPeripheralManager: NSObject {
if !success {
bluetoothPeripheral.parameterUpdateNeededAtNextConnect()
}
case .watlaaMaster:
break
}
@ -306,9 +398,7 @@ class BluetoothPeripheralManager: NSObject {
}
// MARK: - extensions
// MARK: extension BluetoothPeripheralManaging
// MARK: - conform to BluetoothPeripheralManaging
extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
@ -404,6 +494,14 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
newTransmitter = M5StackBluetoothTransmitter(address: m5Stack.address, name: m5Stack.name, delegate: self, blePassword: blePassword, bluetoothPeripheralType: bluetoothPeripheral.bluetoothPeripheralType())
}
case .watlaaMaster:
if let watlaa = bluetoothPeripheral as? Watlaa {
newTransmitter = WatlaaBluetoothTransmitterMaster(address: watlaa.address, name: watlaa.name, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, bluetoothPeripheralType: .watlaaMaster)
}
}
bluetoothTransmitters[index] = newTransmitter
@ -426,6 +524,9 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
return
}
// check if transmitter being deleted is assigned to cgmTransmitterDelegate, if so we need to set it also to nil, otherwise the bluetoothTransmitter deinit function wouldn't get called
setCGMTransmitterToNilAtDelegate(withIndexInBluetoothTransmitters: index)
// set bluetoothTransmitter to nil, this will also initiate a disconnect
bluetoothTransmitters[index] = nil
@ -468,6 +569,9 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
if let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral) {
// check if transmitter being deleted is assigned to cgmTransmitterDelegate, if so we need to set it also to nil, otherwise the bluetoothTransmitter deinit function wouldn't get called
setCGMTransmitterToNilAtDelegate(withIndexInBluetoothTransmitters: index)
bluetoothTransmitters[index] = nil
}
@ -475,12 +579,17 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
}
// MARK: extension M5StackBluetoothDelegate
// MARK: - conform to BluetoothTransmitterDelegate
extension BluetoothPeripheralManager: BluetoothTransmitterDelegate {
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
// temporary, till all cgm's are moved to second tab
if bluetoothTransmitter is CGMTransmitter {
onCGMTransmitterCreation((bluetoothTransmitter as! CGMTransmitter))
}
// if tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral is nil, then this is a connection to an already known/stored BluetoothTransmitter. BluetoothPeripheralManager is not interested in this info.
guard let tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral else {
trace("in didConnect, tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral is nil, no further processing", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
@ -530,10 +639,18 @@ extension BluetoothPeripheralManager: BluetoothTransmitterDelegate {
self.callBackAfterDiscoveringDevice = nil
}
// assign tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral to nil here
self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = nil
}
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
trace("in deviceDidUpdateBluetoothState, no further action", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
if bluetoothTransmitter.deviceAddress == nil {
/// this bluetoothTransmitter is created to start scanning for a new, unknown M5Stack, so start scanning
_ = bluetoothTransmitter.startScanning()
}
}
@ -549,7 +666,28 @@ extension BluetoothPeripheralManager: BluetoothTransmitterDelegate {
}
// MARK: conform to M5StackBluetoothTransmitterDelegate
// MARK: - conform to WatlaaBluetoothTransmitterDelegate
extension BluetoothPeripheralManager: WatlaaBluetoothTransmitterDelegate {
func isReadyToReceiveData(watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster) {
// request battery level
watlaaBluetoothTransmitter.readBatteryLevel()
}
func receivedBattery(level: Int, watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster) {
guard let index = bluetoothTransmitters.firstIndex(of: watlaaBluetoothTransmitter), let watlaa = bluetoothPeripherals[index] as? Watlaa else {return}
watlaa.batteryLevel = level
}
}
// MARK: - conform to M5StackBluetoothTransmitterDelegate
extension BluetoothPeripheralManager: M5StackBluetoothTransmitterDelegate {
@ -636,7 +774,7 @@ extension BluetoothPeripheralManager: M5StackBluetoothTransmitterDelegate {
}
/// bluetoothPeripheral is asking for an update of all parameters, send them
/// M5Stack is asking for an update of all parameters, send them
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter) else {
@ -675,7 +813,7 @@ extension BluetoothPeripheralManager: M5StackBluetoothTransmitterDelegate {
}
// MARK: private functions related to M5Stack
// MARK: - private functions related to M5Stack
/// send all parameters to m5Stack
/// - parameters:

View File

@ -0,0 +1 @@
"watlaaViewscreenTitle" = "Watlaa";

View File

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>3191</string>
<string>3234</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>

View File

@ -0,0 +1,13 @@
import Foundation
class TextsWatlaaView {
static private let filename = "WatlaaView"
static let watlaaViewscreenTitle: String = {
return NSLocalizedString("watlaaViewscreenTitle", tableName: filename, bundle: Bundle.main, value: "Watlaa", comment: "when Watlaa list is shown, title of the view")
}()
}

View File

@ -227,17 +227,17 @@ class BluetoothPeripheralViewController: UIViewController {
/// user cliks done button
public func doneButtonHandler() {
if let bluetoothPeripheralASNSObject = bluetoothPeripheralAsNSObject, let coreDataManager = coreDataManager {
if let bluetoothPeripheralAsNSObject = bluetoothPeripheralAsNSObject, let coreDataManager = coreDataManager {
// set variable delegate in bluetoothPeripheralASNSObject to nil, no need anymore to receive info
bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: false)?.variableBluetoothTransmitterDelegate = nil
bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralAsNSObject, createANewOneIfNecesssary: false)?.variableBluetoothTransmitterDelegate = nil
// set alias temp value, possibly this is a nil value
bluetoothPeripheralASNSObject.setAlias(aliasTemporaryValue)
bluetoothPeripheralAsNSObject.setAlias(aliasTemporaryValue)
// temp values stored by viewmodel needs to be written to bluetoothPeripheralASNSObject
bluetoothPeripheralViewModel.writeTempValues(to: bluetoothPeripheralASNSObject)
bluetoothPeripheralViewModel.writeTempValues(to: bluetoothPeripheralAsNSObject)
// save all changes now
coreDataManager.saveChanges()

View File

@ -516,7 +516,7 @@ class M5StackBluetoothPeripheralViewModel {
}
// MARK: - extension BluetoothTransmitterDelegate
// MARK: - conform to BluetoothTransmitterDelegate
extension M5StackBluetoothPeripheralViewModel: BluetoothTransmitterDelegate {
@ -535,7 +535,7 @@ extension M5StackBluetoothPeripheralViewModel: BluetoothTransmitterDelegate {
}
// MARK: - extension M5StackBluetoothTransmitterDelegate
// MARK: - conform to M5StackBluetoothTransmitterDelegate
extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelegate {
@ -773,12 +773,12 @@ extension M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
if let m5StackPeripheral = bluetoothPeripheral as? M5Stack {
if let m5Stack = bluetoothPeripheral as? M5Stack {
storeTempValues(from: m5StackPeripheral)
storeTempValues(from: m5Stack)
// also request batteryLevel, this may have been updated
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5StackPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter {
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5Stack, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter {
_ = m5StackBluetoothTransmitter.readBatteryLevel()

View File

@ -0,0 +1,174 @@
import UIKit
import CoreBluetooth
class WatlaaMasterBluetoothPeripheralViewModel {
// MARK: - private properties
/// settings correspond to watlaa specific rows in viewcontroller
private enum WatlaaSetting: Int, CaseIterable {
/// batteryLevel
case batteryLevel
}
/// reference to bluetoothPeripheralManager
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging?
/// reference to the tableView
private weak var tableView: UITableView?
/// reference to BluetoothPeripheralViewController that will own this WatlaaMasterBluetoothPeripheralViewModel - needed to present stuff etc
private weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
private weak var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
}
// MARK: - conform to BluetoothPeripheralViewModel
extension WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
self.bluetoothPeripheralManager = bluetoothPeripheralManager
self.tableView = tableView
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
if let watlaaPeripheral = bluetoothPeripheral as? Watlaa {
storeTempValues(from: watlaaPeripheral)
// also request batteryLevel, this may have been updated
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: watlaaPeripheral, createANewOneIfNecesssary: false), let watlaaBluetoothTransmitter = blueToothTransmitter as? WatlaaBluetoothTransmitterMaster {
_ = watlaaBluetoothTransmitter.readBatteryLevel()
}
}
}
func screenTitle() -> String {
return TextsWatlaaView.watlaaViewscreenTitle
}
func sectionTitle(forSection section: Int) -> String {
return "section title tbc"
}
func update(cell: UITableViewCell, forRow rawValue: Int, forSection section: Int, for bluetoothPeripheral: BluetoothPeripheral, doneButtonOutlet: UIBarButtonItem) {
// verify that bluetoothPeripheralAsNSObject is an M5Stack
guard let watlaa = bluetoothPeripheral as? Watlaa else {
fatalError("WatlaaMasterBluetoothPeripheralViewModel update, bluetoothPeripheral is not Watlaa")
}
// default value for accessoryView is nil
cell.accessoryView = nil
switch section {
case 1:
guard let setting = WatlaaSetting(rawValue: rawValue) else { fatalError("WatlaaMasterBluetoothPeripheralViewModel update, unexpected setting") }
switch setting {
case .batteryLevel:
cell.textLabel?.text = Texts_BluetoothPeripheralsView.batteryLevel
cell.detailTextLabel?.text = watlaa.batteryLevel?.description
cell.accessoryType = .none
}
default:
fatalError("in WatlaaMasterBluetoothPeripheralViewModel update, unhandled section number")
}
}
func userDidSelectRow(withSettingRawValue rawValue: Int, forSection section: Int, for bluetoothPeripheral: BluetoothPeripheral, bluetoothPeripheralManager: BluetoothPeripheralManaging, doneButtonOutlet: UIBarButtonItem) {
switch section {
case 1:
guard let setting = WatlaaSetting(rawValue: rawValue) else { fatalError("WatlaaMasterBluetoothPeripheralViewModel userDidSelectRow, unexpected setting") }
switch setting {
case .batteryLevel:
// user can't do anything by clicking on battery row
break
}
default:
fatalError("in WatlaaMasterBluetoothPeripheralViewModel update, unhandled section number")
}
}
func numberOfSettings(inSection section: Int) -> Int {
return WatlaaSetting.allCases.count
}
func numberOfSections() -> Int {
// for the moment only one specific section for watlaa
return 1
}
func storeTempValues(from bluetoothPeripheral: BluetoothPeripheral) {
}
func writeTempValues(to bluetoothPeripheral: BluetoothPeripheral) {
}
}
// MARK: - conform to BluetoothTransmitterDelegate
extension WatlaaMasterBluetoothPeripheralViewModel: BluetoothTransmitterDelegate {
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
bluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: bluetoothTransmitter)
}
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
bluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: bluetoothTransmitter)
}
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
bluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state, bluetoothTransmitter: bluetoothTransmitter)
}
}
// MARK: - conform to WatlaaBluetoothTransmitterDelegate
extension WatlaaMasterBluetoothPeripheralViewModel: WatlaaBluetoothTransmitterDelegate {
func isReadyToReceiveData(watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster) {
// viewcontroller doesn't use this
}
func receivedBattery(level: Int, watlaaBluetoothTransmitter: WatlaaBluetoothTransmitterMaster) {
// batteryLevel should get updated in Watlaa object by bluetoothPeripheralManager, here's the trigger to update the table
tableView?.reloadRows(at: [IndexPath(row: WatlaaSetting.batteryLevel.rawValue, section: 1)], with: .none)
}
}

View File

@ -408,7 +408,12 @@ final class RootViewController: UIViewController {
})
// setup bluetoothPeripheralManager
bluetoothPeripheralManager = BluetoothPeripheralManager(coreDataManager: coreDataManager)
bluetoothPeripheralManager = BluetoothPeripheralManager(coreDataManager: coreDataManager, cgmTransmitterDelegate: self, onCGMTransmitterCreation: {
(cgmTransmitter: CGMTransmitter?) in
self.cgmTransmitter = cgmTransmitter
})
}
@ -813,6 +818,10 @@ final class RootViewController: UIViewController {
case .blueReader:
cgmTransmitter = CGMBlueReaderTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self)
case .watlaa:
// watlaa transmitter needs to be set through bluetooth devices tab
cgmTransmitter = nil
}
// assign calibrator
@ -820,7 +829,7 @@ final class RootViewController: UIViewController {
case .dexcomG4, .dexcomG5, .dexcomG6:
calibrator = DexcomCalibrator()
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1, .blueReader:
case .miaomiao, .GNSentry, .Blucon, .Bubble, .Droplet1, .blueReader, .watlaa:
// for all transmitters used with Libre1, calibrator is either NoCalibrator or Libre1Calibrator, depending if oopWeb is supported by the transmitter and on value of webOOPEnabled in settings
calibrator = RootViewController.getCalibrator(transmitterType: selectedTransmitterType, webOOPEnabled: UserDefaults.standard.webOOPEnabled)
}
@ -1329,6 +1338,10 @@ final class RootViewController: UIViewController {
/// conform to CGMTransmitterDelegate
extension RootViewController:CGMTransmitterDelegate {
func getCGMTransmitter() -> CGMTransmitter? {
return cgmTransmitter
}
func error(message: String) {
let alert = UIAlertController(title: Texts_Common.warning, message: message, actionHandler: nil)