redesign M5Stack stuff, as preperation to move all bluetooth stuff to that page
This commit is contained in:
parent
bfdbd281a7
commit
4248d359e1
|
@ -10,7 +10,6 @@
|
|||
A48D2DE552F4A356AA32746A /* Pods_xdrip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 662BEA7F7991B9BD2E7D3EA4 /* Pods_xdrip.framework */; };
|
||||
EE9947E822EEDD2E00DCB876 /* CGMBubbleTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE9947E722EEDD2E00DCB876 /* CGMBubbleTransmitter.swift */; };
|
||||
F8025C0A21D94FD700ECF0C0 /* CBManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */; };
|
||||
F8025C1121DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C1021DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift */; };
|
||||
F8025C1321DA683400ECF0C0 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025C1221DA683400ECF0C0 /* Data.swift */; };
|
||||
F8025E4E21ED450300ECF0C0 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E4D21ED450300ECF0C0 /* Double.swift */; };
|
||||
F8025E5021EE746400ECF0C0 /* Calibrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8025E4F21EE746400ECF0C0 /* Calibrator.swift */; };
|
||||
|
@ -25,7 +24,6 @@
|
|||
F80ED2EC236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2E9236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift */; };
|
||||
F80ED2ED236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2EA236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift */; };
|
||||
F80ED2EE236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2EB236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift */; };
|
||||
F80ED2F32379C6CD0005C035 /* M5StackBluetoothDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80ED2F22379C6CD0005C035 /* M5StackBluetoothDelegate.swift */; };
|
||||
F81D6D4822BD5F62005EFAE2 /* DexcomShareUploadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81D6D4722BD5F62005EFAE2 /* DexcomShareUploadManager.swift */; };
|
||||
F81D6D4E22BFC762005EFAE2 /* TextsDexcomShareTestResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81D6D4D22BFC762005EFAE2 /* TextsDexcomShareTestResult.swift */; };
|
||||
F81D6D5222C27F18005EFAE2 /* BgReading+DexcomShare.swift in Sources */ = {isa = PBXBuildFile; fileRef = F81D6D5122C27F18005EFAE2 /* BgReading+DexcomShare.swift */; };
|
||||
|
@ -55,11 +53,19 @@
|
|||
F821CF9522ADB0D7005C1E43 /* HealthKitManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F821CF9422ADB0D7005C1E43 /* HealthKitManager.swift */; };
|
||||
F821CF9722AE589E005C1E43 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F821CF9622AE589E005C1E43 /* HealthKit.framework */; };
|
||||
F821CF9D22AEF483005C1E43 /* BGReadingSpeaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = F821CF9C22AEF483005C1E43 /* BGReadingSpeaker.swift */; };
|
||||
F8297F45238DC4AC00D74D66 /* BluetoothPerpheralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F43238DC4AC00D74D66 /* BluetoothPerpheralManager.swift */; };
|
||||
F8297F46238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F44238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift */; };
|
||||
F8297F4E238DCAD800D74D66 /* BluetoothPeripheralsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F4B238DCAD800D74D66 /* BluetoothPeripheralsViewController.swift */; };
|
||||
F8297F4F238DCAD800D74D66 /* BluetoothPeripheralNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F4C238DCAD800D74D66 /* BluetoothPeripheralNavigationController.swift */; };
|
||||
F8297F52238ECA3200D74D66 /* BluetoothPeripheralViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F51238ECA3200D74D66 /* BluetoothPeripheralViewController.swift */; };
|
||||
F8297F56238ED07700D74D66 /* BluetoothPeripheralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F55238ED07700D74D66 /* BluetoothPeripheralManager.swift */; };
|
||||
F8297F59238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F57238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift */; };
|
||||
F8297F5A238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F58238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift */; };
|
||||
F8297F5C238FC53100D74D66 /* M5Stack+BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F5B238FC53100D74D66 /* M5Stack+BluetoothPeripheral.swift */; };
|
||||
F8297F5E238FC77C00D74D66 /* BluetoothPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F5D238FC77C00D74D66 /* BluetoothPeripheral.swift */; };
|
||||
F8297F6023902FC300D74D66 /* BluetoothPeripheralType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F5F23902FC300D74D66 /* BluetoothPeripheralType.swift */; };
|
||||
F8297F62239267F900D74D66 /* BluetoothTransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F61239267F900D74D66 /* BluetoothTransmitterDelegate.swift */; };
|
||||
F8297F6623942D4200D74D66 /* M5StackBluetoothTransmitterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8297F6523942D4200D74D66 /* M5StackBluetoothTransmitterDelegate.swift */; };
|
||||
F8365EBC239868A600B0501B /* M5StackBluetoothPeripheralViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8365EBB239868A600B0501B /* M5StackBluetoothPeripheralViewModel.swift */; };
|
||||
F856CE5B22EDC8E50083E436 /* ConstantsBluetoothPairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = F856CE5A22EDC8E50083E436 /* ConstantsBluetoothPairing.swift */; };
|
||||
F85DC2ED21CFE2F500B9F74A /* BgReading+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2E721CFE2F500B9F74A /* BgReading+CoreDataProperties.swift */; };
|
||||
F85DC2EF21CFE2F500B9F74A /* Sensor+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2E921CFE2F500B9F74A /* Sensor+CoreDataProperties.swift */; };
|
||||
|
@ -67,20 +73,20 @@
|
|||
F85DC2F421CFE3D400B9F74A /* Sensor+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2F121CFE3D400B9F74A /* Sensor+CoreDataClass.swift */; };
|
||||
F85DC2F521CFE3D400B9F74A /* BgReading+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F85DC2F221CFE3D400B9F74A /* BgReading+CoreDataClass.swift */; };
|
||||
F867E2612252ADAB000FD265 /* Calibration+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F867E25D2252ADAB000FD265 /* Calibration+CoreDataProperties.swift */; };
|
||||
F8691888239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8691887239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift */; };
|
||||
F869188A23A043890065B607 /* BluetoothPeripheralsView.strings in Resources */ = {isa = PBXBuildFile; fileRef = F869188923A043880065B607 /* BluetoothPeripheralsView.strings */; };
|
||||
F869188C23A044340065B607 /* TextsM5StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F869188B23A044340065B607 /* TextsM5StackView.swift */; };
|
||||
F869189023A155100065B607 /* BluetoothPeripheralView.strings in Resources */ = {isa = PBXBuildFile; fileRef = F869188F23A155100065B607 /* BluetoothPeripheralView.strings */; };
|
||||
F889CB60236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F889CB5F236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift */; };
|
||||
F889CB61236D844600A81068 /* M5StacksView.strings in Resources */ = {isa = PBXBuildFile; fileRef = F889CB63236D844600A81068 /* M5StacksView.strings */; };
|
||||
F889CB6F236D84AC00A81068 /* M5StackView.strings in Resources */ = {isa = PBXBuildFile; fileRef = F889CB71236D84AC00A81068 /* M5StackView.strings */; };
|
||||
F889CB7F236D850600A81068 /* DexcomShareTestResults.strings in Resources */ = {isa = PBXBuildFile; fileRef = F889CB81236D850600A81068 /* DexcomShareTestResults.strings */; };
|
||||
F897AAF92200F2D200CDDD10 /* CBPeripheralState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897AAF82200F2D200CDDD10 /* CBPeripheralState.swift */; };
|
||||
F897AAFB2201018800CDDD10 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = F897AAFA2201018800CDDD10 /* String.swift */; };
|
||||
F898EDEA233F53BF00BFB79B /* UIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDE9233F53BF00BFB79B /* UIButton.swift */; };
|
||||
F898EDEC233F549100BFB79B /* UIBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDEB233F549100BFB79B /* UIBarButtonItem.swift */; };
|
||||
F898EDEE233F852200BFB79B /* M5StackNameAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDED233F852200BFB79B /* M5StackNameAccessor.swift */; };
|
||||
F898EDF2234A8A0500BFB79B /* UInt8.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDF1234A8A0500BFB79B /* UInt8.swift */; };
|
||||
F898EDF4234A8A3200BFB79B /* UInt16.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDF3234A8A3200BFB79B /* UInt16.swift */; };
|
||||
F898EDF6234A8A5700BFB79B /* UInt32.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDF5234A8A5700BFB79B /* UInt32.swift */; };
|
||||
F898EDF8234F8EDF00BFB79B /* M5StackName+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDF7234F8EDE00BFB79B /* M5StackName+CoreDataProperties.swift */; };
|
||||
F898EDFA234F8EE500BFB79B /* M5StackName+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = F898EDF9234F8EE500BFB79B /* M5StackName+CoreDataClass.swift */; };
|
||||
F8A1584D22ECA445007F5B5D /* SettingsViewDevelopmentSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A1584C22ECA445007F5B5D /* SettingsViewDevelopmentSettingsViewModel.swift */; };
|
||||
F8A1584F22ECB281007F5B5D /* SettingsViewInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A1584E22ECB281007F5B5D /* SettingsViewInfoViewModel.swift */; };
|
||||
F8A1585122EDB597007F5B5D /* ConstantsBGGraphBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8A1585022EDB597007F5B5D /* ConstantsBGGraphBuilder.swift */; };
|
||||
|
@ -237,8 +243,6 @@
|
|||
F8EEDD552300136F00D2D610 /* DexcomShareTestResult.strings in Resources */ = {isa = PBXBuildFile; fileRef = F8EEDD572300136F00D2D610 /* DexcomShareTestResult.strings */; };
|
||||
F8EEDD6423020FAD00D2D610 /* NoCalibrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8EEDD6323020FAD00D2D610 /* NoCalibrator.swift */; };
|
||||
F8F62270233AA3B200BE8796 /* M5StackAccessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F6226F233AA3B200BE8796 /* M5StackAccessor.swift */; };
|
||||
F8F62276233D1CE600BE8796 /* TextsM5StacksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F62275233D1CE600BE8796 /* TextsM5StacksView.swift */; };
|
||||
F8F62278233D1CED00BE8796 /* TextsM5StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8F62277233D1CED00BE8796 /* TextsM5StackView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -247,7 +251,6 @@
|
|||
E2648F65F347D56D7DFFFAB7 /* Pods-xdrip.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-xdrip.release.xcconfig"; path = "Target Support Files/Pods-xdrip/Pods-xdrip.release.xcconfig"; sourceTree = "<group>"; };
|
||||
EE9947E722EEDD2E00DCB876 /* CGMBubbleTransmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGMBubbleTransmitter.swift; sourceTree = "<group>"; };
|
||||
F8025C0921D94FD700ECF0C0 /* CBManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBManagerState.swift; sourceTree = "<group>"; };
|
||||
F8025C1021DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitterDelegate.swift; sourceTree = "<group>"; };
|
||||
F8025C1221DA683400ECF0C0 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
|
||||
F8025E4D21ED450300ECF0C0 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
|
||||
F8025E4F21EE746400ECF0C0 /* Calibrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calibrator.swift; sourceTree = "<group>"; };
|
||||
|
@ -262,7 +265,6 @@
|
|||
F80ED2E9236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackBluetoothSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
F80ED2EA236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackGeneralSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
F80ED2EB236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewM5StackWiFiSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
F80ED2F22379C6CD0005C035 /* M5StackBluetoothDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = M5StackBluetoothDelegate.swift; sourceTree = "<group>"; };
|
||||
F81D6D4522B67F55005EFAE2 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/SpeakReading.strings; sourceTree = "<group>"; };
|
||||
F81D6D4722BD5F62005EFAE2 /* DexcomShareUploadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DexcomShareUploadManager.swift; sourceTree = "<group>"; };
|
||||
F81D6D4D22BFC762005EFAE2 /* TextsDexcomShareTestResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextsDexcomShareTestResult.swift; sourceTree = "<group>"; };
|
||||
|
@ -295,11 +297,19 @@
|
|||
F821CF9822AE589E005C1E43 /* xdrip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = xdrip.entitlements; sourceTree = "<group>"; };
|
||||
F821CF9C22AEF483005C1E43 /* BGReadingSpeaker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BGReadingSpeaker.swift; sourceTree = "<group>"; };
|
||||
F8297F41238C3A6400D74D66 /* xdrip v5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v5.xcdatamodel"; sourceTree = "<group>"; };
|
||||
F8297F43238DC4AC00D74D66 /* BluetoothPerpheralManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPerpheralManager.swift; sourceTree = "<group>"; };
|
||||
F8297F44238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralManaging.swift; sourceTree = "<group>"; };
|
||||
F8297F4B238DCAD800D74D66 /* BluetoothPeripheralsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralsViewController.swift; sourceTree = "<group>"; };
|
||||
F8297F4C238DCAD800D74D66 /* BluetoothPeripheralNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralNavigationController.swift; sourceTree = "<group>"; };
|
||||
F8297F51238ECA3200D74D66 /* BluetoothPeripheralViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralViewController.swift; sourceTree = "<group>"; };
|
||||
F8297F55238ED07700D74D66 /* BluetoothPeripheralManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralManager.swift; sourceTree = "<group>"; };
|
||||
F8297F57238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextsBluetoothPeripheralsView.swift; sourceTree = "<group>"; };
|
||||
F8297F58238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextsBluetoothPeripheralView.swift; sourceTree = "<group>"; };
|
||||
F8297F5B238FC53100D74D66 /* M5Stack+BluetoothPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "M5Stack+BluetoothPeripheral.swift"; sourceTree = "<group>"; };
|
||||
F8297F5D238FC77C00D74D66 /* BluetoothPeripheral.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheral.swift; sourceTree = "<group>"; };
|
||||
F8297F5F23902FC300D74D66 /* BluetoothPeripheralType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralType.swift; sourceTree = "<group>"; };
|
||||
F8297F61239267F900D74D66 /* BluetoothTransmitterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitterDelegate.swift; sourceTree = "<group>"; };
|
||||
F8297F6523942D4200D74D66 /* M5StackBluetoothTransmitterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = M5StackBluetoothTransmitterDelegate.swift; sourceTree = "<group>"; };
|
||||
F8365EBB239868A600B0501B /* M5StackBluetoothPeripheralViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = M5StackBluetoothPeripheralViewModel.swift; sourceTree = "<group>"; };
|
||||
F846CDD523046BAC00DCF016 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/SettingsViews.strings"; sourceTree = "<group>"; };
|
||||
F846CDD623046BAE00DCF016 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/SettingsViews.strings; sourceTree = "<group>"; };
|
||||
F856CE5A22EDC8E50083E436 /* ConstantsBluetoothPairing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsBluetoothPairing.swift; sourceTree = "<group>"; };
|
||||
|
@ -310,31 +320,12 @@
|
|||
F85DC2F121CFE3D400B9F74A /* Sensor+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sensor+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F85DC2F221CFE3D400B9F74A /* BgReading+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BgReading+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F867E25D2252ADAB000FD265 /* Calibration+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Calibration+CoreDataProperties.swift"; path = "xdrip/Core Data/extensions/Calibration+CoreDataProperties.swift"; sourceTree = SOURCE_ROOT; };
|
||||
F8691887239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothPeripheralViewModel.swift; sourceTree = "<group>"; };
|
||||
F869188923A043880065B607 /* BluetoothPeripheralsView.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = BluetoothPeripheralsView.strings; sourceTree = "<group>"; };
|
||||
F869188B23A044340065B607 /* TextsM5StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextsM5StackView.swift; sourceTree = "<group>"; };
|
||||
F869188F23A155100065B607 /* BluetoothPeripheralView.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = BluetoothPeripheralView.strings; sourceTree = "<group>"; };
|
||||
F889CB5F236C3DCB00A81068 /* CGMBlueReaderTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMBlueReaderTransmitter.swift; sourceTree = "<group>"; };
|
||||
F889CB62236D844600A81068 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB64236D849200A81068 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB65236D849400A81068 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB66236D849500A81068 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB67236D849700A81068 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB68236D849800A81068 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/M5StacksView.strings"; sourceTree = "<group>"; };
|
||||
F889CB69236D849900A81068 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB6A236D849B00A81068 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/M5StacksView.strings"; sourceTree = "<group>"; };
|
||||
F889CB6B236D849C00A81068 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB6C236D849D00A81068 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB6D236D849E00A81068 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/M5StacksView.strings"; sourceTree = "<group>"; };
|
||||
F889CB6E236D849F00A81068 /* es-ES */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-ES"; path = "es-ES.lproj/M5StacksView.strings"; sourceTree = "<group>"; };
|
||||
F889CB70236D84AC00A81068 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB72236D84B000A81068 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB73236D84B100A81068 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB74236D84B200A81068 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB75236D84B300A81068 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB76236D84B400A81068 /* pl-PL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pl-PL"; path = "pl-PL.lproj/M5StackView.strings"; sourceTree = "<group>"; };
|
||||
F889CB77236D84B500A81068 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB78236D84B600A81068 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB79236D84B800A81068 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/M5StackView.strings"; sourceTree = "<group>"; };
|
||||
F889CB7A236D84B900A81068 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB7B236D84BA00A81068 /* es-MX */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-MX"; path = "es-MX.lproj/M5StackView.strings"; sourceTree = "<group>"; };
|
||||
F889CB7C236D84BC00A81068 /* es-ES */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-ES"; path = "es-ES.lproj/M5StackView.strings"; sourceTree = "<group>"; };
|
||||
F889CB80236D850600A81068 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/DexcomShareTestResults.strings; sourceTree = "<group>"; };
|
||||
F889CB82236D850C00A81068 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/DexcomShareTestResults.strings; sourceTree = "<group>"; };
|
||||
F889CB83236D851000A81068 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/DexcomShareTestResults.strings; sourceTree = "<group>"; };
|
||||
|
@ -358,8 +349,6 @@
|
|||
F889CB95236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/ErrorMessages.strings; sourceTree = "<group>"; };
|
||||
F889CB96236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/HomeView.strings; sourceTree = "<group>"; };
|
||||
F889CB97236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
F889CB98236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/M5StacksView.strings; sourceTree = "<group>"; };
|
||||
F889CB99236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/M5StackView.strings; sourceTree = "<group>"; };
|
||||
F889CB9A236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/NightScoutTestResult.strings; sourceTree = "<group>"; };
|
||||
F889CB9B236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SettingsViews.strings; sourceTree = "<group>"; };
|
||||
F889CB9C236D89C800A81068 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/SpeakReading.strings; sourceTree = "<group>"; };
|
||||
|
@ -368,13 +357,10 @@
|
|||
F897AAFA2201018800CDDD10 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
|
||||
F898EDE9233F53BF00BFB79B /* UIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIButton.swift; sourceTree = "<group>"; };
|
||||
F898EDEB233F549100BFB79B /* UIBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBarButtonItem.swift; sourceTree = "<group>"; };
|
||||
F898EDED233F852200BFB79B /* M5StackNameAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = M5StackNameAccessor.swift; sourceTree = "<group>"; };
|
||||
F898EDF0234A494C00BFB79B /* xdrip v3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v3.xcdatamodel"; sourceTree = "<group>"; };
|
||||
F898EDF1234A8A0500BFB79B /* UInt8.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UInt8.swift; sourceTree = "<group>"; };
|
||||
F898EDF3234A8A3200BFB79B /* UInt16.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UInt16.swift; sourceTree = "<group>"; };
|
||||
F898EDF5234A8A5700BFB79B /* UInt32.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UInt32.swift; sourceTree = "<group>"; };
|
||||
F898EDF7234F8EDE00BFB79B /* M5StackName+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "M5StackName+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
F898EDF9234F8EE500BFB79B /* M5StackName+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "M5StackName+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
F8A1584C22ECA445007F5B5D /* SettingsViewDevelopmentSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewDevelopmentSettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
F8A1584E22ECB281007F5B5D /* SettingsViewInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewInfoViewModel.swift; sourceTree = "<group>"; };
|
||||
F8A1585022EDB597007F5B5D /* ConstantsBGGraphBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsBGGraphBuilder.swift; sourceTree = "<group>"; };
|
||||
|
@ -636,6 +622,7 @@
|
|||
F8EA6C8121B723BC0082976B /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
|
||||
F8EA6CA821BBE3010082976B /* UniqueId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniqueId.swift; sourceTree = "<group>"; };
|
||||
F8EA6CAC21BC2CA40082976B /* BluetoothTransmitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitter.swift; sourceTree = "<group>"; };
|
||||
F8EBB030239701DA0058B0D4 /* xdrip v6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "xdrip v6.xcdatamodel"; sourceTree = "<group>"; };
|
||||
F8EEDD3D22FD80A500D2D610 /* LibreOOPResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibreOOPResponse.swift; sourceTree = "<group>"; };
|
||||
F8EEDD3E22FD80A600D2D610 /* LibreOOPClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibreOOPClient.swift; sourceTree = "<group>"; };
|
||||
F8EEDD3F22FD80A600D2D610 /* LibreMeasurement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LibreMeasurement.swift; sourceTree = "<group>"; };
|
||||
|
@ -658,8 +645,6 @@
|
|||
F8EEDD622300139A00D2D610 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/DexcomShareTestResult.strings; sourceTree = "<group>"; };
|
||||
F8EEDD6323020FAD00D2D610 /* NoCalibrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCalibrator.swift; sourceTree = "<group>"; };
|
||||
F8F6226F233AA3B200BE8796 /* M5StackAccessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = M5StackAccessor.swift; sourceTree = "<group>"; };
|
||||
F8F62275233D1CE600BE8796 /* TextsM5StacksView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextsM5StacksView.swift; sourceTree = "<group>"; };
|
||||
F8F62277233D1CED00BE8796 /* TextsM5StackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextsM5StackView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -869,7 +854,7 @@
|
|||
F8297F42238DC4AC00D74D66 /* BluetoothPeripheral */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8297F43238DC4AC00D74D66 /* BluetoothPerpheralManager.swift */,
|
||||
F8297F55238ED07700D74D66 /* BluetoothPeripheralManager.swift */,
|
||||
F8297F44238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift */,
|
||||
);
|
||||
path = BluetoothPeripheral;
|
||||
|
@ -896,7 +881,9 @@
|
|||
F8297F50238ECA3200D74D66 /* BluetoothPeripheralViewController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8691887239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift */,
|
||||
F8297F51238ECA3200D74D66 /* BluetoothPeripheralViewController.swift */,
|
||||
F8365EBB239868A600B0501B /* M5StackBluetoothPeripheralViewModel.swift */,
|
||||
);
|
||||
path = BluetoothPeripheralViewController;
|
||||
sourceTree = "<group>";
|
||||
|
@ -927,22 +914,23 @@
|
|||
F85DC2F921D2CCC000B9F74A /* Storyboards */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F889CB81236D850600A81068 /* DexcomShareTestResults.strings */,
|
||||
F8B3A7B3226A0A71004BA588 /* Alerts.strings */,
|
||||
F8B3A80B227A3E97004BA588 /* AlertTypesSettingsView.strings */,
|
||||
F869188923A043880065B607 /* BluetoothPeripheralsView.strings */,
|
||||
F8B48AA222B2FA9A009BCC01 /* CalibrationRequest.strings */,
|
||||
F8BDD444221C9D0D006EAB84 /* Common.strings */,
|
||||
F8EEDD572300136F00D2D610 /* DexcomShareTestResult.strings */,
|
||||
F889CB81236D850600A81068 /* DexcomShareTestResults.strings */,
|
||||
F8BDD44A221C9D70006EAB84 /* ErrorMessages.strings */,
|
||||
F8B48A9E22B2FA7B009BCC01 /* HomeView.strings */,
|
||||
F8AC426821ADEBD70078C348 /* LaunchScreen.storyboard */,
|
||||
F8BDD436221A0349006EAB84 /* Localizable.strings */,
|
||||
F889CB63236D844600A81068 /* M5StacksView.strings */,
|
||||
F889CB71236D84AC00A81068 /* M5StackView.strings */,
|
||||
F8AC426321ADEBD60078C348 /* Main.storyboard */,
|
||||
F8B3A788225D4473004BA588 /* NightScoutTestResult.strings */,
|
||||
F8BDD457221DEF22006EAB84 /* SettingsViews.strings */,
|
||||
F8B48A9A22B2FA66009BCC01 /* SpeakReading.strings */,
|
||||
F869188F23A155100065B607 /* BluetoothPeripheralView.strings */,
|
||||
);
|
||||
path = Storyboards;
|
||||
sourceTree = "<group>";
|
||||
|
@ -979,8 +967,10 @@
|
|||
F85DC2FF21D3E83100B9F74A /* GenericBluetoothTransmitter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8297F61239267F900D74D66 /* BluetoothTransmitterDelegate.swift */,
|
||||
F8297F5D238FC77C00D74D66 /* BluetoothPeripheral.swift */,
|
||||
F8EA6CAC21BC2CA40082976B /* BluetoothTransmitter.swift */,
|
||||
F8025C1021DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift */,
|
||||
F8297F5F23902FC300D74D66 /* BluetoothPeripheralType.swift */,
|
||||
);
|
||||
path = GenericBluetoothTransmitter;
|
||||
sourceTree = "<group>";
|
||||
|
@ -996,11 +986,12 @@
|
|||
F8A389B82315DB080010F405 /* M5Stack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F80ED2F22379C6CD0005C035 /* M5StackBluetoothDelegate.swift */,
|
||||
F8A389C4231FB9B30010F405 /* Utilities */,
|
||||
F8A389BD231DC7DC0010F405 /* M5StackMessages */,
|
||||
F8297F5B238FC53100D74D66 /* M5Stack+BluetoothPeripheral.swift */,
|
||||
F8A389B92315DC060010F405 /* M5StackBluetoothTransmitter.swift */,
|
||||
F8297F6523942D4200D74D66 /* M5StackBluetoothTransmitterDelegate.swift */,
|
||||
F8A389BD231DC7DC0010F405 /* M5StackMessages */,
|
||||
F8A389BB231713580010F405 /* M5StackTransmitterOpCode.swift */,
|
||||
F8A389C4231FB9B30010F405 /* Utilities */,
|
||||
);
|
||||
path = M5Stack;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1267,7 +1258,6 @@
|
|||
F8B3A819227DEC92004BA588 /* README.md */,
|
||||
F8B3A815227DEC91004BA588 /* SensorsAccessor.swift */,
|
||||
F8F6226F233AA3B200BE8796 /* M5StackAccessor.swift */,
|
||||
F898EDED233F852200BFB79B /* M5StackNameAccessor.swift */,
|
||||
);
|
||||
path = accessors;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1367,6 +1357,8 @@
|
|||
F8BDD44C221CAA26006EAB84 /* Texts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F8297F57238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift */,
|
||||
F8297F58238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift */,
|
||||
F8B3A7B1226A0878004BA588 /* TextsAlerts.swift */,
|
||||
F8B3A809227A3D11004BA588 /* TextsAlertTypeSettings.swift */,
|
||||
F81FA005228E09D40028C70F /* TextsCalibration.swift */,
|
||||
|
@ -1374,11 +1366,10 @@
|
|||
F81D6D4D22BFC762005EFAE2 /* TextsDexcomShareTestResult.swift */,
|
||||
F8BDD43E221B5BAF006EAB84 /* TextsErrorMessages.swift */,
|
||||
F81FA009228F53680028C70F /* TextsHomeView.swift */,
|
||||
F8F62275233D1CE600BE8796 /* TextsM5StacksView.swift */,
|
||||
F8F62277233D1CED00BE8796 /* TextsM5StackView.swift */,
|
||||
F8B3A782225D37F2004BA588 /* TextsNightScoutTestResult.swift */,
|
||||
F8BDD451221DEAB1006EAB84 /* TextsSettingsView.swift */,
|
||||
F8B48A9322B2A705009BCC01 /* TextsSpeakReading.swift */,
|
||||
F869188B23A044340065B607 /* TextsM5StackView.swift */,
|
||||
);
|
||||
path = Texts;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1452,8 +1443,6 @@
|
|||
F8EA6CA421B9A25B0082976B /* classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F898EDF9234F8EE500BFB79B /* M5StackName+CoreDataClass.swift */,
|
||||
F898EDF7234F8EDE00BFB79B /* M5StackName+CoreDataProperties.swift */,
|
||||
F804870A2336D90200EBDDB7 /* M5Stack+CoreDataClass.swift */,
|
||||
F804870B2336D90200EBDDB7 /* M5Stack+CoreDataProperties.swift */,
|
||||
F8B3A79122635A25004BA588 /* AlertEntry+CoreDataClass.swift */,
|
||||
|
@ -1564,6 +1553,7 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F869189023A155100065B607 /* BluetoothPeripheralView.strings in Resources */,
|
||||
F8BDD442221C9D0D006EAB84 /* Common.strings in Resources */,
|
||||
F8AC426A21ADEBD70078C348 /* LaunchScreen.storyboard in Resources */,
|
||||
F8BDD438221A0349006EAB84 /* Localizable.strings in Resources */,
|
||||
|
@ -1585,13 +1575,13 @@
|
|||
F889CB6F236D84AC00A81068 /* M5StackView.strings in Resources */,
|
||||
F8B3A80D227A3E98004BA588 /* AlertTypesSettingsView.strings in Resources */,
|
||||
F8B3A7D3226CC0B7004BA588 /* xdripalert.aif in Resources */,
|
||||
F889CB61236D844600A81068 /* M5StacksView.strings in Resources */,
|
||||
F8AC426721ADEBD70078C348 /* Assets.xcassets in Resources */,
|
||||
F8EEDD552300136F00D2D610 /* DexcomShareTestResult.strings in Resources */,
|
||||
F8B3A7CF226CC0B7004BA588 /* shorthigh4.mp3 in Resources */,
|
||||
F821CF7D22A46CDD005C1E43 /* 1-millisecond-of-silence.mp3 in Resources */,
|
||||
F8B3A7CE226CC0B7004BA588 /* shorthigh2.mp3 in Resources */,
|
||||
F889CB7F236D850600A81068 /* DexcomShareTestResults.strings in Resources */,
|
||||
F869188A23A043890065B607 /* BluetoothPeripheralsView.strings in Resources */,
|
||||
F821CF7F22A4EDCF005C1E43 /* 20ms-of-silence.caf in Resources */,
|
||||
F8B3A7CC226CC0B7004BA588 /* shorthigh1.mp3 in Resources */,
|
||||
F8AC426521ADEBD60078C348 /* Main.storyboard in Resources */,
|
||||
|
@ -1676,6 +1666,7 @@
|
|||
F8A54B0122D9179100934E7A /* LibreSensorState.swift in Sources */,
|
||||
F8EA6C8221B723BC0082976B /* Date.swift in Sources */,
|
||||
F8A54AE622D911BA00934E7A /* KeepAliveTxMessage.swift in Sources */,
|
||||
F8297F6023902FC300D74D66 /* BluetoothPeripheralType.swift in Sources */,
|
||||
F81FA006228E09D40028C70F /* TextsCalibration.swift in Sources */,
|
||||
F8A54ABA22D9111900934E7A /* GlucoseData.swift in Sources */,
|
||||
F8B3A84A227F090E004BA588 /* SettingsViewGeneralSettingsViewModel.swift in Sources */,
|
||||
|
@ -1690,6 +1681,7 @@
|
|||
F8B3A853227F2743004BA588 /* AlertsSettingsViewController.swift in Sources */,
|
||||
F8B3A849227F090E004BA588 /* SettingsViewSpeakSettingsViewModel.swift in Sources */,
|
||||
F8BDD43F221B5BAF006EAB84 /* TextsErrorMessages.swift in Sources */,
|
||||
F8365EBC239868A600B0501B /* M5StackBluetoothPeripheralViewModel.swift in Sources */,
|
||||
F8B3A7FA2278E0E8004BA588 /* SettingsViewModelProtocol.swift in Sources */,
|
||||
F85DC2F521CFE3D400B9F74A /* BgReading+CoreDataClass.swift in Sources */,
|
||||
F8A54AEA22D911BA00934E7A /* PairRequestTxMessage.swift in Sources */,
|
||||
|
@ -1709,11 +1701,14 @@
|
|||
F8EA6CA921BBE3010082976B /* UniqueId.swift in Sources */,
|
||||
F8A1585122EDB597007F5B5D /* ConstantsBGGraphBuilder.swift in Sources */,
|
||||
F81D6D4822BD5F62005EFAE2 /* DexcomShareUploadManager.swift in Sources */,
|
||||
F8297F62239267F900D74D66 /* BluetoothTransmitterDelegate.swift in Sources */,
|
||||
F8A7406E22D9C0E700967CFC /* CGMBluconTransmitter.swift in Sources */,
|
||||
F8A1586B22EDB967007F5B5D /* ConstantsMaster.swift in Sources */,
|
||||
F80859292364D61B00F3829D /* UserDefaults+charts.swift in Sources */,
|
||||
F8A389C3231F1A4B0010F405 /* M5StackReadBlePassWordTxMessage.swift in Sources */,
|
||||
F8297F5E238FC77C00D74D66 /* BluetoothPeripheral.swift in Sources */,
|
||||
F8B3A7B2226A0878004BA588 /* TextsAlerts.swift in Sources */,
|
||||
F8297F5C238FC53100D74D66 /* M5Stack+BluetoothPeripheral.swift in Sources */,
|
||||
F8297F46238DC4AC00D74D66 /* BluetoothPeripheralManaging.swift in Sources */,
|
||||
F8A54B0022D9179100934E7A /* LibreDataParser.swift in Sources */,
|
||||
F8025E5421EE8D2100ECF0C0 /* Libre1Calibrator.swift in Sources */,
|
||||
|
@ -1728,7 +1723,6 @@
|
|||
F897AAF92200F2D200CDDD10 /* CBPeripheralState.swift in Sources */,
|
||||
F8A54AE522D911BA00934E7A /* TransmitterVersionRxMessage.swift in Sources */,
|
||||
F821CF57229BF43A005C1E43 /* SnoozeParameters.swift in Sources */,
|
||||
F8F62278233D1CED00BE8796 /* TextsM5StackView.swift in Sources */,
|
||||
F8A54AFF22D9179100934E7A /* CRC.swift in Sources */,
|
||||
F8B3A79722635A25004BA588 /* AlertEntry+CoreDataProperties.swift in Sources */,
|
||||
F80610C4222D4E4D00D8F236 /* ActionClosureable-extension.swift in Sources */,
|
||||
|
@ -1736,7 +1730,6 @@
|
|||
F821CF9522ADB0D7005C1E43 /* HealthKitManager.swift in Sources */,
|
||||
F8B3A81D227DEC92004BA588 /* CalibrationsAccessor.swift in Sources */,
|
||||
F8A54AE122D911BA00934E7A /* SensorDataTxMessage.swift in Sources */,
|
||||
F898EDEE233F852200BFB79B /* M5StackNameAccessor.swift in Sources */,
|
||||
F821CF9D22AEF483005C1E43 /* BGReadingSpeaker.swift in Sources */,
|
||||
F8297F4E238DCAD800D74D66 /* BluetoothPeripheralsViewController.swift in Sources */,
|
||||
F8EEDD4622FD80A600D2D610 /* LibreMeasurement.swift in Sources */,
|
||||
|
@ -1752,7 +1745,6 @@
|
|||
F8A1587322EDC893007F5B5D /* ConstantsDexcomShare.swift in Sources */,
|
||||
F8A1586F22EDC7EE007F5B5D /* ConstantsSuspensionPrevention.swift in Sources */,
|
||||
F8A54AB822D9111900934E7A /* TransmitterBatteryInfo.swift in Sources */,
|
||||
F8297F45238DC4AC00D74D66 /* BluetoothPerpheralManager.swift in Sources */,
|
||||
F8B3A82D227F07D6004BA588 /* SettingsNavigationController.swift in Sources */,
|
||||
F8A54AB722D9111900934E7A /* CGMTransmitter.swift in Sources */,
|
||||
F80ED2EC236F68F90005C035 /* SettingsViewM5StackBluetoothSettingsViewModel.swift in Sources */,
|
||||
|
@ -1776,17 +1768,17 @@
|
|||
F8AC425E21ADEBD60078C348 /* AppDelegate.swift in Sources */,
|
||||
F804870D2336D90200EBDDB7 /* M5Stack+CoreDataProperties.swift in Sources */,
|
||||
F821CF8E22AB090C005C1E43 /* DatePickerViewController.swift in Sources */,
|
||||
F8691888239CEEFA0065B607 /* BluetoothPeripheralViewModel.swift in Sources */,
|
||||
F8297F4F238DCAD800D74D66 /* BluetoothPeripheralNavigationController.swift in Sources */,
|
||||
F898EDF8234F8EDF00BFB79B /* M5StackName+CoreDataProperties.swift in Sources */,
|
||||
F8A1585322EDB602007F5B5D /* ConstantsBloodGlucose.swift in Sources */,
|
||||
F80ED2EE236F68F90005C035 /* SettingsViewM5StackWiFiSettingsViewModel.swift in Sources */,
|
||||
F8A389C823203E3E0010F405 /* ConstantsM5Stack.swift in Sources */,
|
||||
F898EDEA233F53BF00BFB79B /* UIButton.swift in Sources */,
|
||||
F8297F6623942D4200D74D66 /* M5StackBluetoothTransmitterDelegate.swift in Sources */,
|
||||
F8A54AE322D911BA00934E7A /* AuthRequestRxMessage.swift in Sources */,
|
||||
F8A54AD722D911BA00934E7A /* CGMG6Transmitter.swift in Sources */,
|
||||
F81F9FF822861E6D0028C70F /* KeyValueObserverTimeKeeper.swift in Sources */,
|
||||
F8B3A858227F6971004BA588 /* UISwitch.swift in Sources */,
|
||||
F8F62276233D1CE600BE8796 /* TextsM5StacksView.swift in Sources */,
|
||||
F8A1586722EDB8BF007F5B5D /* ConstantsHomeView.swift in Sources */,
|
||||
F8A1585922EDB7C6007F5B5D /* ConstantsDefaultAlertLevels.swift in Sources */,
|
||||
F8A54AAD22D6859200934E7A /* SlopeParameters.swift in Sources */,
|
||||
|
@ -1795,7 +1787,6 @@
|
|||
F8B3A80A227A3D11004BA588 /* TextsAlertTypeSettings.swift in Sources */,
|
||||
F8A1586D22EDB9BE007F5B5D /* ConstantsDexcomFollower.swift in Sources */,
|
||||
F80ED2ED236F68F90005C035 /* SettingsViewM5StackGeneralSettingsViewModel.swift in Sources */,
|
||||
F898EDFA234F8EE500BFB79B /* M5StackName+CoreDataClass.swift in Sources */,
|
||||
F8B3A850227F26F8004BA588 /* AlertTypesSettingsViewController.swift in Sources */,
|
||||
F8A7407022DBB24800967CFC /* BluconTransmitterOpCode.swift in Sources */,
|
||||
F8EA6CAD21BC2CA40082976B /* BluetoothTransmitter.swift in Sources */,
|
||||
|
@ -1829,17 +1820,17 @@
|
|||
F8297F52238ECA3200D74D66 /* BluetoothPeripheralViewController.swift in Sources */,
|
||||
F821CF66229EE68B005C1E43 /* NightScoutFollowManager.swift in Sources */,
|
||||
F8A54AF622D9156600934E7A /* CGMGNSEntryTransmitter.swift in Sources */,
|
||||
F869188C23A044340065B607 /* TextsM5StackView.swift in Sources */,
|
||||
F8A389E7232ECE7E0010F405 /* SettingsViewUtilities.swift in Sources */,
|
||||
F8B3A7DF226E48C1004BA588 /* SoundPlayer.swift in Sources */,
|
||||
F8B3A820227DEC92004BA588 /* AlertTypesAccessor.swift in Sources */,
|
||||
F8B3A81E227DEC92004BA588 /* BgReadingsAccessor.swift in Sources */,
|
||||
F8A389C6231FBA110010F405 /* M5StackPacket.swift in Sources */,
|
||||
F8B3A846227F090E004BA588 /* SettingsViewTransmitterSettingsViewModel.swift in Sources */,
|
||||
F80ED2F32379C6CD0005C035 /* M5StackBluetoothDelegate.swift in Sources */,
|
||||
F821CF6B229FC22D005C1E43 /* Endpoint.swift in Sources */,
|
||||
F821CF58229BF43A005C1E43 /* AlertManager.swift in Sources */,
|
||||
F8A389CC232191280010F405 /* M5StackUtilities.swift in Sources */,
|
||||
F8025C1121DA5E8F00ECF0C0 /* BluetoothTransmitterDelegate.swift in Sources */,
|
||||
F8297F59238EE14E00D74D66 /* TextsBluetoothPeripheralsView.swift in Sources */,
|
||||
F898EDEC233F549100BFB79B /* UIBarButtonItem.swift in Sources */,
|
||||
F8A54AD922D911BA00934E7A /* TransmitterVersionTxMessage.swift in Sources */,
|
||||
F8A389CF232AE2EA0010F405 /* M5StackSettingsViewController.swift in Sources */,
|
||||
|
@ -1850,6 +1841,8 @@
|
|||
F8025C1321DA683400ECF0C0 /* Data.swift in Sources */,
|
||||
F80859272364355F00F3829D /* ConstantsGlucoseChart.swift in Sources */,
|
||||
F85DC2EF21CFE2F500B9F74A /* Sensor+CoreDataProperties.swift in Sources */,
|
||||
F8297F56238ED07700D74D66 /* BluetoothPeripheralManager.swift in Sources */,
|
||||
F8297F5A238EE14E00D74D66 /* TextsBluetoothPeripheralView.swift in Sources */,
|
||||
F8A54AFA22D9156600934E7A /* CGMMiaoMiaoTransmitter.swift in Sources */,
|
||||
F8BECB02235CE3E20060DAE1 /* BloodGlucoseChartView.swift in Sources */,
|
||||
F8A1584D22ECA445007F5B5D /* SettingsViewDevelopmentSettingsViewModel.swift in Sources */,
|
||||
|
@ -1869,42 +1862,10 @@
|
|||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
F889CB63236D844600A81068 /* M5StacksView.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
F889CB62236D844600A81068 /* en */,
|
||||
F889CB64236D849200A81068 /* zh */,
|
||||
F889CB65236D849400A81068 /* nl */,
|
||||
F889CB66236D849500A81068 /* fr */,
|
||||
F889CB67236D849700A81068 /* it */,
|
||||
F889CB68236D849800A81068 /* pl-PL */,
|
||||
F889CB69236D849900A81068 /* pt */,
|
||||
F889CB6A236D849B00A81068 /* pt-BR */,
|
||||
F889CB6B236D849C00A81068 /* ru */,
|
||||
F889CB6C236D849D00A81068 /* sl */,
|
||||
F889CB6D236D849E00A81068 /* es-MX */,
|
||||
F889CB6E236D849F00A81068 /* es-ES */,
|
||||
F889CB98236D89C800A81068 /* de */,
|
||||
);
|
||||
name = M5StacksView.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F889CB71236D84AC00A81068 /* M5StackView.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
F889CB70236D84AC00A81068 /* en */,
|
||||
F889CB72236D84B000A81068 /* zh */,
|
||||
F889CB73236D84B100A81068 /* nl */,
|
||||
F889CB74236D84B200A81068 /* it */,
|
||||
F889CB75236D84B300A81068 /* fr */,
|
||||
F889CB76236D84B400A81068 /* pl-PL */,
|
||||
F889CB77236D84B500A81068 /* pt */,
|
||||
F889CB78236D84B600A81068 /* ru */,
|
||||
F889CB79236D84B800A81068 /* pt-BR */,
|
||||
F889CB7A236D84B900A81068 /* sl */,
|
||||
F889CB7B236D84BA00A81068 /* es-MX */,
|
||||
F889CB7C236D84BC00A81068 /* es-ES */,
|
||||
F889CB99236D89C800A81068 /* de */,
|
||||
);
|
||||
name = M5StackView.strings;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2311,7 +2272,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.johandegraeve.iosxdripreader;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.johandegraeve.beatit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "xdrip/xdrip-Bridging-Header.h";
|
||||
|
@ -2339,7 +2300,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.johandegraeve.iosxdripreader;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.johandegraeve.beatit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "xdrip/xdrip-Bridging-Header.h";
|
||||
|
@ -2375,13 +2336,14 @@
|
|||
F8AC429F21B31F160078C348 /* xdrip.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
F8EBB030239701DA0058B0D4 /* xdrip v6.xcdatamodel */,
|
||||
F8297F41238C3A6400D74D66 /* xdrip v5.xcdatamodel */,
|
||||
F889CB9D236D8EEC00A81068 /* xdrip v4.xcdatamodel */,
|
||||
F898EDF0234A494C00BFB79B /* xdrip v3.xcdatamodel */,
|
||||
F85C4A93233632EC00D6A86F /* xdrip v2.xcdatamodel */,
|
||||
F8AC42A021B31F160078C348 /* xdrip.xcdatamodel */,
|
||||
);
|
||||
currentVersion = F8297F41238C3A6400D74D66 /* xdrip v5.xcdatamodel */;
|
||||
currentVersion = F8EBB030239701DA0058B0D4 /* xdrip v6.xcdatamodel */;
|
||||
path = xdrip.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
|
|
|
@ -26,75 +26,75 @@ enum ConstantsLog {
|
|||
static let debuglogging = "xdripdebuglogging"
|
||||
|
||||
/// G5
|
||||
static let categoryCGMG5 = "categoryCGMG5"
|
||||
static let categoryCGMG5 = "CGMG5"
|
||||
|
||||
/// GNSEntry
|
||||
static let categoryCGMGNSEntry = "categoryCGMGNSEntry"
|
||||
static let categoryCGMGNSEntry = "CGMGNSEntry"
|
||||
|
||||
/// Blucon
|
||||
static let categoryBlucon = "categoryBlucon"
|
||||
static let categoryBlucon = "Blucon"
|
||||
|
||||
/// core data manager
|
||||
static let categoryCoreDataManager = "categoryCoreDataManager"
|
||||
static let categoryCoreDataManager = "CoreDataManager"
|
||||
|
||||
/// application data bgreadings
|
||||
static let categoryApplicationDataBgReadings = "categoryApplicationDataBgReadings"
|
||||
static let categoryApplicationDataBgReadings = "ApplicationDataBgReadings"
|
||||
|
||||
/// application data calibrations
|
||||
static let categoryApplicationDataCalibrations = "categoryApplicationDataCalibrations"
|
||||
static let categoryApplicationDataCalibrations = "ApplicationDataCalibrations"
|
||||
|
||||
/// application data sensors
|
||||
static let categoryApplicationDataSensors = "categoryApplicationDataSensors"
|
||||
static let categoryApplicationDataSensors = "ApplicationDataSensors"
|
||||
|
||||
/// application data alerttypes
|
||||
static let categoryApplicationDataAlertTypes = "categoryApplicationDataAlertTypes"
|
||||
static let categoryApplicationDataAlertTypes = "ApplicationDataAlertTypes"
|
||||
|
||||
/// application data alertentries
|
||||
static let categoryApplicationDataAlertEntries = "categoryApplicationDataAlertEntries"
|
||||
static let categoryApplicationDataAlertEntries = "ApplicationDataAlertEntries"
|
||||
|
||||
/// application data for M5Stack
|
||||
static let categoryApplicationDataM5Stacks = "categoryApplicationDataM5Stacks"
|
||||
static let categoryApplicationDataM5Stacks = "ApplicationDataM5Stacks"
|
||||
|
||||
/// application for for M5StackName
|
||||
static let categoryApplicationDataM5StackNames = "categoryApplicationDataM5StackNames"
|
||||
static let categoryApplicationDataM5StackNames = "ApplicationDataM5StackNames"
|
||||
|
||||
/// nightscout uploader
|
||||
static let categoryNightScoutUploadManager = "categoryNightScoutUploadManager"
|
||||
static let categoryNightScoutUploadManager = "NightScoutUploadManager"
|
||||
|
||||
/// nightscout follow
|
||||
static let categoryNightScoutFollowManager = "categoryNightScoutFollowManager"
|
||||
static let categoryNightScoutFollowManager = "NightScoutFollowManager"
|
||||
|
||||
/// alertmanager
|
||||
static let categoryAlertManager = "categoryAlertManager"
|
||||
static let categoryAlertManager = "AlertManager"
|
||||
|
||||
/// playsound
|
||||
static let categoryPlaySound = "categoryPlaySound"
|
||||
static let categoryPlaySound = "PlaySound"
|
||||
|
||||
/// healthkit manager
|
||||
static let categoryHealthKitManager = "categoryHealthKitManager"
|
||||
static let categoryHealthKitManager = "HealthKitManager"
|
||||
|
||||
/// SettingsViewHealthKitSettingsViewModel
|
||||
static let categorySettingsViewHealthKitSettingsViewModel = "categorySettingsViewHealthKitSettingsViewModel"
|
||||
static let categorySettingsViewHealthKitSettingsViewModel = "SettingsViewHealthKitSettingsViewModel"
|
||||
|
||||
/// dexcom share upload manager
|
||||
static let categoryDexcomShareUploadManager = "categoryDexcomShareUploadManager"
|
||||
static let categoryDexcomShareUploadManager = "DexcomShareUploadManager"
|
||||
|
||||
/// droplet 1
|
||||
static let categoryCGMDroplet1 = "categoryCGMDroplet1"
|
||||
static let categoryCGMDroplet1 = "CGMDroplet1"
|
||||
|
||||
/// bluereader
|
||||
static let categoryCGMBlueReader = "categoryCGMBlueReader"
|
||||
static let categoryCGMBlueReader = "CGMBlueReader"
|
||||
|
||||
/// LibreOOPClient
|
||||
static let categoryLibreOOPClient = "categoryLibreOOPClient"
|
||||
static let categoryLibreOOPClient = "LibreOOPClient"
|
||||
|
||||
/// for use in M5Stack
|
||||
static let categoryM5StackBluetoothTransmitter = "categoryM5StackBluetoothTransmitter"
|
||||
static let categoryM5StackBluetoothTransmitter = "M5StackBluetoothTransmitter"
|
||||
|
||||
/// BluetoothPeripheralManager logging
|
||||
static let categoryBluetoothPeripheralManager = "categoryBluetoothPeripheralManager"
|
||||
static let categoryBluetoothPeripheralManager = "BluetoothPeripheralManager"
|
||||
|
||||
/// StatusChartsManager logging
|
||||
static let categoryGlucoseChartManager = "categoryGlucoseChartManager"
|
||||
static let categoryGlucoseChartManager = "GlucoseChartManager"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
import Foundation
|
||||
import os
|
||||
import CoreData
|
||||
|
||||
class M5StackNameAccessor {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
/// CoreDataManager to use
|
||||
private let coreDataManager:CoreDataManager
|
||||
|
||||
/// for logging
|
||||
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryApplicationDataM5StackNames)
|
||||
|
||||
// MARK: - initializer
|
||||
|
||||
init(coreDataManager:CoreDataManager) {
|
||||
self.coreDataManager = coreDataManager
|
||||
}
|
||||
|
||||
// MARK: Public functions
|
||||
|
||||
func getM5StackNames() -> [M5StackName] {
|
||||
|
||||
// create fetchRequest
|
||||
let fetchRequest: NSFetchRequest<M5StackName> = M5StackName.fetchRequest()
|
||||
|
||||
// fetch the M5StackNames
|
||||
var M5StackNames = [M5StackName]()
|
||||
coreDataManager.mainManagedObjectContext.performAndWait {
|
||||
do {
|
||||
// Execute Fetch Request
|
||||
M5StackNames = try fetchRequest.execute()
|
||||
} catch {
|
||||
let fetchError = error as NSError
|
||||
trace("in getM5StackNames, Unable to Execute M5StackNames Fetch Request : %{public}@", log: self.log, type: .error, fetchError.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
return M5StackNames
|
||||
|
||||
}
|
||||
|
||||
func deleteM5StackName(m5StackName: M5StackName) {
|
||||
|
||||
coreDataManager.mainManagedObjectContext.delete(m5StackName)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -4,8 +4,8 @@ import CoreData
|
|||
/// M5Stack
|
||||
///
|
||||
/// M5Stack has
|
||||
/// - an address (received form M5Stack),
|
||||
/// - a name (also received from M5Stack),
|
||||
/// - an address (received from the real device),
|
||||
/// - a name (also received from the real device),
|
||||
/// - shouldConnect with default value true, if true then xdrip will automatically try to connect at app launch
|
||||
/// - blePassword : optional, if this value is set, then it means this M5Stack does have an internally stored password created during M5Stack launch. If it is not set, then the password in the userdefaults will be used. If that is also nil, then the xdrip app can not authenticate towards the M5Stack
|
||||
/// - textColor : color to use, see M5StackColor
|
||||
|
@ -15,13 +15,13 @@ import CoreData
|
|||
/// - brightness : value between 0 and 100
|
||||
public class M5Stack: NSManagedObject {
|
||||
|
||||
/// this property is not stored in coreData. It is used to keep track of parameter updates sent to the M5Stack. If value is true, then xdrip needs to send an update off all parameters to this M5Stack as soon as possible (ie when connected)
|
||||
public var parameterUpdateNeeded = true
|
||||
/// explanation, see function parameterUpdateNotNeededAtNextConnect in protocol BluetoothPeripheral
|
||||
public var parameterUpdateNeeded: Bool = false
|
||||
|
||||
/// create M5Stack, shouldconnect default value = true
|
||||
/// - parameters:
|
||||
/// - rotation is internally stored as Int32, actual value should always be between 0 and 360 so UInt16 as parameter is sufficient.
|
||||
init(address: String, name: String, textColor: M5StackColor, backGroundColor: M5StackColor, rotation: UInt16, brightness: Int, nsManagedObjectContext:NSManagedObjectContext) {
|
||||
init(address: String, name: String, textColor: M5StackColor, backGroundColor: M5StackColor, rotation: UInt16, brightness: Int, alias: String?, nsManagedObjectContext:NSManagedObjectContext) {
|
||||
|
||||
let entity = NSEntityDescription.entity(forEntityName: "M5Stack", in: nsManagedObjectContext)!
|
||||
|
||||
|
@ -34,6 +34,7 @@ public class M5Stack: NSManagedObject {
|
|||
self.backGroundColor = Int32(backGroundColor.rawValue)
|
||||
self.rotation = Int32(rotation)
|
||||
self.brightness = Int16(brightness)
|
||||
self.alias = alias
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// M5Stack+CoreDataProperties.swift
|
||||
//
|
||||
//
|
||||
// Created by Johan Degraeve on 25/11/2019.
|
||||
// Created by Johan Degraeve on 03/12/2019.
|
||||
//
|
||||
//
|
||||
|
||||
|
@ -19,11 +19,11 @@ extension M5Stack {
|
|||
@NSManaged public var address: String
|
||||
@NSManaged public var backGroundColor: Int32
|
||||
@NSManaged public var blepassword: String?
|
||||
@NSManaged public var brightness: Int16
|
||||
@NSManaged public var name: String
|
||||
@NSManaged public var rotation: Int32
|
||||
@NSManaged public var shouldconnect: Bool
|
||||
@NSManaged public var textcolor: Int32
|
||||
@NSManaged public var brightness: Int16
|
||||
@NSManaged public var m5StackName: M5StackName?
|
||||
@NSManaged public var alias: String?
|
||||
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// M5StackName+CoreDataClass.swift
|
||||
//
|
||||
//
|
||||
// Created by Johan Degraeve on 22/09/2019.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
public class M5StackName: NSManagedObject {
|
||||
|
||||
/// create M5StackName
|
||||
init(address: String, userDefinedName: String, nsManagedObjectContext:NSManagedObjectContext) {
|
||||
|
||||
let entity = NSEntityDescription.entity(forEntityName: "M5StackName", in: nsManagedObjectContext)!
|
||||
|
||||
super.init(entity: entity, insertInto: nsManagedObjectContext)
|
||||
|
||||
self.address = address
|
||||
self.userDefinedName = userDefinedName
|
||||
|
||||
}
|
||||
|
||||
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
|
||||
super.init(entity: entity, insertInto: context)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// M5StackName+CoreDataProperties.swift
|
||||
//
|
||||
//
|
||||
// Created by Johan Degraeve on 22/09/2019.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
extension M5StackName {
|
||||
|
||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<M5StackName> {
|
||||
return NSFetchRequest<M5StackName>(entityName: "M5StackName")
|
||||
}
|
||||
|
||||
@NSManaged public var address: String
|
||||
@NSManaged public var userDefinedName: String
|
||||
|
||||
}
|
|
@ -3,6 +3,6 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>xdrip v5.xcdatamodel</string>
|
||||
<string>xdrip v6.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15400" systemVersion="19A603" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="AlertEntry" representedClassName=".AlertEntry" syncable="YES">
|
||||
<attribute name="alertkind" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="start" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="value" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="alertType" maxCount="1" deletionRule="No Action" destinationEntity="AlertType" inverseName="alertEntries" inverseEntity="AlertType"/>
|
||||
</entity>
|
||||
<entity name="AlertType" representedClassName=".AlertType" syncable="YES">
|
||||
<attribute name="enabled" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="name" attributeType="String"/>
|
||||
<attribute name="overridemute" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="snooze" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="snoozeperiod" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="soundname" optional="YES" attributeType="String"/>
|
||||
<attribute name="vibrate" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="alertEntries" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="AlertEntry" inverseName="alertType" inverseEntity="AlertEntry"/>
|
||||
</entity>
|
||||
<entity name="BgReading" representedClassName=".BgReading" syncable="YES">
|
||||
<attribute name="a" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="ageAdjustedRawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="b" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="c" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="calculatedValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="calculatedValueSlope" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="calibrationFlag" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceName" optional="YES" attributeType="String"/>
|
||||
<attribute name="filteredCalculatedValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="filteredData" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="hideSlope" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="String"/>
|
||||
<attribute name="ra" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="rawData" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="rb" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="rc" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="timeStamp" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="calibration" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Calibration" inverseName="bgreadings" inverseEntity="Calibration"/>
|
||||
<relationship name="sensor" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Sensor" inverseName="readings" inverseEntity="Sensor"/>
|
||||
</entity>
|
||||
<entity name="Calibration" representedClassName=".Calibration" syncable="YES">
|
||||
<attribute name="adjustedRawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="bg" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceName" optional="YES" attributeType="String"/>
|
||||
<attribute name="distanceFromEstimate" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="estimateRawAtTimeOfCalibration" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="String"/>
|
||||
<attribute name="intercept" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="possibleBad" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="rawTimeStamp" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="rawValue" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="sensorConfidence" attributeType="Double" usesScalarValueType="YES"/>
|
||||
<attribute name="slope" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="slopeConfidence" attributeType="Double" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="timeStamp" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="bgreadings" toMany="YES" deletionRule="Deny" destinationEntity="BgReading" inverseName="calibration" inverseEntity="BgReading"/>
|
||||
<relationship name="sensor" maxCount="1" deletionRule="Nullify" destinationEntity="Sensor" inverseName="calibrations" inverseEntity="Sensor"/>
|
||||
</entity>
|
||||
<entity name="M5Stack" representedClassName=".M5Stack" syncable="YES">
|
||||
<attribute name="address" attributeType="String"/>
|
||||
<attribute name="alias" optional="YES" attributeType="String"/>
|
||||
<attribute name="backGroundColor" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="blepassword" optional="YES" attributeType="String"/>
|
||||
<attribute name="brightness" optional="YES" attributeType="Integer 16" defaultValueString="100" usesScalarValueType="YES"/>
|
||||
<attribute name="name" attributeType="String"/>
|
||||
<attribute name="rotation" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="shouldconnect" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="textcolor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
</entity>
|
||||
<entity name="Sensor" representedClassName=".Sensor" syncable="YES">
|
||||
<attribute name="endDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="id" attributeType="String"/>
|
||||
<attribute name="startDate" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="calibrations" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Calibration" inverseName="sensor" inverseEntity="Calibration"/>
|
||||
<relationship name="readings" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="BgReading" inverseName="sensor" inverseEntity="BgReading"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="AlertEntry" positionX="-648" positionY="189" width="128" height="105"/>
|
||||
<element name="AlertType" positionX="-657" positionY="180" width="128" height="165"/>
|
||||
<element name="BgReading" positionX="-285.87109375" positionY="31.9921875" width="128" height="330"/>
|
||||
<element name="Calibration" positionX="-859.21484375" positionY="46.21484375" width="128" height="285"/>
|
||||
<element name="M5Stack" positionX="-657" positionY="180" width="128" height="178"/>
|
||||
<element name="Sensor" positionX="-603.0859375" positionY="482.2890625" width="128" height="120"/>
|
||||
</elements>
|
||||
</model>
|
|
@ -0,0 +1,775 @@
|
|||
import Foundation
|
||||
import os
|
||||
import CoreBluetooth
|
||||
import CoreData
|
||||
|
||||
class BluetoothPeripheralManager: NSObject {
|
||||
|
||||
// MARK: - private properties
|
||||
|
||||
/// CoreDataManager to use
|
||||
private 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?] = []
|
||||
|
||||
/// to access m5Stack entity in coredata
|
||||
private var m5StackAccessor: M5StackAccessor
|
||||
|
||||
/// reference to BgReadingsAccessor
|
||||
private var bgReadingsAccessor: BgReadingsAccessor
|
||||
|
||||
/// 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()
|
||||
|
||||
// MARK: - initializer
|
||||
|
||||
init(coreDataManager: CoreDataManager) {
|
||||
|
||||
// initialize properties
|
||||
self.coreDataManager = coreDataManager
|
||||
self.m5StackAccessor = M5StackAccessor(coreDataManager: coreDataManager)
|
||||
self.bgReadingsAccessor = BgReadingsAccessor(coreDataManager: coreDataManager)
|
||||
|
||||
super.init()
|
||||
|
||||
// initialize m5Stacks
|
||||
let m5Stacks = m5StackAccessor.getM5Stacks()
|
||||
for m5Stack in m5Stacks {
|
||||
|
||||
// add it to the list of bluetoothPeripherals
|
||||
bluetoothPeripherals.append(m5Stack)
|
||||
|
||||
if m5Stack.shouldconnect {
|
||||
|
||||
// create an instance of M5StackBluetoothTransmitter, M5StackBluetoothTransmitter will automatically try to connect to the M5Stack with the address that is stored in m5Stack
|
||||
// add it to the array of bluetoothTransmitters
|
||||
|
||||
bluetoothTransmitters.append(M5StackBluetoothTransmitter(address: m5Stack.address, name: m5Stack.name, delegate: self, blePassword: m5Stack.blepassword))
|
||||
|
||||
} else {
|
||||
|
||||
// shouldn't connect, so don't create an instance of M5StackBluetoothTransmitter
|
||||
// but append a nil element
|
||||
bluetoothTransmitters.append(nil)
|
||||
|
||||
}
|
||||
|
||||
// each time the app launches, we will send the parameters to all BluetoothPeripherals
|
||||
m5Stack.parameterUpdateNeededAtNextConnect()
|
||||
|
||||
}
|
||||
|
||||
// when user changes M5Stack related settings, then the transmitter need to get that info
|
||||
addObservers()
|
||||
|
||||
}
|
||||
|
||||
// MARK: - public functions
|
||||
|
||||
/// will send latest reading to all BluetoothTransmitters that need this info and only if it's less than 5 minutes old
|
||||
/// - parameters:
|
||||
/// - to :if nil then latest reading will be sent to all connected BluetoothTransmitters that need this info, otherwise only to the specified BluetoothTransmitter
|
||||
///
|
||||
/// this function has knowledge about different types of BluetoothTransmitter and knows to which it should send to reading, to which not
|
||||
public func sendLatestReading(to bluetoothPeripheral: BluetoothPeripheral? = nil) {
|
||||
|
||||
// get reading of latest 5 minutes
|
||||
let bgReadingToSend = bgReadingsAccessor.getLatestBgReadings(limit: 1, fromDate: Date(timeIntervalSinceNow: -5 * 60), forSensor: nil, ignoreRawData: true, ignoreCalculatedValue: false)
|
||||
|
||||
// check that there's at least 1 reading available
|
||||
guard bgReadingToSend.count >= 1 else {
|
||||
trace("in sendLatestReading, there's no recent reading to send", log: self.log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
if let bluetoothPeripheral = bluetoothPeripheral {
|
||||
|
||||
guard let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral), let bluetoothTransmitter = bluetoothTransmitters[index] else {return}
|
||||
|
||||
// get type of bluetoothPeripheral
|
||||
let bluetoothPeripheralType = bluetoothPeripheral.bluetoothPeripheralType()
|
||||
|
||||
// using bluetoothPeripheralType here so that whenever bluetoothPeripheralType is extended with new cases, we don't forget to handle them
|
||||
switch bluetoothPeripheralType {
|
||||
|
||||
case .M5Stack:
|
||||
|
||||
if let m5StackBluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter {
|
||||
_ = m5StackBluetoothTransmitter.writeBgReadingInfo(bgReading: bgReadingToSend[0])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// send the reading to all bluetoothPeripherals that want to receive a reading
|
||||
// to make sure new types are not forgotten, I use switch
|
||||
|
||||
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
|
||||
|
||||
switch bluetoothPeripheralType {
|
||||
|
||||
case .M5Stack:
|
||||
|
||||
for bluetoothPeripheral in bluetoothPeripherals {
|
||||
|
||||
// get the bluetooth transmitter, and if it's an M5StackBluetoothTransmitter, then send the bgReading
|
||||
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter {
|
||||
|
||||
_ = m5StackBluetoothTransmitter.writeBgReadingInfo(bgReading: bgReadingToSend[0])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - private functions
|
||||
|
||||
/// when user changes M5Stack related settings, then the transmitter need to get that info, add observers
|
||||
private func addObservers() {
|
||||
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName1.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName2.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName3.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword1.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword2.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword3.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackBlePassword.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.bloodGlucoseUnitIsMgDl.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutUrl.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutAPIKey.rawValue, options: .new, context: nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// disconnect from bluetoothPeripheral - and don't reconnect - set shouldconnect to false
|
||||
private func disconnect(fromBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
// device should not reconnect after disconnecting
|
||||
bluetoothPeripheral.dontTryToConnectToThisBluetoothPeripheral()
|
||||
|
||||
// save in coredata
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false) {
|
||||
|
||||
bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func firstIndexInBluetoothPeripherals(bluetoothPeripheral: BluetoothPeripheral) -> Int? {
|
||||
return bluetoothPeripherals.firstIndex(where: {$0.getAddress() == bluetoothPeripheral.getAddress()})
|
||||
}
|
||||
|
||||
private func createNewTransmitter(type: BluetoothPeripheralType) -> BluetoothTransmitter {
|
||||
|
||||
switch type {
|
||||
|
||||
case .M5Stack:
|
||||
|
||||
return M5StackBluetoothTransmitter(address: nil, name: nil, delegate: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 .M5Stack:
|
||||
|
||||
if bluetoothTransmitter is M5StackBluetoothTransmitter {
|
||||
return .M5Stack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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?) {
|
||||
|
||||
guard let keyPath = keyPath else {return}
|
||||
|
||||
guard let keyPathEnum = UserDefaults.Key(rawValue: keyPath) else {return}
|
||||
|
||||
// first check keyValueObserverTimeKeeper
|
||||
switch keyPathEnum {
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName1, UserDefaults.Key.m5StackWiFiName2, UserDefaults.Key.m5StackWiFiName3, UserDefaults.Key.m5StackWiFiPassword1, UserDefaults.Key.m5StackWiFiPassword2, UserDefaults.Key.m5StackWiFiPassword3, UserDefaults.Key.nightScoutAPIKey, UserDefaults.Key.nightScoutUrl, UserDefaults.Key.bloodGlucoseUnitIsMgDl :
|
||||
|
||||
// transmittertype change triggered by user, should not be done within 200 ms
|
||||
if !keyValueObserverTimeKeeper.verifyKey(forKey: keyPathEnum.rawValue, withMinimumDelayMilliSeconds: 200) {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// loop through all bluetoothPeripheralTypes. Do a check on bluetoothPeripheralType, depending on type, loop through all bluetoothPeripherals, and if correct type, write the value to the peripheral
|
||||
// this usage of bluetoothPeripheralType is done to make sure this code is not forgotten when adding a bluetoothPeripheralType
|
||||
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
|
||||
|
||||
switch bluetoothPeripheralType {
|
||||
|
||||
case .M5Stack:
|
||||
|
||||
for bluetoothPeripheral in bluetoothPeripherals {
|
||||
|
||||
// get the bluetooth transmitter, and if it's an M5StackBluetoothTransmitter, then send the bgReading
|
||||
if let bluetoothTransmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = bluetoothTransmitter as? M5StackBluetoothTransmitter {
|
||||
|
||||
// check that bluetoothPeripheral is of type M5Stack, if not then this might be a coding error
|
||||
guard let m5Stack = bluetoothPeripheral as? M5Stack else {
|
||||
trace("in observeValue, transmitter is of type M5StackBluetoothTransmitter but peripheral is not M5Stack", log: self.log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// is value successfully written or not
|
||||
var success = false
|
||||
|
||||
switch keyPathEnum {
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName1:
|
||||
success = m5StackBluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName1, number: 1)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName2:
|
||||
success = m5StackBluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName2, number: 2)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName3:
|
||||
success = m5StackBluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName3, number: 3)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword1:
|
||||
success = m5StackBluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword1, number: 1)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword2:
|
||||
success = m5StackBluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword2, number: 2)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword3:
|
||||
success = m5StackBluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword3, number: 3)
|
||||
|
||||
case UserDefaults.Key.m5StackBlePassword:
|
||||
// only if the password in the settings is not nil, and if the m5Stack doesn't have a password yet, then we will store it in the M5Stack.
|
||||
if let blePassword = UserDefaults.standard.m5StackBlePassword, m5Stack.blepassword == nil {
|
||||
m5Stack.blepassword = blePassword
|
||||
}
|
||||
|
||||
case UserDefaults.Key.bloodGlucoseUnitIsMgDl:
|
||||
success = m5StackBluetoothTransmitter.writeBloodGlucoseUnit(isMgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl)
|
||||
|
||||
case UserDefaults.Key.nightScoutAPIKey:
|
||||
success = m5StackBluetoothTransmitter.writeNightScoutAPIKey(apiKey: UserDefaults.standard.nightScoutAPIKey)
|
||||
|
||||
case UserDefaults.Key.nightScoutUrl:
|
||||
success = m5StackBluetoothTransmitter.writeNightScoutUrl(url: UserDefaults.standard.nightScoutUrl)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// if not successful then set needs parameter update to true for the m5Stack
|
||||
if !success {
|
||||
bluetoothPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// seems to be an M5Stack which is currently disconnected - need to set parameterUpdateNeeded = true, so that all parameters will be sent as soon as reconnect occurs
|
||||
bluetoothPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extensions
|
||||
|
||||
// MARK: extension BluetoothPeripheralManaging
|
||||
|
||||
extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
|
||||
|
||||
/// to scan for a new BluetoothPeripheral - callback will be called when a new BluetoothPeripheral is found and connected
|
||||
func startScanningForNewDevice(type: BluetoothPeripheralType, callback: @escaping (BluetoothPeripheral) -> Void) {
|
||||
|
||||
callBackAfterDiscoveringDevice = callback
|
||||
|
||||
tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = createNewTransmitter(type: type)
|
||||
|
||||
_ = tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral?.startScanning()
|
||||
|
||||
}
|
||||
|
||||
/// stops scanning for new device
|
||||
func stopScanningForNewDevice() {
|
||||
|
||||
if let tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral {
|
||||
|
||||
tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral.stopScanning()
|
||||
|
||||
self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func isScanning() -> Bool {
|
||||
|
||||
if let tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral {
|
||||
|
||||
return tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral.isScanning()
|
||||
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// try to connect to the M5Stack
|
||||
func connect(to bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
// the trick : by calling bluetoothTransmitter(forBluetoothPeripheral: bluetoothPeripheral, createANewOneIfNecesssary: true), there's two cases
|
||||
// - either the bluetoothTransmitter already exists but not connected, it will be found in the call to bluetoothTransmitter and returned, then we connect to it
|
||||
// - either the bluetoothTransmitter doesn't exist yet. It will be created. We assum here that bluetoothPeripheral has a mac address, as a consequence the BluetoothTransmitter will automatically try to connect. Here we try to connect again, but that's no issue
|
||||
|
||||
let transmitter = getBluetoothTransmitter(for: bluetoothPeripheral, createANewOneIfNecesssary: true)
|
||||
|
||||
transmitter?.connect()
|
||||
|
||||
}
|
||||
|
||||
/// returns the BluetoothPeripheral for the specified BluetoothTransmitter
|
||||
/// - parameters:
|
||||
/// - for : the bluetoothTransmitter, for which BluetoothPeripheral should be returned
|
||||
func getBluetoothPeripheral(for bluetoothTransmitter: BluetoothTransmitter) -> BluetoothPeripheral {
|
||||
|
||||
guard let index = bluetoothTransmitters.firstIndex(of: bluetoothTransmitter) else {
|
||||
fatalError("in BluetoothPeripheralManager, function getBluetoothPeripherals, could not find specified bluetoothTransmitter")
|
||||
}
|
||||
|
||||
return bluetoothPeripherals[index]
|
||||
|
||||
}
|
||||
|
||||
/// 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 .M5Stack:
|
||||
|
||||
if let m5Stack = bluetoothPeripheral as? M5Stack {
|
||||
newTransmitter = M5StackBluetoothTransmitter(address: m5Stack.address, name: m5Stack.name, delegate: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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: self.log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
// set bluetoothTransmitter to nil, this will also initiate a disconnect
|
||||
bluetoothTransmitters[index] = nil
|
||||
|
||||
// delete in coredataManager
|
||||
coreDataManager.mainManagedObjectContext.delete(bluetoothPeripherals[index] as! NSManagedObject)
|
||||
|
||||
// remove bluetoothTransmitter and bluetoothPeripheral entry from the two arrays
|
||||
bluetoothTransmitters.remove(at: index)
|
||||
bluetoothPeripherals.remove(at: index)
|
||||
|
||||
// save in coredataManager
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
}
|
||||
|
||||
/// - returns: the bluetoothPeripheral's managed by this BluetoothPeripheralManager
|
||||
func getBluetoothPeripherals() -> [BluetoothPeripheral] {
|
||||
|
||||
return bluetoothPeripherals
|
||||
|
||||
}
|
||||
|
||||
/// - returns: the bluetoothTransmitters managed by this BluetoothPeripheralManager
|
||||
func getBluetoothTransmitters() -> [BluetoothTransmitter] {
|
||||
|
||||
var bluetoothTransmitters: [BluetoothTransmitter] = []
|
||||
|
||||
for bluetoothTransmitter in self.bluetoothTransmitters {
|
||||
if let bluetoothTransmitter = bluetoothTransmitter {
|
||||
bluetoothTransmitters.append(bluetoothTransmitter)
|
||||
}
|
||||
}
|
||||
|
||||
return bluetoothTransmitters
|
||||
|
||||
}
|
||||
|
||||
/// bluetoothtransmitter for this bluetoothPeripheral will be deleted, as a result this will also disconnect the bluetoothPeripheral
|
||||
func setBluetoothTransmitterToNil(forBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
if let index = firstIndexInBluetoothPeripherals(bluetoothPeripheral: bluetoothPeripheral) {
|
||||
|
||||
bluetoothTransmitters[index] = nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: extension M5StackBluetoothDelegate
|
||||
|
||||
extension BluetoothPeripheralManager: BluetoothTransmitterDelegate {
|
||||
|
||||
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
|
||||
|
||||
// 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: self.log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
// check that address and name are not nil, otherwise this looks like a codding 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: self.log, 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: self.log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
// check that it's a peripheral for which we don't know yet the address
|
||||
for buetoothPeripheral in bluetoothPeripherals {
|
||||
if buetoothPeripheral.getAddress() == deviceAddressNewTransmitter {
|
||||
|
||||
trace("in didConnect, transmitter address already known. This is not a new device, will disconnect", log: self.log, 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))
|
||||
|
||||
_ = self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral?.startScanning()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// it's a new peripheral that we will store. No need to continue scanning
|
||||
bluetoothTransmitter.stopScanning()
|
||||
|
||||
// initialize new bluetoothPeripheral
|
||||
var newBluetoothPeripheral: BluetoothPeripheral?
|
||||
|
||||
for bluetoothPeripheralType in BluetoothPeripheralType.allCases {
|
||||
|
||||
switch bluetoothPeripheralType {
|
||||
|
||||
case .M5Stack:
|
||||
|
||||
// create a new BluetoothPeripheral of type M5Stack
|
||||
let newM5Stack = M5Stack(address: deviceAddressNewTransmitter, name: deviceNameNewTransmitter, textColor: UserDefaults.standard.m5StackTextColor ?? ConstantsM5Stack.defaultTextColor, backGroundColor: ConstantsM5Stack.defaultBackGroundColor, rotation: ConstantsM5Stack.defaultRotation, brightness: 100, alias: nil, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
|
||||
|
||||
// assign password stored in UserDefaults (might be nil)
|
||||
newM5Stack.blepassword = UserDefaults.standard.m5StackBlePassword
|
||||
|
||||
// add to list of bluetoothPeripherals and bluetoothTransmitters
|
||||
bluetoothPeripherals.append(newM5Stack)
|
||||
bluetoothTransmitters.append(bluetoothTransmitter)
|
||||
|
||||
// no need to keep a reference to the bluetothTransmitter, this is now stored in m5StacksBlueToothTransmitters
|
||||
self.tempBlueToothTransmitterWhileScanningForNewBluetoothPeripheral = nil
|
||||
|
||||
// assign newM5stack to newBluetoothPeripheral
|
||||
newBluetoothPeripheral = newM5Stack
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// call the callback function
|
||||
if let callBackAfterDiscoveringDevice = callBackAfterDiscoveringDevice, let newBluetoothPeripheral = newBluetoothPeripheral {
|
||||
callBackAfterDiscoveringDevice(newBluetoothPeripheral)
|
||||
self.callBackAfterDiscoveringDevice = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
|
||||
trace("in deviceDidUpdateBluetoothState, no further action", log: self.log, type: .info)
|
||||
|
||||
}
|
||||
|
||||
func error(message: String) {
|
||||
trace("in error, no further action", log: self.log, 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: self.log, type: .info)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: conform to M5StackBluetoothTransmitterDelegate
|
||||
|
||||
extension BluetoothPeripheralManager: M5StackBluetoothTransmitterDelegate {
|
||||
|
||||
/// 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: self.log, 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.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: self.log, 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.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: self.log, 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}
|
||||
|
||||
// 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: self.log, 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}
|
||||
|
||||
m5Stack.dontTryToConnectToThisBluetoothPeripheral()
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
// disconnect
|
||||
disconnect(fromBluetoothPeripheral: m5Stack)
|
||||
|
||||
}
|
||||
|
||||
/// bluetoothPeripheral 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: self.log, 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)?.parameterUpdateNotNeededAtNextConnect()
|
||||
} 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)?.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// 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.isParameterUpdateNeededAtNextConnect() {
|
||||
|
||||
// send all parameters
|
||||
if sendAllParametersToM5Stack(to: m5StackBluetoothTransmitter) {
|
||||
m5Stack.parameterUpdateNotNeededAtNextConnect()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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: self.log, 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 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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,33 +1,41 @@
|
|||
import Foundation
|
||||
|
||||
/// used by M5Stack UI view controllers - it's the glue between BluetoothPeripheralManager and UIViewControllers - defines functions to scan for devices, connect/disconnect, delete an M5 stack, change the username, etc.
|
||||
/// used by BluetoothPeripheral UI view controllers - it's the glue between BluetoothPeripheralManager and UIViewControllers - defines functions to scan for devices, connect/disconnect, delete a BluetoothPeripheral, change the username, etc.
|
||||
protocol BluetoothPeripheralManaging: AnyObject {
|
||||
|
||||
/// to scan for a new M5SStack - callback will be called when a new M5Stack is found and connected
|
||||
func startScanningForNewDevice(callback: @escaping (M5Stack) -> Void)
|
||||
/// to scan for a new BluetoothPeripheral - callback will be called when a new BluetoothPeripheral is found and connected
|
||||
func startScanningForNewDevice(type: BluetoothPeripheralType, callback: @escaping (BluetoothPeripheral) -> Void)
|
||||
|
||||
/// will stop scanning, this is again for the case where scanning for a new M5Stack has started
|
||||
/// will stop scanning, this is again for the case where scanning for a new BluetoothPeripheral has started
|
||||
func stopScanningForNewDevice()
|
||||
|
||||
/// try to connect to the M5Stack
|
||||
func connect(toM5Stack m5Stack: M5Stack)
|
||||
/// to know if bluetoothperipheralmanager is currently scanning for a new device
|
||||
func isScanning() -> Bool
|
||||
|
||||
/// returns the M5StackBluetoothTransmitter for the m5stack
|
||||
/// try to connect to the BluetoothPeripheral
|
||||
func connect(to bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
/// returns the BluetoothTransmitter for the specified bluetoothPeripheral
|
||||
/// - parameters:
|
||||
/// - forM5Stack : the m5Stack for which bluetoothTransmitter should be returned
|
||||
/// - createANewOneIfNecesssary : if bluetoothTransmitter is nil, then should one be created ?
|
||||
func m5StackBluetoothTransmitter(forM5stack m5Stack: M5Stack, createANewOneIfNecesssary: Bool) -> M5StackBluetoothTransmitter?
|
||||
/// - for : the bluetoothPeripheral, for which bluetoothTransmitter should be returned
|
||||
/// - createANewOneIfNecesssary : if there's no instance yet, then should one be created ?
|
||||
func getBluetoothTransmitter(for bluetoothPeripheral: BluetoothPeripheral, createANewOneIfNecesssary: Bool) -> BluetoothTransmitter?
|
||||
|
||||
/// deletes the M5Stack in coredata, and also the corresponding M5StackBluetoothTransmitter if there is one will be deleted
|
||||
func deleteM5Stack(m5Stack: M5Stack)
|
||||
/// returns the BluetoothPeripheral for the specified BluetoothTransmitter
|
||||
/// - parameters:
|
||||
/// - for : the bluetoothTransmitter, for which BluetoothPeripheral should be returned
|
||||
func getBluetoothPeripheral(for bluetoothTransmitter: BluetoothTransmitter) -> BluetoothPeripheral
|
||||
|
||||
/// - returns: the M5Stack's managed by this BluetoothPeripheralManager
|
||||
func m5Stacks() -> [M5Stack]
|
||||
/// deletes the BluetoothPeripheral in coredata, and also the corresponding BluetoothTransmitter if there is one will be deleted
|
||||
func deleteBluetoothPeripheral(bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
/// sets flag m5StacksParameterUpdateNeeded for m5Stack to true
|
||||
func updateNeeded(forM5Stack m5Stack: M5Stack)
|
||||
/// - returns: the BluetoothPeripheral's managed by this BluetoothPeripheralManager
|
||||
func getBluetoothPeripherals() -> [BluetoothPeripheral]
|
||||
|
||||
/// bluetoothtransmitter for this m5Stack will be deleted, as a result this will also disconnect the M5Stack
|
||||
func setBluetoothTransmitterToNil(forM5Stack m5Stack: M5Stack)
|
||||
/// - returns: the BluetoothTransmittersl's managed by this BluetoothPeripheralManager
|
||||
func getBluetoothTransmitters() -> [BluetoothTransmitter]
|
||||
|
||||
/// bluetoothtransmitter for this bluetoothperiheral will be deleted, as a result this will also disconnect the bluetoothtransmitter
|
||||
func setBluetoothTransmitterToNil(forBluetoothPeripheral bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
}
|
||||
|
|
|
@ -1,555 +0,0 @@
|
|||
import Foundation
|
||||
import os
|
||||
import CoreBluetooth
|
||||
|
||||
class BluetoothPeripheralManager: NSObject {
|
||||
|
||||
// MARK: - private properties
|
||||
|
||||
/// CoreDataManager to use
|
||||
private let coreDataManager:CoreDataManager
|
||||
|
||||
/// for logging
|
||||
private var log = OSLog(subsystem: ConstantsLog.subSystem, category: ConstantsLog.categoryBluetoothPeripheralManager)
|
||||
|
||||
/// dictionary with key = an instance of M5Stack, and value an instance of M5StackBluetoothTransmitter. Value can be nil in which case we found an M5Stack in the coredata but shouldconnect == false so we don't instanstiate an M5StackBluetoothTransmitter
|
||||
private var m5StacksBlueToothTransmitters = [M5Stack : M5StackBluetoothTransmitter?]()
|
||||
|
||||
/// to access m5Stack entity in coredata
|
||||
private var m5StackAccessor: M5StackAccessor
|
||||
|
||||
/// reference to BgReadingsAccessor
|
||||
private var bgReadingsAccessor: BgReadingsAccessor
|
||||
|
||||
/// 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: ((M5Stack) -> 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 tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack: M5StackBluetoothTransmitter?
|
||||
|
||||
/// to solve problem that sometemes UserDefaults key value changes is triggered twice for just one change
|
||||
private let keyValueObserverTimeKeeper:KeyValueObserverTimeKeeper = KeyValueObserverTimeKeeper()
|
||||
|
||||
// MARK: - initializer
|
||||
|
||||
init(coreDataManager: CoreDataManager) {
|
||||
|
||||
// initialize properties
|
||||
self.coreDataManager = coreDataManager
|
||||
self.m5StackAccessor = M5StackAccessor(coreDataManager: coreDataManager)
|
||||
self.bgReadingsAccessor = BgReadingsAccessor(coreDataManager: coreDataManager)
|
||||
|
||||
super.init()
|
||||
|
||||
// initialize m5Stacks
|
||||
let m5Stacks = m5StackAccessor.getM5Stacks()
|
||||
for m5Stack in m5Stacks {
|
||||
if m5Stack.shouldconnect {
|
||||
// create an instance of M5StackBluetoothTransmitter, M5StackBluetoothTransmitter will automatically try to connect to the M5Stack with the address that is stored in m5Stack
|
||||
self.m5StacksBlueToothTransmitters[m5Stack] = M5StackBluetoothTransmitter(m5Stack: m5Stack, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
} else {
|
||||
// shouldn't connect, so don't create an instance of M5StackBluetoothTransmitter
|
||||
self.m5StacksBlueToothTransmitters[m5Stack] = (M5StackBluetoothTransmitter?).none
|
||||
}
|
||||
|
||||
// each time the app launches, we will send the parameter to all M5Stacks
|
||||
m5Stack.parameterUpdateNeeded = true
|
||||
|
||||
}
|
||||
|
||||
// when user changes M5Stack related settings, then the transmitter need to get that info
|
||||
addObservers()
|
||||
|
||||
}
|
||||
|
||||
// MARK: - public functions
|
||||
|
||||
/// will send latest reading to all M5Stacks, only if it's less than 5 minutes old
|
||||
/// - parameters:
|
||||
/// - forM5Stack : if nil then latest reading will be sent to all connected M5Stacks, otherwise only to the specified M5Stack
|
||||
public func sendLatestReading(forM5Stack m5Stack: M5Stack? = nil) {
|
||||
|
||||
// get reading of latest 5 minutes
|
||||
let bgReadingToSend = bgReadingsAccessor.getLatestBgReadings(limit: 1, fromDate: Date(timeIntervalSinceNow: -5 * 60), forSensor: nil, ignoreRawData: true, ignoreCalculatedValue: false)
|
||||
|
||||
// check that there's at least 1 reading available
|
||||
guard bgReadingToSend.count >= 1 else {
|
||||
trace("in sendLatestReading, there's no recent reading to send", log: self.log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
if let m5Stack = m5Stack {
|
||||
// send bgReading to the single m5Stack
|
||||
_ = m5StackBluetoothTransmitter(forM5stack: m5Stack, createANewOneIfNecesssary: false)?.writeBgReadingInfo(bgReading: bgReadingToSend[0])
|
||||
} else {
|
||||
// send the reading to all M5Stacks
|
||||
for m5StackBlueToothTransmitter in m5StacksBlueToothTransmitters.values {
|
||||
if let transmitter = m5StackBlueToothTransmitter {
|
||||
_ = transmitter.writeBgReadingInfo(bgReading: bgReadingToSend[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - private helper functions
|
||||
|
||||
/// when user changes M5Stack related settings, then the transmitter need to get that info, add observers
|
||||
private func addObservers() {
|
||||
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName1.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName2.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiName3.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword1.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword2.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackWiFiPassword3.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.m5StackBlePassword.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.bloodGlucoseUnitIsMgDl.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutUrl.rawValue, options: .new, context: nil)
|
||||
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.Key.nightScoutAPIKey.rawValue, options: .new, context: nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// send all parameters to m5StackBluetoothTransmitter
|
||||
/// - returns:
|
||||
/// successfully written all parameters or not
|
||||
private func sendAllParameters(toM5Stack m5Stack : M5Stack) -> Bool {
|
||||
|
||||
guard let m5StackBluetoothTransmitterValue = m5StacksBlueToothTransmitters[m5Stack], let m5StackBluetoothTransmitter = m5StackBluetoothTransmitterValue else {
|
||||
trace("in sendAllParameters, there's no m5StackBluetoothTransmitter for the specified m5Stack", log: self.log, type: .info)
|
||||
return false
|
||||
}
|
||||
|
||||
guard m5StackBluetoothTransmitter.isReadyToReceiveData else {
|
||||
trace("in sendAllParameters, bluetoothTransmitter is not ready to receive data", log: self.log, 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 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
|
||||
}
|
||||
|
||||
/// disconnect from M5Stack - and don't reconnect - set shouldconnect to false
|
||||
func disconnect(fromM5stack m5Stack: M5Stack) {
|
||||
|
||||
// device should not reconnect after disconnecting
|
||||
m5Stack.shouldconnect = false
|
||||
|
||||
// save in coredata
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
if let bluetoothTransmitter = m5StacksBlueToothTransmitters[m5Stack] {
|
||||
if let bluetoothTransmitter = bluetoothTransmitter {
|
||||
bluetoothTransmitter.disconnect(reconnectAfterDisconnect: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:- override observe function
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
|
||||
if let keyPath = keyPath {
|
||||
|
||||
if let keyPathEnum = UserDefaults.Key(rawValue: keyPath) {
|
||||
|
||||
// first check keyValueObserverTimeKeeper
|
||||
switch keyPathEnum {
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName1, UserDefaults.Key.m5StackWiFiName2, UserDefaults.Key.m5StackWiFiName3, UserDefaults.Key.m5StackWiFiPassword1, UserDefaults.Key.m5StackWiFiPassword2, UserDefaults.Key.m5StackWiFiPassword3, UserDefaults.Key.nightScoutAPIKey, UserDefaults.Key.nightScoutUrl, UserDefaults.Key.bloodGlucoseUnitIsMgDl :
|
||||
|
||||
// transmittertype change triggered by user, should not be done within 200 ms
|
||||
if !keyValueObserverTimeKeeper.verifyKey(forKey: keyPathEnum.rawValue, withMinimumDelayMilliSeconds: 200) {
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// assuming it's a setting to be sent to all m5Stacks, loop through all M5Stacks
|
||||
// only those settings that are to be handled by all M5Stacks need to be considered here
|
||||
// loop through all m5StacksBlueToothTransmitters
|
||||
for m5StackPair in m5StacksBlueToothTransmitters {
|
||||
if let bluetoothTransmitter = m5StackPair.value {
|
||||
|
||||
// is value successfully written or not
|
||||
var success = false
|
||||
|
||||
switch keyPathEnum {
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName1:
|
||||
success = bluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName1, number: 1)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName2:
|
||||
success = bluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName2, number: 2)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiName3:
|
||||
success = bluetoothTransmitter.writeWifiName(name: UserDefaults.standard.m5StackWiFiName3, number: 3)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword1:
|
||||
success = bluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword1, number: 1)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword2:
|
||||
success = bluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword2, number: 2)
|
||||
|
||||
case UserDefaults.Key.m5StackWiFiPassword3:
|
||||
success = bluetoothTransmitter.writeWifiPassword(password: UserDefaults.standard.m5StackWiFiPassword3, number: 3)
|
||||
|
||||
case UserDefaults.Key.m5StackBlePassword:
|
||||
// only if the password in the settings is not nil, and if the m5Stack doesn't have a password yet, then we will store it in the M5Stack.
|
||||
if let blePassword = UserDefaults.standard.m5StackBlePassword, m5StackPair.key.blepassword == nil {
|
||||
m5StackPair.key.blepassword = blePassword
|
||||
}
|
||||
|
||||
case UserDefaults.Key.bloodGlucoseUnitIsMgDl:
|
||||
success = bluetoothTransmitter.writeBloodGlucoseUnit(isMgDl: UserDefaults.standard.bloodGlucoseUnitIsMgDl)
|
||||
|
||||
case UserDefaults.Key.nightScoutAPIKey:
|
||||
success = bluetoothTransmitter.writeNightScoutAPIKey(apiKey: UserDefaults.standard.nightScoutAPIKey)
|
||||
|
||||
case UserDefaults.Key.nightScoutUrl:
|
||||
success = bluetoothTransmitter.writeNightScoutUrl(url: UserDefaults.standard.nightScoutUrl)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
// if not successful then set needs parameter update to true for the m5Stack
|
||||
if !success {
|
||||
m5StackPair.key.parameterUpdateNeeded = true
|
||||
}
|
||||
|
||||
} else {
|
||||
// seems to be an M5Stack which is currently disconnected - need to send parameterUpdateNeeded = true, so that all parameters will be sent as soon as reconnect occurs
|
||||
m5StackPair.key.parameterUpdateNeeded = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extensions
|
||||
|
||||
// MARK: extension BluetoothPeripheralManaging
|
||||
|
||||
extension BluetoothPeripheralManager: BluetoothPeripheralManaging {
|
||||
|
||||
/// to scan for a new M5SStack - callback will be called when a new M5Stack is found and connected
|
||||
func startScanningForNewDevice(callback: @escaping (M5Stack) -> Void) {
|
||||
|
||||
callBackAfterDiscoveringDevice = callback
|
||||
|
||||
tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack = M5StackBluetoothTransmitter(m5Stack: nil, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
|
||||
_ = tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack?.startScanning()
|
||||
|
||||
}
|
||||
|
||||
/// stops scanning for new device
|
||||
func stopScanningForNewDevice() {
|
||||
|
||||
if let tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack = tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack {
|
||||
|
||||
tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack.stopScanning()
|
||||
|
||||
self.tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack = nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// try to connect to the M5Stack
|
||||
func connect(toM5Stack m5Stack: M5Stack) {
|
||||
|
||||
if let bluetoothTransmitter = m5StacksBlueToothTransmitters[m5Stack] {
|
||||
|
||||
// because m5StacksBlueToothTransmitters is a dictionary whereby the value is optional, bluetoothTransmitter is now optional, so we have to check again if it's nil or not
|
||||
if let bluetoothTransmitter = bluetoothTransmitter {
|
||||
|
||||
// bluetoothtransmitter exists, but not connected, call the connect function
|
||||
_ = bluetoothTransmitter.connect()
|
||||
|
||||
} else {
|
||||
|
||||
// this can be the case where initially shouldconnect was set to false, and user sets it to true via uiviewcontroller, uiviewcontroller calls this function, connect should automatially be initiated
|
||||
let newBlueToothTransmitter = M5StackBluetoothTransmitter(m5Stack: m5Stack, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
|
||||
m5StacksBlueToothTransmitters[m5Stack] = newBlueToothTransmitter
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// I don't think this code will be used, because value m5Stack should always be in m5StacksBlueToothTransmitters, anyway let's add it
|
||||
let newBlueToothTransmitter = M5StackBluetoothTransmitter(m5Stack: m5Stack, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
|
||||
m5StacksBlueToothTransmitters[m5Stack] = newBlueToothTransmitter
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the M5StackBluetoothTransmitter for the m5stack
|
||||
/// - parameters:
|
||||
/// - forM5Stack : the m5Stack for which bluetoothTransmitter should be returned
|
||||
/// - createANewOneIfNecesssary : if bluetoothTransmitter is nil, then should one be created ?
|
||||
func m5StackBluetoothTransmitter(forM5stack m5Stack: M5Stack, createANewOneIfNecesssary: Bool) -> M5StackBluetoothTransmitter? {
|
||||
|
||||
if let bluetoothTransmitter = m5StacksBlueToothTransmitters[m5Stack] {
|
||||
if let bluetoothTransmitter = bluetoothTransmitter {
|
||||
return bluetoothTransmitter
|
||||
}
|
||||
}
|
||||
|
||||
if createANewOneIfNecesssary {
|
||||
let newTransmitter = M5StackBluetoothTransmitter(m5Stack: m5Stack, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
m5StacksBlueToothTransmitters[m5Stack] = newTransmitter
|
||||
return newTransmitter
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// deletes the M5Stack in coredata, and also the corresponding M5StackBluetoothTransmitter if there is one will be deleted
|
||||
func deleteM5Stack(m5Stack: M5Stack) {
|
||||
|
||||
// if in dictionary remove it
|
||||
if m5StacksBlueToothTransmitters.keys.contains(m5Stack) {
|
||||
m5StacksBlueToothTransmitters[m5Stack] = (M5StackBluetoothTransmitter?).none
|
||||
m5StacksBlueToothTransmitters.removeValue(forKey: m5Stack)
|
||||
}
|
||||
|
||||
// delete in coredataManager
|
||||
coreDataManager.mainManagedObjectContext.delete(m5Stack)
|
||||
|
||||
// save in coredataManager
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
}
|
||||
|
||||
/// - returns: the M5Stack's managed by this BluetoothPeripheralManager
|
||||
func m5Stacks() -> [M5Stack] {
|
||||
return Array(m5StacksBlueToothTransmitters.keys)
|
||||
}
|
||||
|
||||
/// sets flag parameterUpdateNeeded for m5Stack to true
|
||||
func updateNeeded(forM5Stack m5Stack: M5Stack) {
|
||||
m5Stack.parameterUpdateNeeded = true
|
||||
}
|
||||
|
||||
/// bluetoothtransmitter for this m5Stack will be deleted, as a result this will also disconnect the M5Stack
|
||||
func setBluetoothTransmitterToNil(forM5Stack m5Stack: M5Stack) {
|
||||
|
||||
self.m5StacksBlueToothTransmitters[m5Stack] = (M5StackBluetoothTransmitter?).none
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: extensions M5StackBluetoothDelegate
|
||||
|
||||
extension BluetoothPeripheralManager: M5StackBluetoothDelegate {
|
||||
|
||||
/// m5Stack is asking for an update of all parameters, send them
|
||||
func isAskingForAllParameters(m5Stack: M5Stack) {
|
||||
|
||||
// send all parameters, if successful,then for this m5Stack we can set parameterUpdateNeeded to false
|
||||
if sendAllParameters(toM5Stack: m5Stack) {
|
||||
m5Stack.parameterUpdateNeeded = false
|
||||
} else {
|
||||
// failed, so we need to set parameterUpdateNeeded to true, so that next time it connects we will send all parameters
|
||||
m5Stack.parameterUpdateNeeded = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// will be called if M5Stack is connected, and authentication was successful, BluetoothPeripheralManager can start sending data like parameter updates or bgreadings
|
||||
func isReadyToReceiveData(m5Stack : M5Stack) {
|
||||
|
||||
// if the M5Stack needs new parameters, then send them
|
||||
if m5Stack.parameterUpdateNeeded {
|
||||
|
||||
// send all parameters
|
||||
if sendAllParameters(toM5Stack: m5Stack) {
|
||||
m5Stack.parameterUpdateNeeded = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// send latest reading
|
||||
sendLatestReading(forM5Stack: m5Stack)
|
||||
|
||||
}
|
||||
|
||||
func didConnect(forM5Stack m5Stack: M5Stack?, address: String?, name: String?, bluetoothTransmitter : M5StackBluetoothTransmitter) {
|
||||
|
||||
guard tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack != nil else {
|
||||
trace("in didConnect, tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack is nil, no further processing", log: self.log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
// we're interested in new M5stack's which were scanned for, so that would mean m5Stack parameter would be nil, and if nil, then address should not yet be any of the known/stored M5Stack's
|
||||
if m5Stack == nil, let address = address, let name = name {
|
||||
|
||||
// go through all the known m5Stacks and see if the address matches to any of them
|
||||
for m5StackPair in m5StacksBlueToothTransmitters {
|
||||
if m5StackPair.key.address == address {
|
||||
|
||||
// it's an already known m5Stack, not storing this, on the contrary disconnecting because maybe it's an m5stack 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 M5StacksBlueToothTransmitter stored in tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack - but this one stopped scanning, so let's recreate an instance of M5StacksBlueToothTransmitter
|
||||
tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack = M5StackBluetoothTransmitter(m5Stack: nil, delegateFixed: self, blePassword: UserDefaults.standard.m5StackBlePassword)
|
||||
_ = tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack?.startScanning()
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// looks like we haven't found the address in list of known M5Stacks, so it's a new M5Stack, stop the scanning
|
||||
bluetoothTransmitter.stopScanning()
|
||||
|
||||
// create a new M5Stack with new peripheral's address and name
|
||||
let newM5Stack = M5Stack(address: address, name: name, textColor: UserDefaults.standard.m5StackTextColor ?? ConstantsM5Stack.defaultTextColor, backGroundColor: ConstantsM5Stack.defaultBackGroundColor, rotation: ConstantsM5Stack.defaultRotation, brightness: 100, nsManagedObjectContext: coreDataManager.mainManagedObjectContext)
|
||||
|
||||
// assign password stored in UserDefaults (might be nil)
|
||||
newM5Stack.blepassword = UserDefaults.standard.m5StackBlePassword
|
||||
|
||||
// add to list of m5StacksBlueToothTransmitters
|
||||
m5StacksBlueToothTransmitters[newM5Stack] = bluetoothTransmitter
|
||||
|
||||
// no need to keep a reference to the bluetothTransmitter, this is now stored in m5StacksBlueToothTransmitters
|
||||
tempM5StackBlueToothTransmitterWhileScanningForNewM5Stack = nil
|
||||
|
||||
// assign n
|
||||
bluetoothTransmitter.m5Stack = newM5Stack
|
||||
|
||||
// call the callback function
|
||||
if let callBackAfterDiscoveringDevice = callBackAfterDiscoveringDevice {
|
||||
callBackAfterDiscoveringDevice(newM5Stack)
|
||||
self.callBackAfterDiscoveringDevice = nil
|
||||
}
|
||||
|
||||
} else {
|
||||
// if m5Stack is not nil, then this is a connect of one of the known M5Stacks
|
||||
// nothing needed
|
||||
}
|
||||
}
|
||||
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, forM5Stack m5Stack: M5Stack) {
|
||||
trace("in deviceDidUpdateBluetoothState, no further action", log: self.log, type: .info)
|
||||
}
|
||||
|
||||
func error(message: String) {
|
||||
trace("in error, no further action", log: self.log, type: .info)
|
||||
}
|
||||
|
||||
/// if a new ble password is received from M5Stack
|
||||
func newBlePassWord(newBlePassword: String, forM5Stack m5Stack: M5Stack) {
|
||||
|
||||
trace("in newBlePassWord, storing the password in M5Stack", log: self.log, type: .info)
|
||||
// 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, tant pis
|
||||
m5Stack.blepassword = newBlePassword
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
}
|
||||
|
||||
/// did the app successfully authenticate towards M5Stack, if no, then disconnect will be done
|
||||
///
|
||||
func authentication(success: Bool, forM5Stack m5Stack:M5Stack) {
|
||||
trace("in authentication with success = %{public}@", log: self.log, 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 {
|
||||
|
||||
m5Stack.shouldconnect = false
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
// disconnect
|
||||
disconnect(fromM5stack: 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(forM5Stack m5Stack: M5Stack) {
|
||||
|
||||
trace("in blePasswordMissing", log: self.log, type: .info)
|
||||
|
||||
m5Stack.shouldconnect = false
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
// disconnect
|
||||
disconnect(fromM5stack: m5Stack)
|
||||
|
||||
}
|
||||
|
||||
/// 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(forM5Stack m5Stack:M5Stack) {
|
||||
|
||||
trace("in m5StackResetRequired", log: self.log, type: .info)
|
||||
|
||||
m5Stack.shouldconnect = false
|
||||
coreDataManager.saveChanges()
|
||||
|
||||
// disconnect
|
||||
disconnect(fromM5stack: m5Stack)
|
||||
|
||||
}
|
||||
|
||||
/// did disconnect from M5Stack
|
||||
func didDisconnect(forM5Stack m5Stack:M5Stack) {
|
||||
// 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 didDisconnect", log: self.log, type: .info)
|
||||
}
|
||||
|
||||
}
|
|
@ -353,10 +353,10 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="1599" y="566"/>
|
||||
</scene>
|
||||
<!--M5Stack Navigation Controller-->
|
||||
<!--Bluetooth Peripheral Navigation Controller-->
|
||||
<scene sceneID="H1e-vw-iaX">
|
||||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="FwD-2z-GTm" userLabel="M5Stack Navigation Controller" customClass="BluetoothPeripheralNavigationController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="FwD-2z-GTm" userLabel="Bluetooth Peripheral Navigation Controller" customClass="BluetoothPeripheralNavigationController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tabBarItem key="tabBarItem" title="" image="M5Stack" selectedImage="M5Stack" id="sgT-p5-hUt">
|
||||
<color key="badgeColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tabBarItem>
|
||||
|
@ -429,10 +429,10 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="2582" y="565"/>
|
||||
</scene>
|
||||
<!--M5 Stacks View Controller-->
|
||||
<!--Bluetooth Peripherals View Controller-->
|
||||
<scene sceneID="0Ef-2k-ynF">
|
||||
<objects>
|
||||
<viewController id="E45-Z1-hcE" userLabel="M5 Stacks View Controller" customClass="BluetoothPeripheralsViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="E45-Z1-hcE" userLabel="Bluetooth Peripherals View Controller" customClass="BluetoothPeripheralsViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="i06-al-mW1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -486,17 +486,17 @@
|
|||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="tableView" destination="dMM-nl-Zfn" id="Z76-9m-jPM"/>
|
||||
<segue destination="FJ0-eY-Fv0" kind="show" identifier="M5StacksToM5StackSegueIdentifier" id="BEa-Az-mem"/>
|
||||
<segue destination="FJ0-eY-Fv0" kind="show" identifier="BluetoothPeripheralsToBluetoothPeripheralSegueIdentifier" id="BEa-Az-mem"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ajO-AG-xfd" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2582" y="-134"/>
|
||||
</scene>
|
||||
<!--M5 Stack View Controller-->
|
||||
<!--Bluetooth Peripheral View Controller-->
|
||||
<scene sceneID="fw3-II-GI1">
|
||||
<objects>
|
||||
<viewController id="FJ0-eY-Fv0" userLabel="M5 Stack View Controller" customClass="BluetoothPeripheralViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<viewController id="FJ0-eY-Fv0" userLabel="Bluetooth Peripheral View Controller" customClass="BluetoothPeripheralViewController" customModule="xdrip" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="0Ho-lg-UtI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -586,7 +586,7 @@
|
|||
<outlet property="scanButtonOutlet" destination="L9f-Ab-Egz" id="z68-tK-4ql"/>
|
||||
<outlet property="tableView" destination="82M-Ti-NV0" id="RQy-kH-bnc"/>
|
||||
<outlet property="trashButtonOutlet" destination="N7o-Nz-l8g" id="Sz3-nt-e7r"/>
|
||||
<segue destination="qbA-EA-RMD" kind="unwind" identifier="M5StackToBluetoothPeripheralsUnWindSegueIdentifier" unwindAction="unwindToBluetoothPeripheralsViewControllerWithSegue:" id="yPp-xT-8cB"/>
|
||||
<segue destination="qbA-EA-RMD" kind="unwind" identifier="BluetoothPeripheralToBluetoothPeripheralsUnWindSegueIdentifier" unwindAction="unwindToBluetoothPeripheralsViewControllerWithSegue:" id="yPp-xT-8cB"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="kwG-Zz-t1q" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"selectAliasText" = "Choose an alias for this Bluetooth Peripheral, the name will be shown in the app and is easier for you to recognize";
|
||||
"aliasAlreadyExists" = "There is already a Bluetooth Peripheral with this alias";
|
||||
"confirmDeletionPeripheral" = "Do you want to delete Bluetooth Peripheral with ";
|
||||
"bluetoothPeripheralAlias" = "Alias";
|
|
@ -0,0 +1,2 @@
|
|||
"screenTitle" = "Bluetooth Devices";
|
||||
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1,6 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -1,14 +1 @@
|
|||
"screenTitle" = "M5Stack";
|
||||
"address" = "Address";
|
||||
"status" = "Status";
|
||||
"connected" = "connected";
|
||||
"notConnected" = "not connected";
|
||||
"alwaysconnect" = "Always Connect";
|
||||
"donotconnect" = "Don't connect";
|
||||
"authenticationFailureWarning" = "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ";
|
||||
"blePasswordMissingWarning" = "You need to set the password in the Settings";
|
||||
"m5StackResetRequiredWarning" = "M5Stack must be reset in order to generate a new temporary password. When done click ";
|
||||
"m5StackAlias" = "Alias";
|
||||
"selectAliasText" = "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize";
|
||||
"userdefinedNameAlreadyExists" = "There is already an M5Stack with this name";
|
||||
"confirmDeletionM5Stack" = "Do you want to delete M5Stack with ";
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
"screenTitle" = "M5Stack List";
|
||||
"m5StackSoftWareHelpCellText" = "Where to find M5Stack software ?";
|
||||
"m5StackSoftWareHelpText" = "Go to";
|
|
@ -0,0 +1,47 @@
|
|||
import Foundation
|
||||
|
||||
class Text_BluetoothPeripheralView {
|
||||
|
||||
static private let filename = "BluetoothPeripheralView"
|
||||
|
||||
static let address: String = {
|
||||
return NSLocalizedString("address", tableName: filename, bundle: Bundle.main, value: "Address", comment: "when M5Stack is shown, title of the cell with the address")
|
||||
}()
|
||||
|
||||
static let status: String = {
|
||||
return NSLocalizedString("status", tableName: filename, bundle: Bundle.main, value: "Status", comment: "when Bluetooth Peripheral is shown, title of the cell with the status")
|
||||
}()
|
||||
|
||||
static let connected: String = {
|
||||
return NSLocalizedString("connected", tableName: filename, bundle: Bundle.main, value: "connected", comment: "when Bluetooth Peripheral is shown, connection status, connected")
|
||||
}()
|
||||
|
||||
static let notConnected: String = {
|
||||
return NSLocalizedString("notConnected", tableName: filename, bundle: Bundle.main, value: "Not Connected", comment: "when Bluetooth Peripheral is shown, connection status, not connected")
|
||||
}()
|
||||
|
||||
static let alwaysConnect: String = {
|
||||
return NSLocalizedString("alwaysconnect", tableName: filename, bundle: Bundle.main, value: "Always Connect", comment: "text in button top right, by clicking, user says that device should always try to connect")
|
||||
}()
|
||||
|
||||
static let donotconnect: String = {
|
||||
return NSLocalizedString("donotconnect", tableName: filename, bundle: Bundle.main, value: "Don't connect", comment: "text in button top right, this button will disable automatic connect")
|
||||
}()
|
||||
|
||||
static let selectAliasText: String = {
|
||||
return NSLocalizedString("selectAliasText", tableName: filename, bundle: Bundle.main, value: "Choose an alias for this Bluetooth Peripheral, the name will be shown in the app and is easier for you to recognize", comment: "Bluetooth Peripheral view, when user clicks alias field")
|
||||
}()
|
||||
|
||||
static let aliasAlreadyExists: String = {
|
||||
return NSLocalizedString("aliasAlreadyExists", tableName: filename, bundle: Bundle.main, value: "There is already a Bluetooth Peripheral with this alias", comment: "Bluetooth Peripheral view, when user clicks alias field")
|
||||
}()
|
||||
|
||||
static let confirmDeletionBluetoothPeripheral: String = {
|
||||
return NSLocalizedString("confirmDeletionPeripheral", tableName: filename, bundle: Bundle.main, value: "Do you want to delete Bluetooth Peripheral with ", comment: "Bluetooth Peripheral view, when user clicks the trash button - this is not the complete sentence, it will be followed either by 'name' or 'alias', depending on the availability of an alias")
|
||||
}()
|
||||
|
||||
static let bluetoothPeripheralAlias: String = {
|
||||
return NSLocalizedString("bluetoothPeripheralAlias", tableName: filename, bundle: Bundle.main, value: "Alias", comment: "BluetoothPeripheral view, this is a name of a BluetoothPeripheral assigned by the user, to recognize the device")
|
||||
}()
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import Foundation
|
||||
|
||||
class Texts_BluetoothPeripheralsView {
|
||||
|
||||
static private let filename = "BluetoothPeripheralsView"
|
||||
|
||||
static let screenTitle: String = {
|
||||
return NSLocalizedString("screenTitle", tableName: filename, bundle: Bundle.main, value: "Bluetooth Devices", comment: "when Bluetooth Peripheral list is shown, title of the view")
|
||||
}()
|
||||
|
||||
}
|
|
@ -1,37 +1,14 @@
|
|||
import Foundation
|
||||
|
||||
|
||||
class Texts_M5StackView {
|
||||
|
||||
static private let filename = "M5StackView"
|
||||
|
||||
static let screenTitle: String = {
|
||||
return NSLocalizedString("screenTitle", tableName: filename, bundle: Bundle.main, value: "M5Stack", comment: "when specific M5 stack is shown, screen title")
|
||||
return NSLocalizedString("screenTitle", tableName: filename, bundle: Bundle.main, value: "M5Stack", comment: "when M5 stack list is shown, title of the view")
|
||||
}()
|
||||
|
||||
static let address: String = {
|
||||
return NSLocalizedString("address", tableName: filename, bundle: Bundle.main, value: "Address", comment: "when M5Stack is shown, title of the cell with the address")
|
||||
}()
|
||||
|
||||
static let status: String = {
|
||||
return NSLocalizedString("status", tableName: filename, bundle: Bundle.main, value: "Status", comment: "when M5Stack is shown, title of the cell with the status")
|
||||
}()
|
||||
|
||||
static let connected: String = {
|
||||
return NSLocalizedString("connected", tableName: filename, bundle: Bundle.main, value: "connected", comment: "when M5Stack is shown, connection status, connected")
|
||||
}()
|
||||
|
||||
static let notConnected: String = {
|
||||
return NSLocalizedString("notConnected", tableName: filename, bundle: Bundle.main, value: "Not Connected", comment: "when M5Stack is shown, connection status, not connected")
|
||||
}()
|
||||
|
||||
static let alwaysConnect: String = {
|
||||
return NSLocalizedString("alwaysconnect", tableName: filename, bundle: Bundle.main, value: "Always Connect", comment: "text in button top right, by clicking, user says that device should always try to connect")
|
||||
}()
|
||||
|
||||
static let donotconnect: String = {
|
||||
return NSLocalizedString("donotconnect", tableName: filename, bundle: Bundle.main, value: "Don't connect", comment: "text in button top right, this button will disable automatic connect")
|
||||
}()
|
||||
|
||||
|
||||
static let authenticationFailureWarning: String = {
|
||||
return NSLocalizedString("authenticationFailureWarning", tableName: filename, bundle: Bundle.main, value: "Authentication to M5Stack Failed, either set the pre-configured password in the Settings, or, if the M5Stack does not have a preconfigured password then reset the M5Stack. M5Stack will disconnect now. You can make a new attempt by clicking ", comment: "in case M5Stack authentication failed")
|
||||
}()
|
||||
|
@ -43,21 +20,14 @@ class Texts_M5StackView {
|
|||
static let m5StackResetRequiredWarning: String = {
|
||||
return NSLocalizedString("m5StackResetRequiredWarning", tableName: filename, bundle: Bundle.main, value: "You need to reset the M5Stack in order to get a new temporary password. When done click'", comment: "in case M5Stack authentication failed, and M5Stack is generating a random password")
|
||||
}()
|
||||
|
||||
static let m5StackSoftWareHelpCellText: String = {
|
||||
return NSLocalizedString("m5StackSoftWareHelpCellText", tableName: filename, bundle: Bundle.main, value: "Where to find M5Stack software ?", comment: "In list of M5Stacks, the last line allows to show info where to find M5Stack software, this is the text in the cell")
|
||||
}()
|
||||
|
||||
static let m5StackSoftWareHelpText: String = {
|
||||
return NSLocalizedString("m5StackSoftWareHelpText", tableName: filename, bundle: Bundle.main, value: "Go to", comment: "this is the text shown when clicking the cell 'where to find M5Stack software'")
|
||||
}()
|
||||
|
||||
static let m5StackAlias: String = {
|
||||
return NSLocalizedString("m5StackAlias", tableName: filename, bundle: Bundle.main, value: "Alias", comment: "M5Stack view, this is a name of an M5Stack assigned by the user, to recognize the device")
|
||||
}()
|
||||
|
||||
static let selectAliasText: String = {
|
||||
return NSLocalizedString("selectAliasText", tableName: filename, bundle: Bundle.main, value: "Choose a name for this M5Stack, the name will be shown in the app and is easier for you to recognize", comment: "M5Stack view, when user clicks userdefinedname (alias) field")
|
||||
}()
|
||||
|
||||
static let userdefinedNameAlreadyExists: String = {
|
||||
return NSLocalizedString("userdefinedNameAlreadyExists", tableName: filename, bundle: Bundle.main, value: "There is already an M5Stack with this name", comment: "M5Stack view, when user clicks userdefinedname (alias) field")
|
||||
}()
|
||||
|
||||
static let confirmDeletionM5Stack: String = {
|
||||
return NSLocalizedString("confirmDeletionM5Stack", tableName: filename, bundle: Bundle.main, value: "Do you want to delete M5Stack with ", comment: "M5Stack view, when user clicks the trash button - this is not the complete sentence, it will be followed either by 'name' or 'alias', depending on the availability of a userdefined name")
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
class Texts_M5StacksView {
|
||||
|
||||
static private let filename = "M5StacksView"
|
||||
|
||||
static let screenTitle: String = {
|
||||
return NSLocalizedString("screenTitle", tableName: filename, bundle: Bundle.main, value: "M5Stack List", comment: "when M5 stack list is shown, title of the view")
|
||||
}()
|
||||
|
||||
static let m5StackSoftWareHelpCellText: String = {
|
||||
return NSLocalizedString("m5StackSoftWareHelpCellText", tableName: filename, bundle: Bundle.main, value: "Where to find M5Stack software ?", comment: "In list of M5Stacks, the last line allows to show info where to find M5Stack software, this is the text in the cell")
|
||||
}()
|
||||
|
||||
static let m5StackSoftWareHelpText: String = {
|
||||
return NSLocalizedString("m5StackSoftWareHelpText", tableName: filename, bundle: Bundle.main, value: "Go to", comment: "this is the text shown when clicking the cell 'where to find M5Stack software'")
|
||||
}()
|
||||
|
||||
}
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
final class CGMG4xDripTransmitter: BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -43,37 +43,40 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDel
|
|||
//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())
|
||||
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)
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
}
|
||||
|
||||
// MARK: - functions
|
||||
// MARK: - MARK: CBCentralManager overriden functions
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
trace("in peripheralDidUpdateNotificationStateFor", log: log, type: .info)
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
//check if value is not nil
|
||||
guard let value = characteristic.value else {
|
||||
trace("in peripheral didUpdateValueFor, characteristic.value is nil", log: log, type: .info)
|
||||
|
@ -96,12 +99,12 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDel
|
|||
//only for logging
|
||||
let data = value.hexEncodedString()
|
||||
trace("in peripheral didUpdateValueFor, data = %{public}@", log: log, type: .debug, data)
|
||||
|
||||
|
||||
switch XdripResponseType(rawValue: value[1]) {
|
||||
case .dataPacket?:
|
||||
//process value and get result
|
||||
let result = processxBridgeDataPacket(value: value)
|
||||
|
||||
|
||||
// check transmitterid, if not correct write correct value and return
|
||||
if let data = checkTransmitterId(receivedTransmitterId: result.transmitterID, expectedTransmitterId: self.transmitterId, log: log) {
|
||||
trace(" in peripheralDidUpdateValueFor, sending transmitterid %{public}@ to xdrip ", log: log, type: .info, self.transmitterId)
|
||||
|
@ -128,7 +131,7 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDel
|
|||
trace(" in peripheral didUpdateValueFor, packet length is not 7, no further processing", log: log, type: .info)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//read txid
|
||||
let receivedTransmitterId = decodeTxID(TxID: value.uint32(position: 2))
|
||||
trace(" in peripheral didUpdateValueFor, received beaconPacket with txid %{public}@", log: log, type: .info, receivedTransmitterId)
|
||||
|
@ -154,6 +157,7 @@ final class CGMG4xDripTransmitter: BluetoothTransmitter, BluetoothTransmitterDel
|
|||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &glucoseDataArray, transmitterBatteryInfo: transmitterBatteryInfo, sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMG5Transmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -136,14 +136,11 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
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())
|
||||
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)
|
||||
|
||||
//assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
|
||||
// start scanning
|
||||
_ = startScanning()
|
||||
}
|
||||
|
@ -183,112 +180,25 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
|
||||
// MARK: CBCentralManager overriden functions
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
|
||||
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
|
||||
// will probably never come here because reconnect doesn't happen with scanning, hence diddiscover will never be called excep the very first time that an app tries to connect to a G5
|
||||
trace("diddiscover peripheral, but last reading was less than 1 minute ago, will ignore", log: log, type: .info)
|
||||
} else {
|
||||
super.centralManager(central, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)
|
||||
}
|
||||
}
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
// if last reading was less than a minute ago, then no need to continue, otherwise continue with process by calling super.centralManager(central, didConnect: peripheral)
|
||||
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
|
||||
trace("connected, but last reading was less than 1 minute ago", log: log, type: .info)
|
||||
// don't disconnect here, keep the connection open, the transmitter will disconnect in a few seconds, assumption is that this will increase battery life
|
||||
} else {
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
}
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
// to be sure waitingPairingConfirmation is reset to false
|
||||
waitingPairingConfirmation = false
|
||||
}
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
trace("didDiscoverCharacteristicsFor", log: log, type: .info)
|
||||
|
||||
// log error if any
|
||||
if let error = error {
|
||||
trace(" error: %{public}@", log: log, type: .error , error.localizedDescription)
|
||||
}
|
||||
|
||||
if let characteristics = service.characteristics {
|
||||
for characteristic in characteristics {
|
||||
|
||||
if let characteristicValue = CBUUID_Characteristic_UUID(rawValue: characteristic.uuid.uuidString) {
|
||||
|
||||
trace(" characteristic : %{public}@", log: log, type: .info, characteristicValue.description)
|
||||
|
||||
switch characteristicValue {
|
||||
case .CBUUID_Backfill:
|
||||
backfillCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Write_Control:
|
||||
writeControlCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Communication:
|
||||
communicationCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Receive_Authentication:
|
||||
receiveAuthenticationCharacteristic = characteristic
|
||||
trace(" calling setNotifyValue true", log: log, type: .info)
|
||||
peripheral.setNotifyValue(true, for: characteristic)
|
||||
|
||||
}
|
||||
} else {
|
||||
trace(" characteristic UUID unknown : %{public}@", log: log, type: .error, characteristic.uuid.uuidString)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace("characteristics is nil. There must be some error.", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
|
||||
/// this transmitter does not support oop web
|
||||
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {}
|
||||
|
||||
// MARK: BluetoothTransmitterDelegate functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
// if status changed to poweredon, and if address = nil then superclass will not start the scanning
|
||||
// but for DexcomG5 we can start scanning
|
||||
if state == .poweredOn {
|
||||
if (address() == nil) {
|
||||
_ = startScanning()
|
||||
if central.state == .poweredOn {
|
||||
if (getAddress() == nil) {
|
||||
_ = startScanning()
|
||||
}
|
||||
}
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
if waitingPairingConfirmation {
|
||||
// device has requested a pairing request and is now in a status of verifying if pairing was successfull or not, this by doing setNotify to writeCharacteristic. If a disconnect occurs now, it means pairing has failed (probably because user didn't approve it
|
||||
|
@ -300,9 +210,13 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
|
||||
// inform delegate
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
|
||||
|
||||
trace("in peripheralDidUpdateNotificationStateFor", log: log, type: .info)
|
||||
|
||||
if let error = error {
|
||||
|
@ -338,12 +252,15 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
} else {
|
||||
trace(" characteristicValue is nil", log: log, type: .error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
guard let characteristic_UUID = CBUUID_Characteristic_UUID(rawValue: characteristic.uuid.uuidString) else {
|
||||
trace("in peripheralDidUpdateValueFor, unknown characteristic received with uuid = %{public}@", log: log, type: .error, characteristic.uuid.uuidString)
|
||||
trace("in peripheralDidUpdateValueFor, unknown characteristic received with uuid = %{public}@", log: log, type: .error, characteristic.uuid.uuidString)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -380,14 +297,14 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
cgmTransmitterDelegate?.cgmTransmitterNeedsPairing()
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// subscribe to writeControlCharacteristic
|
||||
if let writeControlCharacteristic = writeControlCharacteristic {
|
||||
setNotifyValue(true, for: writeControlCharacteristic)
|
||||
} else {
|
||||
trace(" writeControlCharacteristic is nil, can not set notifyValue", log: log, type: .error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -445,8 +362,8 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
//if reset was done recently, less than 5 minutes ago, then ignore the reading
|
||||
if Date() < Date(timeInterval: 5 * 60, since: timeStampTransmitterReset) {
|
||||
trace(" last transmitter reset was less than 5 minutes ago, ignoring this reading", log: log, type: .info)
|
||||
//} else if sensorDataRxMessage.unfiltered == 0.0 {
|
||||
// trace(" sensorDataRxMessage.unfiltered = 0.0, ignoring this reading", log: log, type: .info)
|
||||
//} else if sensorDataRxMessage.unfiltered == 0.0 {
|
||||
// trace(" sensorDataRxMessage.unfiltered = 0.0, ignoring this reading", log: log, type: .info)
|
||||
} else {
|
||||
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
|
||||
// should probably never come here because this check is already done at connection time
|
||||
|
@ -508,8 +425,100 @@ class CGMG5Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTr
|
|||
trace(" characteristic.value is nil", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
|
||||
|
||||
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
|
||||
// will probably never come here because reconnect doesn't happen with scanning, hence diddiscover will never be called excep the very first time that an app tries to connect to a G5
|
||||
trace("diddiscover peripheral, but last reading was less than 1 minute ago, will ignore", log: log, type: .info)
|
||||
} else {
|
||||
super.centralManager(central, didDiscover: peripheral, advertisementData: advertisementData, rssi: RSSI)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
// not calling super.didconnect here
|
||||
|
||||
// if last reading was less than a minute ago, then no need to continue, otherwise continue with process by calling super.centralManager(central, didConnect: peripheral)
|
||||
if Date() < Date(timeInterval: 60, since: timeStampOfLastG5Reading) {
|
||||
trace("connected, but last reading was less than 1 minute ago", log: log, type: .info)
|
||||
// don't disconnect here, keep the connection open, the transmitter will disconnect in a few seconds, assumption is that this will increase battery life
|
||||
} else {
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
}
|
||||
|
||||
// to be sure waitingPairingConfirmation is reset to false
|
||||
waitingPairingConfirmation = false
|
||||
|
||||
}
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
|
||||
// not using super.didDiscoverCharacteristicsFor here
|
||||
|
||||
trace("didDiscoverCharacteristicsFor", log: log, type: .info)
|
||||
|
||||
// log error if any
|
||||
if let error = error {
|
||||
trace(" error: %{public}@", log: log, type: .error , error.localizedDescription)
|
||||
}
|
||||
|
||||
if let characteristics = service.characteristics {
|
||||
for characteristic in characteristics {
|
||||
|
||||
if let characteristicValue = CBUUID_Characteristic_UUID(rawValue: characteristic.uuid.uuidString) {
|
||||
|
||||
trace(" characteristic : %{public}@", log: log, type: .info, characteristicValue.description)
|
||||
|
||||
switch characteristicValue {
|
||||
case .CBUUID_Backfill:
|
||||
backfillCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Write_Control:
|
||||
writeControlCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Communication:
|
||||
communicationCharacteristic = characteristic
|
||||
|
||||
case .CBUUID_Receive_Authentication:
|
||||
receiveAuthenticationCharacteristic = characteristic
|
||||
trace(" calling setNotifyValue true", log: log, type: .info)
|
||||
peripheral.setNotifyValue(true, for: characteristic)
|
||||
|
||||
}
|
||||
} else {
|
||||
trace(" characteristic UUID unknown : %{public}@", log: log, type: .error, characteristic.uuid.uuidString)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace("characteristics is nil. There must be some error.", log: log, type: .error)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
|
||||
/// this transmitter does not support oop web
|
||||
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {}
|
||||
|
||||
// MARK: helper functions
|
||||
|
||||
/// sends SensorTxMessage to transmitter
|
||||
|
|
|
@ -11,7 +11,7 @@ protocol CGMTransmitter {
|
|||
/// get device address, 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 address() -> String?
|
||||
func getAddress() -> String?
|
||||
|
||||
/// get device name, cgmtransmitters should also derive from BlueToothTransmitter, hence no need to implement this function
|
||||
///
|
||||
|
|
|
@ -91,14 +91,11 @@ 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())
|
||||
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)
|
||||
|
||||
//assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
|
||||
}
|
||||
|
||||
// MARK: - private helper functions
|
||||
|
@ -231,52 +228,43 @@ class CGMBluconTransmitter: BluetoothTransmitter {
|
|||
/// this transmitter does not support oop web
|
||||
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {}
|
||||
|
||||
}
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
||||
|
||||
func centralManagerDidConnect(address: String?, name: String?) {
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
trace("in centralManagerDidConnect", log: log, type: .info)
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
trace("in centralManagerDidDisconnectPeripheral", log: log, type: .info)
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
|
||||
|
||||
trace("in peripheralDidUpdateNotificationStateFor", log: log, type: .info)
|
||||
|
||||
// check if error occurred
|
||||
if let error = error {
|
||||
|
||||
|
||||
// no need to log the error, it's already logged in BluetoothTransmitter
|
||||
|
||||
// check if it's an encryption error, if so call delegate
|
||||
|
@ -292,19 +280,22 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
waitingSuccessfulPairing = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
// log the received characteristic value
|
||||
trace("in peripheralDidUpdateValueFor with characteristic UUID = %{public}@", log: log, type: .info, characteristic.uuid.uuidString)
|
||||
|
||||
|
||||
// this is only applicable the very first time that blucon connects and pairing is done
|
||||
if waitingSuccessfulPairing {
|
||||
cgmTransmitterDelegate?.successfullyPaired()
|
||||
waitingSuccessfulPairing = false
|
||||
}
|
||||
|
||||
|
||||
// check if error occured
|
||||
if let error = error {
|
||||
trace(" error: %{public}@", log: log, type: .error , error.localizedDescription)
|
||||
|
@ -330,24 +321,24 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
|
||||
case .wakeUpRequest:
|
||||
|
||||
// start by setting waitingForGlucoseData to false, it might still have value true due to protocol error
|
||||
waitingForGlucoseData = false
|
||||
|
||||
// send getPatchInfoRequest
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.getPatchInfoRequest)
|
||||
// start by setting waitingForGlucoseData to false, it might still have value true due to protocol error
|
||||
waitingForGlucoseData = false
|
||||
|
||||
// send getPatchInfoRequest
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.getPatchInfoRequest)
|
||||
|
||||
// by default set battery level to 100
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: 100), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
// by default set battery level to 100
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: 100), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
case .error14:
|
||||
|
||||
// Blucon didn't receive the next command it was waiting for, need to wait 5 minutes
|
||||
trace(" Timeout received, need to wait 5 minutes or push button to restart!", log: log, type: .error)
|
||||
|
||||
|
||||
// and send Blucon to sleep
|
||||
sendCommandToBlucon(opcode: .sleep)
|
||||
|
||||
|
||||
case .sensorNotDetected:
|
||||
|
||||
// Blucon didn't detect sensor, call delegate
|
||||
|
@ -390,14 +381,14 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
} else {
|
||||
|
||||
trace(" sensorState = %{public}@", log: log, type: .info, sensorState.description)
|
||||
|
||||
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.sleep)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// inform delegate 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
|
||||
|
||||
case .bluconAckResponse:
|
||||
|
@ -409,12 +400,12 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
// assuming bluconAckResponse will arrive less than 5 seconds after having send wakeUpResponse
|
||||
if let timeStampLastWakeUpResponse = timeStampLastWakeUpResponse, abs(timeStampLastWakeUpResponse.timeIntervalSinceNow) < 5 && shouldSendUnknown1CommandAfterReceivingBluconAckResponse {
|
||||
|
||||
// set to false to be sure
|
||||
shouldSendUnknown1CommandAfterReceivingBluconAckResponse = false
|
||||
|
||||
// send unknown1Command
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.unknown1Command)
|
||||
|
||||
// set to false to be sure
|
||||
shouldSendUnknown1CommandAfterReceivingBluconAckResponse = false
|
||||
|
||||
// send unknown1Command
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.unknown1Command)
|
||||
|
||||
} else {
|
||||
|
||||
trace(" no further processing, Blucon is sleeping now and should send a new reading in 5 minutes", log: log, type: .info)
|
||||
|
@ -424,33 +415,33 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
case .unknown1CommandResponse:
|
||||
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.unknown2Command)
|
||||
|
||||
|
||||
case .unknown2CommandResponse:
|
||||
|
||||
// check if there's a battery low indication
|
||||
if valueAsString.startsWith(unknownCommand2BatteryLowIndicator) {
|
||||
|
||||
|
||||
// this is considered as battery level 5%
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: 5), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
}
|
||||
|
||||
|
||||
// if timeStampLastBgReading > 5 minutes ago, then we'll get historic data, otherwise just get the latest reading
|
||||
if abs(timeStampLastBgReading.timeIntervalSinceNow) > 5 * 60 + 10 {
|
||||
|
||||
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.getHistoricDataAllBlocksCommand)
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
// not asking for sensorAge as in Spike and xdripplus, we know the sensorAge because we started with getHistoricDataAllBlocksCommand
|
||||
sendCommandToBlucon(opcode: BluconTransmitterOpCode.getNowDataIndex)
|
||||
|
||||
}
|
||||
|
||||
|
||||
case .multipleBlockResponseIndex:
|
||||
|
||||
if handleNewHistoricData(block: value) {
|
||||
|
||||
|
||||
// when Blucon responds with bluconAckResponse, then there's no need to send unknown1Command
|
||||
shouldSendUnknown1CommandAfterReceivingBluconAckResponse = false
|
||||
|
||||
|
@ -458,11 +449,11 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
sendCommandToBlucon(opcode: .sleep)
|
||||
|
||||
}
|
||||
|
||||
|
||||
case .singleBlockInfoResponsePrefix:
|
||||
|
||||
|
||||
if !waitingForGlucoseData {
|
||||
|
||||
|
||||
// get blockNumber and compose command
|
||||
let commandToSend = BluconTransmitterOpCode.singleBlockInfoPrefix.rawValue + blockNumberForNowGlucoseData(input: value)
|
||||
|
||||
|
@ -478,12 +469,12 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
|
||||
trace(" failed to convert commandToSend to Data", log: log, type: .error)
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// reset waitingForGlucoseData to false as we will not wait for glucosedata, after having processed this reading
|
||||
waitingForGlucoseData = false
|
||||
|
||||
|
||||
// to be sure that waitingForGlucoseData is not having value true due to having broken protcol, verify when SingleBlockInfoPrefix was sent
|
||||
if let timeStampOfSendingSingleBlockInfoPrefix = timeStampOfSendingSingleBlockInfoPrefix {
|
||||
// should be a matter of milliseconds, so take 2 seconds
|
||||
|
@ -503,7 +494,7 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
if abs(timeStampLastBgReading.timeIntervalSinceNow) < 30 {
|
||||
trace(" last reading less than 30 seconds old, ignoring this one", log: log, type: .info)
|
||||
} else {
|
||||
|
||||
|
||||
trace(" creating glucoseValue", log: log, type: .info)
|
||||
|
||||
// create glucose reading with timestamp now
|
||||
|
@ -515,31 +506,50 @@ extension CGMBluconTransmitter: BluetoothTransmitterDelegate {
|
|||
let glucoseData = GlucoseData(timeStamp: timeStampLastBgReading, glucoseLevelRaw: glucoseValue, glucoseLevelFiltered: glucoseValue)
|
||||
var glucoseDataArray = [glucoseData]
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &glucoseDataArray, transmitterBatteryInfo: nil, sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
sendCommandToBlucon(opcode: .sleep)
|
||||
|
||||
}
|
||||
|
||||
|
||||
case .bluconBatteryLowIndication1:
|
||||
|
||||
// this is considered as battery level 3%
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: 3), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
case .bluconBatteryLowIndication2:
|
||||
|
||||
// this is considered as battery level 2%
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: 2), sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
trace("in peripheral didUpdateValueFor, value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import os
|
||||
import CoreBluetooth
|
||||
|
||||
class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMBlueReaderTransmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -39,35 +39,45 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegat
|
|||
// assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
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())
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
trace("in peripheral didUpdateValueFor", log: log, type: .info)
|
||||
|
||||
|
@ -97,7 +107,7 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegat
|
|||
trace(" failed to convert rawDataAsString to double", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// if there's more than one field, then the second field is battery level
|
||||
// there could be 2 fields or more
|
||||
//var batteryLevelAsString:String? = nil
|
||||
|
@ -120,6 +130,7 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegat
|
|||
} else {
|
||||
trace(" value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
@ -135,8 +146,7 @@ class CGMBlueReaderTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegat
|
|||
func reset(requested:Bool) {}
|
||||
|
||||
/// this transmitter does not support oopWeb
|
||||
func setWebOOPEnabled(enabled: Bool) {
|
||||
}
|
||||
func setWebOOPEnabled(enabled: Bool) {}
|
||||
|
||||
/// this transmitter does not support oop web
|
||||
func setWebOOPSiteAndToken(oopWebSite: String, oopWebToken: String) {}
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMBubbleTransmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -90,10 +90,8 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
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())
|
||||
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)
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
}
|
||||
|
||||
// MARK: - public functions
|
||||
|
@ -107,31 +105,45 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
|
||||
|
||||
if error == nil && characteristic.isNotifying {
|
||||
_ = sendStartReadingCommmand()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
if let value = characteristic.value {
|
||||
|
||||
|
@ -150,10 +162,10 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
let hardware = value[2].description + ".0"
|
||||
let firmware = value[2].description + "." + value[3].description
|
||||
let batteryPercentage = Int(value[4])
|
||||
|
||||
|
||||
// send hardware, firmware and batteryPercentage to delegate
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: batteryPercentage), sensorState: nil, sensorTimeInMinutes: nil, firmware: firmware, hardware: hardware, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
||||
|
||||
// confirm receipt
|
||||
_ = writeDataToPeripheral(data: Data([0x02, 0x00, 0x00, 0x00, 0x00, 0x2B]), type: .withoutResponse)
|
||||
|
||||
|
@ -168,7 +180,7 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
if (Crc.LibreCrc(data: &rxBuffer, headerOffset: bubbleHeaderLength)) {
|
||||
|
||||
if let libreSensorSerialNumber = LibreSensorSerialNumber(withUID: Data(rxBuffer.subdata(in: 0..<8))) {
|
||||
|
||||
|
||||
|
||||
// verify serial number and if changed inform delegate
|
||||
if libreSensorSerialNumber.serialNumber != sensorSerialNumber {
|
||||
|
@ -185,16 +197,16 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
|
||||
// inform delegate about new sensorSerialNumber
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &emptyArray, transmitterBatteryInfo: nil, sensorState: nil, sensorTimeInMinutes: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: sensorSerialNumber)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
LibreDataParser.libreDataProcessor(sensorSerialNumber: sensorSerialNumber, webOOPEnabled: webOOPEnabled, oopWebSite: oopWebSite, oopWebToken: oopWebToken, libreData: (rxBuffer.subdata(in: bubbleHeaderLength..<(344 + bubbleHeaderLength))), cgmTransmitterDelegate: cgmTransmitterDelegate, transmitterBatteryInfo: nil, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, timeStampLastBgReading: timeStampLastBgReading, completionHandler: {(timeStampLastBgReading:Date) in
|
||||
self.timeStampLastBgReading = timeStampLastBgReading
|
||||
|
||||
})
|
||||
|
||||
|
||||
//reset the buffer
|
||||
resetRxBuffer()
|
||||
|
||||
|
@ -208,8 +220,9 @@ class CGMBubbleTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, C
|
|||
} else {
|
||||
trace("in peripheral didUpdateValueFor, value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
||||
/// to ask pairing - empty function because Bubble doesn't need pairing
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import os
|
||||
import CoreBluetooth
|
||||
|
||||
class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMDroplet1Transmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -39,35 +39,39 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
// assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service_Droplet)], CBUUID_ReceiveCharacteristic: CBUUID_ReceiveCharacteristic_Droplet, CBUUID_WriteCharacteristic: CBUUID_WriteCharacteristic_Droplet, startScanningAfterInit: CGMTransmitterType.Droplet1.startScanningAfterInit())
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
trace("in peripheral didUpdateValueFor", log: log, type: .info)
|
||||
|
||||
|
@ -88,7 +92,7 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
trace(" there's less than 3 spaces", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// get first field
|
||||
let firstField = String(valueAsString[valueAsString.startIndex..<indexesOfSplitter[0]])
|
||||
|
||||
|
@ -97,7 +101,7 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
cgmTransmitterDelegate?.sensorNotDetected()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// first field : first digits are rawvalue, to be multiplied with 100, last two digits are sensor type indicator, 10=L1, 20=L2, 30=US 14 day, 40=Lpro/h
|
||||
let rawValueAsString = firstField[0..<(firstField.count - 2)] + "00"
|
||||
let sensorTypeIndicator = firstField[(firstField.count - 2)..<firstField.count]
|
||||
|
@ -108,7 +112,7 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
trace(" failed to convert rawValueAsString to double", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// third field is battery percentage, stop if convert to Int fails
|
||||
guard let batteryPercentage = Int(String(valueAsString[valueAsString.index(after: indexesOfSplitter[1])..<indexesOfSplitter[2]])) else {
|
||||
trace(" failed to convert batteryPercentage field to Int", log: log, type: .error)
|
||||
|
@ -120,7 +124,7 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
trace(" failed to convert sensorTimeInMinutes field to Int", log: log, type: .error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// send to delegate
|
||||
var glucoseDataArray = [GlucoseData(timeStamp: Date(), glucoseLevelRaw: rawValueAsDouble)]
|
||||
cgmTransmitterDelegate?.cgmTransmitterInfoReceived(glucoseData: &glucoseDataArray, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: batteryPercentage), sensorState: nil, sensorTimeInMinutes: sensorTimeInMinutes * 10, firmware: nil, hardware: nil, hardwareSerialNumber: nil, bootloader: nil, sensorSerialNumber: nil)
|
||||
|
@ -128,6 +132,7 @@ class CGMDroplet1Transmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
} else {
|
||||
trace(" value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMGNSEntryTransmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -105,40 +105,42 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
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())
|
||||
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)
|
||||
|
||||
//assign CGMTransmitterDelegate
|
||||
cgmTransmitterDelegate = delegate
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
}
|
||||
|
||||
// MARK: BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
trace("in centralManagerDidConnect", log: log, type: .info)
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
trace("in centralManagerDidDisconnectPeripheral", log: log, type: .info)
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
trace("in peripheralDidUpdateNotificationStateFor", log: log, type: .info)
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
// log the received characteristic value
|
||||
trace("in peripheralDidUpdateValueFor with characteristic UUID = %{public}@, matches characteristic name %{public}@", log: log, type: .info, characteristic.uuid.uuidString, receivedCharacteristicUUIDToCharacteristic(characteristicUUID: characteristic.uuid.uuidString)?.description ?? "not available")
|
||||
|
@ -181,7 +183,7 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
var valueDecoded = XORENC(inD: [UInt8](value))
|
||||
|
||||
let valueDecodedAsHexString = Data(valueDecoded).hexEncodedString()
|
||||
trace(" in peripheralDidUpdateValueFor, GNW Notify with hex value = %{public}@", log: log, type: .info , valueDecodedAsHexString)
|
||||
trace(" in peripheralDidUpdateValueFor, GNW Notify with hex value = %{public}@", log: log, type: .info , valueDecodedAsHexString)
|
||||
|
||||
// reading status, as per GNSEntry documentation
|
||||
let readingStatus = getIntAtPosition(numberOfBytes: 1, position: 0, data: &valueDecoded)
|
||||
|
@ -218,10 +220,10 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
loop: while Int(7.0 + i * 2.0) < valueDecoded.count - 1 && i < amountOfPerMinuteReadings + amountOfPer15MinuteReadings {
|
||||
// timestamp of the reading in minutes, counting from 1 1 1970
|
||||
let readingTimeStampInMinutes:Double = currentTimeInMinutes - (i < amountOfPerMinuteReadings ? i : i * 15.0)
|
||||
|
||||
|
||||
// get the reading value (mgdl)
|
||||
let readingValueInMgDl = getIntAtPosition(numberOfBytes: 2, position: Int(7 + i * 2), data: &valueDecoded)
|
||||
|
||||
|
||||
//new reading should be at least 30 seconds younger than timeStampLastBgReadingStoredInDatabase
|
||||
if readingTimeStampInMinutes > ((timeStampLastBgReadingInMinutes * 2) + 1)/2 {
|
||||
|
||||
|
@ -233,7 +235,7 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
timeStampLastAddedGlucoseDataInMinutes = readingTimeStampInMinutes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
break loop
|
||||
}
|
||||
|
@ -251,6 +253,7 @@ class CGMGNSEntryTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
|
|
@ -2,7 +2,7 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate, CGMTransmitter {
|
||||
class CGMMiaoMiaoTransmitter:BluetoothTransmitter, CGMTransmitter {
|
||||
|
||||
// MARK: - properties
|
||||
|
||||
|
@ -86,10 +86,8 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
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())
|
||||
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)
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
}
|
||||
|
||||
// MARK: - public functions
|
||||
|
@ -103,31 +101,45 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address:String?, name:String?) {
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: address, name: name)
|
||||
override func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
|
||||
super.centralManager(central, didConnect: peripheral)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidConnect(address: deviceAddress, name: deviceName)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state)
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
cgmTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state)
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
cgmTransmitterDelegate?.cgmTransmitterDidDisconnect()
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
|
||||
|
||||
if error == nil && characteristic.isNotifying {
|
||||
_ = sendStartReadingCommand()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
if let value = characteristic.value {
|
||||
|
||||
|
@ -155,7 +167,7 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
let firmware = String(describing: rxBuffer[14...15].hexEncodedString())
|
||||
let hardware = String(describing: rxBuffer[16...17].hexEncodedString())
|
||||
let batteryPercentage = Int(rxBuffer[13])
|
||||
|
||||
|
||||
LibreDataParser.libreDataProcessor(sensorSerialNumber: LibreSensorSerialNumber(withUID: Data(rxBuffer.subdata(in: 5..<13)))?.serialNumber, webOOPEnabled: webOOPEnabled, oopWebSite: oopWebSite, oopWebToken: oopWebToken, libreData: (rxBuffer.subdata(in: miaoMiaoHeaderLength..<(344 + miaoMiaoHeaderLength))), cgmTransmitterDelegate: cgmTransmitterDelegate, transmitterBatteryInfo: TransmitterBatteryInfo.percentage(percentage: batteryPercentage), firmware: firmware, hardware: hardware, hardwareSerialNumber: nil, bootloader: nil, timeStampLastBgReading: timeStampLastBgReading, completionHandler: {(timeStampLastBgReading:Date) in
|
||||
self.timeStampLastBgReading = timeStampLastBgReading
|
||||
|
||||
|
@ -218,6 +230,8 @@ class CGMMiaoMiaoTransmitter:BluetoothTransmitter, BluetoothTransmitterDelegate,
|
|||
} else {
|
||||
trace("in peripheral didUpdateValueFor, value is nil, no further processing", log: log, type: .error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: CGMTransmitter protocol functions
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import Foundation
|
||||
|
||||
/// Every class that represents a bluetooth peripheral type needs to conform to this protocol. Classes being core data classes, ie NSManagedObject classes. Example M5Stack conforms to this protocol.
|
||||
///
|
||||
protocol BluetoothPeripheral {
|
||||
|
||||
// MARK:- functions related to generic parameters like address, alias, devicename,..
|
||||
|
||||
/// what type of peripheral is this
|
||||
func bluetoothPeripheralType() -> BluetoothPeripheralType
|
||||
|
||||
/// mac address of the peripheral
|
||||
///
|
||||
/// implementation will always be the same, ie return the address
|
||||
func getAddress() -> String
|
||||
|
||||
/// userdefined alias of the peripheral
|
||||
///
|
||||
/// implementation will always be the same, ie the alias
|
||||
func getAlias() -> String?
|
||||
|
||||
/// device name as given by the peripheral
|
||||
func getDeviceName() -> String
|
||||
|
||||
/// set the alias
|
||||
func setAlias(_ value: String?)
|
||||
|
||||
// MARK:- connection related functions
|
||||
|
||||
/// tells the app that it should not try to connect to this bluetoothperipheral
|
||||
///
|
||||
/// it's just an internal boolean value that is stored
|
||||
func dontTryToConnectToThisBluetoothPeripheral()
|
||||
|
||||
/// tells the app that it should always try to connect to this bluetoothperipheral
|
||||
///
|
||||
/// it's just an internal boolean value that is stored
|
||||
func alwaysTryToConnectToThisBluetoothPeripheral()
|
||||
|
||||
/// should xdrip try to connect yes or no ?
|
||||
///
|
||||
/// it's just an internal boolean value that is stored
|
||||
func shouldXdripTryToConnectToThisBluetoothPeripheral() -> Bool
|
||||
|
||||
/// when peripheral reconnects, app should not send list of parameters
|
||||
///
|
||||
/// - For example in case of M5Stack, user may change rotation or background color while it's not connected.
|
||||
/// - In that case parameterUpdateNeededAtNextConnect will be called.
|
||||
/// - Then later, when reconnecting isParameterUpdateNeededAtNextConnect tells us that app should send all parameters to the M5Stack.
|
||||
/// - After that a call is made to parameterUpdateNotNeededAtNextConnect
|
||||
func parameterUpdateNotNeededAtNextConnect()
|
||||
|
||||
/// when peripheral reconnects, app should not send list of parameters
|
||||
///
|
||||
/// - For example in case of M5Stack, user may change rotation or background color while it's not connected.
|
||||
/// - In that case parameterUpdateNeededAtNextConnect will be called.
|
||||
/// - Then later, when reconnecting isParameterUpdateNeededAtNextConnect tells us that app should send all parameters to the M5Stack.
|
||||
/// - After that a call is made to parameterUpdateNotNeededAtNextConnect
|
||||
func parameterUpdateNeededAtNextConnect()
|
||||
|
||||
/// when peripheral reconnects, should app send a list of parameters ?
|
||||
///
|
||||
/// - For example in case of M5Stack, user may change rotation or background color while it's not connected.
|
||||
/// - In that case parameterUpdateNeededAtNextConnect will be called.
|
||||
/// - Then later, when reconnecting isParameterUpdateNeededAtNextConnect tells us that app should send all parameters to the M5Stack.
|
||||
/// - After that a call is made to parameterUpdateNotNeededAtNextConnect
|
||||
func isParameterUpdateNeededAtNextConnect() -> Bool
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import Foundation
|
||||
|
||||
|
||||
enum BluetoothPeripheralType: String, CaseIterable {
|
||||
|
||||
/// M5Stack
|
||||
case M5Stack = "M5Stack"
|
||||
|
||||
func getViewModel() -> BluetoothPeripheralViewModel {
|
||||
|
||||
switch self {
|
||||
|
||||
case .M5Stack:
|
||||
return M5StackBluetoothPeripheralViewModel()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2,21 +2,23 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
/// generic bluetoothtransmitter class that handles scanning, connect, discover services, discover characteristics, subscribe to receive characteristic, reconnect.
|
||||
/// Generic bluetoothtransmitter class that handles scanning, connect, discover services, discover characteristics, subscribe to receive characteristic, reconnect. This class is a base class for specific type of transmitters.
|
||||
///
|
||||
/// The class assumes that the transmitter has a receive and transmit characterisitc (which is mostly the case)
|
||||
/// The class assumes that the transmitter has a receive and transmit characterisitc (which is mostly the case) - incase there's more characteristics to be processed, then the derived class will need to override didUpdateValueFor function
|
||||
class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
|
||||
|
||||
// MARK: - properties
|
||||
// MARK: - public properties
|
||||
|
||||
/// the BluetoothTransmitterDelegate
|
||||
public weak var bluetoothTransmitterDelegate:BluetoothTransmitterDelegate?
|
||||
/// 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?
|
||||
|
||||
// MARK: - private properties
|
||||
|
||||
/// the address of the transmitter. If nil then transmitter never connected, so we don't know the name.
|
||||
private var deviceAddress:String?
|
||||
/// the address of the transmitter. If nil then transmitter never connected, so we don't know the address.
|
||||
private(set) var deviceAddress:String?
|
||||
|
||||
/// the name of the transmitter. If nil then transmitter never connected, so we don't know the name
|
||||
private var deviceName:String?
|
||||
private(set) var deviceName:String?
|
||||
|
||||
/// uuid used for scanning, can be empty string, if empty string then scan all devices - only possible if app is in foreground
|
||||
private let CBUUID_Advertisement:String?
|
||||
|
@ -58,11 +60,14 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
private var receiveCharacteristic:CBCharacteristic?
|
||||
|
||||
/// used in BluetoothTransmitter class, eg if after calling discoverServices new method is called and time is exceed, then cancel connection
|
||||
let maxTimeToWaitForPeripheralResponse = 5.0
|
||||
private let maxTimeToWaitForPeripheralResponse = 5.0
|
||||
|
||||
/// 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:
|
||||
|
@ -74,7 +79,8 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
/// - servicesCBUUIDs: service uuid's
|
||||
/// - CBUUID_ReceiveCharacteristic: receive characteristic uuid
|
||||
/// - CBUUID_WriteCharacteristic: write characteristic uuid
|
||||
init(addressAndName:BluetoothTransmitter.DeviceAddressAndName, CBUUID_Advertisement:String?, servicesCBUUIDs:[CBUUID], CBUUID_ReceiveCharacteristic:String, CBUUID_WriteCharacteristic:String, startScanningAfterInit:Bool) {
|
||||
/// - delegate : a
|
||||
init(addressAndName:BluetoothTransmitter.DeviceAddressAndName, CBUUID_Advertisement:String?, servicesCBUUIDs:[CBUUID], CBUUID_ReceiveCharacteristic:String, CBUUID_WriteCharacteristic:String, startScanningAfterInit:Bool, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?) {
|
||||
|
||||
switch addressAndName {
|
||||
|
||||
|
@ -99,6 +105,9 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
//initialize timeStampLastStatusUpdate
|
||||
timeStampLastStatusUpdate = Date()
|
||||
|
||||
// assign delegate
|
||||
self.fixedBluetoothTransmitterDelegate = bluetoothTransmitterDelegate
|
||||
|
||||
super.init()
|
||||
|
||||
initialize()
|
||||
|
@ -153,6 +162,14 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
self.centralManager?.stopScan()
|
||||
}
|
||||
|
||||
/// is the transmitter currently scanning or not
|
||||
func isScanning() -> Bool {
|
||||
if let centralManager = centralManager {
|
||||
return centralManager.isScanning
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// start bluetooth scanning for device
|
||||
func startScanning() -> BluetoothTransmitter.startScanningResult {
|
||||
|
||||
|
@ -342,10 +359,13 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
||||
timeStampLastStatusUpdate = Date()
|
||||
|
||||
trace("connected to peripheral with name %{public}@, will discover services", log: log, type: .info, deviceName ?? "'unknown'")
|
||||
trace("connected to peripheral with name %{public}@", log: log, type: .info, deviceName ?? "'unknown'")
|
||||
|
||||
fixedBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: self)
|
||||
variableBluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: self)
|
||||
|
||||
peripheral.discoverServices(servicesCBUUIDs)
|
||||
|
||||
bluetoothTransmitterDelegate?.centralManagerDidConnect(address: deviceAddress, name: deviceName)
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
|
||||
|
@ -359,13 +379,15 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
|
||||
centralManager?.connect(peripheral, options: nil)
|
||||
|
||||
bluetoothTransmitterDelegate?.centralManagerDidFailToConnect(error: error)
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
timeStampLastStatusUpdate = Date()
|
||||
|
||||
trace("in centralManagerDidUpdateState, for peripheral with name %{public}@, new state is %{public}@", log: log, type: .info, deviceName ?? "'unknown'", "\(central.state.toString())")
|
||||
|
||||
fixedBluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: central.state, bluetoothTransmitter: self)
|
||||
variableBluetoothTransmitterDelegate?.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 {
|
||||
|
@ -377,20 +399,20 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
}
|
||||
}
|
||||
|
||||
bluetoothTransmitterDelegate?.centralManagerDidUpdateState(state: central.state)
|
||||
}
|
||||
|
||||
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
timeStampLastStatusUpdate = Date()
|
||||
|
||||
trace(" didDisconnect peripheral with name %{public}@", log: log, type: .info , deviceName ?? "'unknown'")
|
||||
|
||||
fixedBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: self)
|
||||
variableBluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: self)
|
||||
|
||||
if let error = error {
|
||||
trace(" error: %{public}@", log: log, type: .error , error.localizedDescription)
|
||||
}
|
||||
|
||||
bluetoothTransmitterDelegate?.centralManagerDidDisconnectPeripheral(error: error)
|
||||
|
||||
// check if automatic reconnect is needed or not
|
||||
if !reconnectAfterDisconnect {
|
||||
|
||||
|
@ -473,9 +495,6 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
trace("didUpdateNotificationStateFor for peripheral with name %{public}@, characteristic %{public}@, characteristic description %{public}@, error = %{public}@", log: log, type: .error, deviceName ?? "'unkonwn'", String(describing: characteristic.uuid), String(characteristic.debugDescription), error.localizedDescription)
|
||||
}
|
||||
|
||||
// call delegate
|
||||
bluetoothTransmitterDelegate?.peripheralDidUpdateNotificationStateFor(characteristic: characteristic, error: error)
|
||||
|
||||
}
|
||||
|
||||
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
@ -483,15 +502,14 @@ class BluetoothTransmitter: NSObject, CBCentralManagerDelegate, CBPeripheralDele
|
|||
|
||||
if let error = error {
|
||||
trace("didUpdateValueFor for peripheral with name %{public}@, characteristic %{public}@, characteristic description %{public}@, error = %{public}@, no further processing", log: log, type: .error, deviceName ?? "'unknown'", String(describing: characteristic.uuid), String(characteristic.debugDescription), error.localizedDescription)
|
||||
} else {
|
||||
bluetoothTransmitterDelegate?.peripheralDidUpdateValueFor(characteristic: characteristic, error: error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: methods to get address and name
|
||||
|
||||
/// read device address
|
||||
func address() -> String? {
|
||||
func getAddress() -> String? {
|
||||
return deviceAddress
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,20 @@
|
|||
import Foundation
|
||||
import CoreBluetooth
|
||||
|
||||
/// Defines functions similar as CBCentralManagerDelegate, CBPeripheralDelegate, with a different name and signature
|
||||
///
|
||||
/// Goal is that delegates that conform to this protocol have a way to receive information about bluetooth activities. Example centralManager didDisconnectPeripheral is handled in class BluetoothTransmitter, however a delegate may be interested that a disconnect occurred for showing info to the user. The implementation of centralManager didDisconnectPeripheral in BluetoothTransmitter class would first do own stuff (eg try to reconnect) and at the end call the corresponding delegate function. For some methods, the implementation in the class BluetoothTransmitter will do nothing but calling the corresponding method in the protocol BluetoothTransmitterDelegate, example centralManager didUpdateValueFor characteristic.
|
||||
///
|
||||
/// If a Delegate is not interested in information, then it just needs to implement an empty closure
|
||||
///
|
||||
/// Most delegates will only implement just a very fiew of the methods
|
||||
protocol BluetoothTransmitterDelegate:AnyObject {
|
||||
/// called when centralManager didConnect was called in BlueToothTransmitter class
|
||||
/// the BlueToothTransmitter class handles the reconnect but the delegate class can for instance show the connection status to the user
|
||||
/// delegate used for any type of BluetoothTransmitter
|
||||
protocol BluetoothTransmitterDelegate: AnyObject {
|
||||
|
||||
// MARK: - Generic functions that can be used for any type of BluetoothTransmitter
|
||||
|
||||
/// did connect to
|
||||
/// - parameters:
|
||||
/// - address: the address that was received from the transmitter during connection phase
|
||||
/// - name: the name that was received from the transmitter during connection phase
|
||||
func centralManagerDidConnect(address:String?, name:String?)
|
||||
/// - bluetoothTransmitter : the bluetoothTransmitter to which the connection is made
|
||||
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter)
|
||||
|
||||
/// called when centralManager didFailToConnect was called in BlueToothTransmitter class
|
||||
/// the BlueToothTransmitter class handles will try to reconnect but the delegate class can for instance show the connection status to the user
|
||||
func centralManagerDidFailToConnect(error: Error?)
|
||||
/// did disconnect from bluetoothTransmitter
|
||||
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter)
|
||||
|
||||
/// called when centralManagerDidUpdateState was called in BlueToothTransmitter class
|
||||
/// if an address is already stored (ie device already connected before) then the BlueToothTransmitter class will try to reconnect and/or scan
|
||||
func centralManagerDidUpdateState(state: CBManagerState)
|
||||
/// the ios device did change bluetooth status
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter)
|
||||
|
||||
/// if an address is already stored (ie device already connected before) then the BlueToothTransmitter class will try to reconnect and/or scan
|
||||
///
|
||||
/// the BlueToothTransmitter will also log the error if there is one
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?)
|
||||
|
||||
/// called when peripheral didUpdateNotificationStateFor was called in BlueToothTransmitter class
|
||||
///
|
||||
/// the BlueToothTransmitter class will log the error if any and call the delegate function
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?)
|
||||
|
||||
/// called when peripheral didUpdateValueFor was called in BlueToothTransmitter class
|
||||
/// the BlueToothTransmitter class will not do anything just call the delegate function
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import Foundation
|
||||
|
||||
extension M5Stack: BluetoothPeripheral {
|
||||
|
||||
func getDeviceName() -> String {
|
||||
return name
|
||||
}
|
||||
|
||||
func setAlias(_ value: String?) {
|
||||
alias = value
|
||||
}
|
||||
|
||||
func getAlias() -> String? {
|
||||
return alias
|
||||
}
|
||||
|
||||
// get the mac address
|
||||
func getAddress() -> String {
|
||||
return address
|
||||
}
|
||||
|
||||
// get the type of BluetoothPeripheral: "M5Strack", ...
|
||||
func bluetoothPeripheralType() -> BluetoothPeripheralType {
|
||||
return .M5Stack
|
||||
}
|
||||
|
||||
func dontTryToConnectToThisBluetoothPeripheral() {
|
||||
shouldconnect = false
|
||||
}
|
||||
|
||||
func alwaysTryToConnectToThisBluetoothPeripheral() {
|
||||
shouldconnect = true
|
||||
}
|
||||
|
||||
func shouldXdripTryToConnectToThisBluetoothPeripheral() -> Bool {
|
||||
return shouldconnect
|
||||
}
|
||||
|
||||
func parameterUpdateNotNeededAtNextConnect() {
|
||||
parameterUpdateNeeded = false
|
||||
}
|
||||
|
||||
func parameterUpdateNeededAtNextConnect() {
|
||||
parameterUpdateNeeded = true
|
||||
}
|
||||
|
||||
func isParameterUpdateNeededAtNextConnect() -> Bool {
|
||||
return parameterUpdateNeeded
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
import Foundation
|
||||
import CoreBluetooth
|
||||
|
||||
protocol M5StackBluetoothDelegate: AnyObject {
|
||||
|
||||
/// if a new ble password is received from M5Stack
|
||||
func newBlePassWord(newBlePassword: String, forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// did the app successfully authenticate towards M5Stack
|
||||
///
|
||||
/// in case of failure, then user should set the correct password in the M5Stack ini file, or, in case there's no password set in the ini file, switch off and on the M5Stack
|
||||
func authentication(success: Bool, forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// there's no ble password set during M5Stack init, user should set it in the settings
|
||||
func blePasswordMissing(forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// it's an M5Stack without password configired in the ini file. xdrip app has been requesting temp password to M5Stack but this was already done once. M5Stack needs to be reset
|
||||
func m5StackResetRequired(forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// did connect to M5Stack
|
||||
/// - parameters:
|
||||
/// - forM5Stack : if nil then it's the first connection to a new M5Stack, time to create a new M5Stack instance with address and string which should now not be nil
|
||||
/// - bluetoothTransmitter : is needed in case we want to disconnect from it
|
||||
func didConnect(forM5Stack m5Stack: M5Stack?, address: String?, name: String?, bluetoothTransmitter : M5StackBluetoothTransmitter)
|
||||
|
||||
/// did disconnect from M5Stack
|
||||
func didDisconnect(forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// the ios device did change bluetooth status
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, forM5Stack m5Stack:M5Stack)
|
||||
|
||||
/// to pass some text error message, delegate can decide to show to user, log, ...
|
||||
func error(message: String)
|
||||
|
||||
/// will be called if M5Stack is connected, and authentication was successful
|
||||
func isReadyToReceiveData(m5Stack : M5Stack)
|
||||
|
||||
func isAskingForAllParameters(m5Stack: M5Stack)
|
||||
|
||||
}
|
|
@ -2,18 +2,13 @@ import Foundation
|
|||
import CoreBluetooth
|
||||
import os
|
||||
|
||||
/// bluetoothTransmitter for an M5 Stack
|
||||
/// bluetoothTransmitter for an M5Stack
|
||||
/// - will start scanning as soon as created or as soon as bluetooth is switched on
|
||||
/// - there's only one characteristic which is used for write and notify, not read. To get data from the M5Stack, xdrip app will write a specific opcode, then M5Stack will reply and the reply will arrive as notify. So we don't use .withResponse
|
||||
final class M5StackBluetoothTransmitter: BluetoothTransmitter, BluetoothTransmitterDelegate {
|
||||
final class M5StackBluetoothTransmitter: BluetoothTransmitter {
|
||||
|
||||
// MARK: - public properties
|
||||
|
||||
/// will be used to pass data back
|
||||
///
|
||||
/// there's two delegates, one public, one private. The private one will be assigned during object creation. There's two because two other classes want to receive feedback : BluetoothPeripheralManager and UIViewControllers. There's only one instance of BluetoothPeripheralManager and it's always the same. An instance will be assigned to m5StackBluetoothTransmitterDelegateFixed. There can be different UIViewController' and they can change, an instance will be assigned to m5StackBluetoothTransmitterDelegateVariable
|
||||
public weak var m5StackBluetoothTransmitterDelegateVariable: M5StackBluetoothDelegate?
|
||||
|
||||
// MARK: - private properties
|
||||
|
||||
/// service to be discovered
|
||||
|
@ -31,56 +26,34 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter, BluetoothTransmit
|
|||
/// temporary storage for packages received from M5Stack, with the password in it
|
||||
private var blePasswordM5StackPacket = M5StackPacket()
|
||||
|
||||
/// m5Stack instance for which this bluetooth transmitter is working, if nil then this bluetoothTransmitter is created to start scanning for a new, unknown M5Stack. In that case, the value needs to be assigned as soon as an M5Stack is created
|
||||
public var m5Stack: M5Stack?
|
||||
|
||||
/// will be used to pass data back
|
||||
///
|
||||
/// there's two delegates, one public, one private. The private one will be assigned during object creation. There's two because two other classes want to receive feedback : BluetoothPeripheralManager and UIViewControllers. There's only one instance of BluetoothPeripheralManager and it's always the same. An instance will be assigned to m5StackBluetoothTransmitterDelegateFixed. There can be different UIViewController' and they can change, an instance will be assigned to m5StackBluetoothTransmitterDelegateVariable
|
||||
private weak var m5StackBluetoothTransmitterDelegateFixed:M5StackBluetoothDelegate!
|
||||
|
||||
/// is the transmitter ready to receive data like parameter updates or reading values
|
||||
private (set) var isReadyToReceiveData: Bool = false
|
||||
|
||||
/// 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]
|
||||
|
||||
|
||||
// MARK: - initializer
|
||||
|
||||
/// - parameters:
|
||||
/// - m5Stack : an instance of M5Stack, if nil then this instance is created to scan for a new M5Stack, address and name not yet known, so not possible yet to create an M5Stack instance
|
||||
/// - delegateFixed : there's two delegates, one public, one private. The private one will be assigned during object creation. There's two because two other classes want to receive feedback : BluetoothPeripheralManager and UIViewControllers. There's only one instance of BluetoothPeripheralManager and it's always the same. An instance will be assigned to m5StackBluetoothTransmitterDelegateFixed. There can be different UIViewController' and they can change, an instance will be assigned to m5StackBluetoothTransmitterDelegateVariable
|
||||
/// - 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 : the M5StackBluetoothTransmitterDelegate
|
||||
/// - blePassword : optional. If nil then xdrip will send a M5StackReadBlePassWordTxMessage to the M5Stack, so this would be a case where the M5Stack (all M5Stacks managed by xdrip) do not have a fixed blepassword
|
||||
/// The blepassword in the M5Stack object gets priority over the blePassword in the parameter list
|
||||
init(m5Stack: M5Stack?, delegateFixed: M5StackBluetoothDelegate, blePassword: String?) {
|
||||
init(address:String?, name: String?, delegate: M5StackBluetoothTransmitterDelegate, blePassword: String?) {
|
||||
|
||||
// assign addressname and name or expected devicename
|
||||
// assign addressname and name, assume it's not been connected before
|
||||
var newAddressAndName:BluetoothTransmitter.DeviceAddressAndName = BluetoothTransmitter.DeviceAddressAndName.notYetConnected(expectedName: "M5Stack")
|
||||
if let m5Stack = m5Stack {
|
||||
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: m5Stack.address, name: m5Stack.name)
|
||||
|
||||
// if address not nil, then we've already connected before to this device, we know the address and name
|
||||
if let address = address, let name = name {
|
||||
newAddressAndName = BluetoothTransmitter.DeviceAddressAndName.alreadyConnectedBefore(address: address, name: name)
|
||||
}
|
||||
|
||||
// as mentioned in the parameter documentation, the blePassword in the M5Stack parameter gets priority over the password in the parameter blePassword
|
||||
if let m5Stack = m5Stack, let blePassword = m5Stack.blepassword {
|
||||
// m5Stack object is not nil and does have a blePassword, use that value
|
||||
self.blePassword = blePassword
|
||||
} else {
|
||||
// use blePassword that was in the parameter list, possibly nil value
|
||||
self.blePassword = blePassword
|
||||
}
|
||||
|
||||
self.m5Stack = m5Stack
|
||||
// assign blePassword
|
||||
self.blePassword = blePassword
|
||||
|
||||
self.m5StackBluetoothTransmitterDelegateFixed = delegateFixed
|
||||
|
||||
// call super
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service)], CBUUID_ReceiveCharacteristic: CBUUID_TxRxCharacteristic, CBUUID_WriteCharacteristic: CBUUID_TxRxCharacteristic, startScanningAfterInit: false)
|
||||
|
||||
// set self as delegate for BluetoothTransmitterDelegate - this parameter is defined in the parent class BluetoothTransmitter
|
||||
bluetoothTransmitterDelegate = self
|
||||
|
||||
// start scanning, probably the scanning will not yet start, this will happen only when centralManagerDidUpdateState is called
|
||||
_ = startScanning()
|
||||
super.init(addressAndName: newAddressAndName, CBUUID_Advertisement: nil, servicesCBUUIDs: [CBUUID(string: CBUUID_Service)], CBUUID_ReceiveCharacteristic: CBUUID_TxRxCharacteristic, CBUUID_WriteCharacteristic: CBUUID_TxRxCharacteristic, startScanningAfterInit: false, bluetoothTransmitterDelegate: delegate)
|
||||
|
||||
}
|
||||
|
||||
|
@ -266,51 +239,38 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter, BluetoothTransmit
|
|||
} else {return false}
|
||||
}
|
||||
|
||||
// MARK: - BluetoothTransmitterDelegate functions
|
||||
// MARK: - overriden BluetoothTransmitter functions
|
||||
|
||||
func centralManagerDidConnect(address: String?, name: String?) {
|
||||
m5StackBluetoothTransmitterDelegateFixed.didConnect(forM5Stack: m5Stack, address: address, name: name, bluetoothTransmitter: self)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.didConnect(forM5Stack: m5Stack, address: address, name: name, bluetoothTransmitter: self)
|
||||
}
|
||||
|
||||
func centralManagerDidFailToConnect(error: Error?) {
|
||||
trace("in centralManagerDidFailToConnect", log: log, type: .error)
|
||||
}
|
||||
|
||||
func centralManagerDidUpdateState(state: CBManagerState) {
|
||||
override func centralManagerDidUpdateState(_ central: CBCentralManager) {
|
||||
|
||||
if let m5Stack = m5Stack {
|
||||
|
||||
m5StackBluetoothTransmitterDelegateFixed!.deviceDidUpdateBluetoothState(state: state, forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.deviceDidUpdateBluetoothState(state: state, forM5Stack: m5Stack)
|
||||
|
||||
} else {
|
||||
super.centralManagerDidUpdateState(central)
|
||||
|
||||
if deviceAddress == nil {
|
||||
/// this bluetoothTransmitter is created to start scanning for a new, unknown M5Stack, so start scanning
|
||||
_ = startScanning()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func centralManagerDidDisconnectPeripheral(error: Error?) {
|
||||
override func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
|
||||
|
||||
super.centralManager(central, didDisconnectPeripheral: peripheral, error: error)
|
||||
|
||||
// can not write data anymore to the device
|
||||
isReadyToReceiveData = false
|
||||
|
||||
if let m5Stack = m5Stack {
|
||||
m5StackBluetoothTransmitterDelegateFixed!.didDisconnect(forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.didDisconnect(forM5Stack: m5Stack)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateNotificationStateFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateNotificationStateFor: characteristic, error: error)
|
||||
|
||||
// check if subscribe to notifications succeeded
|
||||
if characteristic.isNotifying {
|
||||
|
||||
// time to send password to M5Stack, if there isn't one known in the settings then we assume that the user didn't set a password in the M5Stack config (M5NS.INI) and that we didn't connect to this M5Stack yet after the last M5Stack restart. So in that case we will request a random password
|
||||
if let blePassword = blePassword, let authenticateTxMessageData = M5StackAuthenticateTXMessage(password: blePassword).data {
|
||||
|
||||
|
||||
if !writeDataToPeripheral(data: authenticateTxMessageData, type: .withoutResponse) {
|
||||
trace("failed to send authenticateTx to M5Stack", log: log, type: .error)
|
||||
} else {
|
||||
|
@ -324,16 +284,19 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter, BluetoothTransmit
|
|||
} else {
|
||||
trace("successfully sent readBlePassWordTx to M5Stack", log: log, type: .error)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
trace("in peripheralDidUpdateNotificationStateFor, failed to subscribe for characteristic %{public}@", log: log, type: .error, characteristic.uuid.description)
|
||||
trace("in peripheralDidUpdateNotificationStateFor, failed to subscribe for characteristic %{public}@", log: log, type: .error, characteristic.uuid.description)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func peripheralDidUpdateValueFor(characteristic: CBCharacteristic, error: Error?) {
|
||||
override func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
|
||||
|
||||
super.peripheral(peripheral, didUpdateValueFor: characteristic, error: error)
|
||||
|
||||
//check if value is not nil
|
||||
guard let value = characteristic.value else {
|
||||
trace("in peripheral didUpdateValueFor, characteristic.value is nil", log: log, type: .info)
|
||||
|
@ -363,82 +326,74 @@ final class M5StackBluetoothTransmitter: BluetoothTransmitter, BluetoothTransmit
|
|||
|
||||
trace(" received new password, will store it", log: log, type: .error)
|
||||
|
||||
guard let m5Stack = m5Stack else {return}// would be a software error if this happens
|
||||
|
||||
blePasswordM5StackPacket.addNewPacket(value: value)
|
||||
|
||||
if let newBlePassword = blePasswordM5StackPacket.getText() {
|
||||
|
||||
self.blePassword = newBlePassword
|
||||
|
||||
m5StackBluetoothTransmitterDelegateFixed!.newBlePassWord(newBlePassword: newBlePassword, forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.newBlePassWord(newBlePassword: newBlePassword, forM5Stack: m5Stack)
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)? .newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.newBlePassWord(newBlePassword: newBlePassword, m5StackBluetoothTransmitter: self)
|
||||
|
||||
}
|
||||
|
||||
|
||||
// this is usually a case where M5Stack has restarted, so it needs to get time and timeoffset
|
||||
sendLocalTimeAndUTCTimeOffSetInSecondsToM5Stack()
|
||||
|
||||
// this is the time when the M5stack is ready to receive readings or parameter updates
|
||||
isReadyToReceiveData = true
|
||||
m5StackBluetoothTransmitterDelegateFixed!.isReadyToReceiveData(m5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.isReadyToReceiveData(m5Stack: m5Stack)
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
|
||||
|
||||
case .authenticateSuccessRx:
|
||||
// received from M5Stack, need to inform delegates, send timestamp to M5Stack, and also set isReadyToReceiveData to true
|
||||
|
||||
trace(" successfully authenticated", log: log, type: .error)
|
||||
|
||||
guard let m5Stack = m5Stack else {return}// would be a software error if this happens
|
||||
|
||||
// inform delegates
|
||||
m5StackBluetoothTransmitterDelegateFixed!.authentication(success: true, forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.authentication(success: true, forM5Stack: m5Stack)
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: true, m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: true, m5StackBluetoothTransmitter: self)
|
||||
|
||||
// even though not requested, and even if M5Stack may already have it, send the local time
|
||||
sendLocalTimeAndUTCTimeOffSetInSecondsToM5Stack()
|
||||
|
||||
// this is the time when the M5stack is ready to receive readings or parameter updates
|
||||
isReadyToReceiveData = true
|
||||
m5StackBluetoothTransmitterDelegateFixed!.isReadyToReceiveData(m5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.isReadyToReceiveData(m5Stack: m5Stack)
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isReadyToReceiveData(m5StackBluetoothTransmitter: self)
|
||||
|
||||
case .authenticateFailureRx:
|
||||
// received authentication failure, inform delegates
|
||||
if let m5Stack = m5Stack {
|
||||
m5StackBluetoothTransmitterDelegateFixed!.authentication(success: false, forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.authentication(success: false, forM5Stack: m5Stack)
|
||||
}
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: false, m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.authentication(success: false, m5StackBluetoothTransmitter: self)
|
||||
|
||||
case .readBlePassWordError1Rx:
|
||||
if let m5Stack = m5Stack {
|
||||
m5StackBluetoothTransmitterDelegateFixed!.blePasswordMissing(forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.blePasswordMissing(forM5Stack: m5Stack)
|
||||
}
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.blePasswordMissing(m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.blePasswordMissing(m5StackBluetoothTransmitter: self)
|
||||
|
||||
case .readBlePassWordError2Rx:
|
||||
if let m5Stack = m5Stack {
|
||||
|
||||
m5StackBluetoothTransmitterDelegateFixed!.m5StackResetRequired(forM5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.m5StackResetRequired(forM5Stack: m5Stack)
|
||||
}
|
||||
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.m5StackResetRequired(m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.m5StackResetRequired(m5StackBluetoothTransmitter: self)
|
||||
|
||||
case .readTimeStampRx:
|
||||
|
||||
// M5Stack is requesting for timestamp
|
||||
sendLocalTimeAndUTCTimeOffSetInSecondsToM5Stack()
|
||||
|
||||
case .readAllParametersRx:
|
||||
|
||||
// M5Stack is asking for all parameters
|
||||
|
||||
guard let m5Stack = m5Stack else {return}// would be a software error if this happens
|
||||
|
||||
m5StackBluetoothTransmitterDelegateFixed!.isAskingForAllParameters(m5Stack: m5Stack)
|
||||
m5StackBluetoothTransmitterDelegateVariable?.isAskingForAllParameters(m5Stack: m5Stack)
|
||||
(fixedBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isAskingForAllParameters(m5StackBluetoothTransmitter: self)
|
||||
(variableBluetoothTransmitterDelegate as? M5StackBluetoothTransmitterDelegate)?.isAskingForAllParameters(m5StackBluetoothTransmitter: self)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: private helper functions
|
||||
|
||||
/// sends local time in seconds since 1.1.1970 and also timeoffset from UTC in seconds. to M5Stack
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import Foundation
|
||||
|
||||
protocol M5StackBluetoothTransmitterDelegate: BluetoothTransmitterDelegate {
|
||||
|
||||
/// will be called if M5StackBluetoothTransmitter is connected and ready to receive data
|
||||
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
/// M5StackBluetoothTransmitter wants to receive all parameters
|
||||
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
/// if a new ble password is received from M5StackBluetoothTransmitter
|
||||
func newBlePassWord(newBlePassword: String, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
/// did the app successfully authenticate towards M5Stack
|
||||
///
|
||||
/// in case of failure, then user should set the correct password in the M5Stack ini file, or, in case there's no password set in the ini file, switch off and on the M5Stack
|
||||
func authentication(success: Bool, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
/// there's no ble password set during M5Stack init, user should set it in the settings
|
||||
func blePasswordMissing(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
/// it's an M5Stack without password configired in the ini file. xdrip app has been requesting temp password to M5Stack but this was already done once. M5Stack needs to be reset
|
||||
func m5StackResetRequired(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter)
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@ final class BluetoothPeripheralNavigationController: UINavigationController {
|
|||
private var coreDataManager:CoreDataManager?
|
||||
|
||||
/// a bluetoothPeripheralManager
|
||||
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging?
|
||||
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging!
|
||||
|
||||
// MARK:- public functions
|
||||
|
||||
|
@ -34,7 +34,7 @@ final class BluetoothPeripheralNavigationController: UINavigationController {
|
|||
extension BluetoothPeripheralNavigationController: UINavigationControllerDelegate {
|
||||
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
|
||||
|
||||
if let bluetoothPeripheralsViewController = viewController as? BluetoothPeripheralsViewController, let coreDataManager = coreDataManager, let bluetoothPeripheralManager = bluetoothPeripheralManager {
|
||||
if let bluetoothPeripheralsViewController = viewController as? BluetoothPeripheralsViewController, let coreDataManager = coreDataManager {
|
||||
bluetoothPeripheralsViewController.configure(coreDataManager: coreDataManager, bluetoothPeripheralManager: bluetoothPeripheralManager)
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
|
||||
protocol BluetoothPeripheralViewModel: BluetoothTransmitterDelegate {
|
||||
|
||||
/// 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
|
||||
/// - settingRowOffset :needs to be set to number of generic settings in BluetoothPeripheralViewController
|
||||
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, settingRowOffset:Int, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate)
|
||||
|
||||
/// screen title for uiviewcontroller
|
||||
func screenTitle() -> String
|
||||
|
||||
/// user clicked done button in uiviewcontroller
|
||||
/// - parameters:
|
||||
/// - bluetoothPeripheral : the bluetoothPeripheral being shown
|
||||
func doneButtonHandler(bluetoothPeripheral: BluetoothPeripheral?)
|
||||
|
||||
/// updates the contents of a cell, for setting with rawValue withSettingRawValue
|
||||
func update(cell: UITableViewCell, withSettingRawValue rawValue: Int, for bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
/// user clicked a row, this function does the necessary
|
||||
func userDidSelectRow(withSettingRawValue rawValue: Int, for bluetoothPeripheral: BluetoothPeripheral, bluetoothPeripheralManager: BluetoothPeripheralManaging, doneButtonOutlet: UIBarButtonItem)
|
||||
|
||||
/// get number of settings in the viewmodel
|
||||
func numberOfSettings() -> Int
|
||||
|
||||
/// used when new peripheral is discovered and connected, to temporary store values in model (eg in case of M5Stack, store the rotation value which would be a default value)
|
||||
func storeTempValues(from bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
/// used when user clicks done button in uiviewcontroller
|
||||
func writeTempValues(to bluetoothPeripheral: BluetoothPeripheral)
|
||||
|
||||
}
|
|
@ -0,0 +1,542 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import CoreBluetooth
|
||||
|
||||
/// - a case per attribute that can be set
|
||||
/// - these are attributes specific to M5Stack, the generic ones are defined in BluetoothPeripheralViewController
|
||||
fileprivate enum Setting:Int, CaseIterable {
|
||||
|
||||
/// ble password
|
||||
case blePassword = 0
|
||||
|
||||
/// textColor
|
||||
case textColor = 1
|
||||
|
||||
/// backGroundColor
|
||||
case backGroundColor = 2
|
||||
|
||||
/// rotation
|
||||
case rotation = 3
|
||||
|
||||
/// case brightness
|
||||
case brightness = 4
|
||||
|
||||
}
|
||||
|
||||
class M5StackBluetoothPeripheralViewModel {
|
||||
|
||||
// MARK: - private properties
|
||||
|
||||
/// textColor to be used in M5Stack
|
||||
///
|
||||
/// temp storage of value while user is editing the M5Stack attributes
|
||||
private var textColorTemporaryValue: M5StackColor?
|
||||
|
||||
/// roration to be used in M5Stack
|
||||
///
|
||||
/// temp storage of value while user is editing the M5Stack attributes
|
||||
private var rotationTempValue: UInt16?
|
||||
|
||||
/// backGroundColor to be used in M5Stack
|
||||
///
|
||||
/// temp storage of value while user is editing the M5Stack attributes
|
||||
private var backGroundColorTemporaryValue: M5StackColor?
|
||||
|
||||
/// brightness to be used in M5Stack
|
||||
///
|
||||
/// temp storage of value while user is editing the M5Stack attributes
|
||||
private var brightnessTemporaryValue: Int?
|
||||
|
||||
/// possible rotation keys, , the value is shown to the user
|
||||
private let rotationStrings: [String] = [ "0", "90", "180", "270"]
|
||||
|
||||
/// possible brightness values, the value is shown to the user
|
||||
private let brightnessStrings: [String] = ["0", "10", "20", "30", "40", "50", "60", "70", "80", "90", "100"]
|
||||
|
||||
/// reference to bluetoothPeripheralManager
|
||||
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging?
|
||||
|
||||
/// reference to the tableView
|
||||
private weak var tableView: UITableView?
|
||||
|
||||
/// reference to BluetoothPeripheralViewController that will own this M5StackBluetoothPeripheralViewModel - needed to present stuff etc
|
||||
private weak var bluetoothPeripheralViewController: BluetoothPeripheralViewController?
|
||||
|
||||
private weak var bluetoothTransmitterDelegate: BluetoothTransmitterDelegate?
|
||||
|
||||
/// this is actually the number of setting rows defined in BluetoothPeripheralViewController
|
||||
private var settingRowOffset: Int!
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extension BluetoothTransmitterDelegate
|
||||
|
||||
extension M5StackBluetoothPeripheralViewModel: BluetoothTransmitterDelegate {
|
||||
|
||||
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
|
||||
bluetoothTransmitterDelegate?.didConnectTo(bluetoothTransmitter: bluetoothTransmitter)
|
||||
}
|
||||
|
||||
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
|
||||
bluetoothTransmitterDelegate?.didDisconnectFrom(bluetoothTransmitter: bluetoothTransmitter)
|
||||
}
|
||||
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, bluetoothTransmitter: BluetoothTransmitter) {
|
||||
bluetoothTransmitterDelegate?.deviceDidUpdateBluetoothState(state: state, bluetoothTransmitter: bluetoothTransmitter)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extension M5StackBluetoothTransmitterDelegate
|
||||
|
||||
extension M5StackBluetoothPeripheralViewModel: M5StackBluetoothTransmitterDelegate {
|
||||
|
||||
func isAskingForAllParameters(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
// viewcontroller doesn't use this
|
||||
}
|
||||
|
||||
func isReadyToReceiveData(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
// viewcontroller doesn't use this
|
||||
}
|
||||
|
||||
func newBlePassWord(newBlePassword: String, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
|
||||
// note : blePassword is also saved in BluetoothPeripheralManager, it will be saved two times
|
||||
if let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack {
|
||||
|
||||
m5StackPeripheral.blepassword = newBlePassword
|
||||
|
||||
tableView?.reloadRows(at: [IndexPath(row: Setting.blePassword.rawValue + settingRowOffset, section: 0)], with: .none)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func authentication(success: Bool, m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
|
||||
if !success, let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack {
|
||||
|
||||
// show warning, inform that user should set password or reset M5Stack
|
||||
let alert = UIAlertController(title: Texts_Common.warning, message: Texts_M5StackView.authenticationFailureWarning + " " + Text_BluetoothPeripheralView.alwaysConnect, actionHandler: {
|
||||
|
||||
// by the time user clicks 'ok', the M5stack will be disconnected by the BluetoothPeripheralManager (see authentication in BluetoothPeripheralManager)
|
||||
self.bluetoothPeripheralViewController?.setShouldConnectToFalse(for: m5StackPeripheral)
|
||||
|
||||
})
|
||||
|
||||
bluetoothPeripheralViewController?.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func blePasswordMissing(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
|
||||
guard let m5StackPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack else {return}
|
||||
|
||||
// show warning, inform that user should set password
|
||||
let alert = UIAlertController(title: Texts_Common.warning, message: Texts_M5StackView.authenticationFailureWarning + " " + Text_BluetoothPeripheralView.alwaysConnect, actionHandler: {
|
||||
|
||||
// by the time user clicks 'ok', the M5stack will be disconnected by the BluetoothPeripheralManager (see authentication in BluetoothPeripheralManager)
|
||||
self.bluetoothPeripheralViewController?.setShouldConnectToFalse(for: m5StackPeripheral)
|
||||
|
||||
})
|
||||
|
||||
bluetoothPeripheralViewController?.present(alert, animated: true, completion: nil)
|
||||
|
||||
}
|
||||
|
||||
func m5StackResetRequired(m5StackBluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
|
||||
guard let m5StackBluetoothPeripheral = bluetoothPeripheralManager?.getBluetoothPeripheral(for: m5StackBluetoothTransmitter) as? M5Stack else {return}
|
||||
|
||||
// show warning, inform that user should reset M5Stack
|
||||
let alert = UIAlertController(title: Texts_Common.warning, message: Texts_M5StackView.m5StackResetRequiredWarning + " " + Text_BluetoothPeripheralView.alwaysConnect, actionHandler: {
|
||||
|
||||
// by the time user clicks 'ok', the M5stack will be disconnected by the BluetoothPeripheralManager (see authentication in BluetoothPeripheralManager)
|
||||
self.bluetoothPeripheralViewController?.setShouldConnectToFalse(for: m5StackBluetoothPeripheral)
|
||||
|
||||
})
|
||||
|
||||
bluetoothPeripheralViewController?.present(alert, animated: true, completion: nil)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extension BluetoothPeripheralViewModelProtocol
|
||||
|
||||
extension M5StackBluetoothPeripheralViewModel: BluetoothPeripheralViewModel {
|
||||
|
||||
func writeTempValues(to bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
guard let m5StackBluetoothPeripheral = bluetoothPeripheral as? M5Stack else {return}
|
||||
|
||||
if let textColorTemporaryValue = textColorTemporaryValue {
|
||||
m5StackBluetoothPeripheral.textcolor = Int32(textColorTemporaryValue.rawValue)
|
||||
}
|
||||
|
||||
if let rotation = rotationTempValue {
|
||||
m5StackBluetoothPeripheral.rotation = Int32(rotation)
|
||||
}
|
||||
|
||||
if let backGroundColor = backGroundColorTemporaryValue {
|
||||
m5StackBluetoothPeripheral.backGroundColor = Int32(backGroundColor.rawValue)
|
||||
}
|
||||
|
||||
if let brightness = brightnessTemporaryValue {
|
||||
m5StackBluetoothPeripheral.brightness = Int16(brightness)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func storeTempValues(from bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
guard let m5StackBluetoothPeripheral = bluetoothPeripheral as? M5Stack else {return}
|
||||
|
||||
// temporary store the value of textColor, user can change this via the view, it will be stored back in the m5StackASNSObject only after clicking 'done' button
|
||||
textColorTemporaryValue = M5StackColor(forUInt16: UInt16(m5StackBluetoothPeripheral.textcolor))
|
||||
|
||||
// temporary store the value of rotation, user can change this via the view, it will be stored back in the m5StackASNSObject only after clicking 'done' button
|
||||
rotationTempValue = UInt16(m5StackBluetoothPeripheral.rotation)
|
||||
|
||||
// temporary store the value of backGroundColor, user can change this via the view, it will be stored back in the m5StackASNSObject only after clicking 'done' button
|
||||
backGroundColorTemporaryValue = M5StackColor(forUInt16: UInt16(m5StackBluetoothPeripheral.backGroundColor))
|
||||
|
||||
// temporary store the value of brightness, user can change this via the view, it will be stored back in the m5StackASNSObject only after clicking 'done' button
|
||||
brightnessTemporaryValue = Int(m5StackBluetoothPeripheral.brightness)
|
||||
|
||||
}
|
||||
|
||||
func numberOfSettings() -> Int {
|
||||
return Setting.allCases.count
|
||||
}
|
||||
|
||||
func userDidSelectRow(withSettingRawValue rawValue: Int, for bluetoothPeripheral: BluetoothPeripheral, bluetoothPeripheralManager: BluetoothPeripheralManaging, doneButtonOutlet: UIBarButtonItem) {
|
||||
|
||||
guard let setting = Setting(rawValue: rawValue) else { fatalError("M5StackBluetoothPeripheralViewModel userDidSelectRow, unexpected setting") }
|
||||
|
||||
switch setting {
|
||||
|
||||
case .blePassword:
|
||||
break
|
||||
|
||||
case .textColor:
|
||||
var texts = [String]()
|
||||
var colors = [M5StackColor]()
|
||||
for textColor in M5StackColor.allCases {
|
||||
texts.append(textColor.description)
|
||||
colors.append(textColor)
|
||||
}
|
||||
|
||||
//find index for color stored in M5Stack or userdefaults
|
||||
var selectedRow:Int?
|
||||
if let textColor = textColorTemporaryValue {
|
||||
selectedRow = texts.firstIndex(of:textColor.description)
|
||||
} else if let textColor = UserDefaults.standard.m5StackTextColor?.description {
|
||||
selectedRow = texts.firstIndex(of:textColor)
|
||||
}
|
||||
|
||||
// configure PickerViewData
|
||||
let pickerViewData = PickerViewData(withMainTitle: nil, withSubTitle: Texts_SettingsView.m5StackTextColor, withData: texts, selectedRow: selectedRow, withPriority: nil, actionButtonText: nil, cancelButtonText: nil, onActionClick: {(_ index: Int) in
|
||||
|
||||
if index != selectedRow {
|
||||
|
||||
// set temp value textColor to new textColor
|
||||
self.textColorTemporaryValue = colors[index]
|
||||
|
||||
// send value to M5Stack, if that would fail then set updateNeeded for that m5Stack
|
||||
if let m5StackPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
if let textColor = self.textColorTemporaryValue, let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5StackPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter, m5StackBluetoothTransmitter.writeTextColor(textColor: textColor) {
|
||||
// do nothing, textColor successfully written to m5Stack - although it's not yet 100% sure because
|
||||
} else {
|
||||
m5StackPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
}
|
||||
|
||||
// reload table
|
||||
self.tableView?.reloadRows(at: [IndexPath(row: Setting.textColor.rawValue + self.settingRowOffset, section: 0)], with: .none)
|
||||
|
||||
// enable the done button
|
||||
doneButtonOutlet.enable()
|
||||
|
||||
}
|
||||
|
||||
}, onCancelClick: nil, didSelectRowHandler: nil)
|
||||
|
||||
// create and present PickerViewController
|
||||
if let bluetoothPeripheralViewController = bluetoothPeripheralViewController {
|
||||
PickerViewController.displayPickerViewController(pickerViewData: pickerViewData, parentController: bluetoothPeripheralViewController)
|
||||
}
|
||||
|
||||
case .backGroundColor:
|
||||
var texts = [String]()
|
||||
var colors = [M5StackColor]()
|
||||
for backGroundColor in M5StackColor.allCases {
|
||||
texts.append(backGroundColor.description)
|
||||
colors.append(backGroundColor)
|
||||
}
|
||||
|
||||
//find index for color stored in M5Stack or userdefaults
|
||||
var selectedRow:Int?
|
||||
if let backGroundColor = backGroundColorTemporaryValue {
|
||||
// backGroundColor is an instance of textColor, description gives us the textual representation
|
||||
selectedRow = texts.firstIndex(of:backGroundColor.description)
|
||||
} else {
|
||||
selectedRow = texts.firstIndex(of:ConstantsM5Stack.defaultBackGroundColor.description)
|
||||
}
|
||||
|
||||
// configure PickerViewData
|
||||
let pickerViewData = PickerViewData(withMainTitle: nil, withSubTitle: Texts_SettingsView.m5StackbackGroundColor, withData: texts, selectedRow: selectedRow, withPriority: nil, actionButtonText: nil, cancelButtonText: nil, onActionClick: {(_ index: Int) in
|
||||
|
||||
if index != selectedRow {
|
||||
|
||||
// set temp value backGroundColor to new backGroundColor
|
||||
self.backGroundColorTemporaryValue = colors[index]
|
||||
|
||||
// send value to M5Stack, if that would fail then set updateNeeded for that m5Stack
|
||||
if let m5StackPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
if let backGroundColor = self.backGroundColorTemporaryValue, let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5StackPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter, m5StackBluetoothTransmitter.writeBackGroundColor(backGroundColor: backGroundColor) {
|
||||
// do nothing, backGroundColor successfully written to m5Stack - although it's not yet 100% sure because write returns true without waiting for response from bluetooth peripheral
|
||||
} else {
|
||||
m5StackPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
}
|
||||
|
||||
// reload table
|
||||
self.tableView?.reloadRows(at: [IndexPath(row: Setting.backGroundColor.rawValue + self.settingRowOffset, section: 0)], with: .none)
|
||||
|
||||
// enable the done button
|
||||
doneButtonOutlet.enable()
|
||||
|
||||
}
|
||||
|
||||
}, onCancelClick: nil, didSelectRowHandler: nil)
|
||||
|
||||
// create and present PickerViewController
|
||||
if let bluetoothPeripheralViewController = bluetoothPeripheralViewController {
|
||||
PickerViewController.displayPickerViewController(pickerViewData: pickerViewData, parentController: bluetoothPeripheralViewController)
|
||||
}
|
||||
|
||||
case .rotation:
|
||||
//find index for rotation stored in M5Stack or userdefaults
|
||||
var selectedRow:Int? = nil
|
||||
if let rotation = rotationTempValue {
|
||||
selectedRow = Int(rotation)
|
||||
} else {
|
||||
selectedRow = Int(ConstantsM5Stack.defaultRotation)
|
||||
}
|
||||
|
||||
// configure PickerViewData
|
||||
let pickerViewData = PickerViewData(withMainTitle: nil, withSubTitle: Texts_SettingsView.m5StackRotation, withData: rotationStrings, selectedRow: selectedRow, withPriority: nil, actionButtonText: nil, cancelButtonText: nil, onActionClick: {(_ index: Int) in
|
||||
|
||||
if index != selectedRow {
|
||||
|
||||
// set rotationTempValue to new rotation
|
||||
self.rotationTempValue = UInt16(index)
|
||||
|
||||
// send value to M5Stack, if that would fail then set updateNeeded for that m5Stack
|
||||
if let m5StackAsPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5StackAsPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter, m5StackBluetoothTransmitter.writeRotation(rotation: index) {
|
||||
// do nothing, rotation successfully written to m5Stack - although it's not yet 100% sure because write returns true without waiting for response from bluetooth peripheral
|
||||
} else {
|
||||
m5StackAsPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
}
|
||||
|
||||
// reload table
|
||||
self.tableView?.reloadRows(at: [IndexPath(row: Setting.rotation.rawValue + self.settingRowOffset, section: 0)], with: .none)
|
||||
|
||||
// enable the done button
|
||||
doneButtonOutlet.enable()
|
||||
|
||||
}
|
||||
|
||||
}, onCancelClick: nil, didSelectRowHandler: nil)
|
||||
|
||||
// create and present PickerViewController
|
||||
if let bluetoothPeripheralViewController = bluetoothPeripheralViewController {
|
||||
PickerViewController.displayPickerViewController(pickerViewData: pickerViewData, parentController: bluetoothPeripheralViewController)
|
||||
}
|
||||
|
||||
case .brightness:
|
||||
|
||||
//find index for brightness stored in M5Stack or use 100 as default value
|
||||
var selectedRow:Int? = nil
|
||||
// brightness goes from 0 to 100, in steps of 10. Dividing by 10 gives the selected row
|
||||
if let brightness = brightnessTemporaryValue {
|
||||
selectedRow = brightness/10
|
||||
} else {
|
||||
// default value is 100
|
||||
selectedRow = 10
|
||||
}
|
||||
|
||||
// configure PickerViewData
|
||||
let pickerViewData = PickerViewData(withMainTitle: nil, withSubTitle: Texts_SettingsView.m5StackBrightness, withData: brightnessStrings, selectedRow: selectedRow, withPriority: nil, actionButtonText: nil, cancelButtonText: nil, onActionClick: {(_ index: Int) in
|
||||
|
||||
if index != selectedRow {
|
||||
|
||||
// set rotationTempValue to new rotation
|
||||
self.brightnessTemporaryValue = index * 10
|
||||
|
||||
// send value to M5Stack, if that would fail then set updateNeeded for that m5Stack
|
||||
if let m5StackPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
if let blueToothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: m5StackPeripheral, createANewOneIfNecesssary: false), let m5StackBluetoothTransmitter = blueToothTransmitter as? M5StackBluetoothTransmitter, m5StackBluetoothTransmitter.writeBrightness(brightness: index * 10) {
|
||||
// do nothing, brightness successfully written to m5Stack - although it's not yet 100% sure because write returns true without waiting for response from bluetooth peripheral
|
||||
} else {
|
||||
m5StackPeripheral.parameterUpdateNeededAtNextConnect()
|
||||
}
|
||||
}
|
||||
|
||||
// reload table
|
||||
self.tableView?.reloadRows(at: [IndexPath(row: Setting.brightness.rawValue + self.settingRowOffset, section: 0)], with: .none)
|
||||
|
||||
// enable the done button
|
||||
doneButtonOutlet.enable()
|
||||
|
||||
}
|
||||
|
||||
}, onCancelClick: nil, didSelectRowHandler: nil)
|
||||
|
||||
// create and present PickerViewController
|
||||
if let bluetoothPeripheralViewController = bluetoothPeripheralViewController {
|
||||
PickerViewController.displayPickerViewController(pickerViewData: pickerViewData, parentController: bluetoothPeripheralViewController)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
func update(cell: UITableViewCell, withSettingRawValue rawValue: Int, for bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
// verify that rawValue is within range of setting
|
||||
guard let setting = Setting(rawValue: rawValue) else { fatalError("M5StackBluetoothPeripheralViewModel update, Unexpected setting")
|
||||
}
|
||||
|
||||
// verify that bluetoothPeripheralAsNSObject is an M5Stack
|
||||
guard let m5Stack = bluetoothPeripheral as? M5Stack else {
|
||||
fatalError("M5StackBluetoothPeripheralViewModel update, bluetoothPeripheral is not M5Stack")
|
||||
}
|
||||
|
||||
// default value for accessoryView is nil
|
||||
cell.accessoryView = nil
|
||||
|
||||
// configure the cell depending on setting
|
||||
switch setting {
|
||||
|
||||
case .blePassword:
|
||||
cell.textLabel?.text = Texts_Common.password
|
||||
cell.detailTextLabel?.text = m5Stack.blepassword
|
||||
cell.accessoryType = .none
|
||||
|
||||
case .textColor:
|
||||
cell.textLabel?.text = Texts_SettingsView.m5StackTextColor
|
||||
|
||||
if let textColor = textColorTemporaryValue {
|
||||
cell.detailTextLabel?.text = textColor.description
|
||||
} else {
|
||||
if let textColor = UserDefaults.standard.m5StackTextColor {
|
||||
cell.detailTextLabel?.text = textColor.description
|
||||
} else {
|
||||
cell.detailTextLabel?.text = ConstantsM5Stack.defaultTextColor.description
|
||||
}
|
||||
}
|
||||
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .backGroundColor:
|
||||
cell.textLabel?.text = Texts_SettingsView.m5StackbackGroundColor
|
||||
|
||||
if let backGroundColor = backGroundColorTemporaryValue {
|
||||
cell.detailTextLabel?.text = backGroundColor.description
|
||||
} else {
|
||||
cell.detailTextLabel?.text = ConstantsM5Stack.defaultBackGroundColor.description
|
||||
}
|
||||
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .rotation:
|
||||
cell.textLabel?.text = Texts_SettingsView.m5StackRotation
|
||||
|
||||
if let rotation = rotationTempValue {
|
||||
cell.detailTextLabel?.text = rotationStrings[Int(rotation)]
|
||||
} else {
|
||||
cell.detailTextLabel?.text = rotationStrings[Int(ConstantsM5Stack.defaultRotation)]
|
||||
}
|
||||
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
case .brightness:
|
||||
cell.textLabel?.text = Texts_SettingsView.m5StackBrightness
|
||||
|
||||
if let brightness = brightnessTemporaryValue {
|
||||
cell.detailTextLabel?.text = brightnessStrings[Int(brightness/10)]
|
||||
} else {
|
||||
cell.detailTextLabel?.text = brightnessStrings[brightnessStrings.count - 1]
|
||||
}
|
||||
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func doneButtonHandler(bluetoothPeripheral: BluetoothPeripheral?) {
|
||||
|
||||
if let bluetoothPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
|
||||
// store value of textColor
|
||||
if let textColor = textColorTemporaryValue {
|
||||
bluetoothPeripheral.textcolor = Int32(textColor.rawValue)
|
||||
}
|
||||
|
||||
// store value of backGroundColor
|
||||
if let backGroundColor = backGroundColorTemporaryValue {
|
||||
bluetoothPeripheral.backGroundColor = Int32(backGroundColor.rawValue)
|
||||
}
|
||||
|
||||
// store value of rotation
|
||||
if let rotation = rotationTempValue {
|
||||
bluetoothPeripheral.rotation = Int32(rotation)
|
||||
}
|
||||
|
||||
// store value of brightness
|
||||
if let brightness = brightnessTemporaryValue {
|
||||
bluetoothPeripheral.brightness = Int16(brightness)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func screenTitle() -> String {
|
||||
Texts_M5StackView.screenTitle
|
||||
}
|
||||
|
||||
/// - 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
|
||||
/// - settingRowOffset :needs to be set to number of generic settings in BluetoothPeripheralViewController
|
||||
func configure(bluetoothPeripheral: BluetoothPeripheral?, bluetoothPeripheralManager: BluetoothPeripheralManaging, tableView: UITableView, bluetoothPeripheralViewController: BluetoothPeripheralViewController, settingRowOffset:Int, bluetoothTransmitterDelegate: BluetoothTransmitterDelegate) {
|
||||
|
||||
self.bluetoothPeripheralManager = bluetoothPeripheralManager
|
||||
|
||||
self.tableView = tableView
|
||||
|
||||
self.bluetoothPeripheralViewController = bluetoothPeripheralViewController
|
||||
|
||||
self.settingRowOffset = settingRowOffset
|
||||
|
||||
self.bluetoothTransmitterDelegate = bluetoothTransmitterDelegate
|
||||
|
||||
if let bluetoothPeripheral = bluetoothPeripheral as? M5Stack {
|
||||
|
||||
storeTempValues(from: bluetoothPeripheral)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import UIKit
|
||||
import CoreBluetooth
|
||||
|
||||
/// uiviewcontroller to show list of M5Stacks, first uiviewcontroller when clicking the M5Stack tab
|
||||
/// uiviewcontroller to show list of BluetoothPeripherals, first uiviewcontroller when clicking the BluetoothPeripheral tab
|
||||
final class BluetoothPeripheralsViewController: UIViewController {
|
||||
|
||||
// MARK: - IBOutlet's and IBAction's
|
||||
|
@ -14,8 +14,8 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
|
||||
@IBAction func unwindToBluetoothPeripheralsViewController (segue: UIStoryboardSegue) {
|
||||
|
||||
// reinitialise m5Stacks because we're coming back from M5StackViewController where an M5Stack may have been added or deleted
|
||||
initializeM5Stacks()
|
||||
// reinitialise bluetoothPeripherals because we're coming back from BluetoothPeripheralViewController where a BluetoothPeripheral may have been added or deleted
|
||||
initializeBluetoothPeripherals()
|
||||
|
||||
// reload the table
|
||||
tableView.reloadSections(IndexSet(integer: 0), with: .none)
|
||||
|
@ -27,11 +27,8 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
private var coreDataManager:CoreDataManager?
|
||||
|
||||
/// a bluetoothPeripheralManager
|
||||
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging?
|
||||
|
||||
/// list of M5Stack's
|
||||
private var m5Stacks: [M5Stack] = []
|
||||
|
||||
private weak var bluetoothPeripheralManager: BluetoothPeripheralManaging!
|
||||
|
||||
// MARK: public functions
|
||||
|
||||
/// configure
|
||||
|
@ -40,7 +37,7 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
// initalize private properties
|
||||
self.coreDataManager = coreDataManager
|
||||
self.bluetoothPeripheralManager = bluetoothPeripheralManager
|
||||
initializeM5Stacks()
|
||||
initializeBluetoothPeripherals()
|
||||
|
||||
}
|
||||
|
||||
|
@ -50,9 +47,10 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
|
||||
super.viewDidLoad()
|
||||
|
||||
title = Texts_M5StacksView.screenTitle
|
||||
title = Texts_BluetoothPeripheralsView.screenTitle
|
||||
|
||||
setupView()
|
||||
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
|
@ -67,12 +65,13 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
|
||||
switch segueIdentifierAsCase {
|
||||
|
||||
case BluetoothPeripheralViewController.SegueIdentifiers.M5StacksToM5StackSegueIdentifier:
|
||||
guard let vc = segue.destination as? BluetoothPeripheralViewController, let coreDataManager = coreDataManager, let bluetoothPeripheralManager = bluetoothPeripheralManager else {
|
||||
fatalError("In BluetoothPeripheralsViewController, prepare for segue, viewcontroller is not M5StackViewController or coreDataManager is nil or bluetoothPeripheralManager is nil" )
|
||||
case BluetoothPeripheralViewController.SegueIdentifiers.BluetoothPeripheralsToBluetoothPeripheralSegueIdentifier:
|
||||
guard let vc = segue.destination as? BluetoothPeripheralViewController, let coreDataManager = coreDataManager else {
|
||||
fatalError("In BluetoothPeripheralsViewController, prepare for segue, viewcontroller is not BluetoothPeripheralViewController or coreDataManager is nil" )
|
||||
}
|
||||
|
||||
vc.configure(m5Stack: sender as? M5Stack, coreDataManager: coreDataManager, bluetoothPeripheralManager: bluetoothPeripheralManager)
|
||||
vc.configure(bluetoothPeripheral: sender as? BluetoothPeripheral, coreDataManager: coreDataManager, bluetoothPeripheralManager: bluetoothPeripheralManager, expectedBluetoothPeripheralType: .M5Stack)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,8 +82,8 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
/// user clicked add button
|
||||
private func addButtonAction() {
|
||||
|
||||
/// go to screen to add a new M5Stack
|
||||
self.performSegue(withIdentifier: BluetoothPeripheralViewController.SegueIdentifiers.M5StacksToM5StackSegueIdentifier.rawValue, sender: nil)
|
||||
/// go to screen to add a new BluetoothPeripheral
|
||||
self.performSegue(withIdentifier: BluetoothPeripheralViewController.SegueIdentifiers.BluetoothPeripheralsToBluetoothPeripheralSegueIdentifier.rawValue, sender: nil)
|
||||
|
||||
}
|
||||
|
||||
|
@ -109,30 +108,27 @@ final class BluetoothPeripheralsViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
/// calls tableView.reloadRows for the row where forM5Stack is shown
|
||||
private func updateRow(forM5Stack m5Stack: M5Stack) {
|
||||
/// calls tableView.reloadRows for the row where bluetoothPeripheral is shown
|
||||
private func updateRow(for bluetoothPeripheral: BluetoothPeripheral) {
|
||||
|
||||
if let index = m5Stacks.firstIndex(of: m5Stack) {
|
||||
if let index = bluetoothPeripheralManager.getBluetoothPeripherals().firstIndex(where: {$0.getAddress() == bluetoothPeripheral.getAddress()}) {
|
||||
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// initializes m5Stacks array
|
||||
private func initializeM5Stacks() {
|
||||
/// initializes bluetoothPeripherals
|
||||
/// - sets the delegates of each transmitter to self
|
||||
private func initializeBluetoothPeripherals() {
|
||||
|
||||
if let bluetoothPeripheralManager = bluetoothPeripheralManager {
|
||||
m5Stacks = bluetoothPeripheralManager.m5Stacks()
|
||||
for bluetoothtTransmitter in bluetoothPeripheralManager.getBluetoothTransmitters() {
|
||||
|
||||
for m5Stack in m5Stacks {
|
||||
bluetoothPeripheralManager.m5StackBluetoothTransmitter(forM5stack: m5Stack, createANewOneIfNecesssary: false)?.m5StackBluetoothTransmitterDelegateVariable = self
|
||||
}
|
||||
bluetoothtTransmitter.variableBluetoothTransmitterDelegate = self
|
||||
|
||||
} else {// should never happen or it would be a coding error, but let's assign to empty string
|
||||
m5Stacks = []
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// MARK: - extensions
|
||||
|
@ -144,7 +140,7 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
|
|||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
// add 1 for the row that will show help info
|
||||
return m5Stacks.count + 1
|
||||
return bluetoothPeripheralManager.getBluetoothPeripherals().count + 1
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
@ -152,27 +148,27 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
|
|||
guard let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.reuseIdentifier, for: indexPath) as? SettingsTableViewCell else { fatalError("Unexpected Table View Cell") }
|
||||
|
||||
// the last row is the help info
|
||||
if indexPath.row == m5Stacks.count {
|
||||
if indexPath.row == bluetoothPeripheralManager.getBluetoothPeripherals().count {
|
||||
|
||||
cell.textLabel?.text = Texts_M5StacksView.m5StackSoftWareHelpCellText
|
||||
cell.textLabel?.text = Texts_M5StackView.m5StackSoftWareHelpCellText
|
||||
cell.detailTextLabel?.text = nil
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
return cell
|
||||
|
||||
}
|
||||
|
||||
// textLabel should be the userdefinedname of the M5Stack, or if userdefinedname == nil, then the address
|
||||
cell.textLabel?.text = m5Stacks[indexPath.row].m5StackName?.userDefinedName
|
||||
// textLabel should be the user defined alias of the BluetoothPeripheral, or if user defined alias == nil, then the devicename
|
||||
cell.textLabel?.text = bluetoothPeripheralManager.getBluetoothPeripherals()[indexPath.row].getAlias()
|
||||
if cell.textLabel?.text == nil {
|
||||
cell.textLabel?.text = m5Stacks[indexPath.row].address
|
||||
cell.textLabel?.text = bluetoothPeripheralManager.getBluetoothPeripherals()[indexPath.row].getDeviceName()
|
||||
}
|
||||
|
||||
// detail is the connection status
|
||||
cell.detailTextLabel?.text = Texts_M5StackView.notConnected // start with not connected
|
||||
if let bluetoothTransmitter = bluetoothPeripheralManager?.m5StackBluetoothTransmitter(forM5stack: m5Stacks[indexPath.row], createANewOneIfNecesssary: false) {
|
||||
cell.detailTextLabel?.text = Text_BluetoothPeripheralView.notConnected // start with not connected
|
||||
if let bluetoothTransmitter = bluetoothPeripheralManager.getBluetoothTransmitter(for: bluetoothPeripheralManager.getBluetoothPeripherals()[indexPath.row], createANewOneIfNecesssary: false) {
|
||||
|
||||
if let connectionStatus = bluetoothTransmitter.getConnectionStatus(), connectionStatus == CBPeripheralState.connected {
|
||||
cell.detailTextLabel?.text = Texts_M5StackView.connected
|
||||
cell.detailTextLabel?.text = Text_BluetoothPeripheralView.connected
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -184,7 +180,7 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
|
|||
}
|
||||
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
// only 1 section, namely the list of M5Stacks
|
||||
// only 1 section, namely the list of BluetoothPeripherals
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -193,15 +189,15 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
|
|||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
|
||||
// the last row is the help info
|
||||
if indexPath.row == m5Stacks.count {
|
||||
if indexPath.row == bluetoothPeripheralManager.getBluetoothPeripherals().count {
|
||||
|
||||
let alert = UIAlertController(title: Texts_HomeView.info, message: Texts_M5StacksView.m5StackSoftWareHelpText + " " + ConstantsM5Stack.githubURLM5Stack, actionHandler: nil)
|
||||
let alert = UIAlertController(title: Texts_HomeView.info, message: Texts_M5StackView.m5StackSoftWareHelpText + " " + ConstantsM5Stack.githubURLM5Stack, actionHandler: nil)
|
||||
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
|
||||
} else {
|
||||
|
||||
self.performSegue(withIdentifier: BluetoothPeripheralViewController.SegueIdentifiers.M5StacksToM5StackSegueIdentifier.rawValue, sender: m5Stacks[indexPath.row])
|
||||
self.performSegue(withIdentifier: BluetoothPeripheralViewController.SegueIdentifiers.BluetoothPeripheralsToBluetoothPeripheralSegueIdentifier.rawValue, sender: bluetoothPeripheralManager.getBluetoothPeripherals()[indexPath.row])
|
||||
|
||||
}
|
||||
|
||||
|
@ -209,65 +205,31 @@ extension BluetoothPeripheralsViewController: UITableViewDataSource, UITableView
|
|||
|
||||
}
|
||||
|
||||
// MARK: extension M5StackBluetoothDelegate
|
||||
// MARK: - extension BluetoothTransmitterDelegate
|
||||
|
||||
extension BluetoothPeripheralsViewController: M5StackBluetoothDelegate {
|
||||
extension BluetoothPeripheralsViewController: BluetoothTransmitterDelegate {
|
||||
|
||||
func isAskingForAllParameters(m5Stack: M5Stack) {
|
||||
// viewcontroller doesn't use this
|
||||
}
|
||||
|
||||
func isReadyToReceiveData(m5Stack: M5Stack) {
|
||||
// viewcontroller doesn't use this
|
||||
}
|
||||
|
||||
func newBlePassWord(newBlePassword: String, forM5Stack m5Stack: M5Stack) {
|
||||
func didConnectTo(bluetoothTransmitter: BluetoothTransmitter) {
|
||||
|
||||
// blePassword is also saved in BluetoothPerpheralManager, tant pis
|
||||
m5Stack.blepassword = newBlePassword
|
||||
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))
|
||||
|
||||
}
|
||||
|
||||
func authentication(success: Bool, forM5Stack m5Stack: M5Stack) {
|
||||
// no further handling, means when this view is open, user won't see that authentication is failing
|
||||
}
|
||||
|
||||
func blePasswordMissing(forM5Stack m5Stack: M5Stack) {
|
||||
// no further handling, means when this view is open, user won't see that ble password is missing
|
||||
}
|
||||
|
||||
func m5StackResetRequired(forM5Stack m5Stack: M5Stack) {
|
||||
// no further handling, means when this view is open, user won't see that reset is required
|
||||
}
|
||||
|
||||
func didConnect(forM5Stack m5Stack: M5Stack?, address: String?, name: String?, bluetoothTransmitter: M5StackBluetoothTransmitter) {
|
||||
func didDisconnectFrom(bluetoothTransmitter: BluetoothTransmitter) {
|
||||
|
||||
if let m5Stack = m5Stack {
|
||||
updateRow(forM5Stack: m5Stack)
|
||||
}
|
||||
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))
|
||||
|
||||
}
|
||||
|
||||
func didDisconnect(forM5Stack m5Stack: M5Stack) {
|
||||
|
||||
updateRow(forM5Stack: m5Stack)
|
||||
|
||||
}
|
||||
|
||||
func deviceDidUpdateBluetoothState(state: CBManagerState, forM5Stack m5Stack: M5Stack) {
|
||||
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
|
||||
if state == CBManagerState.poweredOff {
|
||||
updateRow(forM5Stack: m5Stack)
|
||||
updateRow(for: bluetoothPeripheralManager.getBluetoothPeripheral(for: bluetoothTransmitter))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func error(message: String) {
|
||||
// no further handling, means when this view is open, user won't see the error message
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue