temp commit

This commit is contained in:
Johan Degraeve 2020-02-17 18:06:53 +01:00
parent 3e8d7839c5
commit d96fd7a5db
33 changed files with 1204 additions and 1311 deletions

View File

@ -190,14 +190,6 @@
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 */; };
F8DF765323E34F4500063910 /* DexcomG5+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF765223E34F4500063910 /* DexcomG5+CoreDataClass.swift */; };
F8DF765523E34FD500063910 /* DexcomG5+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF765423E34FD500063910 /* DexcomG5+CoreDataProperties.swift */; };
F8DF765C23E350B100063910 /* DexcomG5+BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF765B23E350B100063910 /* DexcomG5+BluetoothPeripheral.swift */; };
F8DF766023E38FC100063910 /* BLEPeripheral+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF765F23E38FC100063910 /* BLEPeripheral+CoreDataClass.swift */; };
F8DF766223E390D100063910 /* BLEPeripheral+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF766123E390D100063910 /* BLEPeripheral+CoreDataProperties.swift */; };
F8DF766423E781C100063910 /* BLEPeripheralAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF766323E781C100063910 /* BLEPeripheralAccessor.swift */; };
F8DF766823E782E400063910 /* DexcomG5Accessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF766723E782E400063910 /* DexcomG5Accessor.swift */; };
F8DF766D23ED9B0900063910 /* DexcomG5BluetoothPeripheralViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DF766C23ED9B0900063910 /* DexcomG5BluetoothPeripheralViewModel.swift */; };
F8E3A2A323D4E7E200E5E98A /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F8E3A2A223D4E7E200E5E98A /* Default-568h@2x.png */; };
F8E3A2A523D78FBD00E5E98A /* SettingsViewAppleWatchSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3A2A423D78FBD00E5E98A /* SettingsViewAppleWatchSettingsViewModel.swift */; };
F8E3A2A923D906C200E5E98A /* WatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3A2A823D906C200E5E98A /* WatchManager.swift */; };
@ -624,15 +616,6 @@
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>"; };
F8DF764E23DCF64F00063910 /* xdrip v10.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v10.xcdatamodel"; sourceTree = "<group>"; };
F8DF765123E34E6A00063910 /* xdrip v11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v11.xcdatamodel"; sourceTree = "<group>"; };
F8DF765223E34F4500063910 /* DexcomG5+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DexcomG5+CoreDataClass.swift"; sourceTree = "<group>"; };
F8DF765423E34FD500063910 /* DexcomG5+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DexcomG5+CoreDataProperties.swift"; sourceTree = "<group>"; };
F8DF765B23E350B100063910 /* DexcomG5+BluetoothPeripheral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DexcomG5+BluetoothPeripheral.swift"; sourceTree = "<group>"; };
F8DF765F23E38FC100063910 /* BLEPeripheral+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BLEPeripheral+CoreDataClass.swift"; sourceTree = "<group>"; };
F8DF766123E390D100063910 /* BLEPeripheral+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BLEPeripheral+CoreDataProperties.swift"; sourceTree = "<group>"; };
F8DF766323E781C100063910 /* BLEPeripheralAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEPeripheralAccessor.swift; sourceTree = "<group>"; };
F8DF766723E782E400063910 /* DexcomG5Accessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomG5Accessor.swift; sourceTree = "<group>"; };
F8DF766C23ED9B0900063910 /* DexcomG5BluetoothPeripheralViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomG5BluetoothPeripheralViewModel.swift; sourceTree = "<group>"; };
F8E3A2A223D4E7E200E5E98A /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
F8E3A2A423D78FBD00E5E98A /* SettingsViewAppleWatchSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewAppleWatchSettingsViewModel.swift; sourceTree = "<group>"; };
F8E3A2A823D906C200E5E98A /* WatchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchManager.swift; sourceTree = "<group>"; };
@ -1157,8 +1140,6 @@
F8B3A815227DEC91004BA588 /* SensorsAccessor.swift */,
F8F6226F233AA3B200BE8796 /* M5StackAccessor.swift */,
F830992B23C694F4005741DF /* WatlaaAccessor.swift */,
F8DF766323E781C100063910 /* BLEPeripheralAccessor.swift */,
F8DF766723E782E400063910 /* DexcomG5Accessor.swift */,
);
path = accessors;
sourceTree = "<group>";
@ -1294,46 +1275,6 @@
path = Charts;
sourceTree = "<group>";
};
F8DF765923E350B100063910 /* Dexcom */ = {
isa = PBXGroup;
children = (
F8DF765A23E350B100063910 /* G5 */,
);
path = Dexcom;
sourceTree = "<group>";
};
F8DF765A23E350B100063910 /* G5 */ = {
isa = PBXGroup;
children = (
F8DF765B23E350B100063910 /* DexcomG5+BluetoothPeripheral.swift */,
);
path = G5;
sourceTree = "<group>";
};
F8DF766923ED9AF100063910 /* CGM */ = {
isa = PBXGroup;
children = (
F8DF766A23ED9AF100063910 /* Dexcom */,
);
path = CGM;
sourceTree = "<group>";
};
F8DF766A23ED9AF100063910 /* Dexcom */ = {
isa = PBXGroup;
children = (
F8DF766B23ED9AF100063910 /* DexcomG5 */,
);
path = Dexcom;
sourceTree = "<group>";
};
F8DF766B23ED9AF100063910 /* DexcomG5 */ = {
isa = PBXGroup;
children = (
F8DF766C23ED9B0900063910 /* DexcomG5BluetoothPeripheralViewModel.swift */,
);
path = DexcomG5;
sourceTree = "<group>";
};
F8E3A2A723D906B600E5E98A /* Watch */ = {
isa = PBXGroup;
children = (
@ -1402,10 +1343,6 @@
F804870B2336D90200EBDDB7 /* M5Stack+CoreDataProperties.swift */,
F85DC2F121CFE3D400B9F74A /* Sensor+CoreDataClass.swift */,
F85DC2E921CFE2F500B9F74A /* Sensor+CoreDataProperties.swift */,
F8DF765223E34F4500063910 /* DexcomG5+CoreDataClass.swift */,
F8DF765423E34FD500063910 /* DexcomG5+CoreDataProperties.swift */,
F8DF765F23E38FC100063910 /* BLEPeripheral+CoreDataClass.swift */,
F8DF766123E390D100063910 /* BLEPeripheral+CoreDataProperties.swift */,
);
path = classes;
sourceTree = "<group>";
@ -1436,7 +1373,6 @@
F8F971AE23A5914C00C3F17D /* CGM */ = {
isa = PBXGroup;
children = (
F8DF765923E350B100063910 /* Dexcom */,
);
path = CGM;
sourceTree = "<group>";
@ -1692,7 +1628,6 @@
F8F9723623A5928D00C3F17D /* Models */ = {
isa = PBXGroup;
children = (
F8DF766923ED9AF100063910 /* CGM */,
F830992423C32226005741DF /* watlaa */,
F8F9723A23A5934300C3F17D /* M5StickC */,
F8F9723723A5928D00C3F17D /* M5Stack */,
@ -1925,7 +1860,6 @@
F898EDF6234A8A5700BFB79B /* UInt32.swift in Sources */,
F8F9723223A5915900C3F17D /* M5StackReadBlePassWordTxMessage.swift in Sources */,
F8A54AAF22D686CD00934E7A /* NightScoutBgReading.swift in Sources */,
F8DF765323E34F4500063910 /* DexcomG5+CoreDataClass.swift in Sources */,
F8F9720F23A5915900C3F17D /* NSData+CRC.swift in Sources */,
F8A1585722EDB754007F5B5D /* ConstantsCoreData.swift in Sources */,
F821CF9022AB1068005C1E43 /* DatePickerViewData.swift in Sources */,
@ -2004,9 +1938,7 @@
F8F62270233AA3B200BE8796 /* M5StackAccessor.swift in Sources */,
F830991C23C2909E005741DF /* Watlaa+CoreDataClass.swift in Sources */,
F8A1586122EDB844007F5B5D /* ConstantsNotifications.swift in Sources */,
F8DF765523E34FD500063910 /* DexcomG5+CoreDataProperties.swift in Sources */,
F8F9720423A5915900C3F17D /* TransmitterVersionTxMessage.swift in Sources */,
F8DF765C23E350B100063910 /* DexcomG5+BluetoothPeripheral.swift in Sources */,
F8F9720323A5915900C3F17D /* CGMG5Transmitter.swift in Sources */,
F8B3A81C227DEC92004BA588 /* AlertEntriesAccessor.swift in Sources */,
F8A1585B22EDB7EA007F5B5D /* ConstantsDexcomG5.swift in Sources */,
@ -2026,13 +1958,11 @@
F8691888239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift in Sources */,
F8297F4F238DCAD800D74D66 /* BluetoothPeripheralNavigationController.swift in Sources */,
F8A1585322EDB602007F5B5D /* ConstantsBloodGlucose.swift in Sources */,
F8DF766023E38FC100063910 /* BLEPeripheral+CoreDataClass.swift in Sources */,
F80ED2EE236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift in Sources */,
F8A389C823203E3E0010F405 /* ConstantsM5Stack.swift in Sources */,
F898EDEA233F53BF00BFB79B /* UIButton.swift in Sources */,
F81F9FF822861E6D0028C70F /* KeyValueObserverTimeKeeper.swift in Sources */,
F8B3A858227F6971004BA588 /* UISwitch.swift in Sources */,
F8DF766823E782E400063910 /* DexcomG5Accessor.swift in Sources */,
F830990523B94ED7005741DF /* TimeScheduleViewController.swift in Sources */,
F8F9722123A5915900C3F17D /* LibreSensorSerialNumber.swift in Sources */,
F8A1586722EDB8BF007F5B5D /* ConstantsHomeView.swift in Sources */,
@ -2065,7 +1995,6 @@
F8F9721C23A5915900C3F17D /* LibreOOPResponse.swift in Sources */,
F81F9FFC2288C7530028C70F /* NewAlertSettingsViewController.swift in Sources */,
F898EDF2234A8A0500BFB79B /* UInt8.swift in Sources */,
F8DF766423E781C100063910 /* BLEPeripheralAccessor.swift in Sources */,
F81FA0002289E4990028C70F /* AlertSettingsViewControllerData.swift in Sources */,
F856CE5B22EDC8E50083E436 /* ConstantsBluetoothPairing.swift in Sources */,
F8F971B823A5914D00C3F17D /* BluetoothPeripheral.swift in Sources */,
@ -2112,7 +2041,6 @@
F8025C1321DA683400ECF0C0 /* Data.swift in Sources */,
F8F9722023A5915900C3F17D /* LibreGlucoseSmoothing.swift in Sources */,
F80859272364355F00F3829D /* ConstantsGlucoseChart.swift in Sources */,
F8DF766D23ED9B0900063910 /* DexcomG5BluetoothPeripheralViewModel.swift in Sources */,
F85DC2EF21CFE2F500B9F74A /* Sensor+CoreDataProperties.swift in Sources */,
F8297F56238ED07700D74D66 /* BluetoothPeripheralManager.swift in Sources */,
F8297F5A238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift in Sources */,
@ -2126,7 +2054,6 @@
F8A1584F22ECB281007F5B5D /* SettingsViewInfoViewModel.swift in Sources */,
F8B3A845227F090E004BA588 /* SettingsViewDexcomSettingsViewModel.swift in Sources */,
F8F9720C23A5915900C3F17D /* SensorDataTxMessage.swift in Sources */,
F8DF766223E390D100063910 /* BLEPeripheral+CoreDataProperties.swift in Sources */,
F8A1585F22EDB81E007F5B5D /* ConstantsLog.swift in Sources */,
F8A1586522EDB89D007F5B5D /* ConstantsDefaultAlertTypeSettings.swift in Sources */,
);
@ -2552,7 +2479,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 3009;
DEVELOPMENT_TEAM = 92C77A2942;
DEVELOPMENT_TEAM = RNX44PP998;
INFOPLIST_FILE = "$(SRCROOT)/xdrip/Supporting Files/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
@ -2580,7 +2507,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 3009;
DEVELOPMENT_TEAM = 92C77A2942;
DEVELOPMENT_TEAM = RNX44PP998;
INFOPLIST_FILE = "$(SRCROOT)/xdrip/Supporting Files/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
@ -2624,7 +2551,6 @@
F8AC429F21B31F160078C348 /* xdrip.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
F8DF765123E34E6A00063910 /* xdrip v11.xcdatamodel */,
F8DF764E23DCF64F00063910 /* xdrip v10.xcdatamodel */,
F830991523C28E79005741DF /* xdrip v9.xcdatamodel */,
F830990323B3928E005741DF /* xdrip v8.xcdatamodel */,
@ -2636,7 +2562,7 @@
F85C4A93233632EC00D6A86F /* xdrip v2.xcdatamodel */,
F8AC42A021B31F160078C348 /* xdrip.xcdatamodel */,
);
currentVersion = F8DF765123E34E6A00063910 /* xdrip v11.xcdatamodel */;
currentVersion = F8DF764E23DCF64F00063910 /* xdrip v10.xcdatamodel */;
path = xdrip.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;

View File

@ -179,4 +179,21 @@ enum BluetoothPeripheralType: String, CaseIterable {
}
/// can a transmitter be reset ? For example Dexcom G5 (and G6) can be reset
///
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
func resetPossible() -> Bool {
switch self {
case .M5StackType, .M5StickCType, .watlaaMaster:
return false
case .DexcomG5Type:
return true
}
}
}

View File

@ -30,7 +30,9 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, CGMTransmitter {
/// - 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
/// - transmitterID: expected transmitterID, 5 characters
init(address:String?, name: String?, transmitterID:String, delegate:CGMTransmitterDelegate) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, transmitterID:String, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: nil)
if let address = address {
@ -38,41 +40,17 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, CGMTransmitter {
}
//assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
//assign transmitterId
self.transmitterId = transmitterID
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: CBUUID_Advertisement_G4, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_G4)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_G4, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_G4, startScanningAfterInit: CGMTransmitterType.dexcomG4.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: CBUUID_Advertisement_G4, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_G4)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_G4, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_G4, startScanningAfterInit: CGMTransmitterType.dexcomG4.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
// MARK: - MARK: CBCentralManager overriden functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
@ -162,11 +140,6 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because G4 doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because G4 doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -4,13 +4,16 @@ import os
class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: - properties
// MARK: - public properties
/// G5 or G6 transmitter firmware version - only used internally, if nil then it was never received
///
/// created public because inheriting classes need it
var firmwareVersion:String?
var firmware:String?
/// CGMG5TransmitterDelegate
public weak var cGMG5TransmitterDelegate: CGMG5TransmitterDelegate?
// MARK: UUID's
// advertisement
@ -100,7 +103,10 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
/// - 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
/// - transmitterID: expected transmitterID, 6 characters
init(address:String?, name: String?, transmitterID:String, cGMTransmitterDelegate:CGMTransmitterDelegate) {
/// - bluetoothTransmitterDelegate : a NluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
/// - cGMG5TransmitterDelegate : a CGMG5TransmitterDelegate
init(address:String?, name: String?, transmitterID:String, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMG5TransmitterDelegate: CGMG5TransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "DEXCOM" + transmitterID[transmitterID.index(transmitterID.startIndex, offsetBy: 4)..<transmitterID.endIndex])
@ -124,11 +130,14 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
self.G5ResetRequested = false
// initialize - CBUUID_Receive_Authentication.rawValue and CBUUID_Write_Control.rawValue will probably not be used in the superclass
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: CBUUID_Advertisement_G5, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_G5)], CBUUID_ReceiveCharacteristic: CBUUID_Characteristic_UUID.CBUUID_Receive_Authentication.rawValue, CBUUID_WriteCharacteristic: CBUUID_Characteristic_UUID.CBUUID_Write_Control.rawValue, startScanningAfterInit: CGMTransmitterType.dexcomG5.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: CBUUID_Advertisement_G5, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_G5)], CBUUID_ReceiveCharacteristic: CBUUID_Characteristic_UUID.CBUUID_Receive_Authentication.rawValue, CBUUID_WriteCharacteristic: CBUUID_Characteristic_UUID.CBUUID_Write_Control.rawValue, startScanningAfterInit: CGMTransmitterType.dexcomG5.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
//assign CGMTransmitterDelegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
// assign cGMG5TransmitterDelegate
self.cGMG5TransmitterDelegate = cGMG5TransmitterDelegate
// start scanning
_ = startScanning()
}
@ -166,7 +175,7 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
}
// MARK: CBCentralManager overriden functions
// MARK: BluetoothTransmitter overriden functions
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
@ -180,8 +189,12 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
}
}
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
/// to ask pairing
override func initiatePairing() {
// assuming that the transmitter is effectively awaiting the pairing, otherwise this obviously won't work
sendPairingRequest()
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
@ -193,12 +206,10 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
waitingPairingConfirmation = false
// inform delegate
cgmTransmitterDelegate?.pairingFailed()
bluetoothTransmitterDelegate.pairingFailed()
}
// inform delegate
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
@ -282,7 +293,7 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
sendKeepAliveMessage()
// delegate needs to be informed that pairing is needed
cgmTransmitterDelegate?.cgmTransmitterNeedsPairing()
bluetoothTransmitterDelegate.transmitterNeedsPairing(bluetoothTransmitter: self)
} else {
@ -319,12 +330,12 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
// if this is the first sensorDataRx after a successful pairing, then inform delegate that pairing is finished
if waitingPairingConfirmation {
waitingPairingConfirmation = false
cgmTransmitterDelegate?.successfullyPaired()
bluetoothTransmitterDelegate.successfullyPaired()
}
if let sensorDataRxMessage = SensorDataRxMessage(data: value) {
if firmwareVersion != nil {
if firmware != nil {
// transmitterversion was already recceived, let's see if we need to get the batterystatus
if Date() > Date(timeInterval: ConstantsDexcomG5.batteryReadPeriodInHours * 60 * 60, since: timeStampOfLastBatteryReading) {
@ -359,7 +370,7 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
} else {
timeStampOfLastG5Reading = Date()
let glucoseData = GlucoseData(timeStamp: sensorDataRxMessage.timestamp, glucoseLevelRaw: scaleRawValue(firmwareVersion: firmwareVersion, rawValue: sensorDataRxMessage.unfiltered), glucoseLevelFiltered: scaleRawValue(firmwareVersion: firmwareVersion, rawValue: sensorDataRxMessage.unfiltered))
let glucoseData = GlucoseData(timeStamp: sensorDataRxMessage.timestamp, glucoseLevelRaw: scaleRawValue(firmwareVersion: firmware, rawValue: sensorDataRxMessage.unfiltered), glucoseLevelFiltered: scaleRawValue(firmwareVersion: firmware, rawValue: sensorDataRxMessage.unfiltered))
var glucoseDataArray = [glucoseData]
@ -489,12 +500,6 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing
func initiatePairing() {
// assuming that the transmitter is effectively awaiting the pairing, otherwise this obviously won't work
sendPairingRequest()
}
/// to ask transmitter reset
func reset(requested:Bool) {
G5ResetRequested = requested
@ -548,10 +553,10 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
if let resetRxMessage = ResetRxMessage(data: value) {
if resetRxMessage.status == 0 {
trace("resetRxMessage status is 0, considering reset successful", log: log, category: ConstantsLog.categoryCGMG5, type: .info)
cgmTransmitterDelegate?.reset(successful: true)
bluetoothTransmitterDelegate.reset(successful: true)
} else {
trace("resetRxMessage status is %{public}d, considering reset failed", log: log, category: ConstantsLog.categoryCGMG5, type: .info, resetRxMessage.status)
cgmTransmitterDelegate?.reset(successful: false)
bluetoothTransmitterDelegate.reset(successful: false)
}
} else {
trace("resetRxMessage is nil", log: log, category: ConstantsLog.categoryCGMG5, type: .error)
@ -567,16 +572,23 @@ class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
}
private func processTransmitterVersionRxMessage(value:Data) {
if let transmitterVersionRxMessage = TransmitterVersionRxMessage(data: value) {
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: nil, sensorState: nil, sensorTimeInMinutes: nil, firmware: transmitterVersionRxMessage.firmwareVersion.hexEncodedString(), hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
// assign transmitterVersion
firmwareVersion = transmitterVersionRxMessage.firmwareVersion.hexEncodedString()
firmware = transmitterVersionRxMessage.firmwareVersion.hexEncodedString()
// send to delegate
cGMG5TransmitterDelegate?.received(firmware: firmware!, cGMG5Transmitter: self)
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: nil, sensorState: nil, sensorTimeInMinutes: nil, firmware: firmware, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
} else {
trace("transmitterVersionRxMessage is nil", log: log, category: ConstantsLog.categoryCGMG5, type: .error)
trace("transmitterVersionRxMessage is nil or firmware to hex is nil", log: log, category: ConstantsLog.categoryCGMG5, type: .error)
}
}
/// calculates encryptionkey

View File

@ -0,0 +1,9 @@
import Foundation
protocol CGMG5TransmitterDelegate: AnyObject {
/// received firmware from CGMG5Transmitter
func received(firmware: String, cGMG5Transmitter: CGMG5Transmitter)
}

View File

@ -8,10 +8,12 @@ class CGMG6Transmitter: CGMG5Transmitter {
/// - parameters:
/// - address: if already connected before, then give here the address that was received during previous connect, if not give nil
/// - transmitterID: expected transmitterID, 6 characters
override init(address:String?, name: String?, transmitterID:String, cGMTransmitterDelegate delegate:CGMTransmitterDelegate) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
override init(address:String?, name: String?, transmitterID:String, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMG5TransmitterDelegate: CGMG5TransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {
// call super.init
super.init(address: address, name: name, transmitterID: transmitterID, cGMTransmitterDelegate: delegate)
super.init(address: address, name: name, transmitterID: transmitterID, bluetoothTransmitterDelegate: bluetoothTransmitterDelegate, cGMG5TransmitterDelegate: cGMG5TransmitterDelegate, cGMTransmitterDelegate: cGMTransmitterDelegate)
}

View File

@ -1,41 +1,9 @@
import Foundation
import CoreBluetooth
/// defines functions that every cgm transmitter should conform to, mainly used by rootviewcontroller
///
/// 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
/// defines functions that every cgm transmitter should conform to
protocol CGMTransmitter:AnyObject {
/// get device name, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
///
/// this function is implemented in class BluetoothTransmitter.swift, it's not necessary for transmitter types to implement this function (as new transmitterType class conform to protocol CGMTransmitter but also extend the BluetoothTransmitter class
func name() -> String?
/// start scanning, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
/// - returns:
/// the scanning result
///
/// this function is implemented in class BluetoothTransmitter.swift, it's not necessary for transmitter types to implement this function (as new transmitterType class conform to protocol CGMTransmitter but also extend the BluetoothTransmitter class
func startScanning() -> BluetoothTransmitter.startScanningResult
/// get connection status, nil if peripheral not yet known, ie never connected or discovered the transmitter
///
/// this function is implemented in class BluetoothTransmitter.swift, it's not necessary for transmitter types to implement this function (as new transmitterType class conform to protocol CGMTransmitter but also extend the BluetoothTransmitter class
func getConnectionStatus() -> CBPeripheralState?
/// to ask transmitter that it initiates pairing
///
/// for transmitter types that don't need pairing, or that don't need pairing initiated by user/view controller, this will be an empty function. Only G5 (and in future maybe G6) will use it. The others can define an empty body
func initiatePairing()
/// to reset the transmitter
/// - parameters:
/// - requested : if true then transmitter must be reset
/// for transmitter types that don't support resetting, this will be an empty function. Only G5 (and in future maybe G6) will use it. The others can define an empty body
func reset(requested:Bool)
/// to set webOOPEnabled - called when user change the setting
///
/// for transmitters who don't support webOOP, there's no need to implemented this function<br>
@ -88,39 +56,6 @@ enum CGMTransmitterType:String, CaseIterable {
/// 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
func needsTransmitterId() -> Bool {
switch self {
case .dexcomG4:
return true
case .dexcomG5, .dexcomG6:
return true
case .miaomiao, .Bubble:
return false
case .GNSentry:
return false
case .Blucon:
return true
case .Droplet1:
return false
case .blueReader:
return false
case .watlaa:
return false
}
}
/// if true, then a class conforming to the protocol CGMTransmitterDelegate will call newSensorDetected if it detects a new sensor is placed. Means there's no need to let the user start and stop a sensor
///
/// example MiaoMiao can detect new sensor, implementation should return true, Dexcom transmitter's can't
@ -242,40 +177,6 @@ enum CGMTransmitterType:String, CaseIterable {
}
}
/// if true, then scanning can start automatically as soon as an instance of the CGM transmitter is created. This is typical for eg Dexcom G5, where an individual transitter can be idenfied via the transmitter id. Also the case for Blucon. For MiaoMiao and G4 xdrip this is different.
///
/// for this type of devices, there's no need to give an option in the UI to manually start scanning.
func startScanningAfterInit() -> Bool {
switch self {
case .dexcomG4:
return false
case .dexcomG5, .dexcomG6:
return true
case .miaomiao, .Bubble:
return false
case .GNSentry:
return false
case .Blucon:
return true
case .Droplet1:
return false
case .blueReader:
return false
case .watlaa:
return false
}
}
/// what unit to use for battery level, like '%', Volt, or nothing at all
///
/// to be used for UI stuff
@ -307,34 +208,4 @@ enum CGMTransmitterType:String, CaseIterable {
}
}
/// can a transmitter be reset ? For example Dexcom G5 (and G6) can be reset
///
/// can be used in UI stuff, if reset not possible then there's no need to show that option in the settings UI
func resetPossible() -> Bool {
switch self {
case .dexcomG4:
return false
case .dexcomG5, .dexcomG6:
return true
case .miaomiao, .Bubble, .Droplet1:
return false
case .GNSentry:
return false
case .Blucon:
return false
case .blueReader:
return false
case .watlaa:
return false
}
}
}

View File

@ -4,17 +4,6 @@ import CoreBluetooth
/// to be implemented for anyone who needs to receive information from a specific type of cgm transmitter
protocol CGMTransmitterDelegate:AnyObject {
/// transmitter reaches final connection status
///
/// example in CGMG4xDripTransmitter, the function is called only when subscription to read characteristic has succeeded, whereas for other like MiaoMiao, the function is called as soon as real connection is made
func cgmTransmitterDidConnect(address:String?, name:String?)
/// transmitter did disconnect
func cgmTransmitterDidDisconnect()
/// the ios device did change bluetooth status
func deviceDidUpdateBluetoothState(state: CBManagerState)
/// will only happen for MiaoMiao transmitter, anyway we can do the stuff for any type of transmitter which means restart the sensor, ask calibration blablabla
func newSensorDetected()
@ -34,24 +23,12 @@ protocol CGMTransmitterDelegate:AnyObject {
/// - sensorSerialNumber : serial number of the sensor, only applicable for Libre transmitters (MiaoMiao, Blucon, ...)
func cgmTransmitterInfoReceived(glucoseData:inout [GlucoseData], transmitterBatteryInfo:TransmitterBatteryInfo?, sensorState:LibreSensorState?, sensorTimeInMinutes:Int?, firmware:String?, hardware:String?, hardwareSerialNumber:String?, bootloader:String?, sensorSerialNumber:String?)
/// transmitter needs bluetooth pairing
func cgmTransmitterNeedsPairing()
/// transmitter successfully paired
func successfullyPaired()
/// transmitter pairing failed
func pairingFailed()
/// transmitter reset result
func reset(successful: Bool)
/// temporary function till all cgm transmitters have moved to bluetooth tab. - this function returns the currently assigned cgmTransmiter
func getCGMTransmitter() -> CGMTransmitter?
/// 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

@ -69,9 +69,11 @@ class CGMBluconTransmitter: BluetoothTransmitter {
/// - 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 address that was received during previous connect, if not give nil
/// - transmitterID: expected transmitterID
/// - delegate : CGMTransmitterDelegate
/// - cGMTransmitterDelegate : CGMTransmitterDelegate
/// - sensorSerialNumber : is needed to allow detection of a new sensor.
init?(address:String?, name: String?, transmitterID:String, delegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, sensorSerialNumber:String?) {
/// - bluetoothTransmitterDelegate : a NluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init?(address:String?, name: String?, transmitterID:String, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, sensorSerialNumber:String?) {
// assign addressname and name or expected devicename
// start by using expected device name
@ -91,10 +93,10 @@ class CGMBluconTransmitter: BluetoothTransmitter {
rxBuffer = Data()
// initialize
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_BluconService)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Blucon, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Blucon, startScanningAfterInit: CGMTransmitterType.Blucon.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_BluconService)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Blucon, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Blucon, startScanningAfterInit: CGMTransmitterType.Blucon.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
//assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
cgmTransmitterDelegate = cGMTransmitterDelegate
}
@ -134,7 +136,7 @@ class CGMBluconTransmitter: BluetoothTransmitter {
/// process new historic data block received from Blucon, one block is the contents when receiving multipleBlockResponseIndex, inclusive the opcode - this is used if we ask all Libre data from the transmitter, which includes sensorTime and sensorStatus
/// - returns:
/// - did receive all data yes or no, if yes, then blucon can go to sleep
/// also calls delegate with result of new readings
/// also calls cGMTransmitterDelegate with result of new readings
private func handleNewHistoricData(block: Data) -> Bool {
//check if buffer needs to be reset
@ -163,7 +165,7 @@ class CGMBluconTransmitter: BluetoothTransmitter {
}
//get readings from buffer and send to delegate
//get readings from buffer and send to cGMTransmitterDelegate
var result = LibreDataParser.parse(libreData: rxBuffer, timeStampLastBgReading: timeStampLastBgReading)
//TODO: sort glucosedata before calling newReadingsReceived
@ -230,32 +232,6 @@ class CGMBluconTransmitter: BluetoothTransmitter {
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
trace("in centralManagerDidConnect", log: log, category: ConstantsLog.categoryBlucon, type: .info)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
trace("in centralManagerDidDisconnectPeripheral", log: log, category: ConstantsLog.categoryBlucon, type: .info)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
@ -267,16 +243,19 @@ class CGMBluconTransmitter: BluetoothTransmitter {
// no need to log the error, it's already logged in BluetoothTransmitter
// check if it's an encryption error, if so call delegate
// check if it's an encryption error, if so call cGMTransmitterDelegate
if error.localizedDescription.uppercased().contains(find: "ENCRYPTION IS INSUFFICIENT") {
cgmTransmitterDelegate?.cgmTransmitterNeedsPairing()
// inform delegate
bluetoothTransmitterDelegate.transmitterNeedsPairing(bluetoothTransmitter: self)
waitingSuccessfulPairing = true
}
} else {
if waitingSuccessfulPairing {
cgmTransmitterDelegate?.successfullyPaired()
// inform delegate
bluetoothTransmitterDelegate.pairingFailed()
waitingSuccessfulPairing = false
}
}
@ -292,7 +271,7 @@ class CGMBluconTransmitter: BluetoothTransmitter {
// this is only applicable the very first time that blucon connects and pairing is done
if waitingSuccessfulPairing {
cgmTransmitterDelegate?.successfullyPaired()
bluetoothTransmitterDelegate.successfullyPaired()
waitingSuccessfulPairing = false
}
@ -341,7 +320,7 @@ class CGMBluconTransmitter: BluetoothTransmitter {
case .sensorNotDetected:
// Blucon didn't detect sensor, call delegate
// Blucon didn't detect sensor, call cGMTransmitterDelegate
cgmTransmitterDelegate?.sensorNotDetected()
// and send Blucon to sleep
@ -352,14 +331,14 @@ class CGMBluconTransmitter: BluetoothTransmitter {
// get serial number
let newSerialNumber = BluconUtilities.decodeSerialNumber(input: value)
// verify serial number and if changed inform delegate
// verify serial number and if changed inform cGMTransmitterDelegate
if newSerialNumber != sensorSerialNumber {
trace(" new sensor detected : %{public}@", log: log, category: ConstantsLog.categoryBlucon, type: .info, newSerialNumber)
sensorSerialNumber = newSerialNumber
// inform delegate about new sensor detected
// inform cGMTransmitterDelegate about new sensor detected
cgmTransmitterDelegate?.newSensorDetected()
// also reset timestamp last reading, to be sure that if new sensor is started, we get historic data
@ -386,7 +365,7 @@ class CGMBluconTransmitter: BluetoothTransmitter {
}
// inform delegate about sensorSerialNumber and sensorState
// inform cGMTransmitterDelegate about sensorSerialNumber and sensorState
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: nil, sensorState: sensorState, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: sensorSerialNumber)
return
@ -542,11 +521,6 @@ class CGMBluconTransmitter: BluetoothTransmitter {
extension CGMBluconTransmitter: CGMTransmitter {
func initiatePairing() {
// nothing to do, Blucon keeps on reconnecting, resulting in continous pairing request
return
}
func reset(requested: Bool) {
// no reset supported for blucon
return

View File

@ -28,7 +28,9 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, CGMTransmitter {
/// - 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?, delegate:CGMTransmitterDelegate) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "blueReader")
@ -37,38 +39,14 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, CGMTransmitter {
}
// assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
cgmTransmitterDelegate = cGMTransmitterDelegate
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_BlueReader)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_BlueReader, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_BlueReader, startScanningAfterInit: CGMTransmitterType.blueReader.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_BlueReader)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_BlueReader, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_BlueReader, startScanningAfterInit: CGMTransmitterType.blueReader.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
@ -135,11 +113,6 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because Bubble doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because Bubble doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -59,7 +59,9 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
/// - webOOPEnabled : enabled or not
/// - oopWebSite : oop web site url to use, only used in case webOOPEnabled = true
/// - oopWebToken : oop web token to use, only used in case webOOPEnabled = true
init(address:String?, name: String?, delegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, sensorSerialNumber:String?, webOOPEnabled: Bool, oopWebSite: String, oopWebToken: String) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, sensorSerialNumber:String?, webOOPEnabled: Bool, oopWebSite: String, oopWebToken: String) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: expectedDeviceNameBubble)
@ -71,7 +73,7 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
self.sensorSerialNumber = sensorSerialNumber
// assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
// initialize rxbuffer
rxBuffer = Data()
@ -87,7 +89,7 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
self.oopWebToken = oopWebToken
self.oopWebSite = oopWebSite
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Bubble)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Bubble, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Bubble, startScanningAfterInit: CGMTransmitterType.Bubble.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Bubble)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Bubble, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Bubble, startScanningAfterInit: CGMTransmitterType.Bubble.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
@ -104,30 +106,6 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
@ -222,11 +200,6 @@ class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because Bubble doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because Bubble doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -28,7 +28,9 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, CGMTransmitter {
/// - 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?, delegate:CGMTransmitterDelegate) {
/// - bluetoothTransmitterDelegate : a NluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "limitter")
@ -37,38 +39,14 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, CGMTransmitter {
}
// assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Droplet)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Droplet, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Droplet, startScanningAfterInit: CGMTransmitterType.Droplet1.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Droplet)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Droplet, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Droplet, startScanningAfterInit: CGMTransmitterType.Droplet1.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
@ -137,11 +115,6 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because Bubble doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because Bubble doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -93,7 +93,9 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, CGMTransmitter {
/// - 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?, delegate:CGMTransmitterDelegate, timeStampLastBgReading:Date) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init?(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate, timeStampLastBgReading:Date) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "GNSentry")
@ -105,39 +107,15 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, CGMTransmitter {
self.timeStampLastBgReadingInMinutes = timeStampLastBgReading.toMillisecondsAsDouble()/1000/60
// initialize
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_GNWService), CBUUID(string: CBUUID_BatteryService), CBUUID(string: CBUUID_DeviceInformationService)], CBUUID_ReceiveCharacteristic: CBUUID_Characteristic_UUID.CBUUID_GNW_Notify.rawValue, CBUUID_WriteCharacteristic: CBUUID_Characteristic_UUID.CBUUID_GNW_Write.rawValue, startScanningAfterInit: CGMTransmitterType.GNSentry.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_GNWService), CBUUID(string: CBUUID_BatteryService), CBUUID(string: CBUUID_DeviceInformationService)], CBUUID_ReceiveCharacteristic: CBUUID_Characteristic_UUID.CBUUID_GNW_Notify.rawValue, CBUUID_WriteCharacteristic: CBUUID_Characteristic_UUID.CBUUID_GNW_Write.rawValue, startScanningAfterInit: CGMTransmitterType.GNSentry.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
//assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
}
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
@ -258,11 +236,6 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because GNSEntry doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because GNSEntry doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -56,12 +56,13 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
/// - 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
/// - delegate : CGMTransmitterDelegate intance
/// - timeStampLastBgReading : timestamp of last bgReading
/// - webOOPEnabled : enabled or not
/// - oopWebSite : oop web site url to use, only used in case webOOPEnabled = true
/// - oopWebToken : oop web token to use, only used in case webOOPEnabled = true
init(address:String?, name: String?, delegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, webOOPEnabled: Bool, oopWebSite: String, oopWebToken: String) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
/// - cGMTransmitterDelegate : a CGMTransmitterDelegate
init(address:String?, name: String?, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate, cGMTransmitterDelegate:CGMTransmitterDelegate, timeStampLastBgReading:Date, webOOPEnabled: Bool, oopWebSite: String, oopWebToken: String) {
// assign addressname and name or expected devicename
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: expectedDeviceNameMiaoMiao)
@ -70,7 +71,7 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
}
// assign CGMTransmitterDelegate
cgmTransmitterDelegate = delegate
self.cgmTransmitterDelegate = cGMTransmitterDelegate
// initialize rxbuffer
rxBuffer = Data()
@ -86,7 +87,7 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
self.oopWebToken = oopWebToken
self.oopWebSite = oopWebSite
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_MiaoMiao)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_MiaoMiao, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_MiaoMiao, startScanningAfterInit: CGMTransmitterType.miaomiao.startScanningAfterInit(), bluetoothTransmitterDelegate: nil)
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_MiaoMiao)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_MiaoMiao, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_MiaoMiao, startScanningAfterInit: CGMTransmitterType.miaomiao.startScanningAfterInit(), bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
}
@ -103,30 +104,6 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: - overriden BluetoothTransmitter functions
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
super.centralManager(central, didConnect: peripheral)
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
}
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
super.centralManagerDidUpdateState(central)
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
}
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
}
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
@ -236,11 +213,6 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
// MARK: CGMTransmitter protocol functions
/// to ask pairing - empty function because G4 doesn't need pairing
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments
func initiatePairing() {}
/// to ask transmitter reset - empty function because MiaoMiao doesn't support reset
///
/// this function is not implemented in BluetoothTransmitter.swift, otherwise it might be forgotten to look at in future CGMTransmitter developments

View File

@ -10,7 +10,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
// MARK: - public properties
/// variable : it can get a new value during app run, will be used by rootviewcontroller's that want to receive info
public weak var variableBluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
public var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate
// MARK: - private properties
@ -65,9 +65,6 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
/// should the app try to reconnect after disconnect?
private var reconnectAfterDisconnect:Bool = true
/// fixed : it will be set during init and not change, there's also a variable one, named variableBluetoothTransmitterDelegate
private(set) weak var fixedBluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
// MARK: - Initialization
/// - parameters:
@ -79,8 +76,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
/// - servicesCBUUIDs: service uuid's
/// - CBUUID_ReceiveCharacteristic: receive characteristic uuid
/// - CBUUID_WriteCharacteristic: write characteristic uuid
/// - delegate : a
init(addressAndName:BluetoothTransmitter.DeviceAddressAndName, CBUUID_Advertisement:String?, servicesCBUUIDs:[CBUUID], CBUUID_ReceiveCharacteristic:String, CBUUID_WriteCharacteristic:String, startScanningAfterInit:Bool, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?) {
/// - bluetoothTransmitterDelegate : a BluetoothTransmitterDelegate
init(addressAndName:BluetoothTransmitter.DeviceAddressAndName, CBUUID_Advertisement:String?, servicesCBUUIDs:[CBUUID], CBUUID_ReceiveCharacteristic:String, CBUUID_WriteCharacteristic:String, startScanningAfterInit:Bool, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
switch addressAndName {
@ -105,8 +102,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
//initialize timeStampLastStatusUpdate
timeStampLastStatusUpdate = Date()
// assign delegate
self.fixedBluetoothTransmitterDelegate = bluetoothTransmitterDelegate
// assign bluetoothTransmitterDelegate
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
super.init()
@ -367,8 +364,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
trace("connected to peripheral with name %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'")
fixedBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: self)
variableBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: self)
bluetoothTransmitterDelegate.didConnectTo(bluetoothTransmitter: self)
peripheral.discoverServices(servicesCBUUIDs)
@ -394,8 +390,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
trace("in centralManagerDidUpdateState, for peripheral with name %{public}@, new state is %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info, deviceName ?? "'unknown'", "\(central.state.toString())")
fixedBluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state, bluetoothTransmitter: self)
variableBluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state, bluetoothTransmitter: self)
bluetoothTransmitterDelegate.deviceDidUpdateBluetoothState(state: central.state, bluetoothTransmitter: self)
/// in case status changed to powered on and if device address known then try either to retrieveperipherals, or if that doesn't succeed, start scanning
if central.state == .poweredOn, reconnectAfterDisconnect {
@ -415,8 +410,7 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
trace(" didDisconnect peripheral with name %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .info , deviceName ?? "'unknown'")
fixedBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: self)
variableBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: self)
bluetoothTransmitterDelegate.didDisconnectFrom(bluetoothTransmitter: self)
if let error = error {
trace(" error: %{public}@", log: log, category: ConstantsLog.categoryBlueToothTransmitter, type: .error , error.localizedDescription)
@ -520,7 +514,13 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
}
}
/// to ask transmitter that it initiates pairing
///
/// to be overriden. For transmitter types that don't need pairing, or that don't need pairing initiated by user/view controller, this function does not need to be overriden
func initiatePairing() {return}
// MARK: methods to get address and name
/// read device name

View File

@ -17,4 +17,19 @@ protocol BluetoothTransmitterDelegate: AnyObject {
/// the ios device did change bluetooth status
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter)
/// transmitter needs bluetooth pairing, this to allow to notify the user about the fact that pairing is needed
func transmitterNeedsPairing(bluetoothTransmitter: BluetoothTransmitter)
/// transmitter successfully paired
func successfullyPaired()
/// transmitter pairing failed
func pairingFailed()
/// transmitter reset result
func reset(successful: Bool)
/// to pass some text error message, delegate can decide to show to user, log, ...
func error(message: String)
}

View File

@ -35,6 +35,8 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
/// possible rotation values, , the value is how it will be sent to the M5Stack but not how it's stored in the M5Stack object - In the M5Stack object we store an Int value which is used as index in rotationValues and rotationStrings
private let rotationValues: [UInt16] = [ 1, 2, 3, 0]
public weak var m5StackBluetoothTransmitterDelegate: M5StackBluetoothTransmitterDelegate?
// MARK: - initializer
/// - parameters:
@ -61,6 +63,9 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
// assign bluetoothPeripheralType
self.bluetoothPeripheralType = bluetoothPeripheralType
// assign m5StackBluetoothTransmitterDelegate
self.m5StackBluetoothTransmitterDelegate = m5StackBluetoothTransmitterDelegate
// call super
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service)], CBUUID_ReceiveCharacteristic: CBUUID_TxRxCharacteristic, CBUUID_WriteCharacteristic: CBUUID_TxRxCharacteristic, startScanningAfterInit: false, bluetoothTransmitterDelegate: bluetoothTransmitterDelegate)
@ -351,8 +356,7 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
self.blePassword = newBlePassword
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)? .newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: self)
}
@ -364,8 +368,7 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
trace(" successfully authenticated", log: log, category: ConstantsLog.categoryM5StackBluetoothTransmitter, type: .error)
// inform delegates
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: true, m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: true, m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.authentication(success: true, m5StackBluetoothTransmitter: self)
// final steps after successful communication
finalizeConnectionSetup()
@ -373,18 +376,13 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
case .authenticateFailureRx:
// received authentication failure, inform delegates
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: false, m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: false, m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.authentication(success: false, m5StackBluetoothTransmitter: self)
case .readBlePassWordError1Rx:
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.blePasswordMissing(m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.blePasswordMissing(m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.blePasswordMissing(m5StackBluetoothTransmitter: self)
case .readBlePassWordError2Rx:
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.m5StackResetRequired(m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.m5StackResetRequired(m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.m5StackResetRequired(m5StackBluetoothTransmitter: self)
case .readTimeStampRx:
@ -394,8 +392,7 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
case .readAllParametersRx:
// M5Stack is asking for all parameters
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isAskingForAllParameters(m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isAskingForAllParameters(m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.isAskingForAllParameters(m5StackBluetoothTransmitter: self)
case .readBatteryLevelRx:
@ -408,8 +405,7 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
let receivedBatteryLevel = Int(value[1])
// M5Stack is sending batteryLevel, which is in the second byte
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.receivedBattery(level: receivedBatteryLevel, m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.receivedBattery(level: receivedBatteryLevel, m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.receivedBattery(level: receivedBatteryLevel, m5StackBluetoothTransmitter: self)
}
@ -545,8 +541,8 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter {
// this is the time when the M5stack is ready to receive readings or parameter updates
isReadyToReceiveData = true
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
m5StackBluetoothTransmitterDelegate?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
}

View File

@ -1,6 +1,6 @@
import Foundation
protocol M5StackBluetoothTransmitterDelegate {
protocol M5StackBluetoothTransmitterDelegate: AnyObject {
/// will be called if M5StackBluetoothTransmitter is connected and ready to receive data
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)

View File

@ -1,6 +1,6 @@
import Foundation
protocol WatlaaBluetoothTransmitterDelegate {
protocol WatlaaBluetoothTransmitterDelegate: AnyObject {
/// 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)

View File

@ -2,10 +2,6 @@ import Foundation
extension WatlaaBluetoothTransmitterMaster: CGMTransmitter {
func initiatePairing() {
// no pairing needed for watlaa
}
func reset(requested: Bool) {
// no reset need for watlaa
}

View File

@ -4,7 +4,11 @@ import CoreBluetooth
final class WatlaaBluetoothTransmitterMaster: BluetoothTransmitter {
// MARK: UUID's
// MARK: - public properties
public weak var watlaaBluetoothTransmitterDelegate: WatlaaBluetoothTransmitterDelegate?
// MARK: - UUID's
/// Glucose Data Service UUID
let CBUUID_Data_Service = "00001010-1212-EFDE-0137-875F45AC0113"
@ -111,6 +115,9 @@ final class WatlaaBluetoothTransmitterMaster: BluetoothTransmitter {
//assign CGMTransmitterDelegate
self.cgmTransmitterDelegate = cgmTransmitterDelegate
// assign watlaaBluetoothTransmitterDelegate
self.watlaaBluetoothTransmitterDelegate = watlaaBluetoothTransmitterDelegate
//initialize timeStampLastBgReading
timeStampLastBgReading = Date(timeIntervalSince1970: 0)
@ -243,8 +250,7 @@ final class WatlaaBluetoothTransmitterMaster: BluetoothTransmitter {
// 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)
watlaaBluetoothTransmitterDelegate?.receivedBattery(level: receivedBatteryLevel, watlaaBluetoothTransmitter: self)
}
@ -271,8 +277,7 @@ final class WatlaaBluetoothTransmitterMaster: BluetoothTransmitter {
}
// here all characteristics should be known, we can call isReadyToReceiveData
(fixedBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.isReadyToReceiveData(watlaaBluetoothTransmitter: self)
(variableBluetoothTransmitterDelegate as? WatlaaBluetoothTransmitterDelegate)?.isReadyToReceiveData(watlaaBluetoothTransmitter: self)
watlaaBluetoothTransmitterDelegate?.isReadyToReceiveData(watlaaBluetoothTransmitter: self)
}

View File

@ -0,0 +1,259 @@
import UIKit
import CoreBluetooth
import AVFoundation
import AudioToolbox
extension BluetoothPeripheralManager: BluetoothTransmitterDelegate {
/// because extension dont allow var's, this is a workaround as explained here https://medium.com/@valv0/computed-properties-and-extensions-a-pure-swift-approach-64733768112c
private struct PropertyHolder {
/// timestamp of last notification for pairing
static var timeStampLastNotificationForPairing:Date?
/// timer used when asking the transmitter to initiate pairing. The user is waiting for the response, if the response from the transmitter doesn't come within a few seconds, then we'll inform the user
static var transmitterPairingResponseTimer:Timer?
/// constant for key in ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground - initiate pairing
static let applicationManagerKeyInitiatePairing = "RootViewController-InitiatePairing"
}
/// Transmitter is calling this delegate function to indicate that bluetooth pairing is needed. If the app is in the background, the user will be informed, after opening the app a pairing request will be initiated. if the app is in the foreground, the pairing request will be initiated immediately
func transmitterNeedsPairing(bluetoothTransmitter: BluetoothTransmitter) {
trace("transmitter needs pairing", log: log, category: ConstantsLog.categoryRootView, type: .info)
if let timeStampLastNotificationForPairing = PropertyHolder.timeStampLastNotificationForPairing {
// check timestamp of last notification, if too soon then return
if Int(abs(timeStampLastNotificationForPairing.timeIntervalSinceNow)) < ConstantsBluetoothPairing.minimumTimeBetweenTwoPairingNotificationsInSeconds {
return
}
}
// set timeStampLastNotificationForPairing
PropertyHolder.timeStampLastNotificationForPairing = Date()
// remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure NnotificationContent title
notificationContent.title = Texts_Common.warning
notificationContent.body = Texts_HomeView.transmitterNotPaired
// add sound
notificationContent.sound = UNNotificationSound.init(named: UNNotificationSoundName.init(""))
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing, content: notificationContent, trigger: nil)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
trace("Unable add notification request : transmitter needs pairing Notification Request, error : %{public}@", log: self.log, category: ConstantsLog.categoryRootView, type: .error, error.localizedDescription)
}
}
// vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
// add closure to ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground so that if user opens the app, the pairing request will be initiated. This can be done only if the app is opened within 60 seconds.
// If the app is already in the foreground, then userNotificationCenter willPresent will be called, in this function the closure will be removed immediately, and the pairing request will be called. As a result, if the app is in the foreground, the user will not see (or hear) any notification, but the pairing will be initiated
// max timestamp when notification was fired - connection stays open for 1 minute, taking 1 second as d
let maxTimeUserCanOpenApp = Date(timeIntervalSinceNow: TimeInterval(ConstantsDexcomG5.maxTimeToAcceptPairingInSeconds - 1))
// we will not just count on it that the user will click the notification to open the app (assuming the app is in the background, if the app is in the foreground, then we come in another flow)
// whenever app comes from-back to foreground, updateLabelsAndChart needs to be called
ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground(key: PropertyHolder.applicationManagerKeyInitiatePairing, closure: {
// first of all reremove from application key manager
ApplicationManager.shared.removeClosureToRunWhenAppWillEnterForeground(key: PropertyHolder.applicationManagerKeyInitiatePairing)
// first remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// if it was too long since notification was fired, then forget about it - inform user that it's too late
if Date() > maxTimeUserCanOpenApp {
trace("in cgmTransmitterNeedsPairing, user opened the app too late", log: self.log, category: ConstantsLog.categoryRootView, type: .error)
let alert = UIAlertController(title: Texts_Common.warning, message: Texts_HomeView.transmitterPairingTooLate, actionHandler: nil)
self.uIViewController.present(alert, animated: true, completion: nil)
return
}
// initiate the pairing
self.initiateTransmitterPairing(bluetoothTransmitter: bluetoothTransmitter)
})
}
func successfullyPaired() {
// remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// invalidate transmitterPairingResponseTimer
if let transmitterPairingResponseTimer = PropertyHolder.transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
// inform user
let alert = UIAlertController(title: Texts_HomeView.info, message: Texts_HomeView.transmitterPairingSuccessful, actionHandler: nil)
uIViewController.present(alert, animated: true, completion: nil)
}
func pairingFailed() {
// this should be the consequence of the user not accepting the pairing request, there's no need to inform the user
// invalidate transmitterPairingResponseTimer
if let transmitterPairingResponseTimer = PropertyHolder.transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
}
func reset(successful: Bool) {
// reset setting to false
UserDefaults.standard.transmitterResetRequired = false
// Create Notification Content to give info about reset result of reset attempt
let notificationContent = UNMutableNotificationContent()
// Configure NnotificationContent title
notificationContent.title = successful ? Texts_HomeView.info : Texts_Common.warning
notificationContent.body = Texts_HomeView.transmitterResetResult + " : " + (successful ? Texts_HomeView.success : Texts_HomeView.failed)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: ConstantsNotifications.NotificationIdentifierForResetResult.transmitterResetResult, content: notificationContent, trigger: nil)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
trace("Unable add notification request : transmitter reset result, error: %{public}@", log: self.log, category: ConstantsLog.categoryRootView, type: .error, error.localizedDescription)
}
}
}
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)
return
}
// check that address and name are not nil, otherwise this looks like a coding error
guard let deviceAddressNewTransmitter = bluetoothTransmitter.deviceAddress, let deviceNameNewTransmitter = bluetoothTransmitter.deviceName else {
trace("in didConnect, address or name of new transmitter is nil, looks like a coding error", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return
}
// check that tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral and the bluetoothTransmitter to which connection is made are actually the same objects, otherwise it's a connection that is made to a already known/stored BluetoothTransmitter
guard tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral == bluetoothTransmitter else {
trace("in didConnect, tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral is not nil and not equal to bluetoothTransmitter", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
return
}
// check that it's a peripheral for which we don't know yet the address
for buetoothPeripheral in bluetoothPeripherals {
if buetoothPeripheral.blePeripheral.address == deviceAddressNewTransmitter {
trace("in didConnect, transmitter address already known. This is not a new device, will disconnect", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// it's an already known BluetoothTransmitter, not storing this, on the contrary disconnecting because maybe it's a bluetoothTransmitter already known for which user has preferred not to connect to
// If we're actually waiting for a new scan result, then there's an instance of BluetoothTransmitter stored in tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral - but this one stopped scanning, so let's recreate an instance of BluetoothTransmitter
self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = createNewTransmitter(type: getTransmitterType(for: bluetoothTransmitter), transmitterId: buetoothPeripheral.blePeripheral.transmitterId)
_ = self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral?.startScanning()
return
}
}
// it's a new peripheral that we will store. No need to continue scanning
bluetoothTransmitter.stopScanning()
// create bluetoothPeripheral
let newBluetoothPeripheral = getTransmitterType(for: tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral).createNewBluetoothPeripheral(withAddress: deviceAddressNewTransmitter, withName: deviceNameNewTransmitter, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
bluetoothPeripherals.append(newBluetoothPeripheral)
bluetoothTransmitters.append(bluetoothTransmitter)
// call the callback function
if let callBackAfterDiscoveringDevice = callBackAfterDiscoveringDevice {
callBackAfterDiscoveringDevice(newBluetoothPeripheral)
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()
}
}
func error(message: String) {
trace("received error = %{public}@", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info, message)
}
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
// no further action, This is for UIViewcontroller's that also receive this info, means info can only be shown if this happens while user has one of the UIViewcontrollers open
trace("in didDisconnectFrom", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
}
/// will call bluetoothTransmitter.initiatePairing() - also sets timer, if no successful pairing within a few seconds, then info will be given to user asking to wait another few minutes
private func initiateTransmitterPairing(bluetoothTransmitter: BluetoothTransmitter) {
// initiate the pairing
bluetoothTransmitter.initiatePairing()
// invalide the timer, if it exists
if let transmitterPairingResponseTimer = PropertyHolder.transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
// create and schedule timer
PropertyHolder.transmitterPairingResponseTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(informUserThatPairingTimedOut), userInfo: nil, repeats: false)
}
// inform user that pairing request timed out
@objc private func informUserThatPairingTimedOut() {
let alert = UIAlertController(title: Texts_Common.warning, message: "time out", actionHandler: nil)
uIViewController.present(alert, animated: true, completion: nil)
}
}

View File

@ -0,0 +1,15 @@
import Foundation
extension BluetoothPeripheralManager: CGMG5TransmitterDelegate {
func received(firmware: String, cGMG5Transmitter: CGMG5Transmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: cGMG5Transmitter), let dexcomG5 = bluetoothPeripherals[index] as? DexcomG5 else {return}
dexcomG5.firmwareVersion = firmware
coreDataManager.saveChanges()
}
}

View File

@ -0,0 +1,203 @@
import Foundation
// MARK: - conform to M5StackBluetoothTransmitterDelegate
extension BluetoothPeripheralManager: M5StackBluetoothTransmitterDelegate {
func receivedBattery(level: Int, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
m5Stack.batteryLevel = level
}
/// did the app successfully authenticate towards M5Stack, if no, then disconnect will be done
func authentication(success: Bool, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in authentication with success = %{public}@", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info, success.description)
// if authentication not successful then disconnect and don't reconnect, user should verify password or reset the M5Stack, disconnect and set shouldconnect to false, permenantly (ie store in core data)
// disconnection is done because maybe another device is trying to connect to the M5Stack, need to make it free
// also set shouldConnect to false (note that this is also done in M5StackViewController if an instance of that exists, no issue, shouldConnect will be set to false two times
if !success {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// don't try to reconnect after disconnecting
m5Stack.blePeripheral.shouldconnect = false
// store in core data
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
}
/// there's no ble password set, user should set it in the settings - disconnect will be called, shouldconnect is set to false
func blePasswordMissing(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in blePasswordMissing", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// don't try to reconnect after disconnecting
m5Stack.blePeripheral.shouldconnect = false
// store in core data
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
/// if a new ble password is received from M5Stack
func newBlePassWord(newBlePassword: String, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in newBlePassWord, storing the password in M5Stack", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and also the bluetoothPeripheral and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// possibily this is a new scanned m5stack, calling coreDataManager.saveChanges() but still the user may be in M5stackviewcontroller and decide not to save the m5stack, bad luck
m5Stack.blepassword = newBlePassword
coreDataManager.saveChanges()
}
/// it's an M5Stack without password configured in the ini file. xdrip app has been requesting temp password to M5Stack but this was already done once. M5Stack needs to be reset. - disconnect will be called, shouldconnect is set to false
func m5StackResetRequired(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in m5StackResetRequired", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// should not try to reconnect, wait till user decide to push the "always connect button"
m5Stack.blePeripheral.shouldconnect = false
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
/// M5Stack is asking for an update of all parameters, send them
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter) else {
trace("in isAskingForAllParameters, could not find index of bluetoothTransmitter, looks like a coding error", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return
}
// send all parameters, if successful,then for this m5Stack we can set parameterUpdateNeeded to false
if sendAllParametersToM5Stack(to: m5StackBluetoothTransmitter) {
(bluetoothPeripherals[index] as? M5Stack)?.blePeripheral.parameterUpdateNeededAtNextConnect = false
} else {
// failed, so we need to set parameterUpdateNeeded to true, so that next time it connects we will send all parameters
(bluetoothPeripherals[index] as? M5Stack)?.blePeripheral.parameterUpdateNeededAtNextConnect = true
}
}
/// will be called if M5Stack is connected, and authentication was successful, BluetoothPeripheralManager can start sending data like parameter updates or bgreadings
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// if the M5Stack needs new parameters, then send them
if m5Stack.blePeripheral.parameterUpdateNeededAtNextConnect {
// send all parameters
if sendAllParametersToM5Stack(to: m5StackBluetoothTransmitter) {
m5Stack.blePeripheral.parameterUpdateNeededAtNextConnect = false
}
}
// send latest reading
sendLatestReading(to: m5Stack)
}
// MARK: - private functions related to M5Stack
/// send all parameters to m5Stack
/// - parameters:
/// - to : m5StackBluetoothTransmitter to send all parameters
/// - returns:
/// successfully written all parameters or not
private func sendAllParametersToM5Stack(to m5StackBluetoothTransmitter : M5StackBluetoothTransmitter) -> Bool {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return false}
// M5Stack must be ready to receive data
guard m5StackBluetoothTransmitter.isReadyToReceiveData else {
trace("in sendAllParameters, bluetoothTransmitter is not ready to receive data", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
return false
}
// initialise returnValue, result
var success = true
// send bloodglucoseunit
if !m5StackBluetoothTransmitter.writeBloodGlucoseUnit(isMgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl) {success = false}
// send textColor
if !m5StackBluetoothTransmitter.writeTextColor(textColor: M5StackColor(forUInt16: UInt16(m5Stack.textcolor)) ?? UserDefaults.standard.m5StackTextColor ?? ConstantsM5Stack.defaultTextColor) {success = false}
// send backGroundColor
if !m5StackBluetoothTransmitter.writeBackGroundColor(backGroundColor: M5StackColor(forUInt16: UInt16(m5Stack.backGroundColor)) ?? ConstantsM5Stack.defaultBackGroundColor ) {success = false}
// send rotation
if !m5StackBluetoothTransmitter.writeRotation(rotation: Int(m5Stack.rotation)) {success = false}
// send connectToWiFi
if !m5StackBluetoothTransmitter.writeConnectToWiFi(connect: m5Stack.connectToWiFi) {success = false}
// send WiFiSSID's
if let wifiName = UserDefaults.standard.m5StackWiFiName1 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 1) {success = false}
}
if let wifiName = UserDefaults.standard.m5StackWiFiName2 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 2) {success = false}
}
if let wifiName = UserDefaults.standard.m5StackWiFiName3 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 3) {success = false}
}
// send WiFiPasswords
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword1 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 1) {success = false}
}
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword2 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 2) {success = false}
}
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword3 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 3) {success = false}
}
// send nightscout url
if let url = UserDefaults.standard.nightScoutUrl {
if !m5StackBluetoothTransmitter.writeNightScoutUrl(url: url) {success = false}
}
// send nightscout token
if let token = UserDefaults.standard.nightScoutAPIKey {
if !m5StackBluetoothTransmitter.writeNightScoutAPIKey(apiKey: token) {success = false}
}
// return success
return success
}
}

View File

@ -0,0 +1,22 @@
import Foundation
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
coreDataManager.saveChanges()
}
}

View File

@ -2,53 +2,55 @@ import Foundation
import os
import CoreBluetooth
import CoreData
import UIKit
class BluetoothPeripheralManager: NSObject {
// MARK: - public properties
/// all currently known BluetoothPeripheral's (MStacks, cgmtransmitters, watlaa , ...)
public var bluetoothPeripherals: [BluetoothPeripheral] = []
/// the bluetoothTransmitter's, array must have the same size as bluetoothPeripherals. For each element in bluetoothPeripherals, there's an element at the same index in bluetoothTransmitters, which may be nil. nil value means user selected not to connect
public var bluetoothTransmitters: [BluetoothTransmitter?] = []
/// for logging
public var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryBluetoothPeripheralManager)
/// 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
public var onCGMTransmitterCreation: (CGMTransmitter?) -> ()
/// if scan is called, an instance of M5StackBluetoothTransmitter is created with address and name. The new instance will be assigned to this variable, temporary, until a connection is made
public var tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral: BluetoothTransmitter?
/// 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
public var callBackAfterDiscoveringDevice: ((BluetoothPeripheral) -> Void)?
/// will be used to present alerts, for example pairing failed
public let uIViewController: UIViewController
// MARK: - private properties
/// CoreDataManager to use
private let coreDataManager:CoreDataManager
public let coreDataManager:CoreDataManager
/// for logging
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryBluetoothPeripheralManager)
/// dictionary with key = an instance of BluetoothPeripheral, and value an instance of BluetoothTransmitter. Value can be nil in which case we found a BluetoothPeripheral in the coredata but shouldconnect == false so we don't instanstiate a BluetoothTransmitter
//private var m5StacksBlueToothTransmitters = [BluetoothPeripheral : BluetoothTransmitter?]()
/// all currently known BluetoothPeripheral's (MStacks, cgmtransmitters, watlaa , ...)
private var bluetoothPeripherals: [BluetoothPeripheral] = []
/// the bluetoothTransmitter's, array must have the same size as bluetoothPeripherals. For each element in bluetoothPeripherals, there's an element at the same index in bluetoothTransmitters, which may be nil. nil value means user selected not to connect
private var bluetoothTransmitters: [BluetoothTransmitter?] = []
/// reference to BgReadingsAccessor
private var bgReadingsAccessor: BgReadingsAccessor
/// reference to BLEPeripheralAccessor
private var bLEPeripheralAccessor: BLEPeripheralAccessor
/// 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)?
/// if scan is called, an instance of M5StackBluetoothTransmitter is created with address and name. The new instance will be assigned to this variable, temporary, until a connection is made
private var tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral: BluetoothTransmitter?
/// 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
/// - parameters:
/// - onCGMTransmitterCreation : to be called when cgmtransmitter is created
init(coreDataManager: CoreDataManager, cgmTransmitterDelegate: CGMTransmitterDelegate, onCGMTransmitterCreation: @escaping (CGMTransmitter?) -> ()) {
init(coreDataManager: CoreDataManager, cgmTransmitterDelegate: CGMTransmitterDelegate, uIViewController: UIViewController, onCGMTransmitterCreation: @escaping (CGMTransmitter?) -> ()) {
// initialize properties
self.coreDataManager = coreDataManager
@ -56,6 +58,7 @@ class BluetoothPeripheralManager: NSObject {
self.cgmTransmitterDelegate = cgmTransmitterDelegate
self.onCGMTransmitterCreation = onCGMTransmitterCreation
self.bLEPeripheralAccessor = BLEPeripheralAccessor(coreDataManager: coreDataManager)
self.uIViewController = uIViewController
super.init()
@ -125,7 +128,7 @@ class BluetoothPeripheralManager: NSObject {
// 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(CGMG5Transmitter(address: dexcomG5.blePeripheral.address, name: dexcomG5.blePeripheral.name, transmitterID: transmitterId, cGMTransmitterDelegate: cgmTransmitterDelegate))
bluetoothTransmitters.append(CGMG5Transmitter(address: dexcomG5.blePeripheral.address, name: dexcomG5.blePeripheral.name, transmitterID: transmitterId, bluetoothTransmitterDelegate: self, cGMG5TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate))
}
@ -200,6 +203,148 @@ class BluetoothPeripheralManager: NSObject {
}
}
/// disconnect from bluetoothPeripheral - and don't reconnect - set shouldconnect to false
public func disconnect(fromBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral) {
// device should not reconnect after disconnecting
bluetoothPeripheral.blePeripheral.shouldconnect = false
// save in coredata
coreDataManager.saveChanges()
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false) {
_ = bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
}
}
/// returns the bluetoothTransmitter for the bluetoothPeripheral
/// - parameters:
/// - forBluetoothPeripheral : the bluetoothPeripheral for which bluetoothTransmitter should be returned
/// - createANewOneIfNecesssary : if bluetoothTransmitter is nil, then should one be created ?
public func getBluetoothTransmitter(for bluetoothPeripheral: BluetoothPeripheral, createANewOneIfNecesssary: Bool) -> BluetoothTransmitter? {
if let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral) {
if let bluetoothTransmitter = bluetoothTransmitters[index] {
return bluetoothTransmitter
}
if createANewOneIfNecesssary {
var newTransmitter: BluetoothTransmitter? = nil
switch bluetoothPeripheral.bluetoothPeripheralType() {
case .M5StackType, .M5StickCType:
if let m5Stack = bluetoothPeripheral as? M5Stack {
// blePassword : first check if m5Stack has a blepassword configured. If not then user blepassword from userDefaults, which can also still be nil
var blePassword = m5Stack.blepassword
if blePassword == nil {
blePassword = UserDefaults.standard.m5StackBlePassword
}
newTransmitter = M5StackBluetoothTransmitter(address: m5Stack.blePeripheral.address, name: m5Stack.blePeripheral.name, bluetoothTransmitterDelegate: self, m5StackBluetoothTransmitterDelegate: self, blePassword: blePassword, bluetoothPeripheralType: bluetoothPeripheral.bluetoothPeripheralType())
}
case .watlaaMaster:
if let watlaa = bluetoothPeripheral as? Watlaa {
newTransmitter = WatlaaBluetoothTransmitterMaster(address: watlaa.blePeripheral.address, name: watlaa.blePeripheral.name, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, watlaaBluetoothTransmitterDelegate: self, bluetoothPeripheralType: .watlaaMaster)
}
case .DexcomG5Type:
if let dexcomG5 = bluetoothPeripheral as? DexcomG5 {
if let transmitterId = dexcomG5.blePeripheral.transmitterId, let cgmTransmitterDelegate = cgmTransmitterDelegate {
newTransmitter = CGMG5Transmitter(address: dexcomG5.blePeripheral.address, name: dexcomG5.blePeripheral.name, transmitterID: transmitterId, bluetoothTransmitterDelegate: self, cGMG5TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate)
} else {
trace("in getBluetoothTransmitter, case DexcomG5Type but transmitterId is nil or cgmTransmitterDelegate is nil, looks like a coding error ", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
}
}
}
bluetoothTransmitters[index] = newTransmitter
return newTransmitter
}
}
return nil
}
public func getTransmitterType(for bluetoothTransmitter:BluetoothTransmitter) -> BluetoothPeripheralType {
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
// using switch through all cases, to make sure that new future types are supported
switch bluetoothPeripheralType {
case .M5StackType, .M5StickCType:
if let bluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter {
return bluetoothTransmitter.bluetoothPeripheralType
}
case .watlaaMaster:
if bluetoothTransmitter is WatlaaBluetoothTransmitterMaster {
return .watlaaMaster
}
case .DexcomG5Type:
if bluetoothTransmitter is CGMG5Transmitter {
return .DexcomG5Type
}
}
}
// normally we shouldn't get here, but we need to return a value
fatalError("BluetoothPeripheralManager : getTransmitterType did not find a valid type")
}
/// transmitterId only for transmitter types that need it (at the moment only Dexcom and Blucon)
public func createNewTransmitter(type: BluetoothPeripheralType, transmitterId: String?) -> BluetoothTransmitter? {
switch type {
case .M5StackType, .M5StickCType:
return M5StackBluetoothTransmitter(address: nil, name: nil, bluetoothTransmitterDelegate: self, m5StackBluetoothTransmitterDelegate: self, blePassword: UserDefaults.standard.m5StackBlePassword, bluetoothPeripheralType: type)
case .watlaaMaster:
return WatlaaBluetoothTransmitterMaster(address: nil, name: nil, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, watlaaBluetoothTransmitterDelegate: self, bluetoothPeripheralType: type)
case .DexcomG5Type:
guard let transmitterId = transmitterId, let cgmTransmitterDelegate = cgmTransmitterDelegate else {
trace("in createNewTransmitter, transmitterId is nil or cgmTransmitterDelegate is nil", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return nil
}
return CGMG5Transmitter(address: nil, name: nil, transmitterID: transmitterId, bluetoothTransmitterDelegate: self, cGMG5TransmitterDelegate: self, cGMTransmitterDelegate: cgmTransmitterDelegate)
}
}
// 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
@ -234,86 +379,10 @@ class BluetoothPeripheralManager: NSObject {
}
/// disconnect from bluetoothPeripheral - and don't reconnect - set shouldconnect to false
private func disconnect(fromBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral) {
// device should not reconnect after disconnecting
bluetoothPeripheral.blePeripheral.shouldconnect = false
// save in coredata
coreDataManager.saveChanges()
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false) {
_ = bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
}
}
private func firstIndexInBluetoothPeripherals(bluetoothPeripheral: BluetoothPeripheral) -> Int? {
public func firstIndexInBluetoothPeripherals(bluetoothPeripheral: BluetoothPeripheral) -> Int? {
return bluetoothPeripherals.firstIndex(where: {$0.blePeripheral.address == bluetoothPeripheral.blePeripheral.address})
}
/// transmitterId only for transmitter types that need it (at the moment only Dexcom and Blucon)
private func createNewTransmitter(type: BluetoothPeripheralType, transmitterId: String?) -> BluetoothTransmitter? {
switch type {
case .M5StackType, .M5StickCType:
return M5StackBluetoothTransmitter(address: nil, name: nil, bluetoothTransmitterDelegate: self, m5StackBluetoothTransmitterDelegate: self, blePassword: UserDefaults.standard.m5StackBlePassword, bluetoothPeripheralType: type)
case .watlaaMaster:
return WatlaaBluetoothTransmitterMaster(address: nil, name: nil, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, watlaaBluetoothTransmitterDelegate: self, bluetoothPeripheralType: type)
case .DexcomG5Type:
guard let transmitterId = transmitterId, let cgmTransmitterDelegate = cgmTransmitterDelegate else {
trace("in createNewTransmitter, transmitterId is nil or cgmTransmitterDelegate is nil", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return nil
}
return CGMG5Transmitter(address: nil, name: nil, transmitterID: transmitterId, cGMTransmitterDelegate: cgmTransmitterDelegate)
}
}
private func getTransmitterType(for bluetoothTransmitter:BluetoothTransmitter) -> BluetoothPeripheralType {
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
// using switch through all cases, to make sure that new future types are supported
switch bluetoothPeripheralType {
case .M5StackType, .M5StickCType:
if let bluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter {
return bluetoothTransmitter.bluetoothPeripheralType
}
case .watlaaMaster:
if bluetoothTransmitter is WatlaaBluetoothTransmitterMaster {
return .watlaaMaster
}
case .DexcomG5Type:
if bluetoothTransmitter is CGMG5Transmitter {
return .DexcomG5Type
}
}
}
// normally we shouldn't get here, but we need to return a value
fatalError("BluetoothPeripheralManager : getTransmitterType did not find a valid type")
}
// MARK:- override observe function
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
@ -440,7 +509,7 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
if !type.transmitterStartsScanningAfterInit() {
_ = tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral?.startScanning()
}
}
/// stops scanning for new device
@ -477,7 +546,7 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
let transmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: true)
transmitter?.connect()
}
/// returns the BluetoothPeripheral for the specified BluetoothTransmitter
@ -493,75 +562,9 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
}
/// returns the bluetoothTransmitter for the bluetoothPeripheral
/// - parameters:
/// - forBluetoothPeripheral : the bluetoothPeripheral for which bluetoothTransmitter should be returned
/// - createANewOneIfNecesssary : if bluetoothTransmitter is nil, then should one be created ?
func getBluetoothTransmitter(for bluetoothPeripheral: BluetoothPeripheral, createANewOneIfNecesssary: Bool) -> BluetoothTransmitter? {
if let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral) {
if let bluetoothTransmitter = bluetoothTransmitters[index] {
return bluetoothTransmitter
}
if createANewOneIfNecesssary {
var newTransmitter: BluetoothTransmitter? = nil
switch bluetoothPeripheral.bluetoothPeripheralType() {
case .M5StackType, .M5StickCType:
if let m5Stack = bluetoothPeripheral as? M5Stack {
// blePassword : first check if m5Stack has a blepassword configured. If not then user blepassword from userDefaults, which can also still be nil
var blePassword = m5Stack.blepassword
if blePassword == nil {
blePassword = UserDefaults.standard.m5StackBlePassword
}
newTransmitter = M5StackBluetoothTransmitter(address: m5Stack.blePeripheral.address, name: m5Stack.blePeripheral.name, bluetoothTransmitterDelegate: self, m5StackBluetoothTransmitterDelegate: self, blePassword: blePassword, bluetoothPeripheralType: bluetoothPeripheral.bluetoothPeripheralType())
}
case .watlaaMaster:
if let watlaa = bluetoothPeripheral as? Watlaa {
newTransmitter = WatlaaBluetoothTransmitterMaster(address: watlaa.blePeripheral.address, name: watlaa.blePeripheral.name, cgmTransmitterDelegate: cgmTransmitterDelegate, bluetoothTransmitterDelegate: self, watlaaBluetoothTransmitterDelegate: self, bluetoothPeripheralType: .watlaaMaster)
}
case .DexcomG5Type:
if let dexcomG5 = bluetoothPeripheral as? DexcomG5 {
if let transmitterId = dexcomG5.blePeripheral.transmitterId, let cgmTransmitterDelegate = cgmTransmitterDelegate {
newTransmitter = CGMG5Transmitter(address: dexcomG5.blePeripheral.address, name: dexcomG5.blePeripheral.name, transmitterID: transmitterId, cGMTransmitterDelegate: cgmTransmitterDelegate)
} else {
trace("in getBluetoothTransmitter, case DexcomG5Type but transmitterId is nil or cgmTransmitterDelegate is nil, looks like a coding error ", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
}
}
}
bluetoothTransmitters[index] = newTransmitter
return newTransmitter
}
}
return nil
}
/// deletes the BluetoothPeripheral in coredata, and also the corresponding BluetoothTransmitter if there is one will be deleted
func deleteBluetoothPeripheral(bluetoothPeripheral: BluetoothPeripheral) {
// find the bluetoothPeripheral in array bluetoothPeripherals, if it's not there then this looks like a coding error
guard let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral) else {
trace("in deleteBluetoothPeripheral but bluetoothPeripheral not found in bluetoothPeripherals, looks like a coding error ", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
@ -570,10 +573,10 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
// 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
// delete in coredataManager
coreDataManager.mainManagedObjectContext.delete(bluetoothPeripherals[index] as! NSManagedObject)
@ -607,7 +610,7 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
return bluetoothTransmitters
}
/// bluetoothtransmitter for this bluetoothPeripheral will be deleted, as a result this will also disconnect the bluetoothPeripheral
func setBluetoothTransmitterToNil(forBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral) {
@ -615,322 +618,12 @@ extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
// 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
}
}
}
// 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)
return
}
// check that address and name are not nil, otherwise this looks like a coding error
guard let deviceAddressNewTransmitter = bluetoothTransmitter.deviceAddress, let deviceNameNewTransmitter = bluetoothTransmitter.deviceName else {
trace("in didConnect, address or name of new transmitter is nil, looks like a coding error", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return
}
// check that tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral and the bluetoothTransmitter to which connection is made are actually the same objects, otherwise it's a connection that is made to a already known/stored BluetoothTransmitter
guard tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral == bluetoothTransmitter else {
trace("in didConnect, tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral is not nil and not equal to bluetoothTransmitter", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
return
}
// check that it's a peripheral for which we don't know yet the address
for buetoothPeripheral in bluetoothPeripherals {
if buetoothPeripheral.blePeripheral.address == deviceAddressNewTransmitter {
trace("in didConnect, transmitter address already known. This is not a new device, will disconnect", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// it's an already known BluetoothTransmitter, not storing this, on the contrary disconnecting because maybe it's a bluetoothTransmitter already known for which user has preferred not to connect to
// If we're actually waiting for a new scan result, then there's an instance of BluetoothTransmitter stored in tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral - but this one stopped scanning, so let's recreate an instance of BluetoothTransmitter
self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = createNewTransmitter(type: getTransmitterType(for: bluetoothTransmitter), transmitterId: buetoothPeripheral.blePeripheral.transmitterId)
_ = self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral?.startScanning()
return
}
}
// it's a new peripheral that we will store. No need to continue scanning
bluetoothTransmitter.stopScanning()
// create bluetoothPeripheral
let newBluetoothPeripheral = getTransmitterType(for: tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral).createNewBluetoothPeripheral(withAddress: deviceAddressNewTransmitter, withName: deviceNameNewTransmitter, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
bluetoothPeripherals.append(newBluetoothPeripheral)
bluetoothTransmitters.append(bluetoothTransmitter)
// call the callback function
if let callBackAfterDiscoveringDevice = callBackAfterDiscoveringDevice {
callBackAfterDiscoveringDevice(newBluetoothPeripheral)
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()
}
}
func error(message: String) {
trace("in error, no further action", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
}
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
// no further action, This is for UIViewcontroller's that also receive this info, means info can only be shown if this happens while user has one of the UIViewcontrollers open
trace("in didDisconnectFrom", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
}
}
// 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 {
func receivedBattery(level: Int, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
m5Stack.batteryLevel = level
}
/// did the app successfully authenticate towards M5Stack, if no, then disconnect will be done
func authentication(success: Bool, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in authentication with success = %{public}@", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info, success.description)
// if authentication not successful then disconnect and don't reconnect, user should verify password or reset the M5Stack, disconnect and set shouldconnect to false, permenantly (ie store in core data)
// disconnection is done because maybe another device is trying to connect to the M5Stack, need to make it free
// also set shouldConnect to false (note that this is also done in M5StackViewController if an instance of that exists, no issue, shouldConnect will be set to false two times
if !success {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// don't try to reconnect after disconnecting
m5Stack.blePeripheral.shouldconnect = false
// store in core data
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
}
/// there's no ble password set, user should set it in the settings - disconnect will be called, shouldconnect is set to false
func blePasswordMissing(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in blePasswordMissing", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// don't try to reconnect after disconnecting
m5Stack.blePeripheral.shouldconnect = false
// store in core data
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
/// if a new ble password is received from M5Stack
func newBlePassWord(newBlePassword: String, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in newBlePassWord, storing the password in M5Stack", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and also the bluetoothPeripheral and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// possibily this is a new scanned m5stack, calling coreDataManager.saveChanges() but still the user may be in M5stackviewcontroller and decide not to save the m5stack, bad luck
m5Stack.blepassword = newBlePassword
coreDataManager.saveChanges()
}
/// it's an M5Stack without password configured in the ini file. xdrip app has been requesting temp password to M5Stack but this was already done once. M5Stack needs to be reset. - disconnect will be called, shouldconnect is set to false
func m5StackResetRequired(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
trace("in m5StackResetRequired", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// should not try to reconnect, wait till user decide to push the "always connect button"
m5Stack.blePeripheral.shouldconnect = false
coreDataManager.saveChanges()
// disconnect
disconnect(fromBluetoothPeripheral: m5Stack)
}
/// M5Stack is asking for an update of all parameters, send them
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter) else {
trace("in isAskingForAllParameters, could not find index of bluetoothTransmitter, looks like a coding error", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .error)
return
}
// send all parameters, if successful,then for this m5Stack we can set parameterUpdateNeeded to false
if sendAllParametersToM5Stack(to: m5StackBluetoothTransmitter) {
(bluetoothPeripherals[index] as? M5Stack)?.blePeripheral.parameterUpdateNeededAtNextConnect = false
} else {
// failed, so we need to set parameterUpdateNeeded to true, so that next time it connects we will send all parameters
(bluetoothPeripherals[index] as? M5Stack)?.blePeripheral.parameterUpdateNeededAtNextConnect = true
}
}
/// will be called if M5Stack is connected, and authentication was successful, BluetoothPeripheralManager can start sending data like parameter updates or bgreadings
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return}
// if the M5Stack needs new parameters, then send them
if m5Stack.blePeripheral.parameterUpdateNeededAtNextConnect {
// send all parameters
if sendAllParametersToM5Stack(to: m5StackBluetoothTransmitter) {
m5Stack.blePeripheral.parameterUpdateNeededAtNextConnect = false
}
}
// send latest reading
sendLatestReading(to: m5Stack)
}
// MARK: - private functions related to M5Stack
/// send all parameters to m5Stack
/// - parameters:
/// - to : m5StackBluetoothTransmitter to send all parameters
/// - returns:
/// successfully written all parameters or not
private func sendAllParametersToM5Stack(to m5StackBluetoothTransmitter : M5StackBluetoothTransmitter) -> Bool {
// should find the m5StackBluetoothTransmitter in bluetoothTransmitters and it should be an M5Stack
guard let index = bluetoothTransmitters.firstIndex(of: m5StackBluetoothTransmitter), let m5Stack = bluetoothPeripherals[index] as? M5Stack else {return false}
// M5Stack must be ready to receive data
guard m5StackBluetoothTransmitter.isReadyToReceiveData else {
trace("in sendAllParameters, bluetoothTransmitter is not ready to receive data", log: log, category: ConstantsLog.categoryBluetoothPeripheralManager, type: .info)
return false
}
// initialise returnValue, result
var success = true
// send bloodglucoseunit
if !m5StackBluetoothTransmitter.writeBloodGlucoseUnit(isMgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl) {success = false}
// send textColor
if !m5StackBluetoothTransmitter.writeTextColor(textColor: M5StackColor(forUInt16: UInt16(m5Stack.textcolor)) ?? UserDefaults.standard.m5StackTextColor ?? ConstantsM5Stack.defaultTextColor) {success = false}
// send backGroundColor
if !m5StackBluetoothTransmitter.writeBackGroundColor(backGroundColor: M5StackColor(forUInt16: UInt16(m5Stack.backGroundColor)) ?? ConstantsM5Stack.defaultBackGroundColor ) {success = false}
// send rotation
if !m5StackBluetoothTransmitter.writeRotation(rotation: Int(m5Stack.rotation)) {success = false}
// send connectToWiFi
if !m5StackBluetoothTransmitter.writeConnectToWiFi(connect: m5Stack.connectToWiFi) {success = false}
// send WiFiSSID's
if let wifiName = UserDefaults.standard.m5StackWiFiName1 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 1) {success = false}
}
if let wifiName = UserDefaults.standard.m5StackWiFiName2 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 2) {success = false}
}
if let wifiName = UserDefaults.standard.m5StackWiFiName3 {
if !m5StackBluetoothTransmitter.writeWifiName(name: wifiName, number: 3) {success = false}
}
// send WiFiPasswords
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword1 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 1) {success = false}
}
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword2 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 2) {success = false}
}
if let wifiPassword = UserDefaults.standard.m5StackWiFiPassword3 {
if !m5StackBluetoothTransmitter.writeWifiPassword(password: wifiPassword, number: 3) {success = false}
}
// send nightscout url
if let url = UserDefaults.standard.nightScoutUrl {
if !m5StackBluetoothTransmitter.writeNightScoutUrl(url: url) {success = false}
}
// send nightscout token
if let token = UserDefaults.standard.nightScoutAPIKey {
if !m5StackBluetoothTransmitter.writeNightScoutAPIKey(apiKey: token) {success = false}
}
// return success
return success
}
}

View File

@ -57,7 +57,7 @@ class BluetoothPeripheralViewController: UIViewController {
/// action for cancelbutton
@IBAction func cancelButtonAction(_ sender: UIBarButtonItem) {
cancel()
cancelButtonAction()
}
/// outlet for scanButton, to set the text in the scanButton
@ -107,7 +107,11 @@ class BluetoothPeripheralViewController: UIViewController {
/// needed to support the bluetooth peripheral type specific attributes
private var bluetoothPeripheralViewModel: BluetoothPeripheralViewModel!
/// BluetoothPeripheralType for which this viewcontroller is created
private var expectedBluetoothPeripheralType: BluetoothPeripheralType?
/// temp storage of assigned BluetoothTransmitterDelegate
private weak var previouslyAssignedBluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
// MARK:- public functions
@ -134,6 +138,17 @@ class BluetoothPeripheralViewController: UIViewController {
}
/// sets shouldconnect for bluetoothPeripheral to false
public func setShouldConnectToFalse(for bluetoothPeripheral: BluetoothPeripheral) {
bluetoothPeripheral.blePeripheral.shouldconnect = false
coreDataManager?.saveChanges()
self.setConnectButtonLabelText()
}
// MARK: - View Life Cycle
override func viewDidLoad() {
@ -146,21 +161,41 @@ class BluetoothPeripheralViewController: UIViewController {
bluetoothPeripheralViewModel = expectedBluetoothPeripheralType?.viewModel()
// configure the bluetoothPeripheralViewModel
bluetoothPeripheralViewModel?.configure(bluetoothPeripheral: bluetoothPeripheralAsNSObject, bluetoothPeripheralManager: self.bluetoothPeripheralManager, tableView: tableView, bluetoothPeripheralViewController: self, bluetoothTransmitterDelegate: self)
bluetoothPeripheralViewModel?.configure(bluetoothPeripheral: bluetoothPeripheralAsNSObject, bluetoothPeripheralManager: self.bluetoothPeripheralManager, tableView: tableView, bluetoothPeripheralViewController: self)
// still need to assign the delegate in the transmitter object
if let bluetoothPeripheralASNSObject = bluetoothPeripheralAsNSObject {
if let bluetoothPeripheralASNSObject = bluetoothPeripheralAsNSObject, let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: false) {
// set bluetoothPeripheralViewModel as delegate in bluetoothTransmitter
if let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: false) {
bluetoothTransmitter.variableBluetoothTransmitterDelegate = self
}
// this will store the current value of the bluetoothTransitterDelegate, and assign self as new delegate
assignPreviouslyAssignedBluetoothTransmitterDelegateAndSetSelfAsDelegate(bluetoothTransmitter: bluetoothTransmitter, assignDelegateTo: self)
// this will internally store the BluetoothTransmitter type specific delegate
bluetoothPeripheralViewModel.assignBluetoothTransmitterDelegate(to: bluetoothTransmitter)
}
setupView()
}
// MARK: - De-initialization
deinit {
// to be sure that previouslyAssignedBluetoothTransmitterDelegate is reassigned although it's probably already done for example in doneButtonHandler
if let bluetoothPeripheralAsNSObject = bluetoothPeripheralAsNSObject, let previouslyAssignedBluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate, let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralAsNSObject, createANewOneIfNecesssary: false) {
// this will internally reset the BluetoothTransmitter delegate to the original value
bluetoothPeripheralViewModel.reAssignBluetoothTransmitterDelegateToOriginal(for: bluetoothTransmitter)
// reassign delegate
bluetoothTransmitter.bluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate
}
}
// MARK: - other overriden functions
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@ -253,10 +288,16 @@ class BluetoothPeripheralViewController: UIViewController {
/// user cliks done button
public func doneButtonHandler() {
if let bluetoothPeripheralAsNSObject = bluetoothPeripheralAsNSObject, let coreDataManager = coreDataManager {
if let bluetoothPeripheralAsNSObject = bluetoothPeripheralAsNSObject, let coreDataManager = coreDataManager, let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralAsNSObject, createANewOneIfNecesssary: false) {
// set variable delegate in bluetoothPeripheralASNSObject to nil, no need anymore to receive info
bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralAsNSObject, createANewOneIfNecesssary: false)?.variableBluetoothTransmitterDelegate = nil
// no need anymore to receive info from BluetoothTransmitter, reassign previouslyAssignedBluetoothTransmitterDelegate
// previouslyAssignedBluetoothTransmitterDelegate must be non nil here. Otherwise there's a coding error.
guard let previouslyAssignedBluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate else {
fatalError("BluetoothPeripheralViewController, doneButtonHandler, previouslyAssignedBluetoothTransmitterDelegate is nil")
}
// reassign previouslyAssignedBluetoothTransmitterDelegate as delegate in BluetoothTransmitter
bluetoothTransmitter.bluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate
// set alias temp value, possibly this is a nil value
bluetoothPeripheralAsNSObject.blePeripheral.alias = aliasTemporaryValue
@ -266,13 +307,16 @@ class BluetoothPeripheralViewController: UIViewController {
// temp values stored by viewmodel needs to be written to bluetoothPeripheralASNSObject
bluetoothPeripheralViewModel.writeTempValues(to: bluetoothPeripheralAsNSObject)
// this will internally reset the BluetoothTransmitter delegate to the original value
bluetoothPeripheralViewModel.reAssignBluetoothTransmitterDelegateToOriginal(for: bluetoothTransmitter)
// save all changes now
coreDataManager.saveChanges()
}
// don't delete the BluetoothPeripheral when going back to prevous viewcontroller
// don't delete the BluetoothPeripheral when going back to previous viewcontroller
self.deleteBluetoothPeripheralWhenClosingViewController = false
// return to BluetoothPeripheralsViewController
@ -314,8 +358,15 @@ class BluetoothPeripheralViewController: UIViewController {
// if user goes back to previous screen via the back button, then delete the newly discovered BluetoothPeripheral
self.deleteBluetoothPeripheralWhenClosingViewController = true
// set self as delegate in the bluetoothTransmitter
self.bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false)?.variableBluetoothTransmitterDelegate = self
// set self as delegate in the bluetoothTransmitter, and assign currently assigned BluetoothTransmitterDelegate to previouslyAssignedBluetoothTransmitterDelegate
if let bluetoothTransmitter = self.bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false) {
self.assignPreviouslyAssignedBluetoothTransmitterDelegateAndSetSelfAsDelegate(bluetoothTransmitter: bluetoothTransmitter, assignDelegateTo: self)
// this will internally reset the BluetoothTransmitter delegate to the original value
self.bluetoothPeripheralViewModel.assignBluetoothTransmitterDelegate(to: bluetoothTransmitter)
}
// reload the full screen , all rows in all sections in the tableView
self.tableView.reloadData()
@ -365,9 +416,10 @@ class BluetoothPeripheralViewController: UIViewController {
// let's first check if bluetoothPeripheral exists, it should because otherwise connectButton should be disabled
guard let bluetoothPeripheralASNSObject = bluetoothPeripheralAsNSObject else {return}
// user clicked connectbutton. Check first the current value of shouldconnect and change
if bluetoothPeripheralASNSObject.blePeripheral.shouldconnect {
// device should not automaticaly connect, which means, each time the app restarts, it will not try to connect to this bluetoothPeripheral
// device should not automaticaly connect in future, which means, each time the app restarts, it will not try to connect to this bluetoothPeripheral
bluetoothPeripheralASNSObject.blePeripheral.shouldconnect = false
// save the update in coredata
@ -376,11 +428,14 @@ class BluetoothPeripheralViewController: UIViewController {
// update the connect button text
setConnectButtonLabelText()
// normally there should be a bluetoothTransmitter
if let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: false) {
// disconnecting means also deleting the bluetoothTransmitter (which as a consequence also disconnects). Also reassign previouslyAssignedBluetoothTransmitterDelegate, although this is probably not necessary as the bluetoothTransmitter will be set to nil
if let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: false), let previouslyAssignedBluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate {
// set delegate in bluetoothtransmitter to nil, as we're going to disconnect permenantly, so not interested anymore to receive info
bluetoothTransmitter.variableBluetoothTransmitterDelegate = nil
bluetoothTransmitter.bluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate
// this will internally reset the BluetoothTransmitter delegate to the original value
self.bluetoothPeripheralViewModel.reAssignBluetoothTransmitterDelegateToOriginal(for: bluetoothTransmitter)
// this will also set bluetoothTransmitter to nil and also disconnect the peripheral
bluetoothPeripheralManager.setBluetoothTransmitterToNil(forBluetoothPeripheral: bluetoothPeripheralASNSObject)
@ -398,12 +453,14 @@ class BluetoothPeripheralViewController: UIViewController {
// get bluetoothTransmitter
if let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralASNSObject, createANewOneIfNecesssary: true) {
// set delegate
bluetoothTransmitter.variableBluetoothTransmitterDelegate = self
assignPreviouslyAssignedBluetoothTransmitterDelegateAndSetSelfAsDelegate(bluetoothTransmitter: bluetoothTransmitter, assignDelegateTo: self)
// connect
bluetoothTransmitter.connect()
// this will internally store the BluetoothTransmitter type specific delegate
bluetoothPeripheralViewModel.assignBluetoothTransmitterDelegate(to: bluetoothTransmitter)
}
}
@ -442,7 +499,7 @@ class BluetoothPeripheralViewController: UIViewController {
}
/// user clicked cancel button
private func cancel() {
private func cancelButtonAction() {
// just in case scanning for a new device is still ongoing, call stopscanning
bluetoothPeripheralManager.stopScanningForNewDevice()
@ -452,14 +509,14 @@ class BluetoothPeripheralViewController: UIViewController {
}
/// sets shouldconnect for bluetoothPeripheral to false
public func setShouldConnectToFalse(for bluetoothPeripheral: BluetoothPeripheral) {
bluetoothPeripheral.blePeripheral.shouldconnect = false
/// assign current delegate in bluetoothTransmitter to previouslyAssignedBluetoothTransmitterDelegate, and set delegate in to to self
private func assignPreviouslyAssignedBluetoothTransmitterDelegateAndSetSelfAsDelegate(bluetoothTransmitter: BluetoothTransmitter, assignDelegateTo bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
coreDataManager?.saveChanges()
// assign previouslyAssignedBluetoothTransmitterDelegate
previouslyAssignedBluetoothTransmitterDelegate = bluetoothTransmitter.bluetoothTransmitterDelegate
self.setConnectButtonLabelText()
// assign self as BluetoothTransmitterDelegate
bluetoothTransmitter.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
}
@ -703,25 +760,68 @@ extension BluetoothPeripheralViewController: UITableViewDataSource, UITableViewD
}
// MARK: - extension BluetoothTransmitterDelegate
extension BluetoothPeripheralViewController: BluetoothTransmitterDelegate {
func transmitterNeedsPairing(bluetoothTransmitter: BluetoothTransmitter) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.transmitterNeedsPairing(bluetoothTransmitter: bluetoothTransmitter)
// handled in BluetoothPeripheralManager
}
func successfullyPaired() {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.successfullyPaired()
// handled in BluetoothPeripheralManager
}
func pairingFailed() {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.pairingFailed()
// handled in BluetoothPeripheralManager
}
func reset(successful: Bool) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.reset(successful: successful)
// handled in BluetoothPeripheralManager
}
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
tableView.reloadRows(at: [IndexPath(row: Setting.connectionStatus.rawValue, section: 0)], with: .none)
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: bluetoothTransmitter)
tableView.reloadRows(at: [IndexPath(row: Setting.connectionStatus.rawValue, section: 0)], with: .none)
}
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
tableView.reloadRows(at: [IndexPath(row: Setting.connectionStatus.rawValue, section: 0)], with: .none)
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: bluetoothTransmitter)
tableView.reloadRows(at: [IndexPath(row: Setting.connectionStatus.rawValue, section: 0)], with: .none)
}
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
// when bluetooth status changes to powered off, the device, if connected, will disconnect, however didDisConnect doesn't get call (looks like an error in iOS) - so let's reload the cell that shows the connection status, this will refresh the cell
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state, bluetoothTransmitter: bluetoothTransmitter)
// when bluetooth status changes to powered off, the device, if connected, will disconnect, however didDisConnect doesn't get call (looks like an error in iOS) - so let's reload the cell that shows the connection status, this will refresh the cell
// do this whenever the bluetooth status changes
tableView.reloadRows(at: [IndexPath(row: Setting.connectionStatus.rawValue, section: 0)], with: .none)
@ -729,6 +829,9 @@ extension BluetoothPeripheralViewController: BluetoothTransmitterDelegate {
func error(message: String) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.error(message: message)
let alert = UIAlertController(title: Texts_Common.warning, message: message, actionHandler: nil)
self.present(alert, animated: true, completion: nil)

View File

@ -5,12 +5,11 @@ protocol BluetoothPeripheralViewModel {
/// to be called before opening the actual viewcontroller or after discovering a new bluetoothperipheral
/// - parameters :
/// - bluetoothTransmitterDelegate : usually the uiViewController
/// - bluetoothPeripheral : if nil then the viewcontroller is opened to scan for a new peripheral
/// - bluetoothPeripheralManager : reference to bluetoothPeripheralManaging object
/// - tableView : needed to intiate refresh of row
/// - bluetoothPeripheralViewController : BluetoothPeripheralViewController
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate)
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController)
/// screen title for uiviewcontroller
func screenTitle() -> String
@ -37,4 +36,10 @@ protocol BluetoothPeripheralViewModel {
/// used when user clicks done button in uiviewcontroller
func writeTempValues(to bluetoothPeripheral: BluetoothPeripheral)
/// used in BluetoothPeripheralViewController which is unaware of types of transmitters (M5Stack, Watlaa, ...). This to handle that there can be multiple delegates listening for example M5StackBluetoothTransmitter changes. The function assignBluetoothTransmitterDelegate will temporary store the value of the existing delegate (example M5StackBluetoothTransmitterDelegate) and assign itself (ie the viewmodel) as delegate. It should also handle the calling of the functions in the stored delegate (look at an example to understand :) )
func assignBluetoothTransmitterDelegate(to bluetoothTransmitter: BluetoothTransmitter)
/// see explanation assignBluetoothTransmitterDelegate
func reAssignBluetoothTransmitterDelegateToOriginal(for bluetoothTransmitter: BluetoothTransmitter)
}

View File

@ -24,7 +24,8 @@ class DexcomG5BluetoothPeripheralViewModel {
/// reference to BluetoothPeripheralViewController that will own this WatlaaMasterBluetoothPeripheralViewModel - needed to present stuff etc
private weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
private weak var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
/// temporary stores CGMG5TransmitterDelegate
private weak var previouslyAssignedcGMG5TransmitterDelegate: CGMG5TransmitterDelegate?
}
@ -32,7 +33,31 @@ class DexcomG5BluetoothPeripheralViewModel {
extension DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
func assignBluetoothTransmitterDelegate(to bluetoothTransmitter: BluetoothTransmitter) {
guard let cGMG5Transmitter = bluetoothTransmitter as? CGMG5Transmitter else {fatalError("DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel, assignBluetoothTransmitterDelegate, not a CGMG5Transmitter")}
previouslyAssignedcGMG5TransmitterDelegate = cGMG5Transmitter.cGMG5TransmitterDelegate
cGMG5Transmitter.cGMG5TransmitterDelegate = self
}
func reAssignBluetoothTransmitterDelegateToOriginal(for bluetoothTransmitter: BluetoothTransmitter) {
guard let cGMG5Transmitter = bluetoothTransmitter as? CGMG5Transmitter else {fatalError("DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, not a WatlaaBluetoothTransmitterMaster")}
guard let previouslyAssignedcGMG5TransmitterDelegate = previouslyAssignedcGMG5TransmitterDelegate else {
fatalError("DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, previouslyAssignedcGMG5TransmitterDelegate is nil")
return
}
cGMG5Transmitter.cGMG5TransmitterDelegate = previouslyAssignedcGMG5TransmitterDelegate
}
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController) {
self.bluetoothPeripheralManager = bluetoothPeripheralManager
@ -40,8 +65,6 @@ extension DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
if let dexcomG5 = bluetoothPeripheral as? DexcomG5 {
storeTempValues(from: dexcomG5)
@ -147,3 +170,16 @@ extension DexcomG5BluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
}
}
extension DexcomG5BluetoothPeripheralViewModel: CGMG5TransmitterDelegate {
func received(firmware: String, cGMG5Transmitter: CGMG5Transmitter) {
previouslyAssignedcGMG5TransmitterDelegate?.received(firmware: firmware, cGMG5Transmitter: cGMG5Transmitter)
// firmware should get updated in DexcomG5 object by bluetoothPeripheralManager, here's the trigger to update the table
tableView?.reloadRows(at: [IndexPath(row: Settings.firmWareVersion.rawValue, section: 1)], with: .none)
}
}

View File

@ -111,7 +111,8 @@ class M5StackBluetoothPeripheralViewModel {
/// reference to BluetoothPeripheralViewController that will own this M5StackBluetoothPeripheralViewModel - needed to present stuff etc
private(set) weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
private weak var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
/// temporary stores M5StackBluetoothTransmitterDelegate
private weak var previouslyAssignedM5StackBluetoothTransmitterDelegate: M5StackBluetoothTransmitterDelegate?
// MARK: - public functions
@ -497,21 +498,30 @@ extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelega
func receivedBattery(level: Int, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.receivedBattery(level: level, m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
// batteryLevel should get updated in M5Stack object by bluetoothPeripheralManager, here's the trigger to update the table
tableView?.reloadRows(at: [IndexPath(row: SpecificM5StackSettings.batteryLevel.rawValue, section: M5StackSections.allCases.count)], with: .none)
}
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.isAskingForAllParameters(m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
// viewcontroller doesn't use this
}
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.isReadyToReceiveData(m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
// viewcontroller doesn't use this
}
func newBlePassWord(newBlePassword: String, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
// note : blePassword is also saved in BluetoothPeripheralManager, it will be saved two times
if let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack {
@ -525,6 +535,8 @@ extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelega
func authentication(success: Bool, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.authentication(success: success, m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
if !success, let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack {
// show warning, inform that user should set password or reset M5Stack
@ -541,6 +553,8 @@ extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelega
func blePasswordMissing(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.blePasswordMissing(m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
guard let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack else {return}
// show warning, inform that user should set password
@ -557,6 +571,8 @@ extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelega
func m5StackResetRequired(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
previouslyAssignedM5StackBluetoothTransmitterDelegate?.m5StackResetRequired(m5StackBluetoothTransmitter: m5StackBluetoothTransmitter)
guard let m5StackBluetoothPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack else {return}
// show warning, inform that user should reset M5Stack
@ -573,10 +589,34 @@ extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelega
}
// MARK: - extension BluetoothPeripheralViewModelProtocol
// MARK: - conform to BluetoothPeripheralViewModel
extension M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
func assignBluetoothTransmitterDelegate(to bluetoothTransmitter: BluetoothTransmitter) {
guard let m5StackBluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter else {fatalError("M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, assignBluetoothTransmitterDelegate, not a m5StackBluetoothTransmitter")}
previouslyAssignedM5StackBluetoothTransmitterDelegate = m5StackBluetoothTransmitter.m5StackBluetoothTransmitterDelegate
m5StackBluetoothTransmitter.m5StackBluetoothTransmitterDelegate = self
}
func reAssignBluetoothTransmitterDelegateToOriginal(for bluetoothTransmitter: BluetoothTransmitter) {
guard let m5StackBluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter else {fatalError("M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, not a m5StackBluetoothTransmitter")}
guard let previouslyAssignedM5StackBluetoothTransmitter = previouslyAssignedM5StackBluetoothTransmitterDelegate else {
fatalError("M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, previouslyAssignedM5StackBluetoothTransmitter is nil")
return
}
m5StackBluetoothTransmitter.m5StackBluetoothTransmitterDelegate = previouslyAssignedM5StackBluetoothTransmitter
}
func numberOfSections() -> Int {
return numberOfM5Sections()
}
@ -720,7 +760,7 @@ extension M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
/// - bluetoothPeripheralManager : reference to bluetoothPeripheralManaging object
/// - tableView : needed to intiate refresh of row
/// - bluetoothPeripheralViewController : BluetoothPeripheralViewController
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController) {
self.bluetoothPeripheralManager = bluetoothPeripheralManager
@ -728,8 +768,6 @@ extension M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
if let m5Stack = bluetoothPeripheral as? M5Stack {
storeTempValues(from: m5Stack)

View File

@ -22,8 +22,8 @@ class WatlaaMasterBluetoothPeripheralViewModel {
/// reference to BluetoothPeripheralViewController that will own this WatlaaMasterBluetoothPeripheralViewModel - needed to present stuff etc
private weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
private weak var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
/// temporary stores WatlaaBluetoothTransmitterDelegate
private weak var previouslyAssignedWatlaaBluetoothTransmitterDelegate: WatlaaBluetoothTransmitterDelegate?
}
@ -31,7 +31,31 @@ class WatlaaMasterBluetoothPeripheralViewModel {
extension WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
func assignBluetoothTransmitterDelegate(to bluetoothTransmitter: BluetoothTransmitter) {
guard let watlaaBluetoothTransmitter = bluetoothTransmitter as? WatlaaBluetoothTransmitterMaster else {fatalError("WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, assignBluetoothTransmitterDelegate, not a WatlaaBluetoothTransmitterMaster")}
previouslyAssignedWatlaaBluetoothTransmitterDelegate = watlaaBluetoothTransmitter.watlaaBluetoothTransmitterDelegate
watlaaBluetoothTransmitter.watlaaBluetoothTransmitterDelegate = self
}
func reAssignBluetoothTransmitterDelegateToOriginal(for bluetoothTransmitter: BluetoothTransmitter) {
guard let watlaaBluetoothTransmitter = bluetoothTransmitter as? WatlaaBluetoothTransmitterMaster else {fatalError("WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, not a WatlaaBluetoothTransmitterMaster")}
guard let previouslyAssignedWatlaaBluetoothTransmitterDelegate = previouslyAssignedWatlaaBluetoothTransmitterDelegate else {
fatalError("WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel, reAssignBluetoothTransmitterDelegateToOriginal, previouslyAssignedWatlaaBluetoothTransmitterDelegate is nil")
return
}
watlaaBluetoothTransmitter.watlaaBluetoothTransmitterDelegate = previouslyAssignedWatlaaBluetoothTransmitterDelegate
}
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController) {
self.bluetoothPeripheralManager = bluetoothPeripheralManager
@ -39,8 +63,6 @@ extension WatlaaMasterBluetoothPeripheralViewModel: BluetoothPeripheralViewModel
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
if let watlaaPeripheral = bluetoothPeripheral as? Watlaa {
storeTempValues(from: watlaaPeripheral)

View File

@ -29,6 +29,9 @@ final class BluetoothPeripheralsViewController: UIViewController {
/// a bluetoothPeripheralManager
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging!
/// temp storage of assigned BluetoothTransmitterDelegate
private weak var previouslyAssignedBluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
// MARK: public functions
/// configure
@ -41,6 +44,25 @@ final class BluetoothPeripheralsViewController: UIViewController {
}
// MARK: - De-initialization
deinit {
// to be sure that previouslyAssignedBluetoothTransmitterDelegate is reassigned to every existing BluetoothTransmistter
if let previouslyAssignedBluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate {
for bluetoothTransmitter in bluetoothPeripheralManager.getBluetoothTransmitters() {
// assign self as BluetoothTransmitterDelegate
bluetoothTransmitter.bluetoothTransmitterDelegate = previouslyAssignedBluetoothTransmitterDelegate
}
}
}
// MARK: overrides
override func viewDidLoad() {
@ -152,9 +174,14 @@ final class BluetoothPeripheralsViewController: UIViewController {
/// - sets the delegates of each transmitter to self
private func initializeBluetoothPeripherals() {
for bluetoothtTransmitter in bluetoothPeripheralManager.getBluetoothTransmitters() {
for bluetoothTransmitter in bluetoothPeripheralManager.getBluetoothTransmitters() {
bluetoothtTransmitter.variableBluetoothTransmitterDelegate = self
// assign previously assigned BluetoothTransmitterDelegate, we will still pass all info to that delegate also
// every bluetoothTransmitter may in theory have a different bluetoothTransmitterDelegate, so we should create an array of BluetoothTransmitterDelegate, however in practice it will always be the same bluetoothPeripheralManager
previouslyAssignedBluetoothTransmitterDelegate = bluetoothTransmitter.bluetoothTransmitterDelegate
// assign self as BluetoothTransmitterDelegate
bluetoothTransmitter.bluetoothTransmitterDelegate = self
}
@ -217,20 +244,72 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
extension BluetoothPeripheralsViewController: BluetoothTransmitterDelegate {
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
func transmitterNeedsPairing(bluetoothTransmitter: BluetoothTransmitter) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.transmitterNeedsPairing(bluetoothTransmitter: bluetoothTransmitter)
// handled in BluetoothPeripheralManager
}
func successfullyPaired() {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.successfullyPaired()
// handled in BluetoothPeripheralManager
}
func pairingFailed() {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.pairingFailed()
// handled in BluetoothPeripheralManager
}
func reset(successful: Bool) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.reset(successful: successful)
// handled in BluetoothPeripheralManager
}
func error(message: String) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.error(message: message)
// handled in BluetoothPeripheralManager
}
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: bluetoothTransmitter)
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))
}
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: bluetoothTransmitter)
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))
}
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
// need to inform also other delegates
previouslyAssignedBluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state, bluetoothTransmitter: bluetoothTransmitter)
// when bluetooth status changes to powered off, the device, if connected, will disconnect, however didDisConnect doesn't get call (looks like an error in iOS) - so let's reload the cell that shows the connection status, this will refresh the cell
if state == CBManagerState.poweredOff {
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))

View File

@ -3,11 +3,9 @@ import CoreData
import os
import CoreBluetooth
import UserNotifications
import AVFoundation
import AudioToolbox
import SwiftCharts
import HealthKitUI
/// viewcontroller for the home screen
final class RootViewController: UIViewController {
@ -132,9 +130,6 @@ final class RootViewController: UIViewController {
/// constant for key in ApplicationManager.shared.addClosureToRunWhenAppDidEnterBackground - updateLabels
private let applicationManagerKeyUpdateLabelsAndChart = "RootViewController-UpdateLabelsAndChart"
/// constant for key in ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground - initiate pairing
private let applicationManagerKeyInitiatePairing = "RootViewController-InitiatePairing"
/// constant for key in ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground - initial calibration
private let applicationManagerKeyInitialCalibration = "RootViewController-InitialCalibration"
@ -182,24 +177,15 @@ final class RootViewController: UIViewController {
/// WatchManager instance
private var watchManager: WatchManager?
/// timer used when asking the transmitter to initiate pairing. The user is waiting for the response, if the response from the transmitter doesn't come within a few seconds, then we'll inform the user
private var transmitterPairingResponseTimer:Timer?
/// healthkit manager instance
private var healthKitManager:HealthKitManager?
/// reference to activeSensor
private var activeSensor:Sensor?
/// if true, user manually started scanning for a device, when connection is made, we'll inform the user, see cgmTransmitterDidConnect
private var userDidInitiateScanning = false
/// reference to bgReadingSpeaker
private var bgReadingSpeaker:BGReadingSpeaker?
/// timestamp of last notification for pairing
private var timeStampLastNotificationForPairing:Date?
/// manages bluetoothPeripherals that this app knows
private var bluetoothPeripheralManager: BluetoothPeripheralManager?
@ -422,7 +408,7 @@ final class RootViewController: UIViewController {
})
// setup bluetoothPeripheralManager
bluetoothPeripheralManager = BluetoothPeripheralManager(coreDataManager: coreDataManager, cgmTransmitterDelegate: self, onCGMTransmitterCreation: {
bluetoothPeripheralManager = BluetoothPeripheralManager(coreDataManager: coreDataManager, cgmTransmitterDelegate: self, uIViewController: self, onCGMTransmitterCreation: {
(cgmTransmitter: CGMTransmitter?) in
self.cgmTransmitter = cgmTransmitter
@ -630,15 +616,6 @@ final class RootViewController: UIViewController {
// MARK: - private helper functions
// inform user that pairing request timed out
@objc private func informUserThatPairingTimedOut() {
let alert = UIAlertController(title: Texts_Common.warning, message: "time out", actionHandler: nil)
self.present(alert, animated: true, completion: nil)
}
/// will update the chart with endDate = currentDate
private func updateChartWithResetEndDate() {
@ -646,22 +623,6 @@ final class RootViewController: UIViewController {
}
/// will call cgmTransmitter.initiatePairing() - also sets timer, if no successful pairing within a few seconds, then info will be given to user asking to wait another few minutes
private func initiateTransmitterPairing() {
// initiate the pairing
cgmTransmitter?.initiatePairing()
// invalide the timer, if it exists
if let transmitterPairingResponseTimer = transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
// create and schedule timer
transmitterPairingResponseTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(informUserThatPairingTimedOut), userInfo: nil, repeats: false)
}
/// launches timer that will do regular screen updates - and adds closure to ApplicationManager : when going to background, stop the timer, when coming to foreground, restart the timer
///
/// should be called only once immediately after app start, ie in viewdidload
@ -812,35 +773,35 @@ final class RootViewController: UIViewController {
case .dexcomG4:
if let currentTransmitterId = UserDefaults.standard.transmitterId {
cgmTransmitter = CGMG4xDripTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, delegate:self)
cgmTransmitter = CGMG4xDripTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId)
}
case .dexcomG5:
if let currentTransmitterId = UserDefaults.standard.transmitterId {
cgmTransmitter = CGMG5Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, cGMTransmitterDelegate: self)
cgmTransmitter = CGMG5Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, bluetoothTransmitterDelegate: self, cGMTransmitterDelegate: self)
}
case .dexcomG6:
if let currentTransmitterId = UserDefaults.standard.transmitterId {
cgmTransmitter = CGMG6Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, cGMTransmitterDelegate: self)
cgmTransmitter = CGMG6Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, bluetoothTransmitterDelegate: self, cGMTransmitterDelegate: self)
}
case .miaomiao:
cgmTransmitter = CGMMiaoMiaoTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0), webOOPEnabled: UserDefaults.standard.webOOPEnabled, oopWebSite: UserDefaults.standard.webOOPSite ?? ConstantsLibreOOP.site, oopWebToken: UserDefaults.standard.webOOPtoken ?? ConstantsLibreOOP.token)
cgmTransmitter = CGMMiaoMiaoTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, bluetoothTransmitterDelegate: <#BluetoothTransmitterDelegate#>, timeStampLastBgReading: Date(timeIntervalSince1970: 0), webOOPEnabled: UserDefaults.standard.webOOPEnabled, oopWebSite: UserDefaults.standard.webOOPSite ?? ConstantsLibreOOP.site, oopWebToken: UserDefaults.standard.webOOPtoken ?? ConstantsLibreOOP.token)
case .Bubble:
cgmTransmitter = CGMBubbleTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0), sensorSerialNumber: UserDefaults.standard.sensorSerialNumber, webOOPEnabled: UserDefaults.standard.webOOPEnabled, oopWebSite: UserDefaults.standard.webOOPSite ?? ConstantsLibreOOP.site, oopWebToken: UserDefaults.standard.webOOPtoken ?? ConstantsLibreOOP.token)
cgmTransmitter = CGMBubbleTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, bluetoothTransmitterDelegate: <#BluetoothTransmitterDelegate#>, timeStampLastBgReading: Date(timeIntervalSince1970: 0), sensorSerialNumber: UserDefaults.standard.sensorSerialNumber, webOOPEnabled: UserDefaults.standard.webOOPEnabled, oopWebSite: UserDefaults.standard.webOOPSite ?? ConstantsLibreOOP.site, oopWebToken: UserDefaults.standard.webOOPtoken ?? ConstantsLibreOOP.token)
case .GNSentry:
cgmTransmitter = CGMGNSEntryTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0))
cgmTransmitter = CGMGNSEntryTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, bluetoothTransmitterDelegate: <#BluetoothTransmitterDelegate#>, timeStampLastBgReading: Date(timeIntervalSince1970: 0))
case .Blucon:
if let currentTransmitterId = UserDefaults.standard.transmitterId {
cgmTransmitter = CGMBluconTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, delegate: self, timeStampLastBgReading: Date(timeIntervalSince1970: 0), sensorSerialNumber: UserDefaults.standard.sensorSerialNumber)
cgmTransmitter = CGMBluconTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, transmitterID: currentTransmitterId, bluetoothTransmitterDelegate: <#BluetoothTransmitterDelegate#>, timeStampLastBgReading: Date(timeIntervalSince1970: 0), sensorSerialNumber: UserDefaults.standard.sensorSerialNumber)
}
case .Droplet1:
cgmTransmitter = CGMDroplet1Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self)
cgmTransmitter = CGMDroplet1Transmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName)
case .blueReader:
cgmTransmitter = CGMBlueReaderTransmitter(address: UserDefaults.standard.cgmTransmitterDeviceAddress, name: UserDefaults.standard.cgmTransmitterDeviceName, delegate: self)
@ -1381,186 +1342,6 @@ extension RootViewController:CGMTransmitterDelegate {
}
func reset(successful: Bool) {
// reset setting to false
UserDefaults.standard.transmitterResetRequired = false
// Create Notification Content to give info about reset result of reset attempt
let notificationContent = UNMutableNotificationContent()
// Configure NnotificationContent title
notificationContent.title = successful ? Texts_HomeView.info : Texts_Common.warning
notificationContent.body = Texts_HomeView.transmitterResetResult + " : " + (successful ? Texts_HomeView.success : Texts_HomeView.failed)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: ConstantsNotifications.NotificationIdentifierForResetResult.transmitterResetResult, content: notificationContent, trigger: nil)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
trace("Unable add notification request : transmitter reset result, error: %{public}@", log: self.log, category: ConstantsLog.categoryRootView, type: .error, error.localizedDescription)
}
}
}
func pairingFailed() {
// this should be the consequence of the user not accepting the pairing request, there's no need to inform the user
// invalidate transmitterPairingResponseTimer
if let transmitterPairingResponseTimer = transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
}
func successfullyPaired() {
// remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// invalidate transmitterPairingResponseTimer
if let transmitterPairingResponseTimer = transmitterPairingResponseTimer {
transmitterPairingResponseTimer.invalidate()
}
// inform user
let alert = UIAlertController(title: Texts_HomeView.info, message: Texts_HomeView.transmitterPairingSuccessful, actionHandler: nil)
self.present(alert, animated: true, completion: nil)
}
func cgmTransmitterDidConnect(address:String?, name:String?) {
// store address and name, if this is the first connect to a specific device, then this address and name will be used in the future to reconnect to the same device, without having to scan
if let address = address, let name = name {
UserDefaults.standard.cgmTransmitterDeviceAddress = address
UserDefaults.standard.cgmTransmitterDeviceName = name
}
// if the connect is a result of a user initiated start scanning, then display message that connection was successful
if userDidInitiateScanning {
userDidInitiateScanning = false
// additional info for the user
let alert = UIAlertController(title: Texts_HomeView.scanBluetoothDeviceActionTitle, message: Texts_HomeView.bluetoothDeviceConnectedInfo, actionHandler: nil)
self.present(alert, animated: true, completion: nil)
}
}
func cgmTransmitterDidDisconnect() {
// set disconnect timestamp
UserDefaults.standard.lastdisConnectTimestamp = Date()
}
func deviceDidUpdateBluetoothState(state: CBManagerState) {
switch state {
case .unknown:
break
case .resetting:
break
case .unsupported:
break
case .unauthorized:
break
case .poweredOff:
UserDefaults.standard.lastdisConnectTimestamp = Date()
case .poweredOn:
// user changes device bluetooth status to on
if UserDefaults.standard.cgmTransmitterDeviceAddress == nil, let cgmTransmitter = cgmTransmitter, let transmitterType = UserDefaults.standard.transmitterType, transmitterType.startScanningAfterInit() {
// bluetoothDeviceAddress = nil, means app hasn't connected before to the transmitter
// cgmTransmitter != nil, means user has configured transmitter type and transmitterid
// transmitterType.startScanningAfterInit() gives true, means it's ok to start the scanning
// possibly scanning is already running, but that's ok if we call the startScanning function again
_ = cgmTransmitter.startScanning()
}
@unknown default:
break
}
}
/// Transmitter is calling this delegate function to indicate that bluetooth pairing is needed. If the app is in the background, the user will be informed, after opening the app a pairing request will be initiated. if the app is in the foreground, the pairing request will be initiated immediately
func cgmTransmitterNeedsPairing() {
trace("transmitter needs pairing", log: log, category: ConstantsLog.categoryRootView, type: .info)
if let timeStampLastNotificationForPairing = timeStampLastNotificationForPairing {
// check timestamp of last notification, if too soon then return
if Int(abs(timeStampLastNotificationForPairing.timeIntervalSinceNow)) < ConstantsBluetoothPairing.minimumTimeBetweenTwoPairingNotificationsInSeconds {
return
}
}
// set timeStampLastNotificationForPairing
timeStampLastNotificationForPairing = Date()
// remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure NnotificationContent title
notificationContent.title = Texts_Common.warning
notificationContent.body = Texts_HomeView.transmitterNotPaired
// add sound
notificationContent.sound = UNNotificationSound.init(named: UNNotificationSoundName.init(""))
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing, content: notificationContent, trigger: nil)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
trace("Unable add notification request : transmitter needs pairing Notification Request, error : %{public}@", log: self.log, category: ConstantsLog.categoryRootView, type: .error, error.localizedDescription)
}
}
// vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
// add closure to ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground so that if user opens the app, the pairing request will be initiated. This can be done only if the app is opened within 60 seconds.
// If the app is already in the foreground, then userNotificationCenter willPresent will be called, in this function the closure will be removed immediately, and the pairing request will be called. As a result, if the app is in the foreground, the user will not see (or hear) any notification, but the pairing will be initiated
// max timestamp when notification was fired - connection stays open for 1 minute, taking 1 second as d
let maxTimeUserCanOpenApp = Date(timeIntervalSinceNow: TimeInterval(ConstantsDexcomG5.maxTimeToAcceptPairingInSeconds - 1))
// we will not just count on it that the user will click the notification to open the app (assuming the app is in the background, if the app is in the foreground, then we come in another flow)
// whenever app comes from-back to foreground, updateLabelsAndChart needs to be called
ApplicationManager.shared.addClosureToRunWhenAppWillEnterForeground(key: applicationManagerKeyInitiatePairing, closure: {
// first of all reremove from application key manager
ApplicationManager.shared.removeClosureToRunWhenAppWillEnterForeground(key: self.applicationManagerKeyInitiatePairing)
// first remove existing notification if any
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [ConstantsNotifications.NotificationIdentifierForTransmitterNeedsPairing.transmitterNeedsPairing])
// if it was too long since notification was fired, then forget about it
if Date() > maxTimeUserCanOpenApp {
trace("in cgmTransmitterNeedsPairing, user opened the app too late", log: self.log, category: ConstantsLog.categoryRootView, type: .error)
let alert = UIAlertController(title: Texts_Common.warning, message: Texts_HomeView.transmitterPairingTooLate, actionHandler: nil)
self.present(alert, animated: true, completion: nil)
return
}
// initiate the pairing
self.cgmTransmitter?.initiatePairing()
})
}
// Only MioaMiao will call this
func newSensorDetected() {
trace("new sensor detected", log: log, category: ConstantsLog.categoryRootView, type: .info)