Merge branch '2.3.12_Working_Changes' into fetch-request-api

This commit is contained in:
Blake McAnally 2024-06-28 11:49:24 -05:00 committed by GitHub
commit bc77834a86
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
125 changed files with 5329 additions and 3092 deletions

View file

@ -1,6 +1,6 @@
# Exclude automatically generated Swift files
excluded:
- Meshtastic/Protobufs
- MeshtasticProtobufs
line_length: 400

View file

@ -3,11 +3,16 @@
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
25183D462C0A6D97001E31D5 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25183D452C0A6D97001E31D5 /* Logger.swift */; };
259792252C2F114500AD1659 /* ChannelEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */; };
259792262C2F114500AD1659 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
259792272C2F114500AD1659 /* TraceRouteEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */; };
259792282C2F114500AD1659 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25183D452C0A6D97001E31D5 /* Logger.swift */; };
25A978BA2C13F8ED0003AAE7 /* MeshtasticProtobufs in Frameworks */ = {isa = PBXBuildFile; productRef = 25A978B92C13F8ED0003AAE7 /* MeshtasticProtobufs */; };
25A978BC2C13F90D0003AAE7 /* MeshtasticProtobufs in Frameworks */ = {isa = PBXBuildFile; productRef = 25A978BB2C13F90D0003AAE7 /* MeshtasticProtobufs */; };
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; };
6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; };
6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; };
@ -29,11 +34,7 @@
DD007BAE2AA4E91200F5FA12 /* MyInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */; };
DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */; };
DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */ = {isa = PBXBuildFile; productRef = DD0D3D212A55CEB10066DB71 /* CocoaMQTT */; };
DD0E20FC2B87090400F2D100 /* atak.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0E20F92B87090400F2D100 /* atak.pb.swift */; };
DD0E20FD2B87090400F2D100 /* clientonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0E20FA2B87090400F2D100 /* clientonly.pb.swift */; };
DD0E20FE2B87090400F2D100 /* paxcount.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0E20FB2B87090400F2D100 /* paxcount.pb.swift */; };
DD0E21012B8A6F1300F2D100 /* DeviceHardware.json in Resources */ = {isa = PBXBuildFile; fileRef = DD0E21002B8A6BC500F2D100 /* DeviceHardware.json */; };
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */; };
DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD13AA482AB73BF400BA0C98 /* PositionPopover.swift */; };
DD15E4F32B8BA56E00654F61 /* PaxCounterConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD15E4F22B8BA56E00654F61 /* PaxCounterConfig.swift */; };
DD15E4F52B8BFC8E00654F61 /* PaxCounterLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD15E4F42B8BFC8E00654F61 /* PaxCounterLog.swift */; };
@ -68,27 +69,7 @@
DD4975A52B147BA90026544E /* AmbientLightingConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4975A42B147BA90026544E /* AmbientLightingConfig.swift */; };
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; };
DD4F23CD28779A3C001D37CB /* EnvironmentMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4F23CC28779A3C001D37CB /* EnvironmentMetricsLog.swift */; };
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; };
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
DD58C5F22919AD3C00D5BEFB /* ChannelEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD58C5F12919AD3C00D5BEFB /* ChannelEntityExtension.swift */; };
DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5D0A9B2931B9F200F7EA61 /* EthernetModes.swift */; };
DD5E5202298EE33B00D21B61 /* admin.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F0298EE33B00D21B61 /* admin.pb.swift */; };
DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F1298EE33B00D21B61 /* config.pb.swift */; };
DD5E5204298EE33B00D21B61 /* xmodem.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F2298EE33B00D21B61 /* xmodem.pb.swift */; };
DD5E5205298EE33B00D21B61 /* mesh.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F3298EE33B00D21B61 /* mesh.pb.swift */; };
DD5E5206298EE33B00D21B61 /* localonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F4298EE33B00D21B61 /* localonly.pb.swift */; };
DD5E5207298EE33B00D21B61 /* connection_status.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F5298EE33B00D21B61 /* connection_status.pb.swift */; };
DD5E5208298EE33B00D21B61 /* rtttl.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F6298EE33B00D21B61 /* rtttl.pb.swift */; };
DD5E5209298EE33B00D21B61 /* module_config.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F7298EE33B00D21B61 /* module_config.pb.swift */; };
DD5E520A298EE33B00D21B61 /* channel.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51F8298EE33B00D21B61 /* channel.pb.swift */; };
DD5E520C298EE33B00D21B61 /* portnums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FA298EE33B00D21B61 /* portnums.pb.swift */; };
DD5E520D298EE33B00D21B61 /* storeforward.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FB298EE33B00D21B61 /* storeforward.pb.swift */; };
DD5E520E298EE33B00D21B61 /* mqtt.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FC298EE33B00D21B61 /* mqtt.pb.swift */; };
DD5E520F298EE33B00D21B61 /* cannedmessages.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FD298EE33B00D21B61 /* cannedmessages.pb.swift */; };
DD5E5210298EE33B00D21B61 /* telemetry.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FE298EE33B00D21B61 /* telemetry.pb.swift */; };
DD5E5211298EE33B00D21B61 /* remote_hardware.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E51FF298EE33B00D21B61 /* remote_hardware.pb.swift */; };
DD5E5212298EE33B00D21B61 /* apponly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E5200298EE33B00D21B61 /* apponly.pb.swift */; };
DD5E5213298EE33B00D21B61 /* deviceonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E5201298EE33B00D21B61 /* deviceonly.pb.swift */; };
DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5E523E298F5A9E00D21B61 /* AirQualityIndex.swift */; };
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */; };
DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; };
@ -156,7 +137,6 @@
DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */; };
DDC2E15C26CE248F0042C5E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */; };
DDC2E15F26CE248F0042C5E4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15E26CE248F0042C5E4 /* Preview Assets.xcassets */; };
DDC2E17A26CE248F0042C5E4 /* MeshtasticUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E17926CE248F0042C5E4 /* MeshtasticUITests.swift */; };
DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E18E26CE25FE0042C5E4 /* ContentView.swift */; };
DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E1A626CEB3400042C5E4 /* LocationHelper.swift */; };
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC3B273283F411B00AC321C /* LastHeardText.swift */; };
@ -168,6 +148,11 @@
DDCDC6CB29481FCC004C1DDA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DDCDC6CD29481FCC004C1DDA /* Localizable.strings */; };
DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */; };
DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */; };
DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB082C285DDC007E03CA /* AppLog.swift */; };
DDD5BB0B2C285E45007E03CA /* LogDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB0A2C285E45007E03CA /* LogDetail.swift */; };
DDD5BB0D2C285F00007E03CA /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB0C2C285F00007E03CA /* Logger.swift */; };
DDD5BB102C285FB3007E03CA /* AppLogFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB0F2C285FB3007E03CA /* AppLogFilter.swift */; };
DDD5BB162C28B1E4007E03CA /* AppData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD5BB152C28B1E4007E03CA /* AppData.swift */; };
DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD6EEAE29BC024700383354 /* Firmware.swift */; };
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; };
DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; };
@ -177,7 +162,6 @@
DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26452AACC0B7003AFCB7 /* NodeInfoItem.swift */; };
DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB26472AACD6D1003AFCB7 /* NodeMapMapkit.swift */; };
DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443529F6287000EE2349 /* MapButtons.swift */; };
DDDB443D29F6592F00EE2349 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443C29F6592F00EE2349 /* NetworkManager.swift */; };
DDDB444029F79AB000EE2349 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB443F29F79AB000EE2349 /* UserDefaults.swift */; };
DDDB444229F8A88700EE2349 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB444129F8A88700EE2349 /* Double.swift */; };
DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDB444329F8A8DD00EE2349 /* Float.swift */; };
@ -203,7 +187,6 @@
DDDE5A1429AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; };
DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */; };
DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4032B2279A700FCDD05 /* TraceRouteLog.swift */; };
DDE5B4062B227E3200FCDD05 /* TraceRouteEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */; };
DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */; };
DDF45C342BC1A48E005ED5F2 /* MQTTIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */; };
DDF45C372BC46A5A005ED5F2 /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF45C362BC46A5A005ED5F2 /* TimeZone.swift */; };
@ -214,13 +197,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
DDC2E17626CE248F0042C5E4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DDC2E14C26CE248E0042C5E4 /* Project object */;
proxyType = 1;
remoteGlobalIDString = DDC2E15326CE248E0042C5E4;
remoteInfo = MeshtasticClient;
};
DDDE5A0129AF163E00490C6C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DDC2E14C26CE248E0042C5E4 /* Project object */;
@ -245,7 +221,6 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
25183D452C0A6D97001E31D5 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = "<group>"; };
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = "<group>"; };
6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = "<group>"; };
@ -268,13 +243,9 @@
DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoEntityExtension.swift; sourceTree = "<group>"; };
DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityExtension.swift; sourceTree = "<group>"; };
DD05296F2B77F454008E44CD /* MeshtasticDataModelV 26.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 26.xcdatamodel"; sourceTree = "<group>"; };
DD0E20F92B87090400F2D100 /* atak.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = atak.pb.swift; sourceTree = "<group>"; };
DD0E20FA2B87090400F2D100 /* clientonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = clientonly.pb.swift; sourceTree = "<group>"; };
DD0E20FB2B87090400F2D100 /* paxcount.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = paxcount.pb.swift; sourceTree = "<group>"; };
DD0E20FF2B892E1300F2D100 /* MeshtasticDataModelV 28.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 28.xcdatamodel"; sourceTree = "<group>"; };
DD0E21002B8A6BC500F2D100 /* DeviceHardware.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = DeviceHardware.json; sourceTree = "<group>"; };
DD0E9C222A30CE3A00580CBB /* MeshtasticDataModelV14.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV14.xcdatamodel; sourceTree = "<group>"; };
DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminMessageList.swift; sourceTree = "<group>"; };
DD13AA482AB73BF400BA0C98 /* PositionPopover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionPopover.swift; sourceTree = "<group>"; };
DD14E72C2A80738F006E39BC /* MeshtasticDataModelV15.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV15.xcdatamodel; sourceTree = "<group>"; };
DD15E4F22B8BA56E00654F61 /* PaxCounterConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaxCounterConfig.swift; sourceTree = "<group>"; };
@ -327,23 +298,6 @@
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV2.xcdatamodel; sourceTree = "<group>"; };
DD5D0A9B2931B9F200F7EA61 /* EthernetModes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthernetModes.swift; sourceTree = "<group>"; };
DD5E51CC2986643400D21B61 /* MeshtasticDataModelV7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV7.xcdatamodel; sourceTree = "<group>"; };
DD5E51F0298EE33B00D21B61 /* admin.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = admin.pb.swift; sourceTree = "<group>"; };
DD5E51F1298EE33B00D21B61 /* config.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = config.pb.swift; sourceTree = "<group>"; };
DD5E51F2298EE33B00D21B61 /* xmodem.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = xmodem.pb.swift; sourceTree = "<group>"; };
DD5E51F3298EE33B00D21B61 /* mesh.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = mesh.pb.swift; sourceTree = "<group>"; };
DD5E51F4298EE33B00D21B61 /* localonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = localonly.pb.swift; sourceTree = "<group>"; };
DD5E51F5298EE33B00D21B61 /* connection_status.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = connection_status.pb.swift; sourceTree = "<group>"; };
DD5E51F6298EE33B00D21B61 /* rtttl.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = rtttl.pb.swift; sourceTree = "<group>"; };
DD5E51F7298EE33B00D21B61 /* module_config.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = module_config.pb.swift; sourceTree = "<group>"; };
DD5E51F8298EE33B00D21B61 /* channel.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = channel.pb.swift; sourceTree = "<group>"; };
DD5E51FA298EE33B00D21B61 /* portnums.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = portnums.pb.swift; sourceTree = "<group>"; };
DD5E51FB298EE33B00D21B61 /* storeforward.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = storeforward.pb.swift; sourceTree = "<group>"; };
DD5E51FC298EE33B00D21B61 /* mqtt.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = mqtt.pb.swift; sourceTree = "<group>"; };
DD5E51FD298EE33B00D21B61 /* cannedmessages.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = cannedmessages.pb.swift; sourceTree = "<group>"; };
DD5E51FE298EE33B00D21B61 /* telemetry.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = telemetry.pb.swift; sourceTree = "<group>"; };
DD5E51FF298EE33B00D21B61 /* remote_hardware.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = remote_hardware.pb.swift; sourceTree = "<group>"; };
DD5E5200298EE33B00D21B61 /* apponly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = apponly.pb.swift; sourceTree = "<group>"; };
DD5E5201298EE33B00D21B61 /* deviceonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = deviceonly.pb.swift; sourceTree = "<group>"; };
DD5E523E298F5A9E00D21B61 /* AirQualityIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AirQualityIndex.swift; sourceTree = "<group>"; };
DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalNotificationConfig.swift; sourceTree = "<group>"; };
DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfig.swift; sourceTree = "<group>"; };
@ -422,10 +376,6 @@
DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../Assets.xcassets; sourceTree = "<group>"; };
DDC2E15E26CE248F0042C5E4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
DDC2E16526CE248F0042C5E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DDC2E17026CE248F0042C5E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MeshtasticUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DDC2E17926CE248F0042C5E4 /* MeshtasticUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticUITests.swift; sourceTree = "<group>"; };
DDC2E17B26CE248F0042C5E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DDC2E18E26CE25FE0042C5E4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
DDC2E1A626CEB3400042C5E4 /* LocationHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationHelper.swift; sourceTree = "<group>"; };
DDC3B273283F411B00AC321C /* LastHeardText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastHeardText.swift; sourceTree = "<group>"; };
@ -441,8 +391,13 @@
DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserConfig.swift; sourceTree = "<group>"; };
DDD28D362C0CCCD10063CFA3 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = "<group>"; };
DDD28D372C0CD2670063CFA3 /* MeshtasticDataModelV 37.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 37.xcdatamodel"; sourceTree = "<group>"; };
DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeshtasticTests.swift; sourceTree = "<group>"; };
DDD43FE22A78C8900083A3E9 /* MqttClientProxyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MqttClientProxyManager.swift; sourceTree = "<group>"; };
DDD5BB082C285DDC007E03CA /* AppLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLog.swift; sourceTree = "<group>"; };
DDD5BB0A2C285E45007E03CA /* LogDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDetail.swift; sourceTree = "<group>"; };
DDD5BB0C2C285F00007E03CA /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
DDD5BB0F2C285FB3007E03CA /* AppLogFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLogFilter.swift; sourceTree = "<group>"; };
DDD5BB142C28680D007E03CA /* MeshtasticDataModelV 38.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 38.xcdatamodel"; sourceTree = "<group>"; };
DDD5BB152C28B1E4007E03CA /* AppData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppData.swift; sourceTree = "<group>"; };
DDD6EEAE29BC024700383354 /* Firmware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firmware.swift; sourceTree = "<group>"; };
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
@ -453,7 +408,6 @@
DDDB26472AACD6D1003AFCB7 /* NodeMapMapkit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMapMapkit.swift; sourceTree = "<group>"; };
DDDB26492AAD743E003AFCB7 /* MeshtasticDataModelV18.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV18.xcdatamodel; sourceTree = "<group>"; };
DDDB443529F6287000EE2349 /* MapButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapButtons.swift; sourceTree = "<group>"; };
DDDB443C29F6592F00EE2349 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
DDDB443F29F79AB000EE2349 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = "<group>"; };
DDDB444129F8A88700EE2349 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
DDDB444329F8A8DD00EE2349 /* Float.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = "<group>"; };
@ -503,16 +457,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
25A978BA2C13F8ED0003AAE7 /* MeshtasticProtobufs in Frameworks */,
C9697FA527933B8C00250207 /* SQLite in Frameworks */,
DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */,
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DDC2E17226CE248F0042C5E4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -522,6 +469,7 @@
files = (
DDDE59F629AF163D00490C6C /* SwiftUI.framework in Frameworks */,
DDDE59F529AF163D00490C6C /* WidgetKit.framework in Frameworks */,
25A978BC2C13F90D0003AAE7 /* MeshtasticProtobufs in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -606,9 +554,11 @@
DD4A911C2708C57100501B7E /* Settings */ = {
isa = PBXGroup;
children = (
DDD5BB0E2C285F92007E03CA /* Logs */,
DD93800C2BA74CE3008BEC06 /* Channels */,
DD97E96728EFE9A00056DDA4 /* About.swift */,
DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */,
DDD5BB152C28B1E4007E03CA /* AppData.swift */,
DDD5BB082C285DDC007E03CA /* AppLog.swift */,
DD4A911D2708C65400501B7E /* AppSettings.swift */,
DDAB580C2B0DAA9E00147258 /* Routes.swift */,
DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */,
@ -626,33 +576,6 @@
path = Settings;
sourceTree = "<group>";
};
DD5E51EF298EE33B00D21B61 /* meshtastic */ = {
isa = PBXGroup;
children = (
DD0E20F92B87090400F2D100 /* atak.pb.swift */,
DD0E20FA2B87090400F2D100 /* clientonly.pb.swift */,
DD0E20FB2B87090400F2D100 /* paxcount.pb.swift */,
DD5E51F0298EE33B00D21B61 /* admin.pb.swift */,
DD5E51F1298EE33B00D21B61 /* config.pb.swift */,
DD5E51F2298EE33B00D21B61 /* xmodem.pb.swift */,
DD5E51F3298EE33B00D21B61 /* mesh.pb.swift */,
DD5E51F4298EE33B00D21B61 /* localonly.pb.swift */,
DD5E51F5298EE33B00D21B61 /* connection_status.pb.swift */,
DD5E51F6298EE33B00D21B61 /* rtttl.pb.swift */,
DD5E51F7298EE33B00D21B61 /* module_config.pb.swift */,
DD5E51F8298EE33B00D21B61 /* channel.pb.swift */,
DD5E51FA298EE33B00D21B61 /* portnums.pb.swift */,
DD5E51FB298EE33B00D21B61 /* storeforward.pb.swift */,
DD5E51FC298EE33B00D21B61 /* mqtt.pb.swift */,
DD5E51FD298EE33B00D21B61 /* cannedmessages.pb.swift */,
DD5E51FE298EE33B00D21B61 /* telemetry.pb.swift */,
DD5E51FF298EE33B00D21B61 /* remote_hardware.pb.swift */,
DD5E5200298EE33B00D21B61 /* apponly.pb.swift */,
DD5E5201298EE33B00D21B61 /* deviceonly.pb.swift */,
);
path = meshtastic;
sourceTree = "<group>";
};
DD5E523D298F5A7D00D21B61 /* Weather */ = {
isa = PBXGroup;
children = (
@ -774,14 +697,6 @@
path = Map;
sourceTree = "<group>";
};
DDAF8C5626ED07740058C060 /* Protobufs */ = {
isa = PBXGroup;
children = (
DD5E51EF298EE33B00D21B61 /* meshtastic */,
);
path = Protobufs;
sourceTree = "<group>";
};
DDB75A122A0593CD006ED576 /* Map */ = {
isa = PBXGroup;
children = (
@ -798,8 +713,6 @@
DDCDC6CD29481FCC004C1DDA /* Localizable.strings */,
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */,
DDC2E15626CE248E0042C5E4 /* Meshtastic */,
DDC2E16D26CE248F0042C5E4 /* MeshtasticTests */,
DDC2E17826CE248F0042C5E4 /* MeshtasticUITests */,
DDDE59F729AF163D00490C6C /* Widgets */,
DDC2E15526CE248E0042C5E4 /* Products */,
DD8EDE9226F97A2B00A5A10B /* Frameworks */,
@ -811,7 +724,6 @@
isa = PBXGroup;
children = (
DDC2E15426CE248E0042C5E4 /* Meshtastic.app */,
DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */,
DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */,
);
name = Products;
@ -828,7 +740,6 @@
DDC2E1A526CEB32B0042C5E4 /* Helpers */,
DDC2E18826CE24EE0042C5E4 /* Model */,
DDC4D5662754996200A4208E /* Persistence */,
DDAF8C5626ED07740058C060 /* Protobufs */,
DDC2E18926CE24F70042C5E4 /* Resources */,
DDC2E18726CE24E40042C5E4 /* Views */,
DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */,
@ -847,24 +758,6 @@
path = "Preview Content";
sourceTree = "<group>";
};
DDC2E16D26CE248F0042C5E4 /* MeshtasticTests */ = {
isa = PBXGroup;
children = (
DDD3BBD4292D763200D609B3 /* MeshtasticTests.swift */,
DDC2E17026CE248F0042C5E4 /* Info.plist */,
);
path = MeshtasticTests;
sourceTree = "<group>";
};
DDC2E17826CE248F0042C5E4 /* MeshtasticUITests */ = {
isa = PBXGroup;
children = (
DDC2E17926CE248F0042C5E4 /* MeshtasticUITests.swift */,
DDC2E17B26CE248F0042C5E4 /* Info.plist */,
);
path = MeshtasticUITests;
sourceTree = "<group>";
};
DDC2E18726CE24E40042C5E4 /* Views */ = {
isa = PBXGroup;
children = (
@ -917,19 +810,19 @@
DDC2E18D26CE25CB0042C5E4 /* Helpers */ = {
isa = PBXGroup;
children = (
DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */,
DD5E523D298F5A7D00D21B61 /* Weather */,
DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */,
DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */,
DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */,
DD47E3D526F17ED900029299 /* CircleText.swift */,
DDF924C926FBB953009FE055 /* ConnectedDevice.swift */,
DDC3B273283F411B00AC321C /* LastHeardText.swift */,
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */,
DDB6ABDA28B0AC6000384BA1 /* DistanceText.swift */,
DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */,
DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */,
DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */,
DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */,
DDC3B273283F411B00AC321C /* LastHeardText.swift */,
DDB75A202A12B954006ED576 /* LoRaSignalStrength.swift */,
DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */,
DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */,
DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */,
DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */,
DD5E523D298F5A7D00D21B61 /* Weather */,
);
path = Helpers;
sourceTree = "<group>";
@ -945,9 +838,7 @@
DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */,
DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */,
DD964FBC296E6B01007C176F /* EmojiOnlyTextField.swift */,
DDDB443C29F6592F00EE2349 /* NetworkManager.swift */,
DD3619142B1EF9F900C41C8C /* LocationsHandler.swift */,
25183D452C0A6D97001E31D5 /* Logger.swift */,
);
path = Helpers;
sourceTree = "<group>";
@ -970,6 +861,15 @@
path = Mqtt;
sourceTree = "<group>";
};
DDD5BB0E2C285F92007E03CA /* Logs */ = {
isa = PBXGroup;
children = (
DDD5BB0A2C285E45007E03CA /* LogDetail.swift */,
DDD5BB0F2C285FB3007E03CA /* AppLogFilter.swift */,
);
path = Logs;
sourceTree = "<group>";
};
DDDB26402AABEF7B003AFCB7 /* Helpers */ = {
isa = PBXGroup;
children = (
@ -1003,6 +903,7 @@
DD1933772B084F4200771CD5 /* Measurement.swift */,
DDFFA7462B3A7F3C004730DB /* Bundle.swift */,
DDF45C362BC46A5A005ED5F2 /* TimeZone.swift */,
DDD5BB0C2C285F00007E03CA /* Logger.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -1050,32 +951,14 @@
);
name = Meshtastic;
packageProductDependencies = (
DD5394FB276993AD00AD86B1 /* SwiftProtobuf */,
C9697FA427933B8C00250207 /* SQLite */,
DD0D3D212A55CEB10066DB71 /* CocoaMQTT */,
25A978B92C13F8ED0003AAE7 /* MeshtasticProtobufs */,
);
productName = MeshtasticClient;
productReference = DDC2E15426CE248E0042C5E4 /* Meshtastic.app */;
productType = "com.apple.product-type.application";
};
DDC2E17426CE248F0042C5E4 /* MeshtasticUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = DDC2E18426CE248F0042C5E4 /* Build configuration list for PBXNativeTarget "MeshtasticUITests" */;
buildPhases = (
DDC2E17126CE248F0042C5E4 /* Sources */,
DDC2E17226CE248F0042C5E4 /* Frameworks */,
DDC2E17326CE248F0042C5E4 /* Resources */,
);
buildRules = (
);
dependencies = (
DDC2E17726CE248F0042C5E4 /* PBXTargetDependency */,
);
name = MeshtasticUITests;
productName = MeshtasticClientUITests;
productReference = DDC2E17526CE248F0042C5E4 /* MeshtasticUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
DDDE59F329AF163D00490C6C /* WidgetsExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = DDDE5A0529AF163F00490C6C /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
@ -1089,6 +972,9 @@
dependencies = (
);
name = WidgetsExtension;
packageProductDependencies = (
25A978BB2C13F90D0003AAE7 /* MeshtasticProtobufs */,
);
productName = WidgetsExtension;
productReference = DDDE59F429AF163D00490C6C /* WidgetsExtension.appex */;
productType = "com.apple.product-type.app-extension";
@ -1107,10 +993,6 @@
CreatedOnToolsVersion = 12.5.1;
LastSwiftMigration = 1340;
};
DDC2E17426CE248F0042C5E4 = {
CreatedOnToolsVersion = 12.5.1;
TestTargetID = DDC2E15326CE248E0042C5E4;
};
DDDE59F329AF163D00490C6C = {
CreatedOnToolsVersion = 14.2;
};
@ -1134,16 +1016,16 @@
);
mainGroup = DDC2E14B26CE248E0042C5E4;
packageReferences = (
DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */,
C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */,
DD0D3D202A55CEB10066DB71 /* XCRemoteSwiftPackageReference "CocoaMQTT" */,
25A978B82C13F8ED0003AAE7 /* XCLocalSwiftPackageReference "MeshtasticProtobufs" */,
259792242C2F10B600AD1659 /* XCRemoteSwiftPackageReference "swift-protobuf" */,
);
productRefGroup = DDC2E15526CE248E0042C5E4 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
DDC2E15326CE248E0042C5E4 /* Meshtastic */,
DDC2E17426CE248F0042C5E4 /* MeshtasticUITests */,
DDDE59F329AF163D00490C6C /* WidgetsExtension */,
);
};
@ -1164,13 +1046,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
DDC2E17326CE248F0042C5E4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DDDE59F229AF163D00490C6C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@ -1207,14 +1082,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
259792252C2F114500AD1659 /* ChannelEntityExtension.swift in Sources */,
259792262C2F114500AD1659 /* PositionEntityExtension.swift in Sources */,
259792272C2F114500AD1659 /* TraceRouteEntityExtension.swift in Sources */,
259792282C2F114500AD1659 /* Logger.swift in Sources */,
DDDB444829F8A9C900EE2349 /* String.swift in Sources */,
DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */,
DD5E520C298EE33B00D21B61 /* portnums.pb.swift in Sources */,
DD457188293C7E63000C49FB /* BLESignalStrengthIndicator.swift in Sources */,
DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */,
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */,
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */,
DD0E20FD2B87090400F2D100 /* clientonly.pb.swift in Sources */,
D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */,
DD5E523F298F5A9E00D21B61 /* AirQualityIndex.swift in Sources */,
DD964FBF296E76EF007C176F /* WaypointFormMapKit.swift in Sources */,
@ -1223,10 +1100,8 @@
DDDB443629F6287000EE2349 /* MapButtons.swift in Sources */,
DD5D0A9C2931B9F200F7EA61 /* EthernetModes.swift in Sources */,
6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */,
DD5E5203298EE33B00D21B61 /* config.pb.swift in Sources */,
DD798B072915928D005217CD /* ChannelMessageList.swift in Sources */,
DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */,
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */,
DD77093D2AA1AFA3007A8BF0 /* ChannelTips.swift in Sources */,
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */,
DDDB444C29F8AAA600EE2349 /* Color.swift in Sources */,
@ -1237,6 +1112,7 @@
DD93800E2BA74D0C008BEC06 /* ChannelForm.swift in Sources */,
DD41A61529AB0035003C5A37 /* NodeWeatherForecast.swift in Sources */,
DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */,
DDD5BB102C285FB3007E03CA /* AppLogFilter.swift in Sources */,
DD4640202AFF10F4002A5ECB /* WaypointForm.swift in Sources */,
DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */,
DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */,
@ -1255,23 +1131,20 @@
DDDB445429F8AD1600EE2349 /* Data.swift in Sources */,
DDDB26462AACC0B7003AFCB7 /* NodeInfoItem.swift in Sources */,
DD2AD8A8296D2DF9001FF0E7 /* MapViewSwiftUI.swift in Sources */,
DD5E5213298EE33B00D21B61 /* deviceonly.pb.swift in Sources */,
DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */,
DD5E5208298EE33B00D21B61 /* rtttl.pb.swift in Sources */,
DD6193792863875F00E59241 /* SerialConfig.swift in Sources */,
DDDB263F2AABEE20003AFCB7 /* NodeList.swift in Sources */,
DDD5BB0B2C285E45007E03CA /* LogDetail.swift in Sources */,
DDA0B6B2294CDC55001356EC /* Channels.swift in Sources */,
DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */,
B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */,
DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */,
DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */,
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */,
DD5E5209298EE33B00D21B61 /* module_config.pb.swift in Sources */,
DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */,
DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */,
6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */,
DDDB444229F8A88700EE2349 /* Double.swift in Sources */,
DD5E520F298EE33B00D21B61 /* cannedmessages.pb.swift in Sources */,
DDF45C342BC1A48E005ED5F2 /* MQTTIcon.swift in Sources */,
DDA9515A2BC6624100CEA535 /* TelemetryWeather.swift in Sources */,
DDB75A232A13CDA9006ED576 /* BatteryLevelCompact.swift in Sources */,
@ -1287,7 +1160,6 @@
DD33DB622B3D27C7003E1EA0 /* FirmwareApi.swift in Sources */,
DD3CC6B528E33FD100FA9159 /* ShareChannels.swift in Sources */,
DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */,
DD5E5207298EE33B00D21B61 /* connection_status.pb.swift in Sources */,
DD3CC6C228EB9D4900FA9159 /* UpdateCoreData.swift in Sources */,
DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */,
DDB6ABE628B1406100384BA1 /* LoraConfigEnums.swift in Sources */,
@ -1295,19 +1167,14 @@
DDD43FE32A78C8900083A3E9 /* MqttClientProxyManager.swift in Sources */,
DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */,
DDDB26422AABF655003AFCB7 /* NodeListItem.swift in Sources */,
DD0E20FC2B87090400F2D100 /* atak.pb.swift in Sources */,
DDDB444629F8A96500EE2349 /* Character.swift in Sources */,
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */,
DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */,
DD5E520D298EE33B00D21B61 /* storeforward.pb.swift in Sources */,
DD94B7402ACCE3BE00DCD1D1 /* MapSettingsForm.swift in Sources */,
DD964FC2297272AE007C176F /* WaypointEntityExtension.swift in Sources */,
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */,
D93068DB2B81C85E0066FBC8 /* PowerConfig.swift in Sources */,
D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */,
DD0E20FE2B87090400F2D100 /* paxcount.pb.swift in Sources */,
DD5E520A298EE33B00D21B61 /* channel.pb.swift in Sources */,
25183D462C0A6D97001E31D5 /* Logger.swift in Sources */,
DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */,
DD964FC42974767D007C176F /* MapViewFitExtension.swift in Sources */,
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */,
@ -1323,8 +1190,8 @@
D93068DD2B81CA820066FBC8 /* ConfigHeader.swift in Sources */,
DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */,
D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */,
DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */,
DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */,
DD5E5202298EE33B00D21B61 /* admin.pb.swift in Sources */,
DDC1B81A2AB5377B00C71E39 /* MessagesTips.swift in Sources */,
DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */,
DDB75A112A059258006ED576 /* Url.swift in Sources */,
@ -1351,34 +1218,26 @@
D93068D92B81509C0066FBC8 /* TapbackResponses.swift in Sources */,
DD86D40A287F04F100BAEB7A /* InvalidVersion.swift in Sources */,
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */,
DD5E5212298EE33B00D21B61 /* apponly.pb.swift in Sources */,
DDB6ABE228B13FB500384BA1 /* PositionConfigEnums.swift in Sources */,
DD5E520E298EE33B00D21B61 /* mqtt.pb.swift in Sources */,
DD994B69295F88B60013760A /* IntervalEnums.swift in Sources */,
DDDCD5702BB26F5C00BE6B60 /* NodeListFilter.swift in Sources */,
DD1933762B0835D500771CD5 /* PositionAltitudeChart.swift in Sources */,
DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */,
DDDB443D29F6592F00EE2349 /* NetworkManager.swift in Sources */,
DDB6CCFB2AAF805100945AF6 /* NodeMapSwiftUI.swift in Sources */,
DD73FD1128750779000852D6 /* PositionLog.swift in Sources */,
DD5E5206298EE33B00D21B61 /* localonly.pb.swift in Sources */,
DD15E4F52B8BFC8E00654F61 /* PaxCounterLog.swift in Sources */,
DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */,
DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */,
DDAB580D2B0DAA9E00147258 /* Routes.swift in Sources */,
C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */,
D93068D52B812B700066FBC8 /* MessageDestination.swift in Sources */,
DD58C5F22919AD3C00D5BEFB /* ChannelEntityExtension.swift in Sources */,
DDA9515E2BC6F56F00CEA535 /* IndoorAirQuality.swift in Sources */,
DDDB444E29F8AB0E00EE2349 /* Int.swift in Sources */,
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */,
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */,
DDC4C9FF2A8D982900CE201C /* DetectionSensorConfig.swift in Sources */,
D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */,
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
DD5E5210298EE33B00D21B61 /* telemetry.pb.swift in Sources */,
DD77093F2AA1B146007A8BF0 /* UIColor.swift in Sources */,
DD5E5205298EE33B00D21B61 /* mesh.pb.swift in Sources */,
DDF6B2482A9AEBF500BA6931 /* StoreForwardConfig.swift in Sources */,
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */,
DD93800B2BA3F968008BEC06 /* NodeMapContent.swift in Sources */,
@ -1387,22 +1246,11 @@
DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */,
DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */,
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */,
DD5E5211298EE33B00D21B61 /* remote_hardware.pb.swift in Sources */,
D93068D72B8146690066FBC8 /* MessageText.swift in Sources */,
DD5E5204298EE33B00D21B61 /* xmodem.pb.swift in Sources */,
DDE5B4062B227E3200FCDD05 /* TraceRouteEntityExtension.swift in Sources */,
DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DDC2E17126CE248F0042C5E4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DDC2E17A26CE248F0042C5E4 /* MeshtasticUITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DDDE59F029AF163D00490C6C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -1417,11 +1265,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
DDC2E17726CE248F0042C5E4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DDC2E15326CE248E0042C5E4 /* Meshtastic */;
targetProxy = DDC2E17626CE248F0042C5E4 /* PBXContainerItemProxy */;
};
DDDE5A0229AF163E00490C6C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
@ -1590,12 +1433,12 @@
INFOPLIST_FILE = Meshtastic/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Meshtastic;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.3.12;
MARKETING_VERSION = 2.3.11;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -1639,48 +1482,6 @@
};
name = Release;
};
DDC2E18526CE248F0042C5E4 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = GCH7VS5Y9R;
INFOPLIST_FILE = MeshtasticUITests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Meshtastic;
};
name = Debug;
};
DDC2E18626CE248F0042C5E4 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = GCH7VS5Y9R;
INFOPLIST_FILE = MeshtasticUITests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Meshtastic;
};
name = Release;
};
DDDE5A0629AF163F00490C6C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -1702,7 +1503,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.10;
MARKETING_VERSION = 2.3.11;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1735,7 +1536,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.10;
MARKETING_VERSION = 2.3.11;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -1768,15 +1569,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DDC2E18426CE248F0042C5E4 /* Build configuration list for PBXNativeTarget "MeshtasticUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DDC2E18526CE248F0042C5E4 /* Debug */,
DDC2E18626CE248F0042C5E4 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DDDE5A0529AF163F00490C6C /* Build configuration list for PBXNativeTarget "WidgetsExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@ -1788,7 +1580,22 @@
};
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
25A978B82C13F8ED0003AAE7 /* XCLocalSwiftPackageReference "MeshtasticProtobufs" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = MeshtasticProtobufs;
};
/* End XCLocalSwiftPackageReference section */
/* Begin XCRemoteSwiftPackageReference section */
259792242C2F10B600AD1659 /* XCRemoteSwiftPackageReference "swift-protobuf" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-protobuf.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.26.0;
};
};
C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/stephencelis/SQLite.swift.git";
@ -1805,17 +1612,17 @@
minimumVersion = 2.0.0;
};
};
DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-protobuf.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.19.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
25A978B92C13F8ED0003AAE7 /* MeshtasticProtobufs */ = {
isa = XCSwiftPackageProductDependency;
productName = MeshtasticProtobufs;
};
25A978BB2C13F90D0003AAE7 /* MeshtasticProtobufs */ = {
isa = XCSwiftPackageProductDependency;
productName = MeshtasticProtobufs;
};
C9697FA427933B8C00250207 /* SQLite */ = {
isa = XCSwiftPackageProductDependency;
package = C9697FA327933B8C00250207 /* XCRemoteSwiftPackageReference "SQLite.swift" */;
@ -1826,17 +1633,13 @@
package = DD0D3D202A55CEB10066DB71 /* XCRemoteSwiftPackageReference "CocoaMQTT" */;
productName = CocoaMQTT;
};
DD5394FB276993AD00AD86B1 /* SwiftProtobuf */ = {
isa = XCSwiftPackageProductDependency;
package = DD5394FA276993AD00AD86B1 /* XCRemoteSwiftPackageReference "swift-protobuf" */;
productName = SwiftProtobuf;
};
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
DDD5BB142C28680D007E03CA /* MeshtasticDataModelV 38.xcdatamodel */,
DDD28D372C0CD2670063CFA3 /* MeshtasticDataModelV 37.xcdatamodel */,
DD31B04D2BDC6FD30024FA63 /* MeshtasticDataModelV 36.xcdatamodel */,
DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */,
@ -1875,7 +1678,7 @@
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */,
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */,
);
currentVersion = DDD28D372C0CD2670063CFA3 /* MeshtasticDataModelV 37.xcdatamodel */;
currentVersion = DDD5BB142C28680D007E03CA /* MeshtasticDataModelV 38.xcdatamodel */;
name = Meshtastic.xcdatamodeld;
path = Meshtastic/Meshtastic.xcdatamodeld;
sourceTree = "<group>";

View file

@ -1,5 +1,5 @@
{
"originHash" : "32ea1ad7873163554215310b8eea710c94c63f855b5b01c0b790e7b537747ceb",
"originHash" : "2d0b85469585b0d6079eac292d63864096062c24848a49380b9d9727f0ceb96c",
"pins" : [
{
"identity" : "cocoamqtt",
@ -10,24 +10,6 @@
"version" : "2.1.5"
}
},
{
"identity" : "collectionconcurrencykit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
"state" : {
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
"version" : "0.2.0"
}
},
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
"version" : "1.8.2"
}
},
{
"identity" : "mqttcocoaasyncsocket",
"kind" : "remoteSourceControl",
@ -37,15 +19,6 @@
"version" : "1.0.8"
}
},
{
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "fd4df99170f5e9d7cf9aa8312aa8506e0e7a44e7",
"version" : "0.35.0"
}
},
{
"identity" : "sqlite.swift",
"kind" : "remoteSourceControl",
@ -64,67 +37,13 @@
"version" : "3.1.2"
}
},
{
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "0fbc8848e389af3bb55c182bc19ca9d5dc2f255b",
"version" : "1.4.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "ce20dc083ee485524b802669890291c0d8090170",
"version" : "1.22.1"
}
},
{
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "303e5c5c36d6a558407d364878df131c3546fad8",
"version" : "510.0.2"
}
},
{
"identity" : "swiftlint",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/SwiftLint",
"state" : {
"revision" : "b515723b16eba33f15c4677ee65f3fef2ce8c255",
"version" : "0.55.1"
}
},
{
"identity" : "swiftytexttable",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
"state" : {
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
"version" : "0.9.0"
}
},
{
"identity" : "swxmlhash",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"state" : {
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
"version" : "7.0.2"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "9234124cff5e22e178988c18d8b95a8ae8007f76",
"version" : "5.1.2"
"revision" : "9f0c76544701845ad98716f3f6a774a892152bcb",
"version" : "1.26.0"
}
}
],

View file

@ -89,7 +89,6 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
askForAppToLaunch = "Yes"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:README.md">
</FileRef>
<FileRef
location = "group:Meshtastic.xcodeproj">
</FileRef>
<FileRef
location = "group:MeshtasticProtobufs">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,51 @@
{
"originHash" : "a8b652cbdc560223dff5bdd094d446cf377b06bd42ce7a7bc4c008a659f0097d",
"pins" : [
{
"identity" : "cocoamqtt",
"kind" : "remoteSourceControl",
"location" : "https://github.com/emqx/CocoaMQTT",
"state" : {
"revision" : "aff43422925cc30b9af319f4c4dce4f52859baf4",
"version" : "2.1.8"
}
},
{
"identity" : "mqttcocoaasyncsocket",
"kind" : "remoteSourceControl",
"location" : "https://github.com/leeway1208/MqttCocoaAsyncSocket",
"state" : {
"revision" : "ce3e18607fd01079495f86ff6195d8a3ca469f73",
"version" : "1.0.8"
}
},
{
"identity" : "sqlite.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/stephencelis/SQLite.swift.git",
"state" : {
"revision" : "a95fc6df17d108bd99210db5e8a9bac90fe984b8",
"version" : "0.15.3"
}
},
{
"identity" : "starscream",
"kind" : "remoteSourceControl",
"location" : "https://github.com/daltoniam/Starscream.git",
"state" : {
"revision" : "c6bfd1af48efcc9a9ad203665db12375ba6b145a",
"version" : "4.0.8"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "9f0c76544701845ad98716f3f6a774a892152bcb",
"version" : "1.26.0"
}
}
],
"version" : 3
}

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 8/19/22.
//
import Foundation
import MeshtasticProtobufs
enum BluetoothModes: Int, CaseIterable, Identifiable {

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 9/10/22.
//
import Foundation
import MeshtasticProtobufs
// Default of 0 is unset
enum ConfigPresets: Int, CaseIterable, Identifiable {

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 9/21/22.
//
import Foundation
import MeshtasticProtobufs
// Default of 0 is Client
enum ChannelRoles: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import Foundation
import MeshtasticProtobufs
// Default of 0 is Client
enum DeviceRoles: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import Foundation
import MeshtasticProtobufs
enum ScreenUnits: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import Foundation
import MeshtasticProtobufs
enum EthernetMode: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import Foundation
import MeshtasticProtobufs
enum RegionCodes: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import Foundation
import MeshtasticProtobufs
enum GpsFormats: Int, CaseIterable, Identifiable {

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 8/4/22.
//
import Foundation
import MeshtasticProtobufs
enum RoutingError: Int, CaseIterable, Identifiable {

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 9/10/22.
//
import Foundation
import MeshtasticProtobufs
enum SerialBaudRates: Int, CaseIterable, Identifiable {

View file

@ -6,6 +6,7 @@
//
import SwiftUI
import OSLog
func telemetryToCsvFile(telemetry: [TelemetryEntity], metricsType: Int) -> String {
var csvString: String = ""
@ -64,6 +65,27 @@ func detectionsToCsv(detections: [MessageEntity]) -> String {
return csvString
}
func logToCsvFile(log: [OSLogEntryLog]) -> String {
var csvString: String = ""
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mma").replacingOccurrences(of: ",", with: "")
// Create PAX Header
csvString = "Process, Category, Level, Message, \("timestamp".localized)"
for l in log {
csvString += "\n"
csvString += String(l.process)
csvString += ", "
csvString += String(l.category)
csvString += ", "
csvString += String(l.level.description)
csvString += ", "
csvString += String(l.composedMessage)
csvString += ", "
csvString += l.date.formattedDate(format: dateFormatString)
}
return csvString
}
func paxToCsvFile(pax: [PaxCounterEntity]) -> String {
var csvString: String = ""
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmma", options: 0, locale: Locale.current)

View file

@ -5,6 +5,8 @@
// Copyright(c) Garth Vander Houwen 11/7/22.
//
import Foundation
import CoreData
import MeshtasticProtobufs
extension ChannelEntity {

View file

@ -0,0 +1,25 @@
import Foundation
import CoreData
import MeshtasticProtobufs
extension DeviceMetadataEntity {
convenience init(
context: NSManagedObjectContext,
metadata: DeviceMetadata
) {
self.init(context: context)
self.time = Date()
self.deviceStateVersion = Int32(metadata.deviceStateVersion)
self.canShutdown = metadata.canShutdown
self.hasWifi = metadata.hasWifi_p
self.hasBluetooth = metadata.hasBluetooth_p
self.hasEthernet = metadata.hasEthernet_p
self.role = Int32(metadata.role.rawValue)
self.positionFlags = Int32(metadata.positionFlags)
// Swift does strings weird, this does work to get the version without the github hash
let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".")
var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))]
version = version.dropLast()
self.firmwareVersion = String(version)
}
}

View file

@ -0,0 +1,44 @@
import CoreData
import MeshtasticProtobufs
extension ExternalNotificationConfigEntity {
convenience init(
context: NSManagedObjectContext,
config: ModuleConfig.ExternalNotificationConfig
) {
self.init(context: context)
self.enabled = config.enabled
self.usePWM = config.usePwm
self.alertBell = config.alertBell
self.alertBellBuzzer = config.alertBellBuzzer
self.alertBellVibra = config.alertBellVibra
self.alertMessage = config.alertMessage
self.alertMessageBuzzer = config.alertMessageBuzzer
self.alertMessageVibra = config.alertMessageVibra
self.active = config.active
self.output = Int32(config.output)
self.outputBuzzer = Int32(config.outputBuzzer)
self.outputVibra = Int32(config.outputVibra)
self.outputMilliseconds = Int32(config.outputMs)
self.nagTimeout = Int32(config.nagTimeout)
self.useI2SAsBuzzer = config.useI2SAsBuzzer
}
func update(with config: ModuleConfig.ExternalNotificationConfig) {
enabled = config.enabled
usePWM = config.usePwm
alertBell = config.alertBell
alertBellBuzzer = config.alertBellBuzzer
alertBellVibra = config.alertBellVibra
alertMessage = config.alertMessage
alertMessageBuzzer = config.alertMessageBuzzer
alertMessageVibra = config.alertMessageVibra
active = config.active
output = Int32(config.output)
outputBuzzer = Int32(config.outputBuzzer)
outputVibra = Int32(config.outputVibra)
outputMilliseconds = Int32(config.outputMs)
nagTimeout = Int32(config.nagTimeout)
useI2SAsBuzzer = config.useI2SAsBuzzer
}
}

View file

@ -0,0 +1,38 @@
import CoreData
import MeshtasticProtobufs
extension MQTTConfigEntity {
convenience init(
context: NSManagedObjectContext,
config: ModuleConfig.MQTTConfig
) {
self.init(context: context)
self.enabled = config.enabled
self.proxyToClientEnabled = config.proxyToClientEnabled
self.address = config.address
self.username = config.username
self.password = config.password
self.root = config.root
self.encryptionEnabled = config.encryptionEnabled
self.jsonEnabled = config.jsonEnabled
self.tlsEnabled = config.tlsEnabled
self.mapReportingEnabled = config.mapReportingEnabled
self.mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision)
self.mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs)
}
func update(with config: ModuleConfig.MQTTConfig) {
enabled = config.enabled
proxyToClientEnabled = config.proxyToClientEnabled
address = config.address
username = config.username
password = config.password
root = config.root
encryptionEnabled = config.encryptionEnabled
jsonEnabled = config.jsonEnabled
tlsEnabled = config.tlsEnabled
mapReportingEnabled = config.mapReportingEnabled
mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision)
mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs)
}
}

View file

@ -8,6 +8,7 @@
import CoreData
import CoreLocation
import MapKit
import MeshtasticProtobufs
import SwiftUI
extension PositionEntity {

View file

@ -0,0 +1,20 @@
import CoreData
import MeshtasticProtobufs
extension RangeTestConfigEntity {
convenience init(
context: NSManagedObjectContext,
config: ModuleConfig.RangeTestConfig
) {
self.init(context: context)
self.sender = Int32(config.sender)
self.enabled = config.enabled
self.save = config.save
}
func update(with config: ModuleConfig.RangeTestConfig) {
sender = Int32(config.sender)
enabled = config.enabled
save = config.save
}
}

View file

@ -0,0 +1,28 @@
import CoreData
import MeshtasticProtobufs
extension SerialConfigEntity {
convenience init(
context: NSManagedObjectContext,
config: ModuleConfig.SerialConfig
) {
self.init(context: context)
self.enabled = config.enabled
self.echo = config.echo
self.rxd = Int32(config.rxd)
self.txd = Int32(config.txd)
self.baudRate = Int32(config.baud.rawValue)
self.timeout = Int32(config.timeout)
self.mode = Int32(config.mode.rawValue)
}
func update(with config: ModuleConfig.SerialConfig) {
enabled = config.enabled
echo = config.echo
rxd = Int32(config.rxd)
txd = Int32(config.txd)
baudRate = Int32(config.baud.rawValue)
timeout = Int32(config.timeout)
mode = Int32(config.mode.rawValue)
}
}

View file

@ -0,0 +1,24 @@
import CoreData
import MeshtasticProtobufs
extension StoreForwardConfigEntity {
convenience init(
context: NSManagedObjectContext,
config: ModuleConfig.StoreForwardConfig
) {
self.init(context: context)
self.enabled = config.enabled
self.heartbeat = config.heartbeat
self.records = Int32(config.records)
self.historyReturnMax = Int32(config.historyReturnMax)
self.historyReturnWindow = Int32(config.historyReturnWindow)
}
func update(with config: ModuleConfig.StoreForwardConfig) {
enabled = config.enabled
heartbeat = config.heartbeat
records = Int32(config.records)
historyReturnMax = Int32(config.historyReturnMax)
historyReturnWindow = Int32(config.historyReturnWindow)
}
}

View file

@ -7,6 +7,7 @@
import Foundation
import CoreData
import MeshtasticProtobufs
extension UserEntity {
@ -14,10 +15,6 @@ extension UserEntity {
self.value(forKey: "allMessages") as? [MessageEntity] ?? [MessageEntity]()
}
var adminMessageList: [MessageEntity] {
self.value(forKey: "adminMessages") as? [MessageEntity] ?? [MessageEntity]()
}
var sensorMessageList: [MessageEntity] {
self.value(forKey: "detectionSensorMessages") as? [MessageEntity] ?? [MessageEntity]()
}

View file

@ -53,12 +53,12 @@ public extension FileManager {
do {
accumulatedSize += try contentItemURL.regularFileAllocatedSize()
} catch {
Logger.services.error("💥 File Manager Error: \(error.localizedDescription)")
Logger.services.error("💥 File Manager Error: \(error.localizedDescription, privacy: .public)")
}
}
if let error = enumeratorError {
Logger.services.error("💥 AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription)")
Logger.services.error("💥 AllocatedSizeOfDirectory enumeratorError = \(error.localizedDescription, privacy: .public)")
}
return Double(accumulatedSize).toBytes

View file

@ -15,3 +15,15 @@ extension Int {
}
}
}
extension UInt32 {
func toHex() -> String {
return String(format: "!%2X", self)
}
}
extension Int64 {
func toHex() -> String {
return String(format: "!%2X", self)
}
}

View file

@ -0,0 +1,74 @@
//
// Logger.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 6/3/24.
//
import OSLog
extension Logger {
/// The logger's subsystem.
private static var subsystem = Bundle.main.bundleIdentifier!
/// All admin messages
static let admin = Logger(subsystem: subsystem, category: "🏛 Admin")
/// All logs related to data such as decoding error, parsing issues, etc.
static let data = Logger(subsystem: subsystem, category: "🗄️ Data")
/// All logs related to the mesh
static let mesh = Logger(subsystem: subsystem, category: "🕸️ Mesh")
/// All logs related to MQTT
static let mqtt = Logger(subsystem: subsystem, category: "📱 MQTT")
/// All detailed logs originating from the device (radio).
static let radio = Logger(subsystem: subsystem, category: "📟 Radio")
/// All logs related to services such as network calls, location, etc.
static let services = Logger(subsystem: subsystem, category: "🍏 Services")
/// All logs related to tracking and analytics.
static let statistics = Logger(subsystem: subsystem, category: "📊 Stats")
/// Fetch from the logstore
static public func fetch(predicateFormat: String) async throws -> [OSLogEntryLog] {
let store = try OSLogStore(scope: .currentProcessIdentifier)
let position = store.position(timeIntervalSinceLatestBoot: 0)
// let calendar = Calendar.current
// let dayAgo = calendar.date(byAdding: .day, value: -1, to: Date.now)
// let position = store.position(date: dayAgo!)
let predicate = NSPredicate(format: predicateFormat)
let entries = try store.getEntries(at: position, matching: predicate)
var logs: [OSLogEntryLog] = []
for entry in entries {
try Task.checkCancellation()
if let log = entry as? OSLogEntryLog {
logs.append(log)
}
}
if logs.isEmpty { logs = [] }
return logs
}
}
extension OSLogEntryLog.Level {
var description: String {
switch self {
case .undefined: "undefined"
case .debug: "🪲 Debug"
case .info: " Info"
case .notice: "⚠️ Notice"
case .error: "🚨 Error"
case .fault: "💥 Fault"
@unknown default: "default"
}
}
}

View file

@ -0,0 +1,12 @@
import Foundation
import MeshtasticProtobufs
extension NodeInfo {
var isValidPosition: Bool {
hasPosition &&
position.longitudeI != 0 &&
position.latitudeI != 0 &&
position.latitudeI != 373346000 &&
position.longitudeI != -1220090000
}
}

View file

@ -6,6 +6,7 @@
//
import Foundation
import OSLog
extension URL {
@ -30,4 +31,24 @@ extension URL {
return nil
}
}
var attributes: [FileAttributeKey: Any]? {
do {
return try FileManager.default.attributesOfItem(atPath: path)
} catch let error as NSError {
Logger.services.error("FileAttribute error: \(error, privacy: . public)")
}
return nil
}
var fileSize: UInt64 {
return attributes?[.size] as? UInt64 ?? UInt64(0)
}
var fileSizeString: String {
return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
}
var creationDate: Date? {
return attributes?[.creationDate] as? Date
}
}

View file

@ -3,8 +3,10 @@ import CoreData
import CoreBluetooth
import SwiftUI
import MapKit
import MeshtasticProtobufs
import CocoaMQTT
import OSLog
import RegexBuilder
// ---------------------------------------------------------------------------------------
// Meshtastic BLE Device Manager
@ -41,11 +43,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
var TORADIO_characteristic: CBCharacteristic!
var FROMRADIO_characteristic: CBCharacteristic!
var FROMNUM_characteristic: CBCharacteristic!
var LOGRADIO_characteristic: CBCharacteristic!
let meshtasticServiceCBUUID = CBUUID(string: "0x6BA1B218-15A8-461F-9FA8-5DCAE273EAFD")
let TORADIO_UUID = CBUUID(string: "0xF75C76D2-129E-4DAD-A1DD-7866124401E7")
let FROMRADIO_UUID = CBUUID(string: "0x2C55E69E-4993-11ED-B878-0242AC120002")
let EOL_FROMRADIO_UUID = CBUUID(string: "0x8BA2BCC2-EE02-4A55-A531-C525C5E454D5")
let FROMNUM_UUID = CBUUID(string: "0xED9DA18C-A800-4F66-A670-AA7547E34453")
let LOGRADIO_UUID = CBUUID(string: "0x6C6FD238-78FA-436B-AACF-15C5BE1EF2E2")
// MARK: init BLEManager
override init() {
@ -62,7 +66,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
func startScanning() {
if isSwitchedOn {
centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
Logger.services.info(" Scanning Started")
Logger.services.info(" [BLE] Scanning Started")
}
}
@ -70,7 +74,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
func stopScanning() {
if centralManager.isScanning {
centralManager.stopScan()
Logger.services.info("🛑 Stopped Scanning")
Logger.services.info("🛑 [BLE] Stopped Scanning")
}
}
@ -103,7 +107,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
self.timeoutTimerCount = 0
self.startScanning()
} else {
Logger.services.info("🚨 BLE Connecting 2 Second Timeout Timer Fired \(self.timeoutTimerCount) Time(s): \(name)")
Logger.services.info("🚨 [BLE] Connecting 2 Second Timeout Timer Fired \(self.timeoutTimerCount, privacy: .public) Time(s): \(name, privacy: .public)")
}
}
@ -116,7 +120,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
self.automaticallyReconnect = true
}
if connectedPeripheral != nil {
Logger.services.info(" BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")")
Logger.services.info(" [BLE] Disconnecting from: \(self.connectedPeripheral.name, privacy: .public) to connect to \(peripheral.name ?? "Unknown", privacy: .public)")
disconnectPeripheral()
}
@ -130,7 +134,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let context = ["name": "\(peripheral.name ?? "Unknown")"]
timeoutTimer = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true)
RunLoop.current.add(timeoutTimer!, forMode: .common)
Logger.services.info(" BLE Connecting: \(peripheral.name ?? "Unknown")")
Logger.services.info(" BLE Connecting: \(peripheral.name ?? "Unknown", privacy: .public)")
}
// Disconnect Connected Peripheral
@ -194,19 +198,19 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
connectedPeripheral.peripheral.delegate = self
} else {
// we are null just disconnect and start over
lastConnectionError = "Bluetooth connection error, please try again."
lastConnectionError = "🚫 [BLE] Bluetooth connection error, please try again."
disconnectPeripheral()
return
}
// Discover Services
peripheral.discoverServices([meshtasticServiceCBUUID])
Logger.services.info("BLE Connected: \(peripheral.name ?? "Unknown")")
Logger.services.info("[BLE] Connected: \(peripheral.name ?? "Unknown", privacy: .public)")
}
// Called when a Peripheral fails to connect
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
cancelPeripheralConnection()
Logger.services.error("🚫 BLE Failed to Connect: \(peripheral.name ?? "Unknown")")
Logger.services.error("🚫 [BLE] Failed to Connect: \(peripheral.name ?? "Unknown", privacy: .public)")
}
// Disconnect Peripheral Event
@ -222,7 +226,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
if errorCode == 6 { // CBError.Code.connectionTimeout The connection has timed out unexpectedly.
// Happens when device is manually reset / powered off
lastConnectionError = "🚨" + String.localizedStringWithFormat("ble.errorcode.6 %@".localized, e.localizedDescription)
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
} else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us.
// Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work.
if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString {
@ -239,11 +243,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
manager.schedule()
}
lastConnectionError = "🚨 \(e.localizedDescription)"
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
} else if errorCode == 14 { // Peer removed pairing information
// Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that
lastConnectionError = "🚨 " + String.localizedStringWithFormat("ble.errorcode.14 %@".localized, e.localizedDescription)
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(self.lastConnectionError)")
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode, privacy: .public) Error: \(self.lastConnectionError, privacy: .public)")
} else {
if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString {
manager.notifications = [
@ -259,12 +263,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
manager.schedule()
}
lastConnectionError = "🚨 \(e.localizedDescription)"
Logger.services.error("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)")
Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)")
}
} else {
// Disconnected without error which indicates user intent to disconnect
// Happens when swiping to disconnect
Logger.services.info(" BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect")
Logger.services.info(" [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public): User Initiated Disconnect")
}
// Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake
self.startScanning()
@ -273,12 +277,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
// MARK: Peripheral Services functions
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error {
Logger.services.error("🚫 Discover Services error \(error.localizedDescription)")
Logger.services.error("🚫 [BLE] Discover Services error \(error.localizedDescription, privacy: .public)")
}
guard let services = peripheral.services else { return }
for service in services where service.uuid == meshtasticServiceCBUUID {
peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID], for: service)
Logger.services.info("BLE Service for Meshtastic discovered by \(peripheral.name ?? "Unknown")")
peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID, LOGRADIO_UUID], for: service)
Logger.services.info("[BLE] Service for Meshtastic discovered by \(peripheral.name ?? "Unknown", privacy: .public)")
}
}
@ -286,7 +290,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error {
Logger.services.error("🚫 BLE Discover Characteristics error for \(peripheral.name ?? "Unknown") \(error.localizedDescription) disconnecting device")
Logger.services.error("🚫 [BLE] Discover Characteristics error for \(peripheral.name ?? "Unknown", privacy: .public) \(error.localizedDescription, privacy: .public) disconnecting device")
// Try and stop crashes when this error occurs
disconnectPeripheral()
return
@ -298,19 +302,24 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
switch characteristic.uuid {
case TORADIO_UUID:
Logger.services.info("BLE did discover TORADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")")
Logger.services.info("[BLE] did discover TORADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
TORADIO_characteristic = characteristic
case FROMRADIO_UUID:
Logger.services.info("BLE did discover FROMRADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")")
Logger.services.info("[BLE] did discover FROMRADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
FROMRADIO_characteristic = characteristic
peripheral.readValue(for: FROMRADIO_characteristic)
case FROMNUM_UUID:
Logger.services.info("BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")")
Logger.services.info("[BLE] did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
FROMNUM_characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
case LOGRADIO_UUID:
Logger.services.info("✅ [BLE] did discover LOGRADIO (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown", privacy: .public)")
LOGRADIO_characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
default:
break
}
@ -327,13 +336,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
func onMqttConnected() {
mqttProxyConnected = true
mqttError = ""
Logger.services.info("📲 Mqtt Client Proxy onMqttConnected now subscribing to \(self.mqttManager.topic).")
Logger.services.info("📲 [MQTT Client Proxy] onMqttConnected now subscribing to \(self.mqttManager.topic, privacy: .public).")
mqttManager.mqttClientProxy?.subscribe(mqttManager.topic)
}
func onMqttDisconnected() {
mqttProxyConnected = false
Logger.services.info("MQTT Disconnected")
Logger.services.info("📲 MQTT Disconnected")
}
func onMqttMessageReceived(message: CocoaMQTTMessage) {
@ -360,7 +369,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
func onMqttError(message: String) {
mqttProxyConnected = false
mqttError = message
Logger.services.info("📲 Mqtt Client Proxy onMqttError: \(message)")
Logger.services.info("📲 [MQTT Client Proxy] onMqttError: \(message, privacy: .public)")
}
// MARK: Protobuf Methods
@ -387,8 +396,8 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return 0
}
let messageDescription = "🛎️ Requested Device Metadata for node \(toUser.longName ?? "unknown".localized) by \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
let messageDescription = "🛎️ [Device Metadata] Requested for node \(toUser.longName ?? "unknown".localized) by \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
return 0
@ -446,14 +455,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
do {
try context!.save()
Logger.data.info("💾 Saved TraceRoute sent to node: \(String(receivingNode?.user?.longName ?? "unknown".localized))")
Logger.data.info("💾 Saved TraceRoute sent to node: \(String(receivingNode?.user?.longName ?? "unknown".localized), privacy: .public)")
} catch {
context!.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data BluetoothConfigEntity: \(nsError)")
Logger.data.error("Error Updating Core Data BluetoothConfigEntity: \(nsError, privacy: .public)")
}
let logString = String.localizedStringWithFormat("mesh.log.traceroute.sent %@".localized, String(destNum))
let logString = String.localizedStringWithFormat("mesh.log.traceroute.sent %@".localized, destNum.toHex())
MeshLogger.log("🪧 \(logString)")
} catch {
@ -490,7 +499,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
Logger.services.error("didUpdateNotificationStateFor error: \(error?.localizedDescription ?? "Unknown")")
if let error {
Logger.services.error("💥 [BLE] didUpdateNotificationStateFor error: \(characteristic.uuid, privacy: .public) \(error.localizedDescription, privacy: .public)")
} else {
Logger.services.info(" [BLE] peripheral didUpdateNotificationStateFor \(characteristic.uuid, privacy: .public)")
}
}
// MARK: Data Read / Update Characteristic Event
@ -498,20 +511,86 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
if let error {
Logger.services.error("🚫 didUpdateValueFor Characteristic error \(error.localizedDescription)")
Logger.services.error("🚫 [BLE] didUpdateValueFor Characteristic error \(error.localizedDescription, privacy: .public)")
let errorCode = (error as NSError).code
if errorCode == 5 || errorCode == 15 {
// BLE PIN connection errors
// 5 CBATTErrorDomain Code=5 "Authentication is insufficient."
// 15 CBATTErrorDomain Code=15 "Encryption is insufficient."
lastConnectionError = "🚨" + String.localizedStringWithFormat("ble.errorcode.pin %@".localized, error.localizedDescription)
Logger.services.error("\(error.localizedDescription) Please try connecting again and check the PIN carefully.")
Logger.services.error("🚫 [BLE] \(error.localizedDescription, privacy: .public) Please try connecting again and check the PIN carefully.")
self.disconnectPeripheral(reconnect: false)
}
return
}
switch characteristic.uuid {
case LOGRADIO_UUID:
if characteristic.value == nil || characteristic.value!.isEmpty {
return
}
let coordsSearch = Regex {
Capture {
Regex {
"lat="
OneOrMore(.digit)
}
}
Capture {" "}
Capture {
Regex {
"long="
OneOrMore(.digit)
}
}
}
.anchorsMatchLineEndings()
if var log = String(data: characteristic.value!, encoding: .utf8) {
/// Debug Log Level
if log.starts(with: "DEBUG |") {
do {
let logString = log
if let coordsMatch = try coordsSearch.firstMatch(in: logString) {
log = "\(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces))"
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.debug("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)")
} else {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.debug("🕵🏻‍♂️ \(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
}
} catch {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.debug("🕵🏻‍♂️ \(log.replacingOccurrences(of: "DEBUG |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
}
} else if log.starts(with: "INFO |") {
do {
let logString = log
if let coordsMatch = try coordsSearch.firstMatch(in: logString) {
log = "\(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces))"
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.info("🛰️ \(log.prefix(upTo: coordsMatch.range.lowerBound), privacy: .public) \(coordsMatch.0.replacingOccurrences(of: "[,]", with: "", options: .regularExpression), privacy: .private) \(log.suffix(from: coordsMatch.range.upperBound), privacy: .public)")
} else {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.info("📢 \(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
}
} catch {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.info("📢 \(log.replacingOccurrences(of: "INFO |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
}
} else if log.starts(with: "WARN |") {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.warning("⚠️ \(log.replacingOccurrences(of: "WARN |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
} else if log.starts(with: "ERROR |") {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.error("💥 \(log.replacingOccurrences(of: "ERROR |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
} else if log.starts(with: "CRIT |") {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.critical("🧨 \(log.replacingOccurrences(of: "CRIT |", with: "").trimmingCharacters(in: .whitespaces), privacy: .public)")
} else {
log = log.replacingOccurrences(of: "[,]", with: "", options: .regularExpression)
Logger.radio.debug("📟 \(log, privacy: .public)")
}
}
case FROMRADIO_UUID:
@ -524,7 +603,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
decodedInfo = try FromRadio(serializedData: characteristic.value!)
} catch {
Logger.services.error("\(error.localizedDescription) \(characteristic.value!)")
Logger.services.error("💥 \(error.localizedDescription, privacy: .public) \(characteristic.value!, privacy: .public)")
}
// Publish mqttClientProxyMessages received on the from radio
@ -555,6 +634,28 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
connectedPeripheral.num = myInfo?.myNodeNum ?? 0
connectedPeripheral.name = myInfo?.bleName ?? "unknown".localized
connectedPeripheral.longName = myInfo?.bleName ?? "unknown".localized
let newConnection = Int64(UserDefaults.preferredPeripheralNum) != Int64(decodedInfo.myInfo.myNodeNum)
if newConnection {
let container = NSPersistentContainer(name: "Meshtastic")
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let databasePath = url.appendingPathComponent("backup")
.appendingPathComponent("\(UserDefaults.preferredPeripheralNum)")
.appendingPathComponent("Meshtastic.sqlite")
if FileManager.default.fileExists(atPath: databasePath.path) {
do {
disconnectPeripheral(reconnect: false)
try container.restorePersistentStore(from: databasePath)
let request = MyInfoEntity.fetchRequest()
try context?.fetch(request)
UserDefaults.preferredPeripheralNum = Int(myInfo?.myNodeNum ?? 0)
connectTo(peripheral: peripheral)
Logger.data.notice("🗂️ Restored Core data for /\(UserDefaults.preferredPeripheralNum, privacy: .public)")
} catch {
Logger.data.error("🗂️ Restore Core data copy error: \(error, privacy: .public)")
}
}
}
}
}
tryClearExistingChannels()
}
@ -720,7 +821,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
} catch {
context!.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data TraceRouteHOp: \(nsError)")
Logger.data.error("Error Updating Core Data TraceRouteHOp: \(nsError, privacy: .public)")
}
let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.route %@".localized, routeString)
MeshLogger.log("🪧 \(logString)")
@ -747,7 +848,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
invalidVersion = false
lastConnectionError = ""
isSubscribed = true
Logger.mesh.info("🤜 Want Config Complete. ID:\(decodedInfo.configCompleteID)")
Logger.mesh.info("[BLE] 🤜 Want Config Complete. ID:\(decodedInfo.configCompleteID)")
peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected })
// Config conplete returns so we don't read the characteristic again
@ -801,9 +902,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
case FROMNUM_UUID:
Logger.services.info("🗞️ BLE (Notify) characteristic, value will be read next")
Logger.services.info("🗞️ [BLE] (Notify) characteristic value will be read next")
default:
Logger.services.error("Unhandled Characteristic UUID: \(characteristic.uuid)")
Logger.services.error("🚫 Unhandled Characteristic UUID: \(characteristic.uuid, privacy: .public)")
}
if FROMRADIO_characteristic != nil {
// Either Read the config complete value or from num notify value
@ -905,18 +1006,18 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
let logString = String.localizedStringWithFormat("mesh.log.textmessage.sent %@ %@ %@".localized, String(newMessage.messageId), String(fromUserNum), String(toUserNum))
let logString = String.localizedStringWithFormat("mesh.log.textmessage.sent %@ %@ %@".localized, String(newMessage.messageId), fromUserNum.toHex(), toUserNum.toHex())
MeshLogger.log("💬 \(logString)")
do {
try context.save()
Logger.data.info("💾 Saved a new sent message from \(self.connectedPeripheral.num) to \(toUserNum)")
Logger.data.info("💾 Saved a new sent message from \(self.connectedPeripheral.num.toHex(), privacy: .public) to \(toUserNum.toHex(), privacy: .public)")
success = true
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Unresolved Core Data error in Send Message Function your database is corrupted running a node db reset should clean up the data. Error: \(nsError)")
Logger.data.error("Unresolved Core Data error in Send Message Function your database is corrupted running a node db reset should clean up the data. Error: \(nsError, privacy: .public)")
}
}
}
@ -982,11 +1083,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
do {
try context!.save()
Logger.data.info("💾 Updated Waypoint from Waypoint App Packet From: \(fromNodeNum)")
Logger.data.info("💾 Updated Waypoint from Waypoint App Packet From: \(fromNodeNum.toHex(), privacy: .public)")
} catch {
context!.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving NodeInfoEntity from WAYPOINT_APP \(nsError)")
Logger.data.error("Error Saving NodeInfoEntity from WAYPOINT_APP \(nsError, privacy: .public)")
}
}
return success
@ -1060,7 +1161,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return false
}
let messageDescription = "🚀 Sent Set Fixed Postion Admin Message to: \(fromUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: fromUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1085,7 +1186,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return false
}
let messageDescription = "🚀 Sent Remove Fixed Position Admin Message to: \(fromUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: fromUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1155,7 +1256,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return false
}
let messageDescription = "🚀 Sent Shutdown Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1180,7 +1281,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return false
}
let messageDescription = "🚀 Sent Reboot Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1205,7 +1306,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return false
}
let messageDescription = "🚀 Sent Reboot OTA Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1231,7 +1332,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
automaticallyReconnect = false
let messageDescription = "🚀 Sent enter DFU mode Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1256,7 +1357,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
let messageDescription = "🚀 Sent Factory Reset Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1280,7 +1381,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🚀 Sent NodeDB Reset Admin Message to: \(toUser.longName ?? "unknown".localized) from: \(fromUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -1323,7 +1424,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🎛️ Requested Channel \(channel.index) for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
return 0
@ -1347,7 +1448,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Channel \(channel.index) for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
return 0
@ -1493,7 +1594,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
return 0
}
let messageDescription = "🛟 Saved User Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
return 0
@ -1614,7 +1715,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
dataMessage.portnum = PortNum.adminApp
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Ham Parameters for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
return 0
@ -1638,7 +1739,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Bluetooth Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertBluetoothConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1666,7 +1767,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
dataMessage.portnum = PortNum.adminApp
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Device Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertDeviceConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1693,7 +1794,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
dataMessage.portnum = PortNum.adminApp
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Display Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertDisplayConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1720,7 +1821,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved LoRa Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertLoRaConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1751,7 +1852,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Position Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertPositionConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1782,7 +1883,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Power Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertPowerConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1813,7 +1914,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Network Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertNetworkConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1843,7 +1944,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Ambient Lighting Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertAmbientLightingModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1873,7 +1974,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Canned Message Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertCannedMessagesModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1904,7 +2005,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Canned Message Module Messages for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return Int64(meshPacket.id)
}
@ -1934,7 +2035,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Detection Sensor Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertDetectionSensorModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1963,7 +2064,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved External Notification Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertExternalNotificationModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -1992,7 +2093,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved PAX Counter Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertPaxCounterModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2022,7 +2123,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved RTTTL Ringtone Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertRtttlConfigPacket(ringtone: ringtone, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2053,7 +2154,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved MQTT Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertMqttModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2082,7 +2183,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛟 Saved Range Test Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertRangeTestModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2112,7 +2213,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Serial Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertSerialModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2141,7 +2242,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛟 Saved Store & Forward Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertStoreForwardModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2170,7 +2271,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "Saved Telemetry Module Config for \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
upsertTelemetryModuleConfigPacket(config: config, nodeNum: toUser.num, context: context!)
return Int64(meshPacket.id)
}
@ -2201,7 +2302,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Sent a Get Channel \(channelIndex) Request Admin Message for node: \(toUser.longName ?? "unknown".localized))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
@ -2275,7 +2376,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Requested Bluetooth Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2306,7 +2407,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Requested Device Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2337,7 +2438,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Requested Display Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2368,7 +2469,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Requested LoRa Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
@ -2400,7 +2501,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
let messageDescription = "🛎️ Requested Network Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2430,7 +2531,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Position Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2460,7 +2561,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Power Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2490,7 +2591,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Ambient Lighting Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2520,7 +2621,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Canned Messages Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2550,7 +2651,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested External Notificaiton Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2580,7 +2681,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested PAX Counter Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2610,7 +2711,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested RTTTL Ringtone Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2640,7 +2741,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Range Test Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2670,7 +2771,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested MQTT Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2700,7 +2801,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Detection Sensor Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2730,7 +2831,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Serial Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2760,7 +2861,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Store and Forward Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
@ -2790,14 +2891,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Telemetry Module Config on admin channel \(adminIndex) for node: \(toUser.longName ?? "unknown".localized)"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) {
return true
}
return false
}
// Send an admin message to a radio, save a message to core data for logging
private func sendAdminMessageToRadio(meshPacket: MeshPacket, adminDescription: String, fromUser: UserEntity, toUser: UserEntity) -> Bool {
private func sendAdminMessageToRadio(meshPacket: MeshPacket, adminDescription: String) -> Bool {
var toRadio: ToRadio!
toRadio = ToRadio()
@ -2807,25 +2908,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected {
let newMessage = MessageEntity(context: context!)
newMessage.messageId = Int64(meshPacket.id)
newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970)
newMessage.receivedACK = false
newMessage.admin = true
newMessage.adminDescription = adminDescription
newMessage.fromUser = fromUser
newMessage.toUser = toUser
do {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
try context!.save()
Logger.mesh.debug("\(adminDescription)")
return true
} catch {
context!.rollback()
let nsError = error as NSError
Logger.data.error("Error inserting new core data MessageEntity: \(nsError)")
}
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
Logger.mesh.debug("\(adminDescription)")
return true
}
return false
}
@ -2860,7 +2945,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
}
if connectedPeripheral?.peripheral.state ?? CBPeripheralState.disconnected == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
Logger.mesh.debug("📮 Sent a request for a Store & Forward Client History to \(toUser.num) for the last \(120) minutes.")
Logger.mesh.debug("📮 Sent a request for a Store & Forward Client History to \(toUser.num.toHex(), privacy: .public) for the last \(120, privacy: .public) minutes.")
return true
}
return false
@ -2871,9 +2956,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
// Handle each of the store and forward request / response messages
switch storeAndForwardMessage.rr {
case .unset:
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerError:
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerHeartbeat:
/// When we get a router heartbeat we know there is a store and forward node on the network
/// Check if it is the primary S&F Router and save the timestamp of the last heartbeat so that we can show the request message history menu item on node long press if the router has been seen recently
@ -2901,13 +2986,13 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
Logger.data.error("Save Store and Forward Router Error")
}
}
MeshLogger.log("💓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("💓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerPing:
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerPong:
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerBusy:
MeshLogger.log("🐝 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🐝 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerHistory:
/// Set the Router History Last Request Value
guard let routerNode = getNodeInfo(id: Int64(packet.from), context: context) else {
@ -2927,28 +3012,28 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
context.rollback()
Logger.data.error("Save Store and Forward Router Error")
}
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerStats:
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientError:
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("☠️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientHistory:
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📜 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientStats:
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📊 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientPing:
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientPong:
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🏓 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .clientAbort:
MeshLogger.log("🛑 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("🛑 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .UNRECOGNIZED:
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
case .routerTextDirect:
MeshLogger.log("💬 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("💬 Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
textMessageAppPacket(packet: packet, wantRangeTestPackets: false, connectedNode: connectedNodeNum, storeForward: true, context: context)
case .routerTextBroadcast:
MeshLogger.log("✉️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from)")
MeshLogger.log("✉️ Store and Forward \(storeAndForwardMessage.rr) message received from \(packet.from.toHex())")
textMessageAppPacket(packet: packet, wantRangeTestPackets: false, connectedNode: connectedNodeNum, storeForward: true, context: context)
}
}
@ -2969,11 +3054,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
do {
try context.save()
} catch {
Logger.data.error("Failed to clear existing channels from local app database: \(error.localizedDescription)")
Logger.data.error("Failed to clear existing channels from local app database: \(error.localizedDescription, privacy: .public)")
}
}
} catch {
Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription)")
Logger.data.error("Failed to find a node MyInfo to save these channels to: \(error.localizedDescription, privacy: .public)")
}
}
}
@ -2984,7 +3069,7 @@ extension BLEManager: CBCentralManagerDelegate {
// MARK: Bluetooth enabled/disabled
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
Logger.services.debug("🔌 BLE powered on")
Logger.services.info("✅ [BLE] powered on")
isSwitchedOn = true
startScanning()
} else {
@ -3009,7 +3094,7 @@ extension BLEManager: CBCentralManagerDelegate {
default:
status = "default"
}
Logger.services.debug("📜 BLEManager status: \(status)")
Logger.services.info("📜 [BLE] Bluetooth status: \(status)")
}
// Called each time a peripheral is discovered
@ -3017,7 +3102,7 @@ extension BLEManager: CBCentralManagerDelegate {
if self.automaticallyReconnect && peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" {
self.connectTo(peripheral: peripheral)
Logger.services.info("BLE Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown")")
Logger.services.info("✅ [BLE] Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown", privacy: .public)")
}
let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String
let device = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: name ?? "Unknown", shortName: "?", longName: name ?? "Unknown", firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral)

View file

@ -61,7 +61,7 @@ class LocalNotificationManager {
UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
for notification in notifications {
Logger.services.debug("\(notification)")
Logger.services.debug("\(notification, privacy: .public)")
}
}
}

View file

@ -71,6 +71,6 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
Logger.services.error("Location manager error: \(error.localizedDescription)")
Logger.services.error("Location manager error: \(error.localizedDescription, privacy: .public)")
}
}

View file

@ -50,7 +50,7 @@ import OSLog
if self.manager.authorizationStatus == .notDetermined {
self.manager.requestWhenInUseAuthorization()
}
Logger.services.info("📍 Starting location updates")
Logger.services.info("📍 [App] Starting location updates")
Task {
do {
self.updatesStarted = true
@ -70,14 +70,14 @@ import OSLog
}
}
} catch {
Logger.services.error("💥 Could not start location updates: \(error.localizedDescription)")
Logger.services.error("💥 [App] Could not start location updates: \(error.localizedDescription)")
}
return
}
}
func stopLocationUpdates() {
Logger.services.info("🛑 Stopping location updates")
Logger.services.info("🛑 [App] Stopping location updates")
self.updatesStarted = false
}
@ -85,15 +85,15 @@ import OSLog
if smartPostion {
let age = -location.timestamp.timeIntervalSinceNow
if age > 10 {
Logger.services.warning("📍 Bad Location \(self.count): Too Old \(age) seconds ago \(location)")
Logger.services.warning("📍 [App] Bad Location \(self.count, privacy: .public): Too Old \(age, privacy: .public) seconds ago \(location, privacy: .private)")
return false
}
if location.horizontalAccuracy < 0 {
Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location)")
Logger.services.warning("📍 [App] Bad Location \(self.count, privacy: .public): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)")
return false
}
if location.horizontalAccuracy > 5 {
Logger.services.warning("📍 Bad Location \(self.count): Horizontal Accuracy: \(location.horizontalAccuracy) \(location)")
Logger.services.warning("📍 [App] Bad Location \(self.count, privacy: .public): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)")
return false
}
}

View file

@ -6,14 +6,14 @@ extension Logger {
private static var subsystem = Bundle.main.bundleIdentifier!
/// All logs related to data such as decoding error, parsing issues, etc.
static let data = Logger(subsystem: subsystem, category: "🗄️ Data")
public static let data = Logger(subsystem: subsystem, category: "🗄️ Data")
/// All logs related to the mesh
static let mesh = Logger(subsystem: subsystem, category: "🕸️ Mesh")
public static let mesh = Logger(subsystem: subsystem, category: "🕸️ Mesh")
/// All logs related to services such as network calls, location, etc.
static let services = Logger(subsystem: subsystem, category: "🍏 Services")
public static let services = Logger(subsystem: subsystem, category: "🍏 Services")
/// All logs related to tracking and analytics.
static let statistics = Logger(subsystem: subsystem, category: "📈 Stats")
public static let statistics = Logger(subsystem: subsystem, category: "📈 Stats")
}

View file

@ -21,7 +21,7 @@ class OfflineTileManager: ObservableObject {
}
init() {
Logger.services.debug("Documents Directory = \(self.documentsDirectory.absoluteString)")
Logger.services.debug("Documents Directory = \(self.documentsDirectory.absoluteString, privacy: .public)")
createDirectoriesIfNecessary()
}

View file

@ -33,10 +33,10 @@ class MeshLogger {
} else {
try data.write(to: logFile, options: .atomicWrite)
let log = String(data: data, encoding: .utf8) ?? "unknown".localized
Logger.mesh.notice("\(log)")
Logger.mesh.notice("\(log, privacy: .public)")
}
} catch {
Logger.mesh.error("Error writing mesh log data: \(error.localizedDescription)")
Logger.mesh.error("Error writing mesh log data: \(error.localizedDescription, privacy: .public)")
}
}
}

View file

@ -7,6 +7,7 @@
import Foundation
import CoreData
import MeshtasticProtobufs
import SwiftUI
import RegexBuilder
import OSLog
@ -110,12 +111,12 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
myInfoEntity.rebootCount = Int32(myInfo.rebootCount)
do {
try context.save()
Logger.data.info("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))")
Logger.data.info("💾 Saved a new myInfo for node: \(myInfo.myNodeNum.toHex(), privacy: .public)")
return myInfoEntity
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Inserting New Core Data MyInfoEntity: \(nsError)")
Logger.data.error("💥 Error Inserting New Core Data MyInfoEntity: \(nsError, privacy: .public)")
}
} else {
@ -125,16 +126,16 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
do {
try context.save()
Logger.data.info("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
Logger.data.info("💾 Updated myInfo for node: \(myInfo.myNodeNum.toHex(), privacy: .public)")
return fetchedMyInfo[0]
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data MyInfoEntity: \(nsError)")
Logger.data.error("💥 Error Updating Core Data MyInfoEntity: \(nsError, privacy: .public)")
}
}
} catch {
Logger.data.error("Fetch MyInfo Error")
Logger.data.error("💥 Fetch MyInfo Error")
}
return nil
}
@ -181,16 +182,16 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
do {
try context.save()
} catch {
Logger.data.error("Failed to save channel: \(error.localizedDescription)")
Logger.data.error("💥 Failed to save channel: \(error.localizedDescription, privacy: .public)")
}
Logger.data.info("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
} else if channel.role.rawValue > 0 {
Logger.data.error("Trying to save a channel to a MyInfo that does not exist: \(fromNum)")
Logger.data.error("💥Trying to save a channel to a MyInfo that does not exist: \(fromNum.toHex(), privacy: .public)")
}
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
Logger.data.error("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError, privacy: .public)")
}
}
}
@ -198,7 +199,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
if metadata.isInitialized {
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, String(fromNum))
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, fromNum.toHex())
MeshLogger.log("🏷️ \(logString)")
let fetchedNodeRequest = NodeInfoEntity.fetchRequest()
@ -232,13 +233,13 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
do {
try context.save()
} catch {
Logger.data.error("Failed to save device metadata: \(error.localizedDescription)")
Logger.data.error("💥 Failed to save device metadata: \(error.localizedDescription, privacy: .public)")
}
Logger.data.info("💾 Updated Device Metadata from Admin App Packet For: \(fromNum)")
Logger.data.info("💾 Updated Device Metadata from Admin App Packet For: \(fromNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
Logger.data.error("Error Saving MyInfo Channel from ADMIN_APP \(nsError, privacy: .public)")
}
}
}
@ -403,19 +404,19 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
}
do {
try context.save()
Logger.data.info("💾 NodeInfo saved for \(nodeInfo.num)")
Logger.data.info("💾 [NodeInfo] saved for \(nodeInfo.num.toHex(), privacy: .public)")
return fetchedNode[0]
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError)")
Logger.data.error("💥 Error Saving Core Data NodeInfoEntity: \(nsError, privacy: .public)")
}
} catch {
Logger.data.error("Fetch MyInfo Error")
Logger.data.error("💥 Fetch MyInfo Error")
}
}
} catch {
Logger.data.error("Fetch NodeInfoEntity Error")
Logger.data.error("💥 Fetch NodeInfoEntity Error")
}
return nil
}
@ -430,7 +431,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
if !cmmc.messages.isEmpty {
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, String(packet.from))
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, packet.from.toHex())
MeshLogger.log("🥫 \(logString)")
let fetchNodeRequest = NodeInfoEntity.fetchRequest()
@ -446,15 +447,15 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
fetchedNode[0].cannedMessageConfig?.messages = messages
do {
try context.save()
Logger.data.info("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
Logger.data.info("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
Logger.data.error("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError, privacy: .public)")
}
}
} catch {
Logger.data.error("Error Deserializing ADMIN_APP packet.")
Logger.data.error("💥 Error Deserializing ADMIN_APP packet.")
}
}
}
@ -664,6 +665,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
telemetry.voltage = telemetryMessage.deviceMetrics.voltage
telemetry.uptimeSeconds = Int32(telemetryMessage.deviceMetrics.uptimeSeconds)
telemetry.metricsType = 0
Logger.statistics.info("📈 [Mesh Statistics] Channel Utilization: \(telemetryMessage.deviceMetrics.channelUtilization) Airtime: \(telemetryMessage.deviceMetrics.airUtilTx) for Node: \(packet.from.toHex())")
} else if telemetryMessage.variant == Telemetry.OneOf_Variant.environmentMetrics(telemetryMessage.environmentMetrics) {
// Environment Metrics
telemetry.barometricPressure = telemetryMessage.environmentMetrics.barometricPressure
@ -689,7 +691,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
try context.save()
// Only log telemetry from the mesh not the connected device
if connectedNode != Int64(packet.from) {
Logger.data.info("💾 Telemetry Saved for Node: \(packet.from)")
Logger.data.info("💾 [Telemetry] Saved for Node: \(packet.from.toHex())")
} else if telemetry.metricsType == 0 {
// Connected Device Metrics
// ------------------------
@ -730,10 +732,10 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Telemetry for Node \(packet.from) Error: \(nsError)")
Logger.data.error("💥 Error Saving Telemetry for Node \(packet.from, privacy: .public) Error: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("Error Fetching NodeInfoEntity for Node \(packet.from)")
Logger.data.error("💥 Error Fetching NodeInfoEntity for Node \(packet.from.toHex(), privacy: .public)")
}
}

View file

@ -81,28 +81,28 @@ class MqttClientProxyManager {
}
}
func subscribe(topic: String, qos: CocoaMQTTQoS) {
Logger.services.info("📲 MQTT Client Proxy subscribed to: \(topic)")
Logger.mqtt.info("📲 [MQTT Client Proxy] subscribed to: \(topic, privacy: .public)")
mqttClientProxy?.subscribe(topic, qos: qos)
}
func unsubscribe(topic: String) {
mqttClientProxy?.unsubscribe(topic)
Logger.services.info("📲 MQTT Client Proxy unsubscribe for: \(topic)")
Logger.mqtt.info("📲 [MQTT Client Proxy] unsubscribe to topic: \(topic, privacy: .public)")
}
func publish(message: String, topic: String, qos: CocoaMQTTQoS) {
mqttClientProxy?.publish(topic, withString: message, qos: qos)
Logger.services.debug("📲 MQTT Client Proxy publish for: \(topic)")
Logger.mqtt.debug("📲 [MQTT Client Proxy] publish for: \(topic, privacy: .public)")
}
func disconnect() {
if let client = mqttClientProxy {
client.disconnect()
Logger.services.info("📲 MQTT Client Proxy Disconnected")
Logger.mqtt.info("📲 [MQTT Client Proxy] disconnected")
}
}
}
extension MqttClientProxyManager: CocoaMQTTDelegate {
func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
Logger.services.info("📲 MQTT Client Proxy didConnectAck: \(ack)")
Logger.mqtt.info("📲 [MQTT Client Proxy] didConnectAck: \(ack, privacy: .public)")
if ack == .accept {
delegate?.onMqttConnected()
} else {
@ -112,7 +112,7 @@ extension MqttClientProxyManager: CocoaMQTTDelegate {
case .accept:
errorDescription = "No Error"
case .unacceptableProtocolVersion:
errorDescription = "Proto ver"
errorDescription = "Unacceptable Protocol version"
case .identifierRejected:
errorDescription = "Invalid Id"
case .serverUnavailable:
@ -124,40 +124,39 @@ extension MqttClientProxyManager: CocoaMQTTDelegate {
default:
errorDescription = "Unknown Error"
}
Logger.services.error("\(errorDescription)")
Logger.services.error("📲 [MQTT Client Proxy] \(errorDescription, privacy: .public)")
delegate?.onMqttError(message: errorDescription)
self.disconnect()
}
}
func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) {
Logger.services.debug("mqttDidDisconnect: \(err?.localizedDescription ?? "")")
Logger.mqtt.debug("📲 [MQTT Client Proxy] disconnected: \(err?.localizedDescription ?? "", privacy: .public)")
if let error = err {
delegate?.onMqttError(message: error.localizedDescription)
}
delegate?.onMqttDisconnected()
}
func mqtt(_ mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
Logger.services.debug("📲 MQTT Client Proxy didPublishMessage from MqttClientProxyManager: \(message)")
Logger.mqtt.info("📲 [MQTT Client Proxy] published messsage from MqttClientProxyManager: \(message, privacy: .public)")
}
func mqtt(_ mqtt: CocoaMQTT, didPublishAck id: UInt16) {
Logger.services.debug("📲 MQTT Client Proxy didPublishAck from MqttClientProxyManager: \(id)")
Logger.mqtt.info("📲 [MQTT Client Proxy] published Ack from MqttClientProxyManager: \(id, privacy: .public)")
}
public func mqtt(_ mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16) {
delegate?.onMqttMessageReceived(message: message)
Logger.services.debug("📲 MQTT Client Proxy message received on topic: \(message.topic)")
Logger.mqtt.info("📲 [MQTT Client Proxy] message received on topic: \(message.topic, privacy: .public)")
}
func mqtt(_ mqtt: CocoaMQTT, didSubscribeTopics success: NSDictionary, failed: [String]) {
Logger.services.info("📲 MQTT Client Proxy didSubscribeTopics: \(success.allKeys.count) topics. failed: \(failed.count) topics")
Logger.mqtt.debug("📲 [MQTT Client Proxy] subscribed to topics: \(success.allKeys.count, privacy: .public) topics. failed: \(failed.count, privacy: .public) topics")
}
func mqtt(_ mqtt: CocoaMQTT, didUnsubscribeTopics topics: [String]) {
Logger.services.info("didUnsubscribeTopics: \(topics.joined(separator: ", "))")
Logger.mqtt.debug("📲 [MQTT Client Proxy] unsubscribed from topics: \(topics.joined(separator: "- "), privacy: .public)")
}
func mqttDidPing(_ mqtt: CocoaMQTT) {
Logger.services.info("📲 MQTT Client Proxy mqttDidPing")
Logger.mqtt.debug("📲 [MQTT Client Proxy] ping")
}
func mqttDidReceivePong(_ mqtt: CocoaMQTT) {
Logger.services.info("📲 MQTT Client Proxy mqttDidReceivePong")
Logger.mqtt.debug("📲 [MQTT Client Proxy] pong")
}
}

View file

@ -1,28 +0,0 @@
//
// NetworkManager.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen on 4/23/23.
//
import Foundation
import Network
import OSLog
class NetworkManager {
static let shared = NetworkManager()
// MARK: Public methods
func runIfNetwork(completion: @escaping () -> Void ) {
let pathMonitor = NWPathMonitor()
pathMonitor.pathUpdateHandler = {
guard $0.status == .satisfied else {
// No network available
Logger.services.info("Network Not available")
return pathMonitor.cancel()
}
pathMonitor.cancel()
completion()
}
pathMonitor.start(queue: DispatchQueue.global(qos: .background))
}
}

View file

@ -67,7 +67,7 @@
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We use bluetooth to connect to nearby Meshtastic Devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Bluetooth is used to connect an iPhone to a user's meshtastic device to allow text messaging and location data for the mesh network.</string>
<string>Bluetooth is used to connect an iPhone to a user&apos;s meshtastic device to allow text messaging and location data for the mesh network.</string>
<key>NSCameraUsageDescription</key>
<string>We use the camera to share channels using a QR Code</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
@ -116,7 +116,7 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportsDocumentBrowser</key>
<false/>
<true/>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>

View file

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MeshtasticDataModelV 37.xcdatamodel</string>
<string>MeshtasticDataModelV 38.xcdatamodel</string>
</dict>
</plist>

View file

@ -0,0 +1,465 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22758" systemVersion="23F79" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AmbientLightingConfigEntity" representedClassName="AmbientLightingConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="blue" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="current" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="green" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ledState" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="red" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="ambientLightingConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="ambientLightingConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="deviceLoggingEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="bluetoothConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="bluetoothConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="CannedMessageConfigEntity" representedClassName="CannedMessageConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventCcw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventCw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventPress" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinA" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinB" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinPress" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="messages" optional="YES" attributeType="String" minValueString="0" maxValueString="198"/>
<attribute name="rotary1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="updown1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="cannedMessagesConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="cannedMessageConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="ChannelEntity" representedClassName="ChannelEntity" syncable="YES" codeGenerationType="class">
<attribute name="downlinkEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="index" attributeType="Integer 32" minValueString="0" maxValueString="13" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="positionPrecision" optional="YES" attributeType="Integer 32" defaultValueString="32" usesScalarValueType="YES"/>
<attribute name="psk" optional="YES" attributeType="Binary"/>
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="uplinkEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="myInfoChannel" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="channels" inverseEntity="MyInfoEntity"/>
<fetchedProperty name="allPrivateMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="channel == $FETCH_SOURCE.index &amp;&amp; toUser == nil AND isEmoji == false"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="index"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="DetectionSensorConfigEntity" representedClassName="DetectionSensorConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="detectionTriggeredHigh" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="minimumBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="monitorPin" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="stateBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="usePullup" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="detectionSensorConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="detectionSensorConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="buttonGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="buzzerGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="disableTripleClick" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="doubleTapAsButtonPress" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isManaged" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="ledHeartbeatEnabled" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="nodeInfoBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rebroadcastMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="serialEnabled" optional="YES" attributeType="Boolean" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="tzdef" optional="YES" attributeType="String"/>
<relationship name="deviceConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="deviceConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DeviceMetadataEntity" representedClassName="DeviceMetadataEntity" syncable="YES" codeGenerationType="class">
<attribute name="canShutdown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="deviceStateVersion" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
<attribute name="hasBluetooth" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasEthernet" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hwModel" optional="YES" attributeType="String"/>
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="metadataNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="metadata" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="compassNorthTop" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="displayMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="flipScreen" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="headingBold" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="oledType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="screenCarouselInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="screenOnSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="units" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wakeOnTapOrMotion" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="displayConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="displayConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="ExternalNotificationConfigEntity" representedClassName="ExternalNotificationConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="active" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBellBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBellVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessageBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessageVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="nagTimeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputBuzzer" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputVibra" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="useI2SAsBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="usePWM" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="fetchedProperty" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="ExternalNotificationConfigEntity"/>
</fetchedProperty>
</entity>
<entity name="LocationEntity" representedClassName="LocationEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="routeLocation" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RouteEntity" inverseName="locations" inverseEntity="RouteEntity"/>
</entity>
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="bandwidth" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="channelNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="codingRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="frequencyOffset" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ignoreMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="overrideDutyCycle" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="overrideFrequency" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="regionCode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="spreadFactor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sx126xRxBoostedGain" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="txEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="txPower" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="usePreset" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<relationship name="loRaConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="loRaConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="MessageEntity" representedClassName="MessageEntity" syncable="YES" codeGenerationType="class">
<attribute name="ackError" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ackSNR" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="ackTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="admin" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="adminDescription" optional="YES" attributeType="String"/>
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="messagePayload" optional="YES" attributeType="String" defaultValueString=""/>
<attribute name="messagePayloadMarkdown" optional="YES" attributeType="String"/>
<attribute name="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="portNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="read" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="realACK" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="receivedTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="fromUser" optional="YES" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
<relationship name="toUser" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="receivedMessages" inverseEntity="UserEntity"/>
<fetchedProperty name="tapbacks" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="replyID == $FETCH_SOURCE.messageId AND isEmoji == true"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="messageId"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="MQTTConfigEntity" representedClassName="MQTTConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="address" optional="YES" attributeType="String" maxValueString="30"/>
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="encryptionEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="jsonEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="mapPositionPrecision" optional="YES" attributeType="Integer 32" defaultValueString="13" usesScalarValueType="YES"/>
<attribute name="mapPublishIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="mapReportingEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="password" optional="YES" attributeType="String" maxValueString="30"/>
<attribute name="proxyToClientEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="root" optional="YES" attributeType="String" defaultValueString="msh"/>
<attribute name="tlsEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="username" optional="YES" attributeType="String" maxValueString="30"/>
<relationship name="mqttConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="mqttConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="adminIndex" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="peripheralId" optional="YES" attributeType="String"/>
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="channels" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="ChannelEntity" inverseName="myInfoChannel" inverseEntity="ChannelEntity"/>
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="allMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="toUser == nil"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="myNodeNum"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="NetworkConfigEntity" representedClassName="NetworkConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="dns" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ethEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="gateway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ip" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ntpServer" optional="YES" attributeType="String"/>
<attribute name="subnet" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wifiEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="wifiMode" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="wifiPsk" optional="YES" attributeType="String" minValueString="0" maxValueString="60"/>
<attribute name="wifiSsid" optional="YES" attributeType="String" minValueString="0" maxValueString="30"/>
<relationship name="networkConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="networkConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="favorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="firstHeard" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="hopsAway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="lastHeard" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="peripheralId" optional="YES" attributeType="String"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="viaMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="ambientLightingConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="AmbientLightingConfigEntity" inverseName="ambientLightingConfigNode" inverseEntity="AmbientLightingConfigEntity"/>
<relationship name="bluetoothConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="BluetoothConfigEntity" inverseName="bluetoothConfigNode" inverseEntity="BluetoothConfigEntity"/>
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
<relationship name="detectionSensorConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DetectionSensorConfigEntity" inverseName="detectionSensorConfigNode" inverseEntity="DetectionSensorConfigEntity"/>
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DisplayConfigEntity" inverseName="displayConfigNode" inverseEntity="DisplayConfigEntity"/>
<relationship name="externalNotificationConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ExternalNotificationConfigEntity" inverseName="externalNotificationConfigNode" inverseEntity="ExternalNotificationConfigEntity"/>
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
<relationship name="metadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceMetadataEntity" inverseName="metadataNode" inverseEntity="DeviceMetadataEntity"/>
<relationship name="mqttConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MQTTConfigEntity" inverseName="mqttConfigNode" inverseEntity="MQTTConfigEntity"/>
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
<relationship name="networkConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NetworkConfigEntity" inverseName="networkConfigNode" inverseEntity="NetworkConfigEntity"/>
<relationship name="pax" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PaxCounterEntity" inverseName="paxNode" inverseEntity="PaxCounterEntity"/>
<relationship name="paxCounterConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PaxCounterConfigEntity" inverseName="paxCounterConfigNode" inverseEntity="PaxCounterConfigEntity"/>
<relationship name="positionConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PositionConfigEntity" inverseName="positionConfigNode" inverseEntity="PositionConfigEntity"/>
<relationship name="positions" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PositionEntity" inverseName="nodePosition" inverseEntity="PositionEntity"/>
<relationship name="powerConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PowerConfigEntity" inverseName="powerConfigNode" inverseEntity="PowerConfigEntity"/>
<relationship name="rangeTestConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RangeTestConfigEntity" inverseName="rangeTestConfigNode" inverseEntity="RangeTestConfigEntity"/>
<relationship name="rtttlConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RTTTLConfigEntity" inverseName="rtttlConfigNode" inverseEntity="RTTTLConfigEntity"/>
<relationship name="serialConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SerialConfigEntity" inverseName="serialConfigNode" inverseEntity="SerialConfigEntity"/>
<relationship name="storeForwardConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreForwardConfigEntity" inverseName="storeForwardConfigNode" inverseEntity="StoreForwardConfigEntity"/>
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
<relationship name="telemetryConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TelemetryConfigEntity" inverseName="telemetryConfigNode" inverseEntity="TelemetryConfigEntity"/>
<relationship name="traceRoutes" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteEntity" inverseName="node" inverseEntity="TraceRouteEntity"/>
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="num"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="PaxCounterConfigEntity" representedClassName="PaxCounterConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="bleThreshold" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="updateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wifiThreshold" optional="YES" attributeType="Integer 32" defaultValueString="-80" usesScalarValueType="YES"/>
<relationship name="paxCounterConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="paxCounterConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PaxCounterEntity" representedClassName="PaxCounterEntity" syncable="YES" codeGenerationType="class">
<attribute name="ble" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="uptime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wifi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="paxNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="pax" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PositionConfigEntity" representedClassName="PositionConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="broadcastSmartMinimumDistance" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="broadcastSmartMinimumIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="deviceGpsEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fixedPosition" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="gpsAttemptTime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsEnGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="positionBroadcastSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rxGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="smartPositionEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="txGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="positionConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positionConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PositionEntity" representedClassName="PositionEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latest" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="precisionBits" optional="YES" attributeType="Integer 32" defaultValueString="32" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="satsInView" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="seqNo" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="nodePosition" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positions" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PowerConfigEntity" representedClassName="PowerConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="adcMultiplierOverride" optional="YES" attributeType="Float" usesScalarValueType="YES"/>
<attribute name="deviceBatteryInaAddress" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isPowerSaving" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lsSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="minWakeSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="onBatteryShutdownAfterSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="waitBluetoothSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="powerConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="powerConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RangeTestConfigEntity" representedClassName="RangeTestConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="save" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sender" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="color" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="distance" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="elevationGain" optional="YES" attributeType="Double" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="endDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="notes" optional="YES" attributeType="String"/>
<relationship name="locations" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="LocationEntity" inverseName="routeLocation" inverseEntity="LocationEntity"/>
</entity>
<entity name="RTTTLConfigEntity" representedClassName="RTTTLConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="ringtone" optional="YES" attributeType="String" maxValueString="228" defaultValueString=""/>
<relationship name="rtttlConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rtttlConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="SerialConfigEntity" representedClassName="SerialConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="baudRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="echo" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="overrideConsoleSerialPort" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="rxd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="timeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="txd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="serialConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="serialConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="StoreForwardConfigEntity" representedClassName="StoreForwardConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="heartbeat" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="historyReturnMax" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="historyReturnWindow" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isRouter" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="lastHeartbeat" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="lastRequest" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="records" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="storeForwardConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="storeForwardConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TelemetryConfigEntity" representedClassName="TelemetryConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="deviceUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="environmentDisplayFahrenheit" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentMeasurementEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="powerMeasurementEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="powerScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="powerUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="telemetryConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetryConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TelemetryEntity" representedClassName="TelemetryEntity" syncable="YES" codeGenerationType="class">
<attribute name="airUtilTx" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="barometricPressure" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="batteryLevel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="channelUtilization" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="current" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="gasResistance" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="iaq" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="metricsType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="relativeHumidity" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="temperature" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="uptimeSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="voltage" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="nodeTelemetry" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetries" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TraceRouteEntity" representedClassName="TraceRouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hasPositions" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="response" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="route" optional="YES" attributeType="Transformable" customClassName="[UInt32]"/>
<attribute name="routeText" optional="YES" attributeType="String"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="hops" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteHopEntity" inverseName="traceRoute" inverseEntity="TraceRouteHopEntity"/>
<relationship name="node" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="traceRoutes" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TraceRouteHopEntity" representedClassName="TraceRouteHopEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="traceRoute" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TraceRouteEntity" inverseName="hops" inverseEntity="TraceRouteEntity"/>
</entity>
<entity name="UserEntity" representedClassName="UserEntity" syncable="YES" codeGenerationType="class">
<attribute name="hwModel" attributeType="String"/>
<attribute name="isLicensed" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="lastMessage" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="longName" attributeType="String"/>
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="numString" optional="YES" attributeType="String"/>
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="shortName" attributeType="String"/>
<attribute name="userId" attributeType="String"/>
<relationship name="receivedMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="toUser" inverseEntity="MessageEntity"/>
<relationship name="sentMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="fromUser" inverseEntity="MessageEntity"/>
<relationship name="userNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="user" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="adminMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND isEmoji == false AND admin = true"/>
</fetchedProperty>
<fetchedProperty name="allMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false AND portNum != 10 "/>
</fetchedProperty>
<fetchedProperty name="detectionSensorMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND portNum = 10"/>
</fetchedProperty>
</entity>
<entity name="WaypointEntity" representedClassName="WaypointEntity" syncable="YES" codeGenerationType="class">
<attribute name="created" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="expire" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="icon" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="lastUpdated" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="locked" attributeType="Integer 64" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="longDescription" optional="YES" attributeType="String" maxValueString="100"/>
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String" minValueString="1" maxValueString="30"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="id"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
</model>

View file

@ -140,22 +140,22 @@ struct MeshtasticAppleApp: App {
.onChange(of: scenePhase) { (newScenePhase) in
switch newScenePhase {
case .background:
Logger.services.info("🍏 Scene is in the background")
Logger.services.info("🎬 [App] Scene is in the background")
do {
try persistenceController.container.viewContext.save()
Logger.services.info("💾 Saved CoreData ViewContext when the app went to the background.")
Logger.services.info("💾 [App] Saved CoreData ViewContext when the app went to the background.")
} catch {
Logger.services.error("💥 Failed to save viewContext when the app goes to the background.")
Logger.services.error("💥 [App] Failed to save viewContext when the app goes to the background.")
}
case .inactive:
Logger.services.info("🍏 Scene is inactive")
Logger.services.info("🎬 [App] Scene is inactive")
case .active:
Logger.services.info("🍏 Scene is active")
Logger.services.info("🎬 [App] Scene is active")
@unknown default:
Logger.services.error("🍎 Apple must have changed something")
Logger.services.error("🍎 [App] Apple must have changed something")
}
}
}

View file

@ -10,7 +10,7 @@ import OSLog
class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
Logger.services.info("🚀 Meshtstic Apple App launched!")
Logger.services.info("🚀 [App] Meshtstic Apple App launched!")
// Default User Default Values
UserDefaults.standard.register(defaults: ["meshMapRecentering": true])
UserDefaults.standard.register(defaults: ["meshMapShowNodeHistory": true])

View file

@ -89,3 +89,170 @@ extension NSManagedObjectContext {
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [self])
}
}
// Created by Tom Harrington on 5/12/20.
// Copyright © 2020 Atomic Bird LLC. All rights reserved.
// Gist from https://atomicbird.com/blog/core-data-back-up-store/
//
extension NSPersistentContainer {
enum CopyPersistentStoreErrors: Error {
case invalidDestination(String)
case destinationError(String)
case destinationNotRemoved(String)
case copyStoreError(String)
case invalidSource(String)
}
/// Restore a persistent store for a URL `backupURL`.
/// **Be very careful with this**. To restore a persistent store, the current persistent store must be removed from the container. When that happens, **all currently loaded Core Data objects** will become invalid. Using them after restoring will cause your app to crash. When calling this method you **must** ensure that you do not continue to use any previously fetched managed objects or existing fetched results controllers. **If this method does not throw, that does not mean your app is safe.** You need to take extra steps to prevent crashes. The details vary depending on the nature of your app.
/// - Parameter backupURL: A file URL containing backup copies of all currently loaded persistent stores.
/// - Throws: `CopyPersistentStoreError` in various situations.
/// - Returns: Nothing. If no errors are thrown, the restore is complete.
// func restorePersistentStore(from backupURL: URL) throws -> Void {
// guard backupURL.isFileURL else {
// throw CopyPersistentStoreErrors.invalidSource("Backup URL must be a file URL")
// }
//
// for persistentStoreDescription in persistentStoreDescriptions {
// guard let loadedStoreURL = persistentStoreDescription.url else {
// continue
// }
// guard FileManager.default.fileExists(atPath: backupURL.path) else {
// throw CopyPersistentStoreErrors.invalidSource("Missing backup store for \(backupURL)")
// }
// do {
// let storeOptions = persistentStoreDescription.options
// let configurationName = persistentStoreDescription.configuration
// let storeType = persistentStoreDescription.type
//
// // Replace the current store with the backup copy. This has a side effect of removing the current store from the Core Data stack.
// // When restoring, it's necessary to use the current persistent store coordinator.
// try persistentStoreCoordinator.replacePersistentStore(at: loadedStoreURL, destinationOptions: storeOptions, withPersistentStoreFrom: backupURL, sourceOptions: storeOptions, ofType: storeType)
// // Add the persistent store at the same location we've been using, because it was removed in the previous step.
// try persistentStoreCoordinator.addPersistentStore(ofType: storeType, configurationName: configurationName, at: loadedStoreURL, options: storeOptions)
// } catch {
// throw CopyPersistentStoreErrors.copyStoreError("Could not restore: \(error.localizedDescription)")
// }
// }
// }
//
/// Restore backup persistent stores located in the directory referenced by `backupURL`.
///
/// **Be very careful with this**. To restore a persistent store, the current persistent store must be removed from the container. When that happens, **all currently loaded Core Data objects** will become invalid. Using them after restoring will cause your app to crash. When calling this method you **must** ensure that you do not continue to use any previously fetched managed objects or existing fetched results controllers. **If this method does not throw, that does not mean your app is safe.** You need to take extra steps to prevent crashes. The details vary depending on the nature of your app.
/// - Parameter backupURL: A file URL containing backup copies of all currently loaded persistent stores.
/// - Throws: `CopyPersistentStoreError` in various situations.
/// - Returns: Nothing. If no errors are thrown, the restore is complete.
func restorePersistentStore(from backupURL: URL) throws -> Void {
guard backupURL.isFileURL else {
throw CopyPersistentStoreErrors.invalidSource("Backup URL must be a file URL")
}
var isDirectory: ObjCBool = false
if FileManager.default.fileExists(atPath: backupURL.path, isDirectory: &isDirectory) {
if !isDirectory.boolValue {
throw CopyPersistentStoreErrors.invalidSource("Source URL must be a directory")
}
} else {
throw CopyPersistentStoreErrors.invalidSource("Source URL must exist")
}
for persistentStoreDescription in persistentStoreDescriptions {
guard let loadedStoreURL = persistentStoreDescription.url else {
continue
}
let backupStoreURL = backupURL.appendingPathComponent(loadedStoreURL.lastPathComponent)
guard FileManager.default.fileExists(atPath: backupStoreURL.path) else {
throw CopyPersistentStoreErrors.invalidSource("Missing backup store for \(backupStoreURL)")
}
do {
let storeOptions = persistentStoreDescription.options
let configurationName = persistentStoreDescription.configuration
let storeType = persistentStoreDescription.type
// Replace the current store with the backup copy. This has a side effect of removing the current store from the Core Data stack.
// When restoring, it's necessary to use the current persistent store coordinator.
try persistentStoreCoordinator.replacePersistentStore(at: loadedStoreURL, destinationOptions: storeOptions, withPersistentStoreFrom: backupStoreURL, sourceOptions: storeOptions, ofType: storeType)
// Add the persistent store at the same location we've been using, because it was removed in the previous step.
try persistentStoreCoordinator.addPersistentStore(ofType: storeType, configurationName: configurationName, at: loadedStoreURL, options: storeOptions)
} catch {
throw CopyPersistentStoreErrors.copyStoreError("Could not restore: \(error.localizedDescription)")
}
}
}
/// Copy all loaded persistent stores to a new directory. Each currently loaded file-based persistent store will be copied (including journal files, external binary storage, and anything else Core Data needs) into the destination directory to a persistent store with the same name and type as the existing store. In-memory stores, if any, are skipped.
/// - Parameters:
/// - destinationURL: Destination for new persistent store files. Must be a file URL. If `overwriting` is `false` and `destinationURL` exists, it must be a directory.
/// - overwriting: If `true`, any existing copies of the persistent store will be replaced or updated. If `false`, existing copies will not be changed or remoted. When this is `false`, the destination persistent store file must not already exist.
/// - Throws: `CopyPersistentStoreError`
/// - Returns: Nothing. If no errors are thrown, all loaded persistent stores will be copied to the destination directory.
func copyPersistentStores(to destinationURL: URL, overwriting: Bool = false) throws -> Void {
guard !destinationURL.relativeString.contains("/0/") else {
throw CopyPersistentStoreErrors.invalidDestination("Invalid 0 Node Id")
}
guard destinationURL.isFileURL else {
throw CopyPersistentStoreErrors.invalidDestination("Destination URL must be a file URL")
}
// If the destination exists and we aren't overwriting it, then it must be a directory. (If we are overwriting, we'll remove it anyway, so it doesn't matter whether it's a directory).
var isDirectory: ObjCBool = false
if !overwriting && FileManager.default.fileExists(atPath: destinationURL.path, isDirectory: &isDirectory) {
if !isDirectory.boolValue {
throw CopyPersistentStoreErrors.invalidDestination("Destination URL must be a directory")
}
// Don't check if destination stores exist in the destination dir, that comes later on a per-store basis.
}
// If we're overwriting, remove the destination.
if overwriting && FileManager.default.fileExists(atPath: destinationURL.path) {
do {
try FileManager.default.removeItem(at: destinationURL)
} catch {
throw CopyPersistentStoreErrors.destinationNotRemoved("Can't overwrite destination at \(destinationURL)")
}
}
// Create the destination directory
do {
try FileManager.default.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
} catch {
throw CopyPersistentStoreErrors.destinationError("Could not create destination directory at \(destinationURL)")
}
for persistentStoreDescription in persistentStoreDescriptions {
guard let storeURL = persistentStoreDescription.url else {
continue
}
guard persistentStoreDescription.type != NSInMemoryStoreType else {
continue
}
let destinationStoreURL = destinationURL.appendingPathComponent(storeURL.lastPathComponent)
if !overwriting && FileManager.default.fileExists(atPath: destinationStoreURL.path) {
// If the destination exists, the replacePersistentStore call will update it in place. That's fine unless we're not overwriting.
throw CopyPersistentStoreErrors.destinationError("Destination already exists at \(destinationStoreURL)")
}
do {
// Replace an existing backup, if any, with a new one with the same options and type. This doesn't affect the current Core Data stack.
// The function name says "replace", but it works if there's nothing at the destination yet. In that case it creates a new persistent store.
// Note that for backup, it doesn't matter if the persistent store coordinator is the one currently in use or a different one. It could be a class function, for this use.
try persistentStoreCoordinator.replacePersistentStore(at: destinationStoreURL, destinationOptions: persistentStoreDescription.options, withPersistentStoreFrom: storeURL, sourceOptions: persistentStoreDescription.options, ofType: persistentStoreDescription.type)
/// Cleanup extra files
let directory = destinationStoreURL.deletingLastPathComponent()
/// Delete -wal file
do {
try FileManager.default.removeItem(at: directory.appendingPathComponent("Meshtastic.sqlite-wal"))
/// Delete -shm file
do {
try FileManager.default.removeItem(at: directory.appendingPathComponent("Meshtastic.sqlite-shm"))
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite-shm file \(error, privacy: .public)")
}
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite-wal file \(error, privacy: .public)")
}
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite file \(error, privacy: .public)")
throw CopyPersistentStoreErrors.copyStoreError("\(error.localizedDescription)")
}
}
}
}

View file

@ -5,6 +5,7 @@
// Copyright(c) Garth Vander Houwen 10/3/22.
import CoreData
import MeshtasticProtobufs
import OSLog
public func clearPax(destNum: Int64, context: NSManagedObjectContext) -> Bool {
@ -25,7 +26,7 @@ public func clearPax(destNum: Int64, context: NSManagedObjectContext) -> Bool {
return false
}
} catch {
Logger.data.error("Fetch NodeInfoEntity Error")
Logger.data.error("💥 [NodeInfoEntity] fetch data error")
return false
}
}
@ -48,7 +49,7 @@ public func clearPositions(destNum: Int64, context: NSManagedObjectContext) -> B
return false
}
} catch {
Logger.data.error("Fetch NodeInfoEntity Error")
Logger.data.error("💥 [NodeInfoEntity] fetch data error")
return false
}
}
@ -71,7 +72,7 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
return false
}
} catch {
Logger.data.error("Fetch NodeInfoEntity Error")
Logger.data.error("💥 [NodeInfoEntity] fetch data error")
return false
}
}
@ -128,7 +129,7 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext, includeRoutes
func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, String(packet.from))
let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, packet.from.toHex())
MeshLogger.log("📟 \(logString)")
guard packet.from > 0 else { return }
@ -194,7 +195,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
} else {
if packet.from > Int16.max {
let newUser = createUser(num: Int64(packet.from), context: context)
fetchedNode[0].user = newUser
newNode.user = newUser
}
}
@ -207,11 +208,11 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
myInfoEntity.rebootCount = 0
do {
try context.save()
Logger.data.info("💾 Saved a new myInfo for node number: \(String(packet.from))")
Logger.data.info("💾 [MyInfoEntity] Saved a new myInfo for node number: \(packet.from.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Inserting New Core Data MyInfoEntity: \(nsError)")
Logger.data.error("💥 [MyInfoEntity] Error Inserting New Core Data: \(nsError, privacy: .public)")
}
newNode.myInfo = myInfoEntity
@ -264,15 +265,15 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
}
do {
try context.save()
Logger.data.info("💾 Updated NodeInfo from Node Info App Packet For: \(fetchedNode[0].num)")
Logger.data.info("💾 [NodeInfoEntity] Updated from Node Info App Packet For: \(fetchedNode[0].num.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)")
Logger.data.error("💥 [NodeInfoEntity] Error Saving from NODEINFO_APP \(nsError, privacy: .public)")
}
}
} catch {
Logger.data.error("Error Fetching NodeInfoEntity for NODEINFO_APP")
Logger.data.error("💥 [NodeInfoEntity] fetch data error for NODEINFO_APP")
}
}
@ -352,11 +353,11 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
do {
try context.save()
Logger.data.info("💾 Updated Node Position Coordinates, SNR and Time from Position App Packet For: \(fetchedNode[0].num)")
Logger.data.info("💾 Updated Node Position Coordinates from Position App Packet For: \(fetchedNode[0].num.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
Logger.data.error("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError, privacy: .public)")
}
}
} else {
@ -364,16 +365,16 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
if (try? NodeInfo(serializedData: packet.decoded.payload)) != nil {
upsertNodeInfoPacket(packet: packet, context: context)
} else {
Logger.data.error("Empty POSITION_APP Packet: \((try? packet.jsonString()) ?? "JSON Decode Failure")")
Logger.data.error("💥 Empty POSITION_APP Packet: \((try? packet.jsonString()) ?? "JSON Decode Failure", privacy: .public)")
}
}
}
} catch {
Logger.data.error("Error Deserializing POSITION_APP packet.")
Logger.data.error("💥 Error Deserializing POSITION_APP packet.")
}
}
func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.bluetooth.config %@".localized, String(nodeNum))
MeshLogger.log("📶 \(logString)")
@ -390,30 +391,32 @@ func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, node
newBluetoothConfig.enabled = config.enabled
newBluetoothConfig.mode = Int32(config.mode.rawValue)
newBluetoothConfig.fixedPin = Int32(config.fixedPin)
newBluetoothConfig.deviceLoggingEnabled = config.deviceLoggingEnabled
fetchedNode[0].bluetoothConfig = newBluetoothConfig
} else {
fetchedNode[0].bluetoothConfig?.enabled = config.enabled
fetchedNode[0].bluetoothConfig?.mode = Int32(config.mode.rawValue)
fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.fixedPin)
fetchedNode[0].bluetoothConfig?.deviceLoggingEnabled = config.deviceLoggingEnabled
}
do {
try context.save()
Logger.data.info("💾 Updated Bluetooth Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [BluetoothConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data BluetoothConfigEntity: \(nsError)")
Logger.data.error("💥 [BluetoothConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Bluetooth Config")
Logger.data.error("💥 [BluetoothConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Bluetooth Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data BluetoothConfigEntity failed: \(nsError)")
Logger.data.error("💥 [BluetoothConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.device.config %@".localized, String(nodeNum))
MeshLogger.log("📟 \(logString)")
@ -453,22 +456,22 @@ func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: I
}
do {
try context.save()
Logger.data.info("💾 Updated Device Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [DeviceConfigEntity] Updated Device Config for node number: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data DeviceConfigEntity: \(nsError)")
Logger.data.error("💥 [DeviceConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data DeviceConfigEntity failed: \(nsError)")
Logger.data.error("💥 [DeviceConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.display.config %@".localized, String(nodeNum))
let logString = String.localizedStringWithFormat("mesh.log.display.config %@".localized, nodeNum.toHex())
MeshLogger.log("🖥️ \(logString)")
let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest()
@ -509,30 +512,30 @@ func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum:
do {
try context.save()
Logger.data.info("💾 Updated Display Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [DisplayConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data DisplayConfigEntity: \(nsError)")
Logger.data.error("💥 [DisplayConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Display Config")
Logger.data.error("💥 [DisplayConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex()) unable to save Display Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data DisplayConfigEntity failed: \(nsError)")
Logger.data.error("💥 [DisplayConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.lora.config %@".localized, String(nodeNum))
let logString = String.localizedStringWithFormat("mesh.log.lora.config %@".localized, nodeNum.toHex())
MeshLogger.log("📻 \(logString)")
let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest()
@ -580,22 +583,22 @@ func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64
}
do {
try context.save()
Logger.data.info("💾 Updated LoRa Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [LoRaConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data LoRaConfigEntity: \(nsError)")
Logger.data.error("💥 [LoRaConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Lora Config")
Logger.data.error("💥 [LoRaConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Lora Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data LoRaConfigEntity failed: \(nsError)")
Logger.data.error("💥 [LoRaConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.network.config %@".localized, String(nodeNum))
MeshLogger.log("🌐 \(logString)")
@ -623,23 +626,23 @@ func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum:
do {
try context.save()
Logger.data.info("💾 Updated Network Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [NetworkConfigEntity] Updated Network Config for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data WiFiConfigEntity: \(nsError)")
Logger.data.error("💥 [NetworkConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Network Config")
Logger.data.error("💥 [NetworkConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Network Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data NetworkConfigEntity failed: \(nsError)")
Logger.data.error("💥 [NetworkConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.position.config %@".localized, String(nodeNum))
MeshLogger.log("🗺️ \(logString)")
@ -684,22 +687,22 @@ func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNu
}
do {
try context.save()
Logger.data.info("💾 Updated Position Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [PositionConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data PositionConfigEntity: \(nsError)")
Logger.data.error("💥 [PositionConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Position Config")
Logger.data.error("💥 [PositionConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Position Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data PositionConfigEntity failed: \(nsError)")
Logger.data.error("💥 [PositionConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertPowerConfigPacket(config: Meshtastic.Config.PowerConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.power.config %@".localized, String(nodeNum))
MeshLogger.log("🗺️ \(logString)")
@ -731,22 +734,22 @@ func upsertPowerConfigPacket(config: Meshtastic.Config.PowerConfig, nodeNum: Int
}
do {
try context.save()
Logger.data.info("💾 Updated Power Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [PowerConfigEntity] Updated Power Config for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data PowerConfigEntity: \(nsError)")
Logger.data.error("💥 [PowerConfigEntity] Error Updating Core Data PowerConfigEntity: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Power Config")
Logger.data.error("💥 [PowerConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Power Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data PowerConfigEntity failed: \(nsError)")
Logger.data.error("💥 [PowerConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertAmbientLightingModuleConfigPacket(config: Meshtastic.ModuleConfig.AmbientLightingConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightingConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.ambientlighting.config %@".localized, String(nodeNum))
MeshLogger.log("🏮 \(logString)")
@ -784,22 +787,22 @@ func upsertAmbientLightingModuleConfigPacket(config: Meshtastic.ModuleConfig.Amb
do {
try context.save()
Logger.data.info("💾 Updated Ambient Lighting Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [AmbientLightingConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data AmbientLightingConfigEntity: \(nsError)")
Logger.data.error("💥 [AmbientLightingConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Ambient Lighting Module Config")
Logger.data.error("💥 [AmbientLightingConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Ambient Lighting Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data AmbientLightingConfigEntity failed: \(nsError)")
Logger.data.error("💥 [AmbientLightingConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.CannedMessageConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.cannedmessage.config %@".localized, String(nodeNum))
MeshLogger.log("🥫 \(logString)")
@ -845,22 +848,22 @@ func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.Cann
do {
try context.save()
Logger.data.info("💾 Updated Canned Message Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [CannedMessageConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data CannedMessageConfigEntity: \(nsError)")
Logger.data.error("💥 [CannedMessageConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Canned Message Module Config")
Logger.data.error("💥 [CannedMessageConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Canned Message Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data CannedMessageConfigEntity failed: \(nsError)")
Logger.data.error("💥 [CannedMessageConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertDetectionSensorModuleConfigPacket(config: Meshtastic.ModuleConfig.DetectionSensorConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSensorConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.detectionsensor.config %@".localized, String(nodeNum))
MeshLogger.log("🕵️ \(logString)")
@ -900,25 +903,25 @@ func upsertDetectionSensorModuleConfigPacket(config: Meshtastic.ModuleConfig.Det
do {
try context.save()
Logger.data.info("💾 Updated Detection Sensor Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [DetectionSensorConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data DetectionSensorConfigEntity: \(nsError)")
Logger.data.error("💥 [DetectionSensorConfigEntity] Error Updating Core Data : \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Detection Sensor Module Config")
Logger.data.error("💥 [DetectionSensorConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Detection Sensor Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data DetectionSensorConfigEntity failed: \(nsError)")
Logger.data.error("💥 [DetectionSensorConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.externalnotification.config %@".localized, String(nodeNum))
MeshLogger.log("📣 \(logString)")
@ -970,22 +973,22 @@ func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfi
do {
try context.save()
Logger.data.info("💾 Updated External Notification Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [ExternalNotificationConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)")
Logger.data.error("💥 [ExternalNotificationConfigEntity] Error Updating Core Data : \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save External Notification Module Config")
Logger.data.error("💥 [ExternalNotificationConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save External Notification Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data ExternalNotificationConfigEntity failed: \(nsError)")
Logger.data.error("💥 [ExternalNotificationConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertPaxCounterModuleConfigPacket(config: Meshtastic.ModuleConfig.PaxcounterConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.paxcounter.config %@".localized, String(nodeNum))
MeshLogger.log("🧑‍🤝‍🧑 \(logString)")
@ -1012,18 +1015,18 @@ func upsertPaxCounterModuleConfigPacket(config: Meshtastic.ModuleConfig.Paxcount
do {
try context.save()
Logger.data.info("💾 Updated PAX Counter Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [PaxCounterConfigEntity] Updated for node number: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)")
Logger.data.error("💥 [PaxCounterConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save PAX Counter Module Config")
Logger.data.error("💥 [PaxCounterConfigEntity] No Nodes found in local database matching node number \(nodeNum.toHex(), privacy: .public) unable to save PAX Counter Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data PaxCounterConfigEntity failed: \(nsError)")
Logger.data.error("💥 [PaxCounterConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
@ -1048,22 +1051,22 @@ func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, context: NSManage
}
do {
try context.save()
Logger.data.info("💾 Updated RTTTL Ringtone Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [RtttlConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data RtttlConfigEntity: \(nsError)")
Logger.data.error("💥 [RtttlConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save RTTTL Ringtone Config")
Logger.data.error("💥 [RtttlConfigEntity] No nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save RTTTL Ringtone Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data RtttlConfigEntity failed: \(nsError)")
Logger.data.error("💥 [RtttlConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.mqtt.config %@".localized, String(nodeNum))
MeshLogger.log("🌉 \(logString)")
@ -1107,22 +1110,22 @@ func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, no
}
do {
try context.save()
Logger.data.info("💾 Updated MQTT Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [MQTTConfigEntity] Updated for node number: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data MQTTConfigEntity: \(nsError)")
Logger.data.error("💥 [MQTTConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save MQTT Module Config")
Logger.data.error("💥 [MQTTConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save MQTT Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data MQTTConfigEntity failed: \(nsError)")
Logger.data.error("💥 [MQTTConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTestConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.rangetest.config %@".localized, String(nodeNum))
MeshLogger.log("⛰️ \(logString)")
@ -1147,22 +1150,22 @@ func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTest
}
do {
try context.save()
Logger.data.info("💾 Updated Range Test Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [RangeTestConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data RangeTestConfigEntity: \(nsError)")
Logger.data.error("💥 [RangeTestConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Range Test Module Config")
Logger.data.error("💥 [RangeTestConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Range Test Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data RangeTestConfigEntity failed: \(nsError)")
Logger.data.error("💥 [RangeTestConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.serial.config %@".localized, String(nodeNum))
MeshLogger.log("🤖 \(logString)")
@ -1199,29 +1202,25 @@ func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig
do {
try context.save()
Logger.data.info("💾 Updated Serial Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [SerialConfigEntity]Updated Serial Module Config for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data SerialConfigEntity: \(nsError)")
Logger.data.error("💥 [SerialConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config")
Logger.data.error("💥 [SerialConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Serial Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data SerialConfigEntity failed: \(nsError)")
Logger.data.error("💥 [SerialConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertStoreForwardModuleConfigPacket(config: Meshtastic.ModuleConfig.StoreForwardConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.storeforward.config %@".localized, String(nodeNum))
MeshLogger.log("📬 \(logString)")
@ -1253,22 +1252,22 @@ func upsertStoreForwardModuleConfigPacket(config: Meshtastic.ModuleConfig.StoreF
}
do {
try context.save()
Logger.data.info("💾 Updated Store & Forward Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [StoreForwardConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data StoreForwardConfigEntity: \(nsError)")
Logger.data.error("💥 [StoreForwardConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Store & Forward Module Config")
Logger.data.error("💥 [StoreForwardConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Store & Forward Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data DetectionSensorConfigEntity failed: \(nsError)")
Logger.data.error("💥 [StoreForwardConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)")
}
}
func upsertTelemetryModuleConfigPacket(config: Meshtastic.ModuleConfig.TelemetryConfig, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat("mesh.log.telemetry.config %@".localized, String(nodeNum))
MeshLogger.log("📈 \(logString)")
@ -1307,20 +1306,20 @@ func upsertTelemetryModuleConfigPacket(config: Meshtastic.ModuleConfig.Telemetry
do {
try context.save()
Logger.data.info("💾 Updated Telemetry Module Config for node number: \(String(nodeNum))")
Logger.data.info("💾 [TelemetryConfigEntity] Updated Telemetry Module Config for node: \(nodeNum.toHex(), privacy: .public)")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Updating Core Data TelemetryConfigEntity: \(nsError)")
Logger.data.error("💥 [TelemetryConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)")
}
} else {
Logger.data.error("No Nodes found in local database matching node number \(nodeNum) unable to save Telemetry Module Config")
Logger.data.error("💥 [TelemetryConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Telemetry Module Config")
}
} catch {
let nsError = error as NSError
Logger.data.error("Fetching node for core data TelemetryConfigEntity failed: \(nsError)")
Logger.data.error("💥 [TelemetryConfigEntity] Fetching node for core data TelemetryConfigEntity failed: \(nsError, privacy: .public)")
}
}

View file

@ -26,7 +26,6 @@ struct Connect: View {
@State var isUnsetRegion = false
@State var invalidFirmwareVersion = false
@State var liveActivityStarted = false
@State var presentingSwitchPreferredPeripheral = false
@State var selectedPeripherialId = ""
init () {
@ -49,7 +48,7 @@ struct Connect: View {
List {
if bleManager.isSwitchedOn {
Section(header: Text("connected.radio").font(.title)) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
if let connectedPeripheral = bleManager.connectedPeripheral, connectedPeripheral.peripheral.state == .connected {
if #available(iOS 17.0, macOS 14.0, *) {
TipView(BluetoothConnectionTip(), arrowEdge: .bottom)
}
@ -60,9 +59,9 @@ struct Connect: View {
.padding(.trailing)
VStack(alignment: .leading) {
if node != nil {
Text(bleManager.connectedPeripheral.longName).font(.title2)
Text(connectedPeripheral.longName).font(.title2)
}
Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? "unknown".localized)")
Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral?.peripheral.name ?? "unknown".localized)")
.font(.callout).foregroundColor(Color.gray)
if node != nil {
Text("firmware.version").font(.callout)+Text(": \(node?.metadata?.firmwareVersion ?? "unknown".localized)")
@ -91,7 +90,8 @@ struct Connect: View {
.padding([.top, .bottom])
.swipeActions {
Button(role: .destructive) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
if let connectedPeripheral = bleManager.connectedPeripheral,
connectedPeripheral.peripheral.state == .connected {
bleManager.disconnectPeripheral(reconnect: false)
}
} label: {
@ -121,7 +121,8 @@ struct Connect: View {
Text("Num: \(String(node!.num))")
Text("Short Name: \(node?.user?.shortName ?? "?")")
Text("Long Name: \(node?.user?.longName ?? "unknown".localized)")
Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)")
Text("BLE RSSI: \(connectedPeripheral.rssi)")
Button {
if !bleManager.sendShutdown(fromUser: node!.user!, toUser: node!.user!, adminIndex: node!.myInfo!.adminIndex) {
Logger.mesh.error("Shutdown Failed")
@ -210,11 +211,25 @@ struct Connect: View {
}
Button(action: {
if UserDefaults.preferredPeripheralId.count > 0 && peripheral.peripheral.identifier.uuidString != UserDefaults.preferredPeripheralId {
presentingSwitchPreferredPeripheral = true
selectedPeripherialId = peripheral.peripheral.identifier.uuidString
} else {
self.bleManager.connectTo(peripheral: peripheral.peripheral)
if let connectedPeripheral = bleManager.connectedPeripheral, connectedPeripheral.peripheral.state == CBPeripheralState.connected {
bleManager.disconnectPeripheral()
}
let container = NSPersistentContainer(name: "Meshtastic")
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
Logger.data.error("nil File path for back")
return
}
do {
try container.copyPersistentStores(to: url.appendingPathComponent("backup").appendingPathComponent("\(UserDefaults.preferredPeripheralNum)"), overwriting: true)
clearCoreDataDatabase(context: context, includeRoutes: true)
Logger.data.notice("🗂️ Made a core data backup to backup/\(UserDefaults.preferredPeripheralNum)")
} catch {
Logger.data.error("🗂️ Core data backup copy error: \(error, privacy: .public)")
}
}
UserDefaults.preferredPeripheralId = selectedPeripherialId
self.bleManager.connectTo(peripheral: peripheral.peripheral)
}) {
Text(peripheral.name).font(.callout)
}
@ -225,23 +240,6 @@ struct Connect: View {
}.padding([.bottom, .top])
}
}
.confirmationDialog("Connecting to a new radio will clear all local app data on the phone.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) {
Button("Connect to new radio?", role: .destructive) {
UserDefaults.preferredPeripheralId = selectedPeripherialId
UserDefaults.preferredPeripheralNum = 0
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
bleManager.disconnectPeripheral()
}
clearCoreDataDatabase(context: context, includeRoutes: false)
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId })
if radio != nil {
bleManager.connectTo(peripheral: radio!.peripheral)
}
}
}
.textCase(nil)
}
} else {
@ -254,9 +252,9 @@ struct Connect: View {
HStack(alignment: .center) {
Spacer()
#if targetEnvironment(macCatalyst)
if bleManager.connectedPeripheral != nil {
if let connectedPeripheral = bleManager.connectedPeripheral {
Button(role: .destructive, action: {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
if connectedPeripheral.peripheral.state == CBPeripheralState.connected {
bleManager.disconnectPeripheral(reconnect: false)
}
}) {
@ -285,10 +283,18 @@ struct Connect: View {
.padding(.bottom, 10)
}
.navigationTitle("bluetooth")
.navigationBarItems(leading: MeshtasticLogo(), trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", mqttProxyConnected: bleManager.mqttProxyConnected, mqttTopic: bleManager.mqttManager.topic)
})
.navigationBarItems(
leading: MeshtasticLogo(),
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?",
mqttProxyConnected: bleManager.mqttProxyConnected,
mqttTopic: bleManager.mqttManager.topic
)
}
)
}
.sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) {
InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion)
@ -306,18 +312,14 @@ struct Connect: View {
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(bleManager.connectedPeripheral?.num ?? -1))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest)
// Found a node, check it for a region
if !fetchedNode.isEmpty {
node = fetchedNode[0]
if node!.loRaConfig != nil && node!.loRaConfig?.regionCode ?? 0 == RegionCodes.unset.rawValue {
isUnsetRegion = true
} else {
isUnsetRegion = false
}
node = try context.fetch(fetchNodeInfoRequest).first
if let loRaConfig = node?.loRaConfig, loRaConfig.regionCode == RegionCodes.unset.rawValue {
isUnsetRegion = true
} else {
isUnsetRegion = false
}
} catch {
Logger.data.error("💥 Error fetching node info: \(error.localizedDescription)")
}
}
}

View file

@ -89,25 +89,25 @@ class LocalMBTileOverlay: MKTileOverlay {
}
}
override func loadTile(at path: MKTileOverlayPath, result: @escaping (Data?, Error?) -> Void) {
let tileX = Int64(path.x)
let tileY = Int64(path.y)
let tileZ = Int64(path.z)
let tileData = Expression<SQLite.Blob>("tile_data")
let zoomLevel = Expression<Int64>("zoom_level")
let tileColumn = Expression<Int64>("tile_column")
let tileRow = Expression<Int64>("tile_row")
if let dataQuery = try? self.mb.pluck(Table("tiles").select(tileData).filter(zoomLevel == tileZ).filter(tileColumn == tileX).filter(tileRow == tileY)) {
let data = Data(bytes: dataQuery[tileData].bytes, count: dataQuery[tileData].bytes.count)// dataQuery![tileData].bytes
result(data, nil)
} else {
Logger.services.error("No tile here: x:\(tileX) y:\(tileY) z:\(tileZ)")
let error = NSError(domain: "LocalMBTileOverlay", code: 1, userInfo: ["reason": "no_tile"])
result(nil, error)
}
}
// override func loadTile(at path: MKTileOverlayPath, result: @escaping (Data?, Error?) -> Void) {
//
// let tileX = Int64(path.x)
// let tileY = Int64(path.y)
// let tileZ = Int64(path.z)
// let tileData = Expression<SQLite.Blob>("tile_data")
// let zoomLevel = Expression<Int64>("zoom_level")
// let tileColumn = Expression<Int64>("tile_column")
// let tileRow = Expression<Int64>("tile_row")
//
// if let dataQuery = try? self.mb.pluck(Table("tiles").select(tileData).filter(zoomLevel == tileZ).filter(tileColumn == tileX).filter(tileRow == tileY)) {
// let data = Data(bytes: dataQuery[tileData].bytes, count: dataQuery[tileData].bytes.count)// dataQuery![tileData].bytes
// result(data, nil)
// } else {
// Logger.services.error("No tile here: x:\(tileX) y:\(tileY) z:\(tileZ)")
// let error = NSError(domain: "LocalMBTileOverlay", code: 1, userInfo: ["reason": "no_tile"])
// result(nil, error)
// }
// }
}
// public class CustomMapOverlaySource: MKTileOverlay {

View file

@ -5,9 +5,10 @@
// Copyright Garth Vander Houwen 1/10/23.
//
import SwiftUI
import CoreLocation
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct WaypointFormMapKit: View {

View file

@ -5,9 +5,10 @@
// Created by Garth Vander Houwen on 12/24/21.
//
import SwiftUI
import CoreData
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct ChannelMessageList: View {
@StateObject var appState = AppState.shared
@ -115,7 +116,7 @@ struct ChannelMessageList: View {
message.read = true
do {
try context.save()
Logger.data.info("📖 Read message \(message.messageId) ")
Logger.data.info("📖 [App] Read message \(message.messageId) ")
appState.unreadChannelMessages = myInfo.unreadMessages
UIApplication.shared.applicationIconBadgeNumber = appState.unreadChannelMessages + appState.unreadDirectMessages
context.refresh(myInfo, mergeChanges: true)

View file

@ -1,5 +1,6 @@
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct MessageText: View {
static let linkBlue = Color(red: 0.4627, green: 0.8392, blue: 1) /* #76d6ff */

View file

@ -100,7 +100,7 @@ struct UserMessageList: View {
message.read = true
do {
try context.save()
Logger.data.info("📖 Read message \(message.messageId) ")
Logger.data.info("📖 [App] Read message \(message.messageId) ")
appState.unreadDirectMessages = user.unreadMessages
UIApplication.shared.applicationIconBadgeNumber = appState.unreadChannelMessages + appState.unreadDirectMessages

View file

@ -7,6 +7,7 @@
import SwiftUI
import Charts
import MeshtasticProtobufs
import OSLog
struct DetectionSensorLog: View {

View file

@ -5,10 +5,11 @@
// Copyright Garth Vander Houwen 1/10/23.
//
import SwiftUI
import MapKit
import CoreLocation
import MapKit
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct WaypointForm: View {

View file

@ -1,80 +0,0 @@
//
// AdminMessageList.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 7/2/22.
//
/*
Abstract:
A view showing the details for a node.
*/
import SwiftUI
import MapKit
import CoreLocation
struct AdminMessageList: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
var user: UserEntity?
var body: some View {
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddjmmssa", options: 0, locale: Locale.current)
let localeTimeFormat = DateFormatter.dateFormat(fromTemplate: "h:mm:ss a", options: 0, locale: Locale.current)
let dateFormatString = (localeDateFormat ?? "MM/dd/YY j:mm:ss a")
let timeFormatString = (localeTimeFormat ?? "h:mm:ss a")
List {
if user != nil {
ForEach( user!.adminMessageList.reversed() ) { am in
VStack(alignment: .leading) {
Text("\(am.adminDescription ?? "unknown".localized)")
.font(.caption)
Text("Sent \(Date(timeIntervalSince1970: TimeInterval(am.messageTimestamp)).formattedDate(format: dateFormatString))")
.foregroundColor(.gray)
.font(.caption2)
HStack(spacing: 0) {
let ackErrorVal = RoutingError(rawValue: Int(am.ackError))
if am.ackTimestamp > 0 {
if am.realACK {
Text(ackErrorVal?.display ?? "Empty Ack Error")
.foregroundColor(am.receivedACK ? .gray : .red)
.font(.caption2)
} else {
Text("Implicit ACK from another node")
.foregroundColor(.orange)
.font(.caption2)
}
}
if am.receivedACK && am.ackTimestamp > 0 {
Text(" \(Date(timeIntervalSince1970: TimeInterval(am.ackTimestamp)).formattedDate(format: timeFormatString))")
.foregroundColor(am.realACK ? .gray : .orange)
.font(.caption2)
}
}
}
}
}
}
.navigationTitle("admin.log")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
})
.onAppear {
if self.bleManager.context == nil {
self.bleManager.context = context
}
}
}
}

View file

@ -0,0 +1,156 @@
//
// AppData.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 6/8/24.
//
import SwiftUI
import OSLog
import CoreData
import Foundation
struct AppData: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@State private var files = [URL]()
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
var body: some View {
VStack {
Button(action: {
let container = NSPersistentContainer(name: "Meshtastic")
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
Logger.data.error("nil File path for back")
return
}
do {
try container.copyPersistentStores(to: url.appendingPathComponent("backup").appendingPathComponent("\(UserDefaults.preferredPeripheralNum)"), overwriting: true)
loadFiles()
Logger.data.notice("🗂️ Made a core data backup to backup/\(UserDefaults.preferredPeripheralNum)")
} catch {
Logger.data.error("🗂️ Core data backup copy error: \(error, privacy: .public)")
}
}) {
Label {
Text("Backup Database")
.font(idiom == .phone ? .callout : .title)
} icon: {
Image(systemName: "cylinder.split.1x2")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
}
List(files, id: \.self) { file in
HStack {
VStack(alignment: .leading ) {
if file.pathExtension.contains("sqlite") {
Label {
Text("Node Core Data Backup \(file.pathComponents[(idiom == .phone || idiom == .pad) ? 9 : 10])/\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
.swipeActions {
Button(role: .none) {
bleManager.disconnectPeripheral(reconnect: false)
let container = NSPersistentContainer(name: "Meshtastic")
do {
clearCoreDataDatabase(context: context, includeRoutes: true)
try container.restorePersistentStore(from: file.absoluteURL)
let request = MyInfoEntity.fetchRequest()
try context.fetch(request)
UserDefaults.preferredPeripheralId = ""
UserDefaults.preferredPeripheralNum = Int(file.pathComponents[(idiom == .phone || idiom == .pad) ? 9 : 10]) ?? 0
Logger.data.notice("🗂️ Restored a core data backup to backup/\(UserDefaults.preferredPeripheralNum, privacy: .public)")
} catch {
Logger.data.error("🗂️ Core data restore copy error: \(error, privacy: .public)")
}
} label: {
Label("restore", systemImage: "arrow.counterclockwise")
}
Button(role: .destructive) {
do {
try FileManager.default.removeItem(at: file)
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("delete", systemImage: "trash")
}
}
} icon: {
Image(systemName: "cylinder.split.1x2")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
} else {
Label {
Text("\(file.lastPathComponent) - \(file.creationDate?.formatted() ?? "") - \(file.fileSizeString)")
.swipeActions {
Button(role: .destructive) {
do {
try FileManager.default.removeItem(at: file)
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("delete", systemImage: "trash")
}
}
} icon: {
Image(systemName: "doc.text")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
}
}
#if targetEnvironment(macCatalyst)
Spacer()
VStack(alignment: .trailing) {
Button {
do {
try FileManager.default.removeItem(at: file)
loadFiles()
} catch {
Logger.services.error("🗑️ Delete file error: \(error, privacy: .public)")
}
} label: {
Label("", systemImage: "trash")
}
}
#endif
}
}
.navigationBarTitle("File Storage", displayMode: .inline)
.onAppear(perform: {
loadFiles()
})
.listStyle(.inset)
}
private func loadFiles() {
files = []
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
Logger.data.error("🗂️ nil default document directory path for backup, core data backup failed.")
return
}
if let enumerator = FileManager.default.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
for case let fileURL as URL in enumerator {
do {
let fileAttributes = try fileURL.resourceValues(forKeys: [.isRegularFileKey])
if fileAttributes.isRegularFile! {
files.append(fileURL)
}
} catch {
Logger.services.error("📁 Load file: \(fileURL, privacy: .public) error: \(error, privacy: .public)")
}
}
}
}
}

View file

@ -0,0 +1,234 @@
//
// AppLog.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 6/4/24.
//
import SwiftUI
import OSLog
/// Needed for TableColumnForEach
@available(iOS 17.4, *)
struct AppLog: View {
@State private var logs: [OSLogEntryLog] = []
@State private var sortOrder = [KeyPathComparator(\OSLogEntryLog.date, order: .reverse)]
@State private var selection: OSLogEntry.ID?
@State private var selectedLog: OSLogEntryLog?
@State private var presentingErrorDetails: Bool = false
@State private var searchText = ""
@State private var categories: Set<Int> = []
@State private var levels: Set<Int> = []
@State var isExporting = false
@State var exportString = ""
@State var isEditingFilters = false
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
private let dateFormatStyle = Date.FormatStyle()
.hour(.twoDigits(amPM: .omitted))
.minute()
.second()
.secondFraction(.fractional(3))
var body: some View {
Table(logs, selection: $selection, sortOrder: $sortOrder) {
if idiom != .phone {
TableColumn("log.time") { value in
Text(value.date.formatted(dateFormatStyle))
}
.width(min: 125, max: 150)
TableColumn("log.category", value: \.category)
.width(min: 125, max: 150)
TableColumn("log.level") { value in
Text(value.level.description)
}
.width(min: 75, max: 100)
}
TableColumn("log.message", value: \.composedMessage) { value in
Text(value.composedMessage)
.font(idiom == .phone ? .caption : .body)
}
.width(ideal: 200, max: .infinity)
}
.monospaced()
.safeAreaInset(edge: .bottom, alignment: .trailing) {
HStack {
Button(action: {
withAnimation {
isEditingFilters = !isEditingFilters
}
}) {
Image(systemName: !isEditingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill")
.padding(.vertical, 5)
}
.tint(Color(UIColor.secondarySystemBackground))
.foregroundColor(.accentColor)
.buttonStyle(.borderedProminent)
}
.controlSize(.regular)
.padding(5)
}
.padding(.bottom, 5)
.padding(.trailing, 5)
.searchable(text: $searchText, placement: .navigationBarDrawer, prompt: "Search")
.disabled(selection != nil)
.overlay {
if logs.isEmpty {
ContentUnavailableView("No Logs Available", systemImage: "scroll")
}
}
.refreshable {
await logs = searchAppLogs()
logs.sort(using: sortOrder)
}
.onChange(of: sortOrder) { _, sortOrder in
withAnimation {
logs.sort(using: sortOrder)
}
}
.onChange(of: searchText) { _ in
Task {
await logs = searchAppLogs()
logs.sort(using: sortOrder)
}
}
.onChange(of: [categories]) { _ in
Task {
await logs = searchAppLogs()
logs.sort(using: sortOrder)
}
}
.onChange(of: [levels]) { _ in
Task {
await logs = searchAppLogs()
logs.sort(using: sortOrder)
}
}
.onChange(of: selection) { newSelection in
presentingErrorDetails = true
let log = logs.first {
$0.id == newSelection
}
selectedLog = log
}
.sheet(isPresented: $isEditingFilters) {
AppLogFilter(categories: $categories, levels: $levels)
}
.sheet(item: $selectedLog, onDismiss: didDismiss) { log in
LogDetail(log: log)
.padding()
}
.task {
logs = await searchAppLogs()
logs.sort(using: sortOrder)
}
.fileExporter(
isPresented: $isExporting,
document: CsvDocument(emptyCsv: exportString),
contentType: .commaSeparatedText,
defaultFilename: String("Meshtastic Application Logs"),
onCompletion: { result in
switch result {
case .success:
self.isExporting = false
Logger.services.info("Application log download succeeded.")
case .failure(let error):
Logger.services.error("Application log download failed: \(error.localizedDescription)")
}
}
)
.navigationBarTitle("Debug Logs\(logs.isEmpty ? "" : " (\(logs.count))")", displayMode: .inline)
.toolbar {
#if targetEnvironment(macCatalyst)
ToolbarItem(placement: .topBarLeading) {
Button(action: {
Task {
await logs = searchAppLogs()
logs.sort(using: sortOrder)
}
}) {
Image(systemName: "arrow.clockwise.circle")
}
}
#endif
if !logs.isEmpty {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
exportString = logToCsvFile(log: logs)
isExporting = true
}) {
Image(systemName: "square.and.arrow.down")
}
}
}
}
}
func didDismiss() {
selection = nil
selectedLog = nil
}
}
@available(iOS 17.4, *)
extension AppLog {
@MainActor
private func searchAppLogs() async -> [OSLogEntryLog] {
do {
/// Case Insensitive Search Text Predicates
let searchPredicates = ["composedMessage", "category", "subsystem", "process"].map { property in
return NSPredicate(format: "%K CONTAINS[c] %@", property, searchText)
}
/// Create a compound predicate using each text search preicate as an OR
let textSearchPredicate = NSCompoundPredicate(type: .or, subpredicates: searchPredicates)
/// Create an array of predicates to hold our AND predicates
var predicates: [NSPredicate] = []
/// Subsystem Predicate
let subsystemPredicate = NSPredicate(format: "subsystem IN %@", ["com.apple.SwiftUI", "com.apple.coredata", "gvh.MeshtasticClient"])
predicates.append(subsystemPredicate)
/// Categories
if categories.count > 0 {
var categoriesArray: [NSPredicate] = []
for c in categories {
let categoriesPredicate = NSPredicate(format: "category == %@", LogCategories(rawValue: c)?.description ?? "services")
categoriesArray.append(categoriesPredicate)
}
let compoundPredicate = NSCompoundPredicate(type: .or, subpredicates: categoriesArray)
predicates.append(compoundPredicate)
}
/// Log Levels
if levels.count > 0 {
var levelsArray: [NSPredicate] = []
for l in levels {
let levelsPredicate = NSPredicate(format: "messageType == %@", LogLevels(rawValue: l)?.level ?? "info")
levelsArray.append(levelsPredicate)
}
let compoundPredicate = NSCompoundPredicate(type: .or, subpredicates: levelsArray)
predicates.append(compoundPredicate)
}
if predicates.count > 0 || !searchText.isEmpty {
if !searchText.isEmpty {
let filterPredicates = NSCompoundPredicate(type: .and, subpredicates: predicates)
let compoundPredicate = NSCompoundPredicate(type: .and, subpredicates: [textSearchPredicate, filterPredicates])
let logs = try await Logger.fetch(predicateFormat: compoundPredicate.predicateFormat)
return logs
} else {
let filterPredicates = NSCompoundPredicate(type: .and, subpredicates: predicates)
let logs = try await Logger.fetch(predicateFormat: filterPredicates.predicateFormat)
return logs
}
} else {
let logs = try await Logger.fetch(predicateFormat: subsystemPredicate.predicateFormat)
return logs
}
} catch {
return []
}
}
}
extension OSLogEntry: Identifiable { }

View file

@ -76,6 +76,26 @@ struct AppSettings: View {
) {
Button("Erase all app data?", role: .destructive) {
bleManager.disconnectPeripheral()
/// Delete any database backups too
if var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
url = url.appendingPathComponent("backup").appendingPathComponent(String(UserDefaults.preferredPeripheralNum))
do {
try FileManager.default.removeItem(at: url.appendingPathComponent("Meshtastic.sqlite"))
/// Delete -shm file
do {
try FileManager.default.removeItem(at: url.appendingPathComponent("Meshtastic.sqlite-wal"))
do {
try FileManager.default.removeItem(at: url.appendingPathComponent("Meshtastic.sqlite-shm"))
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite-shm file \(error, privacy: .public)")
}
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite-wal file \(error, privacy: .public)")
}
} catch {
Logger.services.error("Error Deleting Meshtastic.sqlite file \(error, privacy: .public)")
}
}
clearCoreDataDatabase(context: context, includeRoutes: true)
context.refreshAllObjects()
UserDefaults.standard.reset()

View file

@ -5,10 +5,11 @@
// Copyright(c) Garth Vander Houwen 4/8/22.
//
import SwiftUI
import CoreData
import MapKit
import MeshtasticProtobufs
import OSLog
import SwiftUI
#if canImport(TipKit)
import TipKit
#endif

View file

@ -5,8 +5,9 @@
// Copyright (c) Garth Vander Houwen 8/18/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct BluetoothConfig: View {
@Environment(\.managedObjectContext) var context
@ -18,6 +19,7 @@ struct BluetoothConfig: View {
@State var mode = 0
@State var fixedPin = "123456"
@State var shortPin = false
@State var deviceLoggingEnabled = false
var pinLength: Int = 6
let numberFormatter: NumberFormatter = {
let formatter = NumberFormatter()
@ -68,18 +70,23 @@ struct BluetoothConfig: View {
.foregroundColor(.red)
}
}
Toggle(isOn: $deviceLoggingEnabled) {
Label("Device Logging Enabled", systemImage: "ladybug")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.bluetoothConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode != nil {
if let myNodeNum = bleManager.connectedPeripheral?.num,
let connectedNode = getNodeInfo(id: myNodeNum, context: context) {
var bc = Config.BluetoothConfig()
bc.enabled = enabled
bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin
bc.fixedPin = UInt32(fixedPin) ?? 123456
let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
bc.deviceLoggingEnabled = deviceLoggingEnabled
let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
@ -90,21 +97,26 @@ struct BluetoothConfig: View {
}
.navigationTitle("bluetooth.config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
})
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
)
}
)
.onAppear {
if self.bleManager.context == nil {
self.bleManager.context = context
}
setBluetoothValues()
// Need to request a BluetoothConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.bluetoothConfig == nil {
if let connectedPeripheral = bleManager.connectedPeripheral, let node, node.bluetoothConfig == nil {
Logger.mesh.info("empty bluetooth config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if node != nil && connectedNode != nil {
_ = bleManager.requestBluetoothConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let connectedNode {
_ = bleManager.requestBluetoothConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
@ -123,11 +135,17 @@ struct BluetoothConfig: View {
if newFixedPin != String(node!.bluetoothConfig!.fixedPin) { hasChanges = true }
}
}
.onChange(of: deviceLoggingEnabled) { newDeviceLogging in
if node != nil && node!.bluetoothConfig != nil {
if newDeviceLogging != node!.bluetoothConfig!.deviceLoggingEnabled { hasChanges = true }
}
}
}
func setBluetoothValues() {
self.enabled = node?.bluetoothConfig?.enabled ?? true
self.mode = Int(node?.bluetoothConfig?.mode ?? 0)
self.fixedPin = String(node?.bluetoothConfig?.fixedPin ?? 123456)
self.deviceLoggingEnabled = node?.bluetoothConfig?.deviceLoggingEnabled ?? false
self.hasChanges = false
}
}

View file

@ -4,8 +4,10 @@
//
// Copyright (c) Garth Vander Houwen 6/13/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct DeviceConfig: View {

View file

@ -5,8 +5,9 @@
// Copyright (c) Garth Vander Houwen 6/7/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct DisplayConfig: View {

View file

@ -7,6 +7,7 @@
import SwiftUI
import CoreData
import MeshtasticProtobufs
import OSLog
struct LoRaConfig: View {

View file

@ -4,8 +4,9 @@
//
// Copyright(c) Garth Vander Houwen 11/26/23
//
import MeshtasticProtobufs
import SwiftUI
@available(iOS 17.0, macOS 14.0, *)
struct AmbientLightingConfig: View {
@Environment(\.self) var environment

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/22/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct CannedMessagesConfig: View {
@Environment(\.managedObjectContext) var context

View file

@ -4,8 +4,9 @@
//
// Copyright(c) Garth Vander Houwen 8/16/23.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
enum DetectionSensorRole: String, CaseIterable, Equatable, Decodable {
case sensor

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/22/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct ExternalNotificationConfig: View {

View file

@ -4,9 +4,10 @@
//
// Copyright (c) Garth Vander Houwen 9/4/22.
//
import SwiftUI
import CoreLocation
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct MQTTConfig: View {

View file

@ -5,6 +5,7 @@
// Copyright Garth Vander Houwen 2/25/24.
//
import MeshtasticProtobufs
import SwiftUI
struct PaxCounterConfig: View {

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/13/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct RangeTestConfig: View {

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/22/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct SerialConfig: View {

View file

@ -4,9 +4,9 @@
//
// Copyright(c) Garth Vander Houwen 8/26/23.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct StoreForwardConfig: View {

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/13/22.
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct TelemetryConfig: View {

View file

@ -4,9 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 8/1/2022
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
import SwiftUI
struct NetworkConfig: View {

View file

@ -6,11 +6,11 @@
//
import SwiftUI
import MeshtasticProtobufs
import OSLog
struct PositionFlags: OptionSet {
let rawValue: Int
static let Altitude = PositionFlags(rawValue: 1)
static let AltitudeMsl = PositionFlags(rawValue: 2)
static let GeoidalSeparation = PositionFlags(rawValue: 4)
@ -28,12 +28,9 @@ struct PositionConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@State var hasChanges = false
@State var hasFlagChanges = false
@State var smartPositionEnabled = true
@State var deviceGpsEnabled = true
@State var gpsMode = 0
@ -72,301 +69,313 @@ struct PositionConfig: View {
/// Intended for use with vehicle not walking speeds
/// walking speeds are likely to be error prone like the compass
@State var includeHeading = false
/// Minimum Version for fixed postion admin messages
@State var minimumVersion = "2.3.3"
@State private var supportedVersion = true
@State private var showingSetFixedAlert = false
// @State private var showingRemoveFixedAlert = false
@ViewBuilder
var positionPacketSection: some View {
Section(header: Text("Position Packet")) {
VStack(alignment: .leading) {
Picker("Broadcast Interval", selection: $positionBroadcastSeconds) {
ForEach(UpdateIntervals.allCases) { at in
if at.rawValue >= 300 {
Text(at.description)
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("The maximum interval that can elapse without a node broadcasting a position")
.foregroundColor(.gray)
.font(.callout)
}
Toggle(isOn: $smartPositionEnabled) {
Label("Smart Position", systemImage: "brain")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
if smartPositionEnabled {
VStack(alignment: .leading) {
Picker("Minimum Interval", selection: $broadcastSmartMinimumIntervalSecs) {
ForEach(UpdateIntervals.allCases) { at in
Text(at.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("The fastest that position updates will be sent if the minimum distance has been satisfied")
.foregroundColor(.gray)
.font(.callout)
}
VStack(alignment: .leading) {
Picker("Minimum Distance", selection: $broadcastSmartMinimumDistance) {
ForEach(10..<151) {
if $0 == 0 {
Text("unset")
} else {
if $0.isMultiple(of: 5) {
Text("\($0)")
.tag($0)
}
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("The minimum distance change in meters to be considered for a smart position broadcast.")
.foregroundColor(.gray)
.font(.callout)
}
}
}
}
@ViewBuilder
var deviceGPSSection: some View {
Section(header: Text("Device GPS")) {
Picker("", selection: $gpsMode) {
ForEach(GpsMode.allCases, id: \.self) { at in
Text(at.description)
.tag(at.id)
}
}
.pickerStyle(SegmentedPickerStyle())
.padding(.top, 5)
.padding(.bottom, 5)
.disabled(fixedPosition && !(gpsMode == 1))
if gpsMode == 1 {
Text("Positions will be provided by your device GPS, if you select disabled or not present you can set a fixed position.")
.foregroundColor(.gray)
.font(.callout)
VStack(alignment: .leading) {
Picker("Update Interval", selection: $gpsUpdateInterval) {
ForEach(GpsUpdateIntervals.allCases) { ui in
Text(ui.description)
}
}
Text("How often should we try to get a GPS position.")
.foregroundColor(.gray)
.font(.callout)
}
}
if (gpsMode != 1 && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? -1) || fixedPosition {
VStack(alignment: .leading) {
Toggle(isOn: $fixedPosition) {
Label("Fixed Position", systemImage: "location.square.fill")
if !(node?.positionConfig?.fixedPosition ?? false) {
Text("Your current location will be set as the fixed position and broadcast over the mesh on the position interval.")
} else {
}
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
}
}
@ViewBuilder
var positionFlagsSection: some View {
Section(header: Text("Position Flags")) {
Text("Optional fields to include when assembling position messages. the more fields are included, the larger the message will be - leading to longer airtime and a higher risk of packet loss")
.foregroundColor(.gray)
.font(.callout)
Toggle(isOn: $includeAltitude) {
Label("Altitude", systemImage: "arrow.up")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSatsinview) {
Label("Number of satellites", systemImage: "skew")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSeqNo) { // 64
Label("Sequence number", systemImage: "number")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeTimestamp) { // 128
Label("timestamp", systemImage: "clock")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeHeading) { // 128
Label("Vehicle heading", systemImage: "location.circle")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSpeed) { // 128
Label("Vehicle speed", systemImage: "speedometer")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
@ViewBuilder
var advancedPositionFlagsSection: some View {
Section(header: Text("Advanced Position Flags")) {
if includeAltitude {
Toggle(isOn: $includeAltitudeMsl) {
Label("Altitude is Mean Sea Level", systemImage: "arrow.up.to.line.compact")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeGeoidalSeparation) {
Label("Altitude Geoidal Separation", systemImage: "globe.americas")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
Toggle(isOn: $includeDop) {
Text("Dilution of precision (DOP) PDOP used by default")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
if includeDop {
Toggle(isOn: $includeHvdop) {
Text("If DOP is set, use HDOP / VDOP values instead of PDOP")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
}
@ViewBuilder
var advancedDeviceGPSSection: some View {
Section(header: Text("Advanced Device GPS")) {
Picker("GPS Receive GPIO", selection: $rxGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Picker("GPS Transmit GPIO", selection: $txGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Picker("GPS EN GPIO", selection: $gpsEnGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("(Re)define PIN_GPS_EN for your board.")
.font(.caption)
}
}
var saveButton: some View {
SaveConfigButton(node: node, hasChanges: $hasChanges) {
if fixedPosition && !supportedVersion {
_ = bleManager.sendPosition(channel: 0, destNum: node?.num ?? 0, wantResponse: true)
}
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral!.num, context: context)
if connectedNode != nil {
var pc = Config.PositionConfig()
pc.positionBroadcastSmartEnabled = smartPositionEnabled
pc.gpsEnabled = gpsMode == 1
pc.gpsMode = Config.PositionConfig.GpsMode(rawValue: gpsMode) ?? Config.PositionConfig.GpsMode.notPresent
pc.fixedPosition = fixedPosition
pc.gpsUpdateInterval = UInt32(gpsUpdateInterval)
pc.positionBroadcastSecs = UInt32(positionBroadcastSeconds)
pc.broadcastSmartMinimumIntervalSecs = UInt32(broadcastSmartMinimumIntervalSecs)
pc.broadcastSmartMinimumDistance = UInt32(broadcastSmartMinimumDistance)
pc.rxGpio = UInt32(rxGpio)
pc.txGpio = UInt32(txGpio)
pc.gpsEnGpio = UInt32(gpsEnGpio)
var pf: PositionFlags = []
if includeAltitude { pf.insert(.Altitude) }
if includeAltitudeMsl { pf.insert(.AltitudeMsl) }
if includeGeoidalSeparation { pf.insert(.GeoidalSeparation) }
if includeDop { pf.insert(.Dop) }
if includeHvdop { pf.insert(.Hvdop) }
if includeSatsinview { pf.insert(.Satsinview) }
if includeSeqNo { pf.insert(.SeqNo) }
if includeTimestamp { pf.insert(.Timestamp) }
if includeSpeed { pf.insert(.Speed) }
if includeHeading { pf.insert(.Heading) }
pc.positionFlags = UInt32(pf.rawValue)
let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
// Disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
var setFixedAlertTitle: String {
if node?.positionConfig?.fixedPosition == true {
return "Remove Fixed Position"
} else {
return "Set Fixed Position"
}
}
var body: some View {
VStack {
Form {
ConfigHeader(title: "Position", config: \.positionConfig, node: node, onAppear: setPositionValues)
Section(header: Text("Position Packet")) {
VStack(alignment: .leading) {
Picker("Broadcast Interval", selection: $positionBroadcastSeconds) {
ForEach(UpdateIntervals.allCases) { at in
if at.rawValue >= 300 {
Text(at.description)
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("The maximum interval that can elapse without a node broadcasting a position")
.foregroundColor(.gray)
.font(.callout)
}
Toggle(isOn: $smartPositionEnabled) {
Label("Smart Position", systemImage: "brain")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
if smartPositionEnabled {
VStack(alignment: .leading) {
Picker("Minimum Interval", selection: $broadcastSmartMinimumIntervalSecs) {
ForEach(UpdateIntervals.allCases) { at in
Text(at.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("The fastest that position updates will be sent if the minimum distance has been satisfied")
.foregroundColor(.gray)
.font(.callout)
}
VStack(alignment: .leading) {
Picker("Minimum Distance", selection: $broadcastSmartMinimumDistance) {
ForEach(10..<151) {
if $0 == 0 {
Text("unset")
} else {
if $0.isMultiple(of: 5) {
Text("\($0)")
.tag($0)
}
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("The minimum distance change in meters to be considered for a smart position broadcast.")
.foregroundColor(.gray)
.font(.callout)
}
}
}
Section(header: Text("Device GPS")) {
Picker("", selection: $gpsMode) {
ForEach(GpsMode.allCases, id: \.self) { at in
Text(at.description)
.tag(at.id)
}
}
.pickerStyle(SegmentedPickerStyle())
.padding(.top, 5)
.padding(.bottom, 5)
if gpsMode == 1 {
Text("Positions will be provided by your device GPS, if you select disabled or not present you can set a fixed position.")
.foregroundColor(.gray)
.font(.callout)
VStack(alignment: .leading) {
Picker("Update Interval", selection: $gpsUpdateInterval) {
ForEach(GpsUpdateIntervals.allCases) { ui in
Text(ui.description)
}
}
Text("How often should we try to get a GPS position.")
.foregroundColor(.gray)
.font(.callout)
}
}
if gpsMode != 1 && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? -1 {
VStack(alignment: .leading) {
Toggle(isOn: $fixedPosition) {
Label("Fixed Position", systemImage: "location.square.fill")
if !(node?.positionConfig?.fixedPosition ?? false) {
Text("Your current location will be set as the fixed position and broadcast over the mesh on the position interval.")
} else {
}
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
}
Section(header: Text("Position Flags")) {
Text("Optional fields to include when assembling position messages. the more fields are included, the larger the message will be - leading to longer airtime and a higher risk of packet loss")
.foregroundColor(.gray)
.font(.callout)
Toggle(isOn: $includeAltitude) {
Label("Altitude", systemImage: "arrow.up")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSatsinview) {
Label("Number of satellites", systemImage: "skew")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSeqNo) { // 64
Label("Sequence number", systemImage: "number")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeTimestamp) { // 128
Label("timestamp", systemImage: "clock")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeHeading) { // 128
Label("Vehicle heading", systemImage: "location.circle")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeSpeed) { // 128
Label("Vehicle speed", systemImage: "speedometer")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
Section(header: Text("Advanced Position Flags")) {
if includeAltitude {
Toggle(isOn: $includeAltitudeMsl) {
Label("Altitude is Mean Sea Level", systemImage: "arrow.up.to.line.compact")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $includeGeoidalSeparation) {
Label("Altitude Geoidal Separation", systemImage: "globe.americas")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
Toggle(isOn: $includeDop) {
Text("Dilution of precision (DOP) PDOP used by default")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
if includeDop {
Toggle(isOn: $includeHvdop) {
Text("If DOP is set use, HDOP / VDOP values instead of PDOP")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
positionPacketSection
deviceGPSSection
positionFlagsSection
advancedPositionFlagsSection
if gpsMode == 1 {
Section(header: Text("Advanced Device GPS")) {
Picker("GPS Receive GPIO", selection: $rxGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Picker("GPS Transmit GPIO", selection: $txGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Picker("GPS EN GPIO", selection: $gpsEnGpio) {
ForEach(0..<49) {
if $0 == 0 {
Text("unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("(Re)define PIN_GPS_EN for your board.")
.font(.caption)
}
advancedDeviceGPSSection
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.positionConfig == nil)
.alert(node?.positionConfig?.fixedPosition ?? false ? "Remove Fixed Position" : "Set Fixed Position", isPresented: $showingSetFixedAlert) {
.alert(setFixedAlertTitle, isPresented: $showingSetFixedAlert) {
Button("Cancel", role: .cancel) {
fixedPosition = !fixedPosition
}
if node?.positionConfig?.fixedPosition ?? false {
Button("Remove", role: .destructive) {
if !bleManager.removeFixedPosition(fromUser: node!.user!, channel: 0) {
Logger.mesh.error("Remove Fixed Position Failed")
}
let mutablePositions = node?.positions?.mutableCopy() as? NSMutableOrderedSet
mutablePositions?.removeAllObjects()
node?.positions = mutablePositions
node?.positionConfig?.fixedPosition = false
do {
try context.save()
Logger.data.info("💾 Updated Position Config with Fixed Position = false")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Position Config Entity \(nsError)")
}
removeFixedPosition()
}
} else {
Button("Set") {
if !bleManager.setFixedPosition(fromUser: node!.user!, channel: 0) {
Logger.mesh.error("Set Position Failed")
}
node?.positionConfig?.fixedPosition = true
do {
try context.save()
Logger.data.info("💾 Updated Position Config with Fixed Position = true")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Position Config Entity \(nsError)")
}
setFixedPosition()
}
}
} message: {
Text(node?.positionConfig?.fixedPosition ?? false ? "This will disable fixed position and remove the currently set position." : "This will send a current position from your phone and enable fixed position.")
}
SaveConfigButton(node: node, hasChanges: $hasChanges) {
if fixedPosition && !supportedVersion {
_ = bleManager.sendPosition(channel: 0, destNum: node?.num ?? 0, wantResponse: true)
}
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode != nil {
var pc = Config.PositionConfig()
pc.positionBroadcastSmartEnabled = smartPositionEnabled
pc.gpsEnabled = gpsMode == 1
pc.gpsMode = Config.PositionConfig.GpsMode(rawValue: gpsMode) ?? Config.PositionConfig.GpsMode.notPresent
pc.fixedPosition = fixedPosition
pc.gpsUpdateInterval = UInt32(gpsUpdateInterval)
pc.positionBroadcastSecs = UInt32(positionBroadcastSeconds)
pc.broadcastSmartMinimumIntervalSecs = UInt32(broadcastSmartMinimumIntervalSecs)
pc.broadcastSmartMinimumDistance = UInt32(broadcastSmartMinimumDistance)
pc.rxGpio = UInt32(rxGpio)
pc.txGpio = UInt32(txGpio)
pc.gpsEnGpio = UInt32(gpsEnGpio)
var pf: PositionFlags = []
if includeAltitude { pf.insert(.Altitude) }
if includeAltitudeMsl { pf.insert(.AltitudeMsl) }
if includeGeoidalSeparation { pf.insert(.GeoidalSeparation) }
if includeDop { pf.insert(.Dop) }
if includeHvdop { pf.insert(.Hvdop) }
if includeSatsinview { pf.insert(.Satsinview) }
if includeSeqNo { pf.insert(.SeqNo) }
if includeTimestamp { pf.insert(.Timestamp) }
if includeSpeed { pf.insert(.Speed) }
if includeHeading { pf.insert(.Heading) }
pc.positionFlags = UInt32(pf.rawValue)
let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
// Disable the button after a successful save
hasChanges = false
goBack()
}
}
}
saveButton
}
.navigationTitle("position.config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
})
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
)
}
)
.onAppear {
if self.bleManager.context == nil {
self.bleManager.context = context
@ -374,133 +383,88 @@ struct PositionConfig: View {
setPositionValues()
supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame
// Need to request a PositionConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
if let connectedPeripheral = bleManager.connectedPeripheral, node?.positionConfig == nil {
Logger.mesh.info("empty position config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if node != nil && connectedNode != nil {
_ = bleManager.requestPositionConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let node, let connectedNode {
_ = bleManager.requestPositionConfig(
fromUser: connectedNode.user!,
toUser: node.user!,
adminIndex: connectedNode.myInfo?.adminIndex ?? 0
)
}
}
}
.onChange(of: fixedPosition) { newFixed in
if supportedVersion {
if node != nil && node!.positionConfig != nil {
if let positionConfig = node?.positionConfig {
/// Fixed Position is off to start
if !node!.positionConfig!.fixedPosition && newFixed {
if !positionConfig.fixedPosition && newFixed {
showingSetFixedAlert = true
} else if node!.positionConfig!.fixedPosition && !newFixed {
} else if positionConfig.fixedPosition && !newFixed {
/// Fixed Position is on to start
showingSetFixedAlert = true
}
}
}
}
.onChange(of: deviceGpsEnabled) { newDeviceGps in
if node != nil && node!.positionConfig != nil {
if newDeviceGps != node!.positionConfig!.deviceGpsEnabled { hasChanges = true }
}
.onChange(of: gpsMode) { _ in
handleChanges()
}
.onChange(of: gpsMode) { newGpsMode in
if node != nil && node!.positionConfig != nil {
if newGpsMode != node!.positionConfig!.gpsMode { hasChanges = true }
}
.onChange(of: rxGpio) { _ in
handleChanges()
}
.onChange(of: rxGpio) { newRxGpio in
if node != nil && node!.positionConfig != nil {
if newRxGpio != node!.positionConfig!.rxGpio { hasChanges = true }
}
.onChange(of: txGpio) { _ in
handleChanges()
}
.onChange(of: txGpio) { newTxGpio in
if node != nil && node!.positionConfig != nil {
if newTxGpio != node!.positionConfig!.txGpio { hasChanges = true }
}
.onChange(of: gpsEnGpio) { _ in
handleChanges()
}
.onChange(of: txGpio) { newGpsEnGpio in
if node != nil && node!.positionConfig != nil {
if newGpsEnGpio != node!.positionConfig!.gpsEnGpio { hasChanges = true }
}
.onChange(of: smartPositionEnabled) { _ in
handleChanges()
}
.onChange(of: smartPositionEnabled) { newSmartPositionEnabled in
if node != nil && node!.positionConfig != nil {
if newSmartPositionEnabled != node!.positionConfig!.smartPositionEnabled { hasChanges = true }
}
.onChange(of: positionBroadcastSeconds) { _ in
handleChanges()
}
.onChange(of: positionBroadcastSeconds) { newPositionBroadcastSeconds in
if node != nil && node!.positionConfig != nil {
if newPositionBroadcastSeconds != node!.positionConfig!.positionBroadcastSeconds { hasChanges = true }
}
.onChange(of: broadcastSmartMinimumIntervalSecs) { _ in
handleChanges()
}
.onChange(of: broadcastSmartMinimumIntervalSecs) { newBroadcastSmartMinimumIntervalSecs in
if node != nil && node!.positionConfig != nil {
if newBroadcastSmartMinimumIntervalSecs != node!.positionConfig!.broadcastSmartMinimumIntervalSecs { hasChanges = true }
}
.onChange(of: broadcastSmartMinimumDistance) { _ in
handleChanges()
}
.onChange(of: broadcastSmartMinimumDistance) { newBroadcastSmartMinimumDistance in
if node != nil && node!.positionConfig != nil {
if newBroadcastSmartMinimumDistance != node!.positionConfig!.broadcastSmartMinimumDistance { hasChanges = true }
}
.onChange(of: gpsUpdateInterval) { _ in
handleChanges()
}
.onChange(of: gpsUpdateInterval) { newGpsUpdateInterval in
if node != nil && node!.positionConfig != nil {
if newGpsUpdateInterval != node!.positionConfig!.gpsUpdateInterval { hasChanges = true }
}
}
.onChange(of: includeAltitude) { altFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Altitude)
if existingValue != altFlag { hasChanges = true }
}
.onChange(of: includeAltitudeMsl) { altMslFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.AltitudeMsl)
if existingValue != altMslFlag { hasChanges = true }
}
.onChange(of: includeSatsinview) { satsFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Satsinview)
if existingValue != satsFlag { hasChanges = true }
}
.onChange(of: includeSeqNo) { seqFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.SeqNo)
if existingValue != seqFlag { hasChanges = true }
}
.onChange(of: includeTimestamp) { timestampFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Timestamp)
if existingValue != timestampFlag { hasChanges = true }
}
.onChange(of: includeTimestamp) { timestampFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Timestamp)
if existingValue != timestampFlag { hasChanges = true }
}
.onChange(of: includeSpeed) { speedFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Speed)
if existingValue != speedFlag { hasChanges = true }
}
.onChange(of: includeHeading) { headingFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Heading)
if existingValue != headingFlag { hasChanges = true }
}
.onChange(of: includeGeoidalSeparation) { geoSepFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.GeoidalSeparation)
if existingValue != geoSepFlag { hasChanges = true }
}
.onChange(of: includeDop) { dopFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Dop)
if existingValue != dopFlag { hasChanges = true }
}
.onChange(of: includeHvdop) { hvdopFlag in
let pf = PositionFlags(rawValue: self.positionFlags)
let existingValue = pf.contains(.Hvdop)
if existingValue != hvdopFlag { hasChanges = true }
.onChange(of: positionFlags) { _ in
handleChanges()
}
}
func handleChanges() {
guard let positionConfig = node?.positionConfig else { return }
let pf = PositionFlags(rawValue: self.positionFlags)
hasChanges = positionConfig.deviceGpsEnabled != deviceGpsEnabled ||
positionConfig.gpsMode != gpsMode ||
positionConfig.rxGpio != rxGpio ||
positionConfig.txGpio != txGpio ||
positionConfig.gpsEnGpio != gpsEnGpio ||
positionConfig.smartPositionEnabled != smartPositionEnabled ||
positionConfig.positionBroadcastSeconds != positionBroadcastSeconds ||
positionConfig.broadcastSmartMinimumIntervalSecs != broadcastSmartMinimumIntervalSecs ||
positionConfig.broadcastSmartMinimumDistance != broadcastSmartMinimumDistance ||
positionConfig.gpsUpdateInterval != gpsUpdateInterval ||
pf.contains(.Altitude) ||
pf.contains(.AltitudeMsl) ||
pf.contains(.Satsinview) ||
pf.contains(.SeqNo) ||
pf.contains(.Timestamp) ||
pf.contains(.Speed) ||
pf.contains(.Heading) ||
pf.contains(.GeoidalSeparation) ||
pf.contains(.Dop) ||
pf.contains(.Hvdop)
}
func setPositionValues() {
self.smartPositionEnabled = node?.positionConfig?.smartPositionEnabled ?? true
self.deviceGpsEnabled = node?.positionConfig?.deviceGpsEnabled ?? false
@ -517,19 +481,54 @@ struct PositionConfig: View {
self.broadcastSmartMinimumIntervalSecs = Int(node?.positionConfig?.broadcastSmartMinimumIntervalSecs ?? 30)
self.broadcastSmartMinimumDistance = Int(node?.positionConfig?.broadcastSmartMinimumDistance ?? 50)
self.positionFlags = Int(node?.positionConfig?.positionFlags ?? 3)
let pf = PositionFlags(rawValue: self.positionFlags)
if pf.contains(.Altitude) { self.includeAltitude = true } else { self.includeAltitude = false }
if pf.contains(.AltitudeMsl) { self.includeAltitudeMsl = true } else { self.includeAltitudeMsl = false }
if pf.contains(.GeoidalSeparation) { self.includeGeoidalSeparation = true } else { self.includeGeoidalSeparation = false }
if pf.contains(.Dop) { self.includeDop = true } else { self.includeDop = false }
if pf.contains(.Hvdop) { self.includeHvdop = true } else { self.includeHvdop = false }
if pf.contains(.Satsinview) { self.includeSatsinview = true } else { self.includeSatsinview = false }
if pf.contains(.SeqNo) { self.includeSeqNo = true } else { self.includeSeqNo = false }
if pf.contains(.Timestamp) { self.includeTimestamp = true } else { self.includeTimestamp = false }
if pf.contains(.Speed) { self.includeSpeed = true } else { self.includeSpeed = false }
if pf.contains(.Heading) { self.includeHeading = true } else { self.includeHeading = false }
self.includeAltitude = pf.contains(.Altitude)
self.includeAltitudeMsl = pf.contains(.AltitudeMsl)
self.includeGeoidalSeparation = pf.contains(.GeoidalSeparation)
self.includeDop = pf.contains(.Dop)
self.includeHvdop = pf.contains(.Hvdop)
self.includeSatsinview = pf.contains(.Satsinview)
self.includeSeqNo = pf.contains(.SeqNo)
self.includeTimestamp = pf.contains(.Timestamp)
self.includeSpeed = pf.contains(.Speed)
self.includeHeading = pf.contains(.Heading)
self.hasChanges = false
}
private func setFixedPosition() {
guard let nodeNum = bleManager.connectedPeripheral?.num,
nodeNum > 0 else { return }
if !bleManager.setFixedPosition(fromUser: node!.user!, channel: 0) {
Logger.mesh.error("Set Position Failed")
}
node?.positionConfig?.fixedPosition = true
do {
try context.save()
Logger.data.info("💾 Updated Position Config with Fixed Position = true")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Position Config Entity \(nsError)")
}
}
private func removeFixedPosition() {
guard let nodeNum = bleManager.connectedPeripheral?.num,
nodeNum > 0 else { return }
if !bleManager.removeFixedPosition(fromUser: node!.user!, channel: 0) {
Logger.mesh.error("Remove Fixed Position Failed")
}
let mutablePositions = node?.positions?.mutableCopy() as? NSMutableOrderedSet
mutablePositions?.removeAllObjects()
node?.positions = mutablePositions
node?.positionConfig?.fixedPosition = false
do {
try context.save()
Logger.data.info("💾 Updated Position Config with Fixed Position = false")
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Position Config Entity \(nsError)")
}
}
}

View file

@ -1,4 +1,5 @@
import SwiftUI
import MeshtasticProtobufs
struct PowerConfig: View {
@Environment(\.managedObjectContext) private var context

View file

@ -0,0 +1,134 @@
//
// AppLogFilter.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 6/15/24.
//
import Foundation
import OSLog
import SwiftUI
enum LogCategories: Int, CaseIterable, Identifiable {
case admin = 0
case data = 1
case mesh = 2
case mqtt = 3
case radio = 4
case services = 5
case stats = 6
var id: Int { self.rawValue }
var description: String {
switch self {
case .admin:
return "🏛 Admin"
case .data:
return "🗄️ Data"
case .mesh:
return "🕸️ Mesh"
case .mqtt:
return "📱 MQTT"
case .radio:
return "📟 Radio"
case .services:
return "🍏 Services"
case .stats:
return "📊 Stats"
}
}
}
enum LogLevels: Int, CaseIterable, Identifiable {
case debug = 0
case info = 1
case notice = 2
case error = 3
case fault = 4
var id: Int { self.rawValue }
var level: String {
switch self {
case .debug:
return "debug"
case .info:
return "info"
case .notice:
return "notice"
case .error:
return "error"
case .fault:
return "fault"
}
}
var description: String {
switch self {
case .debug:
return "🪲 Debug"
case .info:
return " Info"
case .notice:
return "⚠️ Notice"
case .error:
return "🚨 Error"
case .fault:
return "💥 Fault"
}
}
}
struct AppLogFilter: View {
@Environment(\.dismiss) private var dismiss
/// Filters
var filterTitle = "App Log Filters"
@Binding var categories: Set<Int>
@Binding var levels: Set<Int>
@State var editMode = EditMode.active /// the edit mode
var body: some View {
NavigationStack {
Form {
Section(header: Text("Categories")) {
VStack {
List(LogCategories.allCases, selection: $categories) { cat in
Text(cat.description)
}
.listStyle(.plain)
.environment(\.editMode, $editMode) /// bind it here!
.frame(minHeight: 300, maxHeight: .infinity)
}
}
Section(header: Text("Log Levels")) {
VStack {
List(LogLevels.allCases, selection: $levels) { level in
Text(level.description)
}
.listStyle(.plain)
.environment(\.editMode, $editMode) /// bind it here!
.frame(minHeight: 210, maxHeight: .infinity)
}
}
}
#if targetEnvironment(macCatalyst)
Spacer()
Button {
dismiss()
} label: {
Label("close", systemImage: "xmark")
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding(.bottom)
#endif
}
.presentationDetents([.fraction(1.0)])
.presentationDragIndicator(.visible)
}
}

View file

@ -0,0 +1,154 @@
//
// LogDetail.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 6/5/24.
//
import SwiftUI
import MapKit
import OSLog
struct LogDetail: View {
@Environment(\.dismiss) private var dismiss
private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom }
var log: OSLogEntryLog
var font: Font = .title2
private let dateFormatStyle = Date.FormatStyle()
.day(.defaultDigits)
.month(.defaultDigits)
.year(.twoDigits)
.hour(.twoDigits(amPM: .omitted))
.minute()
.second()
.secondFraction(.fractional(3))
var body: some View {
VStack {
HStack {
Text("OS Log Entry Details")
.font(.largeTitle)
}
Divider()
HStack(alignment: .top) {
VStack(alignment: .leading) {
List {
/// Time
Label {
Text("log.time".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.date.formatted(dateFormatStyle))
.font(idiom == .phone ? .caption : .title)
} icon: {
Image(systemName: "timer")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
.padding(.bottom, 5)
.listSectionSeparator(.hidden, edges: .top)
.listSectionSeparator(.visible, edges: .bottom)
/// Subsystem
Label {
Text("log.subsystem".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.subsystem)
.font(idiom == .phone ? .caption : .title)
} icon: {
Image(systemName: "gear")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .caption : .title)
.frame(width: 35)
}
.padding(.bottom, 5)
.listRowSeparator(.visible)
/// Process
Label {
Text("log.process".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.process)
.font(idiom == .phone ? .caption : .title)
} icon: {
Image(systemName: "tag")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .caption : .title)
.frame(width: 35)
}
.padding(.bottom, 5)
.listRowSeparator(.visible)
/// Category
Label {
Text("log.category".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.category)
.font(idiom == .phone ? .caption : .title)
} icon: {
Image(systemName: "square.grid.2x2")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .caption : .title)
.frame(width: 35)
}
.padding(.bottom, 5)
.listRowSeparator(.visible)
/// Level
Label {
Text("log.level".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.level.description)
.font(idiom == .phone ? .caption : .title)
} icon: {
Image(systemName: "stairs")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .caption : .title)
.frame(width: 35)
}
.padding(.bottom, 5)
.listRowSeparator(.visible)
/// message
Label {
Text("log.message".localized + ":")
.font(idiom == .phone ? .caption : .title)
.frame(width: idiom == .phone ? 115 : 190, alignment: .trailing)
Text(log.composedMessage)
.textSelection(.enabled)
.font(idiom == .phone ? .body : .title)
.padding(.bottom, 5)
} icon: {
Image(systemName: "text.bubble")
.symbolRenderingMode(.hierarchical)
.font(idiom == .phone ? .callout : .title)
.frame(width: 35)
}
.listRowSeparator(.hidden)
}
.listStyle(.plain)
}
Spacer()
}
.padding(.top)
#if targetEnvironment(macCatalyst)
Spacer()
Button {
dismiss()
} label: {
Label("close", systemImage: "xmark")
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding(.bottom)
#endif
}
.monospaced()
.presentationDetents([.fraction(0.75), .fraction(0.85), .fraction(1.0)])
.presentationDragIndicator(.visible)
}
}

View file

@ -18,7 +18,7 @@ struct MeshLog: View {
let url = logFile!
logs.removeAll()
var lineCount = 0
let lineLimit = 5000
let lineLimit = 1000
// Get the number of lines
for try await _ in url.lines {
lineCount += 1
@ -41,6 +41,7 @@ struct MeshLog: View {
// Stop adding logs when an error is thrown
}
}
.listStyle(.plain)
.fileExporter(
isPresented: $isExporting,
document: document,

View file

@ -48,6 +48,8 @@ struct Settings: View {
case meshLog
case adminMessageLog
case about
case appLog
case appData
}
var body: some View {
NavigationSplitView {
@ -412,18 +414,33 @@ struct Settings: View {
}
}
.tag(SettingsSidebar.meshLog)
if #available (iOS 17.4, *) {
NavigationLink {
AppLog()
} label: {
Label {
Text("Debug Logs")
} icon: {
Image(systemName: "stethoscope")
}
}
.tag(SettingsSidebar.appLog)
}
}
#if DEBUG
Section(header: Text("Developers")) {
NavigationLink {
let connectedNode = nodes.first(where: { $0.num == preferredNodeNum })
AdminMessageList(user: connectedNode?.user)
AppData()
} label: {
Label {
Text("admin.log")
Text("App Files")
} icon: {
Image(systemName: "building.columns")
Image(systemName: "folder")
}
}
.tag(SettingsSidebar.adminMessageLog)
.tag(SettingsSidebar.appData)
}
#endif
Section(header: Text("Firmware")) {
NavigationLink {
Firmware(node: nodes.first(where: { $0.num == preferredNodeNum }))

View file

@ -7,6 +7,8 @@
import SwiftUI
import CoreData
import CoreImage.CIFilterBuiltins
import MeshtasticProtobufs
#if canImport(TipKit)
import TipKit
#endif

View file

@ -4,8 +4,9 @@
//
// Copyright (c) Garth Vander Houwen 6/27/22.
//
import SwiftUI
import CoreData
import MeshtasticProtobufs
import SwiftUI
struct UserConfig: View {
@ -51,7 +52,7 @@ struct UserConfig: View {
.onChange(of: longName, perform: { _ in
let totalBytes = longName.utf8.count
// Only mess with the value if it is too big
if totalBytes > (isLicensed ? 8 : 36) {
if totalBytes > (isLicensed ? 6 : 36) {
longName = String(longName.dropLast())
}
})

8
MeshtasticProtobufs/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View file

@ -0,0 +1,24 @@
// swift-tools-version: 5.10
import PackageDescription
let package = Package(
name: "MeshtasticProtobufs",
products: [
.library(
name: "MeshtasticProtobufs",
targets: ["MeshtasticProtobufs"]
),
],
dependencies: [
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.19.0"),
],
targets: [
.target(
name: "MeshtasticProtobufs",
dependencies: [
.product(name: "SwiftProtobuf", package: "swift-protobuf")
]
)
]
)

View file

@ -24,19 +24,19 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
/// This message is handled by the Admin module and is responsible for all settings/channel read/write operations.
/// This message is used to do settings operations to both remote AND local nodes.
/// (Prior to 1.2 these operations were done via special ToRadio operations)
struct AdminMessage {
public struct AdminMessage {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// TODO: REPLACE
var payloadVariant: AdminMessage.OneOf_PayloadVariant? = nil
public var payloadVariant: AdminMessage.OneOf_PayloadVariant? = nil
///
/// Send the specified channel in the response to this message
/// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present)
var getChannelRequest: UInt32 {
public var getChannelRequest: UInt32 {
get {
if case .getChannelRequest(let v)? = payloadVariant {return v}
return 0
@ -46,7 +46,7 @@ struct AdminMessage {
///
/// TODO: REPLACE
var getChannelResponse: Channel {
public var getChannelResponse: Channel {
get {
if case .getChannelResponse(let v)? = payloadVariant {return v}
return Channel()
@ -56,7 +56,7 @@ struct AdminMessage {
///
/// Send the current owner data in the response to this message.
var getOwnerRequest: Bool {
public var getOwnerRequest: Bool {
get {
if case .getOwnerRequest(let v)? = payloadVariant {return v}
return false
@ -66,7 +66,7 @@ struct AdminMessage {
///
/// TODO: REPLACE
var getOwnerResponse: User {
public var getOwnerResponse: User {
get {
if case .getOwnerResponse(let v)? = payloadVariant {return v}
return User()
@ -76,7 +76,7 @@ struct AdminMessage {
///
/// Ask for the following config data to be sent
var getConfigRequest: AdminMessage.ConfigType {
public var getConfigRequest: AdminMessage.ConfigType {
get {
if case .getConfigRequest(let v)? = payloadVariant {return v}
return .deviceConfig
@ -86,7 +86,7 @@ struct AdminMessage {
///
/// Send the current Config in the response to this message.
var getConfigResponse: Config {
public var getConfigResponse: Config {
get {
if case .getConfigResponse(let v)? = payloadVariant {return v}
return Config()
@ -96,7 +96,7 @@ struct AdminMessage {
///
/// Ask for the following config data to be sent
var getModuleConfigRequest: AdminMessage.ModuleConfigType {
public var getModuleConfigRequest: AdminMessage.ModuleConfigType {
get {
if case .getModuleConfigRequest(let v)? = payloadVariant {return v}
return .mqttConfig
@ -106,7 +106,7 @@ struct AdminMessage {
///
/// Send the current Config in the response to this message.
var getModuleConfigResponse: ModuleConfig {
public var getModuleConfigResponse: ModuleConfig {
get {
if case .getModuleConfigResponse(let v)? = payloadVariant {return v}
return ModuleConfig()
@ -116,7 +116,7 @@ struct AdminMessage {
///
/// Get the Canned Message Module messages in the response to this message.
var getCannedMessageModuleMessagesRequest: Bool {
public var getCannedMessageModuleMessagesRequest: Bool {
get {
if case .getCannedMessageModuleMessagesRequest(let v)? = payloadVariant {return v}
return false
@ -126,7 +126,7 @@ struct AdminMessage {
///
/// Get the Canned Message Module messages in the response to this message.
var getCannedMessageModuleMessagesResponse: String {
public var getCannedMessageModuleMessagesResponse: String {
get {
if case .getCannedMessageModuleMessagesResponse(let v)? = payloadVariant {return v}
return String()
@ -136,7 +136,7 @@ struct AdminMessage {
///
/// Request the node to send device metadata (firmware, protobuf version, etc)
var getDeviceMetadataRequest: Bool {
public var getDeviceMetadataRequest: Bool {
get {
if case .getDeviceMetadataRequest(let v)? = payloadVariant {return v}
return false
@ -146,7 +146,7 @@ struct AdminMessage {
///
/// Device metadata response
var getDeviceMetadataResponse: DeviceMetadata {
public var getDeviceMetadataResponse: DeviceMetadata {
get {
if case .getDeviceMetadataResponse(let v)? = payloadVariant {return v}
return DeviceMetadata()
@ -156,7 +156,7 @@ struct AdminMessage {
///
/// Get the Ringtone in the response to this message.
var getRingtoneRequest: Bool {
public var getRingtoneRequest: Bool {
get {
if case .getRingtoneRequest(let v)? = payloadVariant {return v}
return false
@ -166,7 +166,7 @@ struct AdminMessage {
///
/// Get the Ringtone in the response to this message.
var getRingtoneResponse: String {
public var getRingtoneResponse: String {
get {
if case .getRingtoneResponse(let v)? = payloadVariant {return v}
return String()
@ -176,7 +176,7 @@ struct AdminMessage {
///
/// Request the node to send it's connection status
var getDeviceConnectionStatusRequest: Bool {
public var getDeviceConnectionStatusRequest: Bool {
get {
if case .getDeviceConnectionStatusRequest(let v)? = payloadVariant {return v}
return false
@ -186,7 +186,7 @@ struct AdminMessage {
///
/// Device connection status response
var getDeviceConnectionStatusResponse: DeviceConnectionStatus {
public var getDeviceConnectionStatusResponse: DeviceConnectionStatus {
get {
if case .getDeviceConnectionStatusResponse(let v)? = payloadVariant {return v}
return DeviceConnectionStatus()
@ -196,7 +196,7 @@ struct AdminMessage {
///
/// Setup a node for licensed amateur (ham) radio operation
var setHamMode: HamParameters {
public var setHamMode: HamParameters {
get {
if case .setHamMode(let v)? = payloadVariant {return v}
return HamParameters()
@ -206,7 +206,7 @@ struct AdminMessage {
///
/// Get the mesh's nodes with their available gpio pins for RemoteHardware module use
var getNodeRemoteHardwarePinsRequest: Bool {
public var getNodeRemoteHardwarePinsRequest: Bool {
get {
if case .getNodeRemoteHardwarePinsRequest(let v)? = payloadVariant {return v}
return false
@ -216,7 +216,7 @@ struct AdminMessage {
///
/// Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use
var getNodeRemoteHardwarePinsResponse: NodeRemoteHardwarePinsResponse {
public var getNodeRemoteHardwarePinsResponse: NodeRemoteHardwarePinsResponse {
get {
if case .getNodeRemoteHardwarePinsResponse(let v)? = payloadVariant {return v}
return NodeRemoteHardwarePinsResponse()
@ -227,7 +227,7 @@ struct AdminMessage {
///
/// Enter (UF2) DFU mode
/// Only implemented on NRF52 currently
var enterDfuModeRequest: Bool {
public var enterDfuModeRequest: Bool {
get {
if case .enterDfuModeRequest(let v)? = payloadVariant {return v}
return false
@ -237,7 +237,7 @@ struct AdminMessage {
///
/// Delete the file by the specified path from the device
var deleteFileRequest: String {
public var deleteFileRequest: String {
get {
if case .deleteFileRequest(let v)? = payloadVariant {return v}
return String()
@ -245,9 +245,19 @@ struct AdminMessage {
set {payloadVariant = .deleteFileRequest(newValue)}
}
///
/// Set zero and offset for scale chips
public var setScale: UInt32 {
get {
if case .setScale(let v)? = payloadVariant {return v}
return 0
}
set {payloadVariant = .setScale(newValue)}
}
///
/// Set the owner for this node
var setOwner: User {
public var setOwner: User {
get {
if case .setOwner(let v)? = payloadVariant {return v}
return User()
@ -261,7 +271,7 @@ struct AdminMessage {
/// The other records are secondary channels.
/// Note: only one channel can be marked as primary.
/// If the client sets a particular channel to be primary, the previous channel will be set to SECONDARY automatically.
var setChannel: Channel {
public var setChannel: Channel {
get {
if case .setChannel(let v)? = payloadVariant {return v}
return Channel()
@ -271,7 +281,7 @@ struct AdminMessage {
///
/// Set the current Config
var setConfig: Config {
public var setConfig: Config {
get {
if case .setConfig(let v)? = payloadVariant {return v}
return Config()
@ -281,7 +291,7 @@ struct AdminMessage {
///
/// Set the current Config
var setModuleConfig: ModuleConfig {
public var setModuleConfig: ModuleConfig {
get {
if case .setModuleConfig(let v)? = payloadVariant {return v}
return ModuleConfig()
@ -291,7 +301,7 @@ struct AdminMessage {
///
/// Set the Canned Message Module messages text.
var setCannedMessageModuleMessages: String {
public var setCannedMessageModuleMessages: String {
get {
if case .setCannedMessageModuleMessages(let v)? = payloadVariant {return v}
return String()
@ -301,7 +311,7 @@ struct AdminMessage {
///
/// Set the ringtone for ExternalNotification.
var setRingtoneMessage: String {
public var setRingtoneMessage: String {
get {
if case .setRingtoneMessage(let v)? = payloadVariant {return v}
return String()
@ -311,7 +321,7 @@ struct AdminMessage {
///
/// Remove the node by the specified node-num from the NodeDB on the device
var removeByNodenum: UInt32 {
public var removeByNodenum: UInt32 {
get {
if case .removeByNodenum(let v)? = payloadVariant {return v}
return 0
@ -321,7 +331,7 @@ struct AdminMessage {
///
/// Set specified node-num to be favorited on the NodeDB on the device
var setFavoriteNode: UInt32 {
public var setFavoriteNode: UInt32 {
get {
if case .setFavoriteNode(let v)? = payloadVariant {return v}
return 0
@ -331,7 +341,7 @@ struct AdminMessage {
///
/// Set specified node-num to be un-favorited on the NodeDB on the device
var removeFavoriteNode: UInt32 {
public var removeFavoriteNode: UInt32 {
get {
if case .removeFavoriteNode(let v)? = payloadVariant {return v}
return 0
@ -341,7 +351,7 @@ struct AdminMessage {
///
/// Set fixed position data on the node and then set the position.fixed_position = true
var setFixedPosition: Position {
public var setFixedPosition: Position {
get {
if case .setFixedPosition(let v)? = payloadVariant {return v}
return Position()
@ -351,7 +361,7 @@ struct AdminMessage {
///
/// Clear fixed position coordinates and then set position.fixed_position = false
var removeFixedPosition: Bool {
public var removeFixedPosition: Bool {
get {
if case .removeFixedPosition(let v)? = payloadVariant {return v}
return false
@ -362,7 +372,7 @@ struct AdminMessage {
///
/// Begins an edit transaction for config, module config, owner, and channel settings changes
/// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings)
var beginEditSettings: Bool {
public var beginEditSettings: Bool {
get {
if case .beginEditSettings(let v)? = payloadVariant {return v}
return false
@ -372,7 +382,7 @@ struct AdminMessage {
///
/// Commits an open transaction for any edits made to config, module config, owner, and channel settings
var commitEditSettings: Bool {
public var commitEditSettings: Bool {
get {
if case .commitEditSettings(let v)? = payloadVariant {return v}
return false
@ -383,7 +393,7 @@ struct AdminMessage {
///
/// Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
/// Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth.
var rebootOtaSeconds: Int32 {
public var rebootOtaSeconds: Int32 {
get {
if case .rebootOtaSeconds(let v)? = payloadVariant {return v}
return 0
@ -394,7 +404,7 @@ struct AdminMessage {
///
/// This message is only supported for the simulator Portduino build.
/// If received the simulator will exit successfully.
var exitSimulator: Bool {
public var exitSimulator: Bool {
get {
if case .exitSimulator(let v)? = payloadVariant {return v}
return false
@ -404,7 +414,7 @@ struct AdminMessage {
///
/// Tell the node to reboot in this many seconds (or <0 to cancel reboot)
var rebootSeconds: Int32 {
public var rebootSeconds: Int32 {
get {
if case .rebootSeconds(let v)? = payloadVariant {return v}
return 0
@ -414,7 +424,7 @@ struct AdminMessage {
///
/// Tell the node to shutdown in this many seconds (or <0 to cancel shutdown)
var shutdownSeconds: Int32 {
public var shutdownSeconds: Int32 {
get {
if case .shutdownSeconds(let v)? = payloadVariant {return v}
return 0
@ -424,7 +434,7 @@ struct AdminMessage {
///
/// Tell the node to factory reset, all device settings will be returned to factory defaults.
var factoryReset: Int32 {
public var factoryReset: Int32 {
get {
if case .factoryReset(let v)? = payloadVariant {return v}
return 0
@ -434,7 +444,7 @@ struct AdminMessage {
///
/// Tell the node to reset the nodedb.
var nodedbReset: Int32 {
public var nodedbReset: Int32 {
get {
if case .nodedbReset(let v)? = payloadVariant {return v}
return 0
@ -442,11 +452,11 @@ struct AdminMessage {
set {payloadVariant = .nodedbReset(newValue)}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// TODO: REPLACE
enum OneOf_PayloadVariant: Equatable {
public enum OneOf_PayloadVariant: Equatable {
///
/// Send the specified channel in the response to this message
/// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present)
@ -513,6 +523,9 @@ struct AdminMessage {
/// Delete the file by the specified path from the device
case deleteFileRequest(String)
///
/// Set zero and offset for scale chips
case setScale(UInt32)
///
/// Set the owner for this node
case setOwner(User)
///
@ -578,7 +591,7 @@ struct AdminMessage {
case nodedbReset(Int32)
#if !swift(>=4.1)
static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool {
public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
@ -667,6 +680,10 @@ struct AdminMessage {
guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() }
return l == r
}()
case (.setScale, .setScale): return {
guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() }
return l == r
}()
case (.setOwner, .setOwner): return {
guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() }
return l == r
@ -751,8 +768,8 @@ struct AdminMessage {
///
/// TODO: REPLACE
enum ConfigType: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum ConfigType: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// TODO: REPLACE
@ -783,11 +800,11 @@ struct AdminMessage {
case bluetoothConfig // = 6
case UNRECOGNIZED(Int)
init() {
public init() {
self = .deviceConfig
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .deviceConfig
case 1: self = .positionConfig
@ -800,7 +817,7 @@ struct AdminMessage {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .deviceConfig: return 0
case .positionConfig: return 1
@ -817,8 +834,8 @@ struct AdminMessage {
///
/// TODO: REPLACE
enum ModuleConfigType: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum ModuleConfigType: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// TODO: REPLACE
@ -873,11 +890,11 @@ struct AdminMessage {
case paxcounterConfig // = 12
case UNRECOGNIZED(Int)
init() {
public init() {
self = .mqttConfig
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .mqttConfig
case 1: self = .serialConfig
@ -896,7 +913,7 @@ struct AdminMessage {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .mqttConfig: return 0
case .serialConfig: return 1
@ -917,14 +934,14 @@ struct AdminMessage {
}
init() {}
public init() {}
}
#if swift(>=4.2)
extension AdminMessage.ConfigType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [AdminMessage.ConfigType] = [
public static let allCases: [AdminMessage.ConfigType] = [
.deviceConfig,
.positionConfig,
.powerConfig,
@ -937,7 +954,7 @@ extension AdminMessage.ConfigType: CaseIterable {
extension AdminMessage.ModuleConfigType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [AdminMessage.ModuleConfigType] = [
public static let allCases: [AdminMessage.ModuleConfigType] = [
.mqttConfig,
.serialConfig,
.extnotifConfig,
@ -958,48 +975,48 @@ extension AdminMessage.ModuleConfigType: CaseIterable {
///
/// Parameters for setting up Meshtastic for ameteur radio usage
struct HamParameters {
public struct HamParameters {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Amateur radio call sign, eg. KD2ABC
var callSign: String = String()
public var callSign: String = String()
///
/// Transmit power in dBm at the LoRA transceiver, not including any amplification
var txPower: Int32 = 0
public var txPower: Int32 = 0
///
/// The selected frequency of LoRA operation
/// Please respect your local laws, regulations, and band plans.
/// Ensure your radio is capable of operating of the selected frequency before setting this.
var frequency: Float = 0
public var frequency: Float = 0
///
/// Optional short name of user
var shortName: String = String()
public var shortName: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// Response envelope for node_remote_hardware_pins
struct NodeRemoteHardwarePinsResponse {
public struct NodeRemoteHardwarePinsResponse {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Nodes and their respective remote hardware GPIO pins
var nodeRemoteHardwarePins: [NodeRemoteHardwarePin] = []
public var nodeRemoteHardwarePins: [NodeRemoteHardwarePin] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -1016,8 +1033,8 @@ extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".AdminMessage"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".AdminMessage"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "get_channel_request"),
2: .standard(proto: "get_channel_response"),
3: .standard(proto: "get_owner_request"),
@ -1039,6 +1056,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
20: .standard(proto: "get_node_remote_hardware_pins_response"),
21: .standard(proto: "enter_dfu_mode_request"),
22: .standard(proto: "delete_file_request"),
23: .standard(proto: "set_scale"),
32: .standard(proto: "set_owner"),
33: .standard(proto: "set_channel"),
34: .standard(proto: "set_config"),
@ -1060,7 +1078,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
100: .standard(proto: "nodedb_reset"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -1274,6 +1292,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
self.payloadVariant = .deleteFileRequest(v)
}
}()
case 23: try {
var v: UInt32?
try decoder.decodeSingularUInt32Field(value: &v)
if let v = v {
if self.payloadVariant != nil {try decoder.handleConflictingOneOf()}
self.payloadVariant = .setScale(v)
}
}()
case 32: try {
var v: User?
var hadOneofValue = false
@ -1456,7 +1482,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -1546,6 +1572,10 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
guard case .deleteFileRequest(let v)? = self.payloadVariant else { preconditionFailure() }
try visitor.visitSingularStringField(value: v, fieldNumber: 22)
}()
case .setScale?: try {
guard case .setScale(let v)? = self.payloadVariant else { preconditionFailure() }
try visitor.visitSingularUInt32Field(value: v, fieldNumber: 23)
}()
case .setOwner?: try {
guard case .setOwner(let v)? = self.payloadVariant else { preconditionFailure() }
try visitor.visitSingularMessageField(value: v, fieldNumber: 32)
@ -1627,7 +1657,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: AdminMessage, rhs: AdminMessage) -> Bool {
public static func ==(lhs: AdminMessage, rhs: AdminMessage) -> Bool {
if lhs.payloadVariant != rhs.payloadVariant {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
@ -1635,7 +1665,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "DEVICE_CONFIG"),
1: .same(proto: "POSITION_CONFIG"),
2: .same(proto: "POWER_CONFIG"),
@ -1647,7 +1677,7 @@ extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding {
}
extension AdminMessage.ModuleConfigType: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "MQTT_CONFIG"),
1: .same(proto: "SERIAL_CONFIG"),
2: .same(proto: "EXTNOTIF_CONFIG"),
@ -1665,15 +1695,15 @@ extension AdminMessage.ModuleConfigType: SwiftProtobuf._ProtoNameProviding {
}
extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".HamParameters"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".HamParameters"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "call_sign"),
2: .standard(proto: "tx_power"),
3: .same(proto: "frequency"),
4: .standard(proto: "short_name"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -1688,7 +1718,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.callSign.isEmpty {
try visitor.visitSingularStringField(value: self.callSign, fieldNumber: 1)
}
@ -1704,7 +1734,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: HamParameters, rhs: HamParameters) -> Bool {
public static func ==(lhs: HamParameters, rhs: HamParameters) -> Bool {
if lhs.callSign != rhs.callSign {return false}
if lhs.txPower != rhs.txPower {return false}
if lhs.frequency != rhs.frequency {return false}
@ -1715,12 +1745,12 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
}
extension NodeRemoteHardwarePinsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".NodeRemoteHardwarePinsResponse"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".NodeRemoteHardwarePinsResponse"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "node_remote_hardware_pins"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -1732,14 +1762,14 @@ extension NodeRemoteHardwarePinsResponse: SwiftProtobuf.Message, SwiftProtobuf._
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.nodeRemoteHardwarePins.isEmpty {
try visitor.visitRepeatedMessageField(value: self.nodeRemoteHardwarePins, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: NodeRemoteHardwarePinsResponse, rhs: NodeRemoteHardwarePinsResponse) -> Bool {
public static func ==(lhs: NodeRemoteHardwarePinsResponse, rhs: NodeRemoteHardwarePinsResponse) -> Bool {
if lhs.nodeRemoteHardwarePins != rhs.nodeRemoteHardwarePins {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true

View file

@ -26,32 +26,32 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
/// any SECONDARY channels.
/// No DISABLED channels are included.
/// This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL
struct ChannelSet {
public struct ChannelSet {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Channel list with settings
var settings: [ChannelSettings] {
public var settings: [ChannelSettings] {
get {return _storage._settings}
set {_uniqueStorage()._settings = newValue}
}
///
/// LoRa config
var loraConfig: Config.LoRaConfig {
public var loraConfig: Config.LoRaConfig {
get {return _storage._loraConfig ?? Config.LoRaConfig()}
set {_uniqueStorage()._loraConfig = newValue}
}
/// Returns true if `loraConfig` has been explicitly set.
var hasLoraConfig: Bool {return _storage._loraConfig != nil}
public var hasLoraConfig: Bool {return _storage._loraConfig != nil}
/// Clears the value of `loraConfig`. Subsequent reads from it will return its default value.
mutating func clearLoraConfig() {_uniqueStorage()._loraConfig = nil}
public mutating func clearLoraConfig() {_uniqueStorage()._loraConfig = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _storage = _StorageClass.defaultInstance
}
@ -65,8 +65,8 @@ extension ChannelSet: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ChannelSet"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".ChannelSet"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "settings"),
2: .standard(proto: "lora_config"),
]
@ -100,7 +100,7 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
@ -116,7 +116,7 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
@ -132,7 +132,7 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: ChannelSet, rhs: ChannelSet) -> Bool {
public static func ==(lhs: ChannelSet, rhs: ChannelSet) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0

View file

@ -20,8 +20,8 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
typealias Version = _2
}
enum Team: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum Team: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// Unspecifed
@ -84,11 +84,11 @@ enum Team: SwiftProtobuf.Enum {
case brown // = 14
case UNRECOGNIZED(Int)
init() {
public init() {
self = .unspecifedColor
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .unspecifedColor
case 1: self = .white
@ -109,7 +109,7 @@ enum Team: SwiftProtobuf.Enum {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .unspecifedColor: return 0
case .white: return 1
@ -136,7 +136,7 @@ enum Team: SwiftProtobuf.Enum {
extension Team: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [Team] = [
public static let allCases: [Team] = [
.unspecifedColor,
.white,
.yellow,
@ -159,8 +159,8 @@ extension Team: CaseIterable {
///
/// Role of the group member
enum MemberRole: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum MemberRole: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// Unspecifed
@ -199,11 +199,11 @@ enum MemberRole: SwiftProtobuf.Enum {
case k9 // = 8
case UNRECOGNIZED(Int)
init() {
public init() {
self = .unspecifed
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .unspecifed
case 1: self = .teamMember
@ -218,7 +218,7 @@ enum MemberRole: SwiftProtobuf.Enum {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .unspecifed: return 0
case .teamMember: return 1
@ -239,7 +239,7 @@ enum MemberRole: SwiftProtobuf.Enum {
extension MemberRole: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [MemberRole] = [
public static let allCases: [MemberRole] = [
.unspecifed,
.teamMember,
.teamLead,
@ -256,55 +256,55 @@ extension MemberRole: CaseIterable {
///
/// Packets for the official ATAK Plugin
struct TAKPacket {
public struct TAKPacket {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Are the payloads strings compressed for LoRA transport?
var isCompressed: Bool = false
public var isCompressed: Bool = false
///
/// The contact / callsign for ATAK user
var contact: Contact {
public var contact: Contact {
get {return _contact ?? Contact()}
set {_contact = newValue}
}
/// Returns true if `contact` has been explicitly set.
var hasContact: Bool {return self._contact != nil}
public var hasContact: Bool {return self._contact != nil}
/// Clears the value of `contact`. Subsequent reads from it will return its default value.
mutating func clearContact() {self._contact = nil}
public mutating func clearContact() {self._contact = nil}
///
/// The group for ATAK user
var group: Group {
public var group: Group {
get {return _group ?? Group()}
set {_group = newValue}
}
/// Returns true if `group` has been explicitly set.
var hasGroup: Bool {return self._group != nil}
public var hasGroup: Bool {return self._group != nil}
/// Clears the value of `group`. Subsequent reads from it will return its default value.
mutating func clearGroup() {self._group = nil}
public mutating func clearGroup() {self._group = nil}
///
/// The status of the ATAK EUD
var status: Status {
public var status: Status {
get {return _status ?? Status()}
set {_status = newValue}
}
/// Returns true if `status` has been explicitly set.
var hasStatus: Bool {return self._status != nil}
public var hasStatus: Bool {return self._status != nil}
/// Clears the value of `status`. Subsequent reads from it will return its default value.
mutating func clearStatus() {self._status = nil}
public mutating func clearStatus() {self._status = nil}
///
/// The payload of the packet
var payloadVariant: TAKPacket.OneOf_PayloadVariant? = nil
public var payloadVariant: TAKPacket.OneOf_PayloadVariant? = nil
///
/// TAK position report
var pli: PLI {
public var pli: PLI {
get {
if case .pli(let v)? = payloadVariant {return v}
return PLI()
@ -314,7 +314,7 @@ struct TAKPacket {
///
/// ATAK GeoChat message
var chat: GeoChat {
public var chat: GeoChat {
get {
if case .chat(let v)? = payloadVariant {return v}
return GeoChat()
@ -322,11 +322,11 @@ struct TAKPacket {
set {payloadVariant = .chat(newValue)}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// The payload of the packet
enum OneOf_PayloadVariant: Equatable {
public enum OneOf_PayloadVariant: Equatable {
///
/// TAK position report
case pli(PLI)
@ -335,7 +335,7 @@ struct TAKPacket {
case chat(GeoChat)
#if !swift(>=4.1)
static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool {
public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
@ -354,7 +354,7 @@ struct TAKPacket {
#endif
}
init() {}
public init() {}
fileprivate var _contact: Contact? = nil
fileprivate var _group: Group? = nil
@ -363,40 +363,40 @@ struct TAKPacket {
///
/// ATAK GeoChat message
struct GeoChat {
public struct GeoChat {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The text message
var message: String = String()
public var message: String = String()
///
/// Uid recipient of the message
var to: String {
public var to: String {
get {return _to ?? String()}
set {_to = newValue}
}
/// Returns true if `to` has been explicitly set.
var hasTo: Bool {return self._to != nil}
public var hasTo: Bool {return self._to != nil}
/// Clears the value of `to`. Subsequent reads from it will return its default value.
mutating func clearTo() {self._to = nil}
public mutating func clearTo() {self._to = nil}
///
/// Callsign of the recipient for the message
var toCallsign: String {
public var toCallsign: String {
get {return _toCallsign ?? String()}
set {_toCallsign = newValue}
}
/// Returns true if `toCallsign` has been explicitly set.
var hasToCallsign: Bool {return self._toCallsign != nil}
public var hasToCallsign: Bool {return self._toCallsign != nil}
/// Clears the value of `toCallsign`. Subsequent reads from it will return its default value.
mutating func clearToCallsign() {self._toCallsign = nil}
public mutating func clearToCallsign() {self._toCallsign = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _to: String? = nil
fileprivate var _toCallsign: String? = nil
@ -405,66 +405,66 @@ struct GeoChat {
///
/// ATAK Group
/// <__group role='Team Member' name='Cyan'/>
struct Group {
public struct Group {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Role of the group member
var role: MemberRole = .unspecifed
public var role: MemberRole = .unspecifed
///
/// Team (color)
/// Default Cyan
var team: Team = .unspecifedColor
public var team: Team = .unspecifedColor
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// ATAK EUD Status
/// <status battery='100' />
struct Status {
public struct Status {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Battery level
var battery: UInt32 = 0
public var battery: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// ATAK Contact
/// <contact endpoint='0.0.0.0:4242:tcp' phone='+12345678' callsign='FALKE'/>
struct Contact {
public struct Contact {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Callsign
var callsign: String = String()
public var callsign: String = String()
///
/// Device callsign
var deviceCallsign: String = String()
public var deviceCallsign: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// Position Location Information from ATAK
struct PLI {
public struct PLI {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@ -472,28 +472,28 @@ struct PLI {
///
/// The new preferred location encoding, multiply by 1e-7 to get degrees
/// in floating point
var latitudeI: Int32 = 0
public var latitudeI: Int32 = 0
///
/// The new preferred location encoding, multiply by 1e-7 to get degrees
/// in floating point
var longitudeI: Int32 = 0
public var longitudeI: Int32 = 0
///
/// Altitude (ATAK prefers HAE)
var altitude: Int32 = 0
public var altitude: Int32 = 0
///
/// Speed
var speed: UInt32 = 0
public var speed: UInt32 = 0
///
/// Course in degrees
var course: UInt32 = 0
public var course: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -513,7 +513,7 @@ extension PLI: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension Team: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "Unspecifed_Color"),
1: .same(proto: "White"),
2: .same(proto: "Yellow"),
@ -533,7 +533,7 @@ extension Team: SwiftProtobuf._ProtoNameProviding {
}
extension MemberRole: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "Unspecifed"),
1: .same(proto: "TeamMember"),
2: .same(proto: "TeamLead"),
@ -547,8 +547,8 @@ extension MemberRole: SwiftProtobuf._ProtoNameProviding {
}
extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TAKPacket"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".TAKPacket"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "is_compressed"),
2: .same(proto: "contact"),
3: .same(proto: "group"),
@ -557,7 +557,7 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
6: .same(proto: "chat"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -598,7 +598,7 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -629,7 +629,7 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TAKPacket, rhs: TAKPacket) -> Bool {
public static func ==(lhs: TAKPacket, rhs: TAKPacket) -> Bool {
if lhs.isCompressed != rhs.isCompressed {return false}
if lhs._contact != rhs._contact {return false}
if lhs._group != rhs._group {return false}
@ -641,14 +641,14 @@ extension TAKPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
}
extension GeoChat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".GeoChat"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".GeoChat"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "message"),
2: .same(proto: "to"),
3: .standard(proto: "to_callsign"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -662,7 +662,7 @@ extension GeoChat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -679,7 +679,7 @@ extension GeoChat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: GeoChat, rhs: GeoChat) -> Bool {
public static func ==(lhs: GeoChat, rhs: GeoChat) -> Bool {
if lhs.message != rhs.message {return false}
if lhs._to != rhs._to {return false}
if lhs._toCallsign != rhs._toCallsign {return false}
@ -689,13 +689,13 @@ extension GeoChat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
extension Group: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Group"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".Group"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "role"),
2: .same(proto: "team"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -708,7 +708,7 @@ extension Group: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.role != .unspecifed {
try visitor.visitSingularEnumField(value: self.role, fieldNumber: 1)
}
@ -718,7 +718,7 @@ extension Group: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Group, rhs: Group) -> Bool {
public static func ==(lhs: Group, rhs: Group) -> Bool {
if lhs.role != rhs.role {return false}
if lhs.team != rhs.team {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
@ -727,12 +727,12 @@ extension Group: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase
}
extension Status: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Status"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".Status"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "battery"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -744,14 +744,14 @@ extension Status: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.battery != 0 {
try visitor.visitSingularUInt32Field(value: self.battery, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Status, rhs: Status) -> Bool {
public static func ==(lhs: Status, rhs: Status) -> Bool {
if lhs.battery != rhs.battery {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
@ -759,13 +759,13 @@ extension Status: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas
}
extension Contact: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Contact"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".Contact"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "callsign"),
2: .standard(proto: "device_callsign"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -778,7 +778,7 @@ extension Contact: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.callsign.isEmpty {
try visitor.visitSingularStringField(value: self.callsign, fieldNumber: 1)
}
@ -788,7 +788,7 @@ extension Contact: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Contact, rhs: Contact) -> Bool {
public static func ==(lhs: Contact, rhs: Contact) -> Bool {
if lhs.callsign != rhs.callsign {return false}
if lhs.deviceCallsign != rhs.deviceCallsign {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
@ -797,8 +797,8 @@ extension Contact: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
extension PLI: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".PLI"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".PLI"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "latitude_i"),
2: .standard(proto: "longitude_i"),
3: .same(proto: "altitude"),
@ -806,7 +806,7 @@ extension PLI: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
5: .same(proto: "course"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -822,7 +822,7 @@ extension PLI: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.latitudeI != 0 {
try visitor.visitSingularSFixed32Field(value: self.latitudeI, fieldNumber: 1)
}
@ -841,7 +841,7 @@ extension PLI: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase,
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: PLI, rhs: PLI) -> Bool {
public static func ==(lhs: PLI, rhs: PLI) -> Bool {
if lhs.latitudeI != rhs.latitudeI {return false}
if lhs.longitudeI != rhs.longitudeI {return false}
if lhs.altitude != rhs.altitude {return false}

View file

@ -22,18 +22,18 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
///
/// Canned message module configuration.
struct CannedMessageModuleConfig {
public struct CannedMessageModuleConfig {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Predefined messages for canned message module separated by '|' characters.
var messages: String = String()
public var messages: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -45,12 +45,12 @@ extension CannedMessageModuleConfig: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension CannedMessageModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".CannedMessageModuleConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".CannedMessageModuleConfig"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "messages"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -62,14 +62,14 @@ extension CannedMessageModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._Messa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.messages.isEmpty {
try visitor.visitSingularStringField(value: self.messages, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessageModuleConfig, rhs: CannedMessageModuleConfig) -> Bool {
public static func ==(lhs: CannedMessageModuleConfig, rhs: CannedMessageModuleConfig) -> Bool {
if lhs.messages != rhs.messages {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true

View file

@ -36,14 +36,14 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
/// FIXME: Add description of multi-channel support and how primary vs secondary channels are used.
/// FIXME: explain how apps use channels for security.
/// explain how remote settings and remote gpio are managed as an example
struct ChannelSettings {
public struct ChannelSettings {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Deprecated in favor of LoraConfig.channel_num
var channelNum: UInt32 = 0
public var channelNum: UInt32 = 0
///
/// A simple pre-shared key for now for crypto.
@ -56,7 +56,7 @@ struct ChannelSettings {
/// `1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01}
/// `2` through 10 = The default channel key, except with 1 through 9 added to the last byte.
/// Shown to user as simple1 through 10
var psk: Data = Data()
public var psk: Data = Data()
///
/// A SHORT name that will be packed into the URL.
@ -67,7 +67,7 @@ struct ChannelSettings {
/// In user interfaces it should be rendered as a local language translation of "X".
/// For channel_num hashing empty string will be treated as "X".
/// Where "X" is selected based on the English words listed above for ModemPreset
var name: String = String()
public var name: String = String()
///
/// Used to construct a globally unique channel ID.
@ -81,58 +81,58 @@ struct ChannelSettings {
/// Those channels do not have a numeric id included in the settings, but instead it is pulled from
/// a table of well known IDs.
/// (see Well Known Channels FIXME)
var id: UInt32 = 0
public var id: UInt32 = 0
///
/// If true, messages on the mesh will be sent to the *public* internet by any gateway ndoe
var uplinkEnabled: Bool = false
public var uplinkEnabled: Bool = false
///
/// If true, messages seen on the internet will be forwarded to the local mesh.
var downlinkEnabled: Bool = false
public var downlinkEnabled: Bool = false
///
/// Per-channel module settings.
var moduleSettings: ModuleSettings {
public var moduleSettings: ModuleSettings {
get {return _moduleSettings ?? ModuleSettings()}
set {_moduleSettings = newValue}
}
/// Returns true if `moduleSettings` has been explicitly set.
var hasModuleSettings: Bool {return self._moduleSettings != nil}
public var hasModuleSettings: Bool {return self._moduleSettings != nil}
/// Clears the value of `moduleSettings`. Subsequent reads from it will return its default value.
mutating func clearModuleSettings() {self._moduleSettings = nil}
public mutating func clearModuleSettings() {self._moduleSettings = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _moduleSettings: ModuleSettings? = nil
}
///
/// This message is specifically for modules to store per-channel configuration data.
struct ModuleSettings {
public struct ModuleSettings {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Bits of precision for the location sent in position packets.
var positionPrecision: UInt32 = 0
public var positionPrecision: UInt32 = 0
///
/// Controls whether or not the phone / clients should mute the current channel
/// Useful for noisy public channels you don't necessarily want to disable
var isClientMuted: Bool = false
public var isClientMuted: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// A pair of a channel number, mode and the (sharable) settings for that channel
struct Channel {
public struct Channel {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@ -141,24 +141,24 @@ struct Channel {
/// The index of this channel in the channel table (from 0 to MAX_NUM_CHANNELS-1)
/// (Someday - not currently implemented) An index of -1 could be used to mean "set by name",
/// in which case the target node will find and set the channel by settings.name.
var index: Int32 = 0
public var index: Int32 = 0
///
/// The new settings, or NULL to disable that channel
var settings: ChannelSettings {
public var settings: ChannelSettings {
get {return _settings ?? ChannelSettings()}
set {_settings = newValue}
}
/// Returns true if `settings` has been explicitly set.
var hasSettings: Bool {return self._settings != nil}
public var hasSettings: Bool {return self._settings != nil}
/// Clears the value of `settings`. Subsequent reads from it will return its default value.
mutating func clearSettings() {self._settings = nil}
public mutating func clearSettings() {self._settings = nil}
///
/// TODO: REPLACE
var role: Channel.Role = .disabled
public var role: Channel.Role = .disabled
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// How this channel is being used (or not).
@ -170,8 +170,8 @@ struct Channel {
/// cross band routing as needed.
/// If a device has only a single radio (the common case) only one channel can be PRIMARY at a time
/// (but any number of SECONDARY channels can't be sent received on that common frequency)
enum Role: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum Role: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// This channel is not in use right now
@ -187,11 +187,11 @@ struct Channel {
case secondary // = 2
case UNRECOGNIZED(Int)
init() {
public init() {
self = .disabled
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .disabled
case 1: self = .primary
@ -200,7 +200,7 @@ struct Channel {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .disabled: return 0
case .primary: return 1
@ -211,7 +211,7 @@ struct Channel {
}
init() {}
public init() {}
fileprivate var _settings: ChannelSettings? = nil
}
@ -220,7 +220,7 @@ struct Channel {
extension Channel.Role: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [Channel.Role] = [
public static let allCases: [Channel.Role] = [
.disabled,
.primary,
.secondary,
@ -241,8 +241,8 @@ extension Channel.Role: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ChannelSettings"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".ChannelSettings"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "channel_num"),
2: .same(proto: "psk"),
3: .same(proto: "name"),
@ -252,7 +252,7 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
7: .standard(proto: "module_settings"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -270,7 +270,7 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -299,7 +299,7 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: ChannelSettings, rhs: ChannelSettings) -> Bool {
public static func ==(lhs: ChannelSettings, rhs: ChannelSettings) -> Bool {
if lhs.channelNum != rhs.channelNum {return false}
if lhs.psk != rhs.psk {return false}
if lhs.name != rhs.name {return false}
@ -313,13 +313,13 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
extension ModuleSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ModuleSettings"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".ModuleSettings"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "position_precision"),
2: .standard(proto: "is_client_muted"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -332,7 +332,7 @@ extension ModuleSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.positionPrecision != 0 {
try visitor.visitSingularUInt32Field(value: self.positionPrecision, fieldNumber: 1)
}
@ -342,7 +342,7 @@ extension ModuleSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: ModuleSettings, rhs: ModuleSettings) -> Bool {
public static func ==(lhs: ModuleSettings, rhs: ModuleSettings) -> Bool {
if lhs.positionPrecision != rhs.positionPrecision {return false}
if lhs.isClientMuted != rhs.isClientMuted {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
@ -351,14 +351,14 @@ extension ModuleSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement
}
extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Channel"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".Channel"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "index"),
2: .same(proto: "settings"),
3: .same(proto: "role"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -372,7 +372,7 @@ extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -389,7 +389,7 @@ extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Channel, rhs: Channel) -> Bool {
public static func ==(lhs: Channel, rhs: Channel) -> Bool {
if lhs.index != rhs.index {return false}
if lhs._settings != rhs._settings {return false}
if lhs.role != rhs.role {return false}
@ -399,7 +399,7 @@ extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
extension Channel.Role: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "DISABLED"),
1: .same(proto: "PRIMARY"),
2: .same(proto: "SECONDARY"),

View file

@ -23,69 +23,69 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
///
/// This abstraction is used to contain any configuration for provisioning a node on any client.
/// It is useful for importing and exporting configurations.
struct DeviceProfile {
public struct DeviceProfile {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Long name for the node
var longName: String {
public var longName: String {
get {return _longName ?? String()}
set {_longName = newValue}
}
/// Returns true if `longName` has been explicitly set.
var hasLongName: Bool {return self._longName != nil}
public var hasLongName: Bool {return self._longName != nil}
/// Clears the value of `longName`. Subsequent reads from it will return its default value.
mutating func clearLongName() {self._longName = nil}
public mutating func clearLongName() {self._longName = nil}
///
/// Short name of the node
var shortName: String {
public var shortName: String {
get {return _shortName ?? String()}
set {_shortName = newValue}
}
/// Returns true if `shortName` has been explicitly set.
var hasShortName: Bool {return self._shortName != nil}
public var hasShortName: Bool {return self._shortName != nil}
/// Clears the value of `shortName`. Subsequent reads from it will return its default value.
mutating func clearShortName() {self._shortName = nil}
public mutating func clearShortName() {self._shortName = nil}
///
/// The url of the channels from our node
var channelURL: String {
public var channelURL: String {
get {return _channelURL ?? String()}
set {_channelURL = newValue}
}
/// Returns true if `channelURL` has been explicitly set.
var hasChannelURL: Bool {return self._channelURL != nil}
public var hasChannelURL: Bool {return self._channelURL != nil}
/// Clears the value of `channelURL`. Subsequent reads from it will return its default value.
mutating func clearChannelURL() {self._channelURL = nil}
public mutating func clearChannelURL() {self._channelURL = nil}
///
/// The Config of the node
var config: LocalConfig {
public var config: LocalConfig {
get {return _config ?? LocalConfig()}
set {_config = newValue}
}
/// Returns true if `config` has been explicitly set.
var hasConfig: Bool {return self._config != nil}
public var hasConfig: Bool {return self._config != nil}
/// Clears the value of `config`. Subsequent reads from it will return its default value.
mutating func clearConfig() {self._config = nil}
public mutating func clearConfig() {self._config = nil}
///
/// The ModuleConfig of the node
var moduleConfig: LocalModuleConfig {
public var moduleConfig: LocalModuleConfig {
get {return _moduleConfig ?? LocalModuleConfig()}
set {_moduleConfig = newValue}
}
/// Returns true if `moduleConfig` has been explicitly set.
var hasModuleConfig: Bool {return self._moduleConfig != nil}
public var hasModuleConfig: Bool {return self._moduleConfig != nil}
/// Clears the value of `moduleConfig`. Subsequent reads from it will return its default value.
mutating func clearModuleConfig() {self._moduleConfig = nil}
public mutating func clearModuleConfig() {self._moduleConfig = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _longName: String? = nil
fileprivate var _shortName: String? = nil
@ -103,8 +103,8 @@ extension DeviceProfile: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".DeviceProfile"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".DeviceProfile"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "long_name"),
2: .standard(proto: "short_name"),
3: .standard(proto: "channel_url"),
@ -112,7 +112,7 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
5: .standard(proto: "module_config"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -128,7 +128,7 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -151,7 +151,7 @@ extension DeviceProfile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: DeviceProfile, rhs: DeviceProfile) -> Bool {
public static func ==(lhs: DeviceProfile, rhs: DeviceProfile) -> Bool {
if lhs._longName != rhs._longName {return false}
if lhs._shortName != rhs._shortName {return false}
if lhs._channelURL != rhs._channelURL {return false}

View file

@ -20,58 +20,58 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
typealias Version = _2
}
struct DeviceConnectionStatus {
public struct DeviceConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// WiFi Status
var wifi: WifiConnectionStatus {
public var wifi: WifiConnectionStatus {
get {return _wifi ?? WifiConnectionStatus()}
set {_wifi = newValue}
}
/// Returns true if `wifi` has been explicitly set.
var hasWifi: Bool {return self._wifi != nil}
public var hasWifi: Bool {return self._wifi != nil}
/// Clears the value of `wifi`. Subsequent reads from it will return its default value.
mutating func clearWifi() {self._wifi = nil}
public mutating func clearWifi() {self._wifi = nil}
///
/// WiFi Status
var ethernet: EthernetConnectionStatus {
public var ethernet: EthernetConnectionStatus {
get {return _ethernet ?? EthernetConnectionStatus()}
set {_ethernet = newValue}
}
/// Returns true if `ethernet` has been explicitly set.
var hasEthernet: Bool {return self._ethernet != nil}
public var hasEthernet: Bool {return self._ethernet != nil}
/// Clears the value of `ethernet`. Subsequent reads from it will return its default value.
mutating func clearEthernet() {self._ethernet = nil}
public mutating func clearEthernet() {self._ethernet = nil}
///
/// Bluetooth Status
var bluetooth: BluetoothConnectionStatus {
public var bluetooth: BluetoothConnectionStatus {
get {return _bluetooth ?? BluetoothConnectionStatus()}
set {_bluetooth = newValue}
}
/// Returns true if `bluetooth` has been explicitly set.
var hasBluetooth: Bool {return self._bluetooth != nil}
public var hasBluetooth: Bool {return self._bluetooth != nil}
/// Clears the value of `bluetooth`. Subsequent reads from it will return its default value.
mutating func clearBluetooth() {self._bluetooth = nil}
public mutating func clearBluetooth() {self._bluetooth = nil}
///
/// Serial Status
var serial: SerialConnectionStatus {
public var serial: SerialConnectionStatus {
get {return _serial ?? SerialConnectionStatus()}
set {_serial = newValue}
}
/// Returns true if `serial` has been explicitly set.
var hasSerial: Bool {return self._serial != nil}
public var hasSerial: Bool {return self._serial != nil}
/// Clears the value of `serial`. Subsequent reads from it will return its default value.
mutating func clearSerial() {self._serial = nil}
public mutating func clearSerial() {self._serial = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _wifi: WifiConnectionStatus? = nil
fileprivate var _ethernet: EthernetConnectionStatus? = nil
@ -81,132 +81,132 @@ struct DeviceConnectionStatus {
///
/// WiFi connection status
struct WifiConnectionStatus {
public struct WifiConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Connection status
var status: NetworkConnectionStatus {
public var status: NetworkConnectionStatus {
get {return _status ?? NetworkConnectionStatus()}
set {_status = newValue}
}
/// Returns true if `status` has been explicitly set.
var hasStatus: Bool {return self._status != nil}
public var hasStatus: Bool {return self._status != nil}
/// Clears the value of `status`. Subsequent reads from it will return its default value.
mutating func clearStatus() {self._status = nil}
public mutating func clearStatus() {self._status = nil}
///
/// WiFi access point SSID
var ssid: String = String()
public var ssid: String = String()
///
/// RSSI of wireless connection
var rssi: Int32 = 0
public var rssi: Int32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _status: NetworkConnectionStatus? = nil
}
///
/// Ethernet connection status
struct EthernetConnectionStatus {
public struct EthernetConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Connection status
var status: NetworkConnectionStatus {
public var status: NetworkConnectionStatus {
get {return _status ?? NetworkConnectionStatus()}
set {_status = newValue}
}
/// Returns true if `status` has been explicitly set.
var hasStatus: Bool {return self._status != nil}
public var hasStatus: Bool {return self._status != nil}
/// Clears the value of `status`. Subsequent reads from it will return its default value.
mutating func clearStatus() {self._status = nil}
public mutating func clearStatus() {self._status = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _status: NetworkConnectionStatus? = nil
}
///
/// Ethernet or WiFi connection status
struct NetworkConnectionStatus {
public struct NetworkConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// IP address of device
var ipAddress: UInt32 = 0
public var ipAddress: UInt32 = 0
///
/// Whether the device has an active connection or not
var isConnected: Bool = false
public var isConnected: Bool = false
///
/// Whether the device has an active connection to an MQTT broker or not
var isMqttConnected: Bool = false
public var isMqttConnected: Bool = false
///
/// Whether the device is actively remote syslogging or not
var isSyslogConnected: Bool = false
public var isSyslogConnected: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// Bluetooth connection status
struct BluetoothConnectionStatus {
public struct BluetoothConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The pairing PIN for bluetooth
var pin: UInt32 = 0
public var pin: UInt32 = 0
///
/// RSSI of bluetooth connection
var rssi: Int32 = 0
public var rssi: Int32 = 0
///
/// Whether the device has an active connection or not
var isConnected: Bool = false
public var isConnected: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// Serial connection status
struct SerialConnectionStatus {
public struct SerialConnectionStatus {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Serial baud rate
var baud: UInt32 = 0
public var baud: UInt32 = 0
///
/// Whether the device has an active connection or not
var isConnected: Bool = false
public var isConnected: Bool = false
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -223,15 +223,15 @@ extension SerialConnectionStatus: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".DeviceConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".DeviceConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "wifi"),
2: .same(proto: "ethernet"),
3: .same(proto: "bluetooth"),
4: .same(proto: "serial"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -246,7 +246,7 @@ extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -266,7 +266,7 @@ extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: DeviceConnectionStatus, rhs: DeviceConnectionStatus) -> Bool {
public static func ==(lhs: DeviceConnectionStatus, rhs: DeviceConnectionStatus) -> Bool {
if lhs._wifi != rhs._wifi {return false}
if lhs._ethernet != rhs._ethernet {return false}
if lhs._bluetooth != rhs._bluetooth {return false}
@ -277,14 +277,14 @@ extension DeviceConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
}
extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".WifiConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".WifiConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "status"),
2: .same(proto: "ssid"),
3: .same(proto: "rssi"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -298,7 +298,7 @@ extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -315,7 +315,7 @@ extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: WifiConnectionStatus, rhs: WifiConnectionStatus) -> Bool {
public static func ==(lhs: WifiConnectionStatus, rhs: WifiConnectionStatus) -> Bool {
if lhs._status != rhs._status {return false}
if lhs.ssid != rhs.ssid {return false}
if lhs.rssi != rhs.rssi {return false}
@ -325,12 +325,12 @@ extension WifiConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
}
extension EthernetConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".EthernetConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".EthernetConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "status"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -342,7 +342,7 @@ extension EthernetConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messag
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -353,7 +353,7 @@ extension EthernetConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messag
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: EthernetConnectionStatus, rhs: EthernetConnectionStatus) -> Bool {
public static func ==(lhs: EthernetConnectionStatus, rhs: EthernetConnectionStatus) -> Bool {
if lhs._status != rhs._status {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
@ -361,15 +361,15 @@ extension EthernetConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messag
}
extension NetworkConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".NetworkConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".NetworkConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "ip_address"),
2: .standard(proto: "is_connected"),
3: .standard(proto: "is_mqtt_connected"),
4: .standard(proto: "is_syslog_connected"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -384,7 +384,7 @@ extension NetworkConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Message
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.ipAddress != 0 {
try visitor.visitSingularFixed32Field(value: self.ipAddress, fieldNumber: 1)
}
@ -400,7 +400,7 @@ extension NetworkConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Message
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: NetworkConnectionStatus, rhs: NetworkConnectionStatus) -> Bool {
public static func ==(lhs: NetworkConnectionStatus, rhs: NetworkConnectionStatus) -> Bool {
if lhs.ipAddress != rhs.ipAddress {return false}
if lhs.isConnected != rhs.isConnected {return false}
if lhs.isMqttConnected != rhs.isMqttConnected {return false}
@ -411,14 +411,14 @@ extension NetworkConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Message
}
extension BluetoothConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".BluetoothConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".BluetoothConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "pin"),
2: .same(proto: "rssi"),
3: .standard(proto: "is_connected"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -432,7 +432,7 @@ extension BluetoothConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messa
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.pin != 0 {
try visitor.visitSingularUInt32Field(value: self.pin, fieldNumber: 1)
}
@ -445,7 +445,7 @@ extension BluetoothConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messa
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: BluetoothConnectionStatus, rhs: BluetoothConnectionStatus) -> Bool {
public static func ==(lhs: BluetoothConnectionStatus, rhs: BluetoothConnectionStatus) -> Bool {
if lhs.pin != rhs.pin {return false}
if lhs.rssi != rhs.rssi {return false}
if lhs.isConnected != rhs.isConnected {return false}
@ -455,13 +455,13 @@ extension BluetoothConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._Messa
}
extension SerialConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".SerialConnectionStatus"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".SerialConnectionStatus"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "baud"),
2: .standard(proto: "is_connected"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -474,7 +474,7 @@ extension SerialConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.baud != 0 {
try visitor.visitSingularUInt32Field(value: self.baud, fieldNumber: 1)
}
@ -484,7 +484,7 @@ extension SerialConnectionStatus: SwiftProtobuf.Message, SwiftProtobuf._MessageI
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: SerialConnectionStatus, rhs: SerialConnectionStatus) -> Bool {
public static func ==(lhs: SerialConnectionStatus, rhs: SerialConnectionStatus) -> Bool {
if lhs.baud != rhs.baud {return false}
if lhs.isConnected != rhs.isConnected {return false}
if lhs.unknownFields != rhs.unknownFields {return false}

View file

@ -22,8 +22,8 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
///
/// Font sizes for the device screen
enum ScreenFonts: SwiftProtobuf.Enum {
typealias RawValue = Int
public enum ScreenFonts: SwiftProtobuf.Enum {
public typealias RawValue = Int
///
/// TODO: REPLACE
@ -38,11 +38,11 @@ enum ScreenFonts: SwiftProtobuf.Enum {
case fontLarge // = 2
case UNRECOGNIZED(Int)
init() {
public init() {
self = .fontSmall
}
init?(rawValue: Int) {
public init?(rawValue: Int) {
switch rawValue {
case 0: self = .fontSmall
case 1: self = .fontMedium
@ -51,7 +51,7 @@ enum ScreenFonts: SwiftProtobuf.Enum {
}
}
var rawValue: Int {
public var rawValue: Int {
switch self {
case .fontSmall: return 0
case .fontMedium: return 1
@ -66,7 +66,7 @@ enum ScreenFonts: SwiftProtobuf.Enum {
extension ScreenFonts: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static let allCases: [ScreenFonts] = [
public static let allCases: [ScreenFonts] = [
.fontSmall,
.fontMedium,
.fontLarge,
@ -77,7 +77,7 @@ extension ScreenFonts: CaseIterable {
///
/// Position with static location information only for NodeDBLite
struct PositionLite {
public struct PositionLite {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
@ -85,15 +85,15 @@ struct PositionLite {
///
/// The new preferred location encoding, multiply by 1e-7 to get degrees
/// in floating point
var latitudeI: Int32 = 0
public var latitudeI: Int32 = 0
///
/// TODO: REPLACE
var longitudeI: Int32 = 0
public var longitudeI: Int32 = 0
///
/// In meters above MSL (but see issue #359)
var altitude: Int32 = 0
public var altitude: Int32 = 0
///
/// This is usually not sent over the mesh (to save space), but it is sent
@ -101,95 +101,95 @@ struct PositionLite {
/// the mesh (because there are devices on the mesh without GPS), it will only
/// be sent by devices which has a hardware GPS clock.
/// seconds since 1970
var time: UInt32 = 0
public var time: UInt32 = 0
///
/// TODO: REPLACE
var locationSource: Position.LocSource = .locUnset
public var locationSource: Position.LocSource = .locUnset
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
struct NodeInfoLite {
public struct NodeInfoLite {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The node number
var num: UInt32 {
public var num: UInt32 {
get {return _storage._num}
set {_uniqueStorage()._num = newValue}
}
///
/// The user info for this node
var user: User {
public var user: User {
get {return _storage._user ?? User()}
set {_uniqueStorage()._user = newValue}
}
/// Returns true if `user` has been explicitly set.
var hasUser: Bool {return _storage._user != nil}
public var hasUser: Bool {return _storage._user != nil}
/// Clears the value of `user`. Subsequent reads from it will return its default value.
mutating func clearUser() {_uniqueStorage()._user = nil}
public mutating func clearUser() {_uniqueStorage()._user = nil}
///
/// This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true.
/// Position.time now indicates the last time we received a POSITION from that node.
var position: PositionLite {
public var position: PositionLite {
get {return _storage._position ?? PositionLite()}
set {_uniqueStorage()._position = newValue}
}
/// Returns true if `position` has been explicitly set.
var hasPosition: Bool {return _storage._position != nil}
public var hasPosition: Bool {return _storage._position != nil}
/// Clears the value of `position`. Subsequent reads from it will return its default value.
mutating func clearPosition() {_uniqueStorage()._position = nil}
public mutating func clearPosition() {_uniqueStorage()._position = nil}
///
/// Returns the Signal-to-noise ratio (SNR) of the last received message,
/// as measured by the receiver. Return SNR of the last received message in dB
var snr: Float {
public var snr: Float {
get {return _storage._snr}
set {_uniqueStorage()._snr = newValue}
}
///
/// Set to indicate the last time we received a packet from this node
var lastHeard: UInt32 {
public var lastHeard: UInt32 {
get {return _storage._lastHeard}
set {_uniqueStorage()._lastHeard = newValue}
}
///
/// The latest device metrics for the node.
var deviceMetrics: DeviceMetrics {
public var deviceMetrics: DeviceMetrics {
get {return _storage._deviceMetrics ?? DeviceMetrics()}
set {_uniqueStorage()._deviceMetrics = newValue}
}
/// Returns true if `deviceMetrics` has been explicitly set.
var hasDeviceMetrics: Bool {return _storage._deviceMetrics != nil}
public var hasDeviceMetrics: Bool {return _storage._deviceMetrics != nil}
/// Clears the value of `deviceMetrics`. Subsequent reads from it will return its default value.
mutating func clearDeviceMetrics() {_uniqueStorage()._deviceMetrics = nil}
public mutating func clearDeviceMetrics() {_uniqueStorage()._deviceMetrics = nil}
///
/// local channel index we heard that node on. Only populated if its not the default channel.
var channel: UInt32 {
public var channel: UInt32 {
get {return _storage._channel}
set {_uniqueStorage()._channel = newValue}
}
///
/// True if we witnessed the node over MQTT instead of LoRA transport
var viaMqtt: Bool {
public var viaMqtt: Bool {
get {return _storage._viaMqtt}
set {_uniqueStorage()._viaMqtt = newValue}
}
///
/// Number of hops away from us this node is (0 if adjacent)
var hopsAway: UInt32 {
public var hopsAway: UInt32 {
get {return _storage._hopsAway}
set {_uniqueStorage()._hopsAway = newValue}
}
@ -197,14 +197,14 @@ struct NodeInfoLite {
///
/// True if node is in our favorites list
/// Persists between NodeDB internal clean ups
var isFavorite: Bool {
public var isFavorite: Bool {
get {return _storage._isFavorite}
set {_uniqueStorage()._isFavorite = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _storage = _StorageClass.defaultInstance
}
@ -215,36 +215,36 @@ struct NodeInfoLite {
/// FIXME, since we write this each time we enter deep sleep (and have infinite
/// flash) it would be better to use some sort of append only data structure for
/// the receive queue and use the preferences store for the other stuff
struct DeviceState {
public struct DeviceState {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Read only settings/info about this node
var myNode: MyNodeInfo {
public var myNode: MyNodeInfo {
get {return _storage._myNode ?? MyNodeInfo()}
set {_uniqueStorage()._myNode = newValue}
}
/// Returns true if `myNode` has been explicitly set.
var hasMyNode: Bool {return _storage._myNode != nil}
public var hasMyNode: Bool {return _storage._myNode != nil}
/// Clears the value of `myNode`. Subsequent reads from it will return its default value.
mutating func clearMyNode() {_uniqueStorage()._myNode = nil}
public mutating func clearMyNode() {_uniqueStorage()._myNode = nil}
///
/// My owner info
var owner: User {
public var owner: User {
get {return _storage._owner ?? User()}
set {_uniqueStorage()._owner = newValue}
}
/// Returns true if `owner` has been explicitly set.
var hasOwner: Bool {return _storage._owner != nil}
public var hasOwner: Bool {return _storage._owner != nil}
/// Clears the value of `owner`. Subsequent reads from it will return its default value.
mutating func clearOwner() {_uniqueStorage()._owner = nil}
public mutating func clearOwner() {_uniqueStorage()._owner = nil}
///
/// Received packets saved for delivery to the phone
var receiveQueue: [MeshPacket] {
public var receiveQueue: [MeshPacket] {
get {return _storage._receiveQueue}
set {_uniqueStorage()._receiveQueue = newValue}
}
@ -253,7 +253,7 @@ struct DeviceState {
/// A version integer used to invalidate old save files when we make
/// incompatible changes This integer is set at build time and is private to
/// NodeDB.cpp in the device code.
var version: UInt32 {
public var version: UInt32 {
get {return _storage._version}
set {_uniqueStorage()._version = newValue}
}
@ -262,27 +262,27 @@ struct DeviceState {
/// We keep the last received text message (only) stored in the device flash,
/// so we can show it on the screen.
/// Might be null
var rxTextMessage: MeshPacket {
public var rxTextMessage: MeshPacket {
get {return _storage._rxTextMessage ?? MeshPacket()}
set {_uniqueStorage()._rxTextMessage = newValue}
}
/// Returns true if `rxTextMessage` has been explicitly set.
var hasRxTextMessage: Bool {return _storage._rxTextMessage != nil}
public var hasRxTextMessage: Bool {return _storage._rxTextMessage != nil}
/// Clears the value of `rxTextMessage`. Subsequent reads from it will return its default value.
mutating func clearRxTextMessage() {_uniqueStorage()._rxTextMessage = nil}
public mutating func clearRxTextMessage() {_uniqueStorage()._rxTextMessage = nil}
///
/// Used only during development.
/// Indicates developer is testing and changes should never be saved to flash.
/// Deprecated in 2.3.1
var noSave: Bool {
public var noSave: Bool {
get {return _storage._noSave}
set {_uniqueStorage()._noSave = newValue}
}
///
/// Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset.
var didGpsReset: Bool {
public var didGpsReset: Bool {
get {return _storage._didGpsReset}
set {_uniqueStorage()._didGpsReset = newValue}
}
@ -291,115 +291,115 @@ struct DeviceState {
/// We keep the last received waypoint stored in the device flash,
/// so we can show it on the screen.
/// Might be null
var rxWaypoint: MeshPacket {
public var rxWaypoint: MeshPacket {
get {return _storage._rxWaypoint ?? MeshPacket()}
set {_uniqueStorage()._rxWaypoint = newValue}
}
/// Returns true if `rxWaypoint` has been explicitly set.
var hasRxWaypoint: Bool {return _storage._rxWaypoint != nil}
public var hasRxWaypoint: Bool {return _storage._rxWaypoint != nil}
/// Clears the value of `rxWaypoint`. Subsequent reads from it will return its default value.
mutating func clearRxWaypoint() {_uniqueStorage()._rxWaypoint = nil}
public mutating func clearRxWaypoint() {_uniqueStorage()._rxWaypoint = nil}
///
/// The mesh's nodes with their available gpio pins for RemoteHardware module
var nodeRemoteHardwarePins: [NodeRemoteHardwarePin] {
public var nodeRemoteHardwarePins: [NodeRemoteHardwarePin] {
get {return _storage._nodeRemoteHardwarePins}
set {_uniqueStorage()._nodeRemoteHardwarePins = newValue}
}
///
/// New lite version of NodeDB to decrease memory footprint
var nodeDbLite: [NodeInfoLite] {
public var nodeDbLite: [NodeInfoLite] {
get {return _storage._nodeDbLite}
set {_uniqueStorage()._nodeDbLite = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _storage = _StorageClass.defaultInstance
}
///
/// The on-disk saved channels
struct ChannelFile {
public struct ChannelFile {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The channels our node knows about
var channels: [Channel] = []
public var channels: [Channel] = []
///
/// A version integer used to invalidate old save files when we make
/// incompatible changes This integer is set at build time and is private to
/// NodeDB.cpp in the device code.
var version: UInt32 = 0
public var version: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
///
/// This can be used for customizing the firmware distribution. If populated,
/// show a secondary bootup screen with custom logo and text for 2.5 seconds.
struct OEMStore {
public struct OEMStore {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The Logo width in Px
var oemIconWidth: UInt32 = 0
public var oemIconWidth: UInt32 = 0
///
/// The Logo height in Px
var oemIconHeight: UInt32 = 0
public var oemIconHeight: UInt32 = 0
///
/// The Logo in XBM bytechar format
var oemIconBits: Data = Data()
public var oemIconBits: Data = Data()
///
/// Use this font for the OEM text.
var oemFont: ScreenFonts = .fontSmall
public var oemFont: ScreenFonts = .fontSmall
///
/// Use this font for the OEM text.
var oemText: String = String()
public var oemText: String = String()
///
/// The default device encryption key, 16 or 32 byte
var oemAesKey: Data = Data()
public var oemAesKey: Data = Data()
///
/// A Preset LocalConfig to apply during factory reset
var oemLocalConfig: LocalConfig {
public var oemLocalConfig: LocalConfig {
get {return _oemLocalConfig ?? LocalConfig()}
set {_oemLocalConfig = newValue}
}
/// Returns true if `oemLocalConfig` has been explicitly set.
var hasOemLocalConfig: Bool {return self._oemLocalConfig != nil}
public var hasOemLocalConfig: Bool {return self._oemLocalConfig != nil}
/// Clears the value of `oemLocalConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalConfig() {self._oemLocalConfig = nil}
public mutating func clearOemLocalConfig() {self._oemLocalConfig = nil}
///
/// A Preset LocalModuleConfig to apply during factory reset
var oemLocalModuleConfig: LocalModuleConfig {
public var oemLocalModuleConfig: LocalModuleConfig {
get {return _oemLocalModuleConfig ?? LocalModuleConfig()}
set {_oemLocalModuleConfig = newValue}
}
/// Returns true if `oemLocalModuleConfig` has been explicitly set.
var hasOemLocalModuleConfig: Bool {return self._oemLocalModuleConfig != nil}
public var hasOemLocalModuleConfig: Bool {return self._oemLocalModuleConfig != nil}
/// Clears the value of `oemLocalModuleConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalModuleConfig() {self._oemLocalModuleConfig = nil}
public mutating func clearOemLocalModuleConfig() {self._oemLocalModuleConfig = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _oemLocalConfig: LocalConfig? = nil
fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil
@ -419,7 +419,7 @@ extension OEMStore: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension ScreenFonts: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "FONT_SMALL"),
1: .same(proto: "FONT_MEDIUM"),
2: .same(proto: "FONT_LARGE"),
@ -427,8 +427,8 @@ extension ScreenFonts: SwiftProtobuf._ProtoNameProviding {
}
extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".PositionLite"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".PositionLite"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "latitude_i"),
2: .standard(proto: "longitude_i"),
3: .same(proto: "altitude"),
@ -436,7 +436,7 @@ extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
5: .standard(proto: "location_source"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -452,7 +452,7 @@ extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.latitudeI != 0 {
try visitor.visitSingularSFixed32Field(value: self.latitudeI, fieldNumber: 1)
}
@ -471,7 +471,7 @@ extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: PositionLite, rhs: PositionLite) -> Bool {
public static func ==(lhs: PositionLite, rhs: PositionLite) -> Bool {
if lhs.latitudeI != rhs.latitudeI {return false}
if lhs.longitudeI != rhs.longitudeI {return false}
if lhs.altitude != rhs.altitude {return false}
@ -483,8 +483,8 @@ extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".NodeInfoLite"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".NodeInfoLite"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "num"),
2: .same(proto: "user"),
3: .same(proto: "position"),
@ -542,7 +542,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
@ -566,7 +566,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
@ -606,7 +606,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: NodeInfoLite, rhs: NodeInfoLite) -> Bool {
public static func ==(lhs: NodeInfoLite, rhs: NodeInfoLite) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
@ -631,8 +631,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
}
extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".DeviceState"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".DeviceState"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
2: .standard(proto: "my_node"),
3: .same(proto: "owner"),
5: .standard(proto: "receive_queue"),
@ -690,7 +690,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
@ -714,7 +714,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
@ -754,7 +754,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: DeviceState, rhs: DeviceState) -> Bool {
public static func ==(lhs: DeviceState, rhs: DeviceState) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
@ -779,13 +779,13 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ChannelFile"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".ChannelFile"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "channels"),
2: .same(proto: "version"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -798,7 +798,7 @@ extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.channels.isEmpty {
try visitor.visitRepeatedMessageField(value: self.channels, fieldNumber: 1)
}
@ -808,7 +808,7 @@ extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: ChannelFile, rhs: ChannelFile) -> Bool {
public static func ==(lhs: ChannelFile, rhs: ChannelFile) -> Bool {
if lhs.channels != rhs.channels {return false}
if lhs.version != rhs.version {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
@ -817,8 +817,8 @@ extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".OEMStore"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".OEMStore"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "oem_icon_width"),
2: .standard(proto: "oem_icon_height"),
3: .standard(proto: "oem_icon_bits"),
@ -829,7 +829,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
8: .standard(proto: "oem_local_module_config"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -848,7 +848,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -880,7 +880,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: OEMStore, rhs: OEMStore) -> Bool {
public static func ==(lhs: OEMStore, rhs: OEMStore) -> Bool {
if lhs.oemIconWidth != rhs.oemIconWidth {return false}
if lhs.oemIconHeight != rhs.oemIconHeight {return false}
if lhs.oemIconBits != rhs.oemIconBits {return false}

View file

@ -20,264 +20,264 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
typealias Version = _2
}
struct LocalConfig {
public struct LocalConfig {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The part of the config that is specific to the Device
var device: Config.DeviceConfig {
public var device: Config.DeviceConfig {
get {return _storage._device ?? Config.DeviceConfig()}
set {_uniqueStorage()._device = newValue}
}
/// Returns true if `device` has been explicitly set.
var hasDevice: Bool {return _storage._device != nil}
public var hasDevice: Bool {return _storage._device != nil}
/// Clears the value of `device`. Subsequent reads from it will return its default value.
mutating func clearDevice() {_uniqueStorage()._device = nil}
public mutating func clearDevice() {_uniqueStorage()._device = nil}
///
/// The part of the config that is specific to the GPS Position
var position: Config.PositionConfig {
public var position: Config.PositionConfig {
get {return _storage._position ?? Config.PositionConfig()}
set {_uniqueStorage()._position = newValue}
}
/// Returns true if `position` has been explicitly set.
var hasPosition: Bool {return _storage._position != nil}
public var hasPosition: Bool {return _storage._position != nil}
/// Clears the value of `position`. Subsequent reads from it will return its default value.
mutating func clearPosition() {_uniqueStorage()._position = nil}
public mutating func clearPosition() {_uniqueStorage()._position = nil}
///
/// The part of the config that is specific to the Power settings
var power: Config.PowerConfig {
public var power: Config.PowerConfig {
get {return _storage._power ?? Config.PowerConfig()}
set {_uniqueStorage()._power = newValue}
}
/// Returns true if `power` has been explicitly set.
var hasPower: Bool {return _storage._power != nil}
public var hasPower: Bool {return _storage._power != nil}
/// Clears the value of `power`. Subsequent reads from it will return its default value.
mutating func clearPower() {_uniqueStorage()._power = nil}
public mutating func clearPower() {_uniqueStorage()._power = nil}
///
/// The part of the config that is specific to the Wifi Settings
var network: Config.NetworkConfig {
public var network: Config.NetworkConfig {
get {return _storage._network ?? Config.NetworkConfig()}
set {_uniqueStorage()._network = newValue}
}
/// Returns true if `network` has been explicitly set.
var hasNetwork: Bool {return _storage._network != nil}
public var hasNetwork: Bool {return _storage._network != nil}
/// Clears the value of `network`. Subsequent reads from it will return its default value.
mutating func clearNetwork() {_uniqueStorage()._network = nil}
public mutating func clearNetwork() {_uniqueStorage()._network = nil}
///
/// The part of the config that is specific to the Display
var display: Config.DisplayConfig {
public var display: Config.DisplayConfig {
get {return _storage._display ?? Config.DisplayConfig()}
set {_uniqueStorage()._display = newValue}
}
/// Returns true if `display` has been explicitly set.
var hasDisplay: Bool {return _storage._display != nil}
public var hasDisplay: Bool {return _storage._display != nil}
/// Clears the value of `display`. Subsequent reads from it will return its default value.
mutating func clearDisplay() {_uniqueStorage()._display = nil}
public mutating func clearDisplay() {_uniqueStorage()._display = nil}
///
/// The part of the config that is specific to the Lora Radio
var lora: Config.LoRaConfig {
public var lora: Config.LoRaConfig {
get {return _storage._lora ?? Config.LoRaConfig()}
set {_uniqueStorage()._lora = newValue}
}
/// Returns true if `lora` has been explicitly set.
var hasLora: Bool {return _storage._lora != nil}
public var hasLora: Bool {return _storage._lora != nil}
/// Clears the value of `lora`. Subsequent reads from it will return its default value.
mutating func clearLora() {_uniqueStorage()._lora = nil}
public mutating func clearLora() {_uniqueStorage()._lora = nil}
///
/// The part of the config that is specific to the Bluetooth settings
var bluetooth: Config.BluetoothConfig {
public var bluetooth: Config.BluetoothConfig {
get {return _storage._bluetooth ?? Config.BluetoothConfig()}
set {_uniqueStorage()._bluetooth = newValue}
}
/// Returns true if `bluetooth` has been explicitly set.
var hasBluetooth: Bool {return _storage._bluetooth != nil}
public var hasBluetooth: Bool {return _storage._bluetooth != nil}
/// Clears the value of `bluetooth`. Subsequent reads from it will return its default value.
mutating func clearBluetooth() {_uniqueStorage()._bluetooth = nil}
public mutating func clearBluetooth() {_uniqueStorage()._bluetooth = nil}
///
/// A version integer used to invalidate old save files when we make
/// incompatible changes This integer is set at build time and is private to
/// NodeDB.cpp in the device code.
var version: UInt32 {
public var version: UInt32 {
get {return _storage._version}
set {_uniqueStorage()._version = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _storage = _StorageClass.defaultInstance
}
struct LocalModuleConfig {
public struct LocalModuleConfig {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The part of the config that is specific to the MQTT module
var mqtt: ModuleConfig.MQTTConfig {
public var mqtt: ModuleConfig.MQTTConfig {
get {return _storage._mqtt ?? ModuleConfig.MQTTConfig()}
set {_uniqueStorage()._mqtt = newValue}
}
/// Returns true if `mqtt` has been explicitly set.
var hasMqtt: Bool {return _storage._mqtt != nil}
public var hasMqtt: Bool {return _storage._mqtt != nil}
/// Clears the value of `mqtt`. Subsequent reads from it will return its default value.
mutating func clearMqtt() {_uniqueStorage()._mqtt = nil}
public mutating func clearMqtt() {_uniqueStorage()._mqtt = nil}
///
/// The part of the config that is specific to the Serial module
var serial: ModuleConfig.SerialConfig {
public var serial: ModuleConfig.SerialConfig {
get {return _storage._serial ?? ModuleConfig.SerialConfig()}
set {_uniqueStorage()._serial = newValue}
}
/// Returns true if `serial` has been explicitly set.
var hasSerial: Bool {return _storage._serial != nil}
public var hasSerial: Bool {return _storage._serial != nil}
/// Clears the value of `serial`. Subsequent reads from it will return its default value.
mutating func clearSerial() {_uniqueStorage()._serial = nil}
public mutating func clearSerial() {_uniqueStorage()._serial = nil}
///
/// The part of the config that is specific to the ExternalNotification module
var externalNotification: ModuleConfig.ExternalNotificationConfig {
public var externalNotification: ModuleConfig.ExternalNotificationConfig {
get {return _storage._externalNotification ?? ModuleConfig.ExternalNotificationConfig()}
set {_uniqueStorage()._externalNotification = newValue}
}
/// Returns true if `externalNotification` has been explicitly set.
var hasExternalNotification: Bool {return _storage._externalNotification != nil}
public var hasExternalNotification: Bool {return _storage._externalNotification != nil}
/// Clears the value of `externalNotification`. Subsequent reads from it will return its default value.
mutating func clearExternalNotification() {_uniqueStorage()._externalNotification = nil}
public mutating func clearExternalNotification() {_uniqueStorage()._externalNotification = nil}
///
/// The part of the config that is specific to the Store & Forward module
var storeForward: ModuleConfig.StoreForwardConfig {
public var storeForward: ModuleConfig.StoreForwardConfig {
get {return _storage._storeForward ?? ModuleConfig.StoreForwardConfig()}
set {_uniqueStorage()._storeForward = newValue}
}
/// Returns true if `storeForward` has been explicitly set.
var hasStoreForward: Bool {return _storage._storeForward != nil}
public var hasStoreForward: Bool {return _storage._storeForward != nil}
/// Clears the value of `storeForward`. Subsequent reads from it will return its default value.
mutating func clearStoreForward() {_uniqueStorage()._storeForward = nil}
public mutating func clearStoreForward() {_uniqueStorage()._storeForward = nil}
///
/// The part of the config that is specific to the RangeTest module
var rangeTest: ModuleConfig.RangeTestConfig {
public var rangeTest: ModuleConfig.RangeTestConfig {
get {return _storage._rangeTest ?? ModuleConfig.RangeTestConfig()}
set {_uniqueStorage()._rangeTest = newValue}
}
/// Returns true if `rangeTest` has been explicitly set.
var hasRangeTest: Bool {return _storage._rangeTest != nil}
public var hasRangeTest: Bool {return _storage._rangeTest != nil}
/// Clears the value of `rangeTest`. Subsequent reads from it will return its default value.
mutating func clearRangeTest() {_uniqueStorage()._rangeTest = nil}
public mutating func clearRangeTest() {_uniqueStorage()._rangeTest = nil}
///
/// The part of the config that is specific to the Telemetry module
var telemetry: ModuleConfig.TelemetryConfig {
public var telemetry: ModuleConfig.TelemetryConfig {
get {return _storage._telemetry ?? ModuleConfig.TelemetryConfig()}
set {_uniqueStorage()._telemetry = newValue}
}
/// Returns true if `telemetry` has been explicitly set.
var hasTelemetry: Bool {return _storage._telemetry != nil}
public var hasTelemetry: Bool {return _storage._telemetry != nil}
/// Clears the value of `telemetry`. Subsequent reads from it will return its default value.
mutating func clearTelemetry() {_uniqueStorage()._telemetry = nil}
public mutating func clearTelemetry() {_uniqueStorage()._telemetry = nil}
///
/// The part of the config that is specific to the Canned Message module
var cannedMessage: ModuleConfig.CannedMessageConfig {
public var cannedMessage: ModuleConfig.CannedMessageConfig {
get {return _storage._cannedMessage ?? ModuleConfig.CannedMessageConfig()}
set {_uniqueStorage()._cannedMessage = newValue}
}
/// Returns true if `cannedMessage` has been explicitly set.
var hasCannedMessage: Bool {return _storage._cannedMessage != nil}
public var hasCannedMessage: Bool {return _storage._cannedMessage != nil}
/// Clears the value of `cannedMessage`. Subsequent reads from it will return its default value.
mutating func clearCannedMessage() {_uniqueStorage()._cannedMessage = nil}
public mutating func clearCannedMessage() {_uniqueStorage()._cannedMessage = nil}
///
/// The part of the config that is specific to the Audio module
var audio: ModuleConfig.AudioConfig {
public var audio: ModuleConfig.AudioConfig {
get {return _storage._audio ?? ModuleConfig.AudioConfig()}
set {_uniqueStorage()._audio = newValue}
}
/// Returns true if `audio` has been explicitly set.
var hasAudio: Bool {return _storage._audio != nil}
public var hasAudio: Bool {return _storage._audio != nil}
/// Clears the value of `audio`. Subsequent reads from it will return its default value.
mutating func clearAudio() {_uniqueStorage()._audio = nil}
public mutating func clearAudio() {_uniqueStorage()._audio = nil}
///
/// The part of the config that is specific to the Remote Hardware module
var remoteHardware: ModuleConfig.RemoteHardwareConfig {
public var remoteHardware: ModuleConfig.RemoteHardwareConfig {
get {return _storage._remoteHardware ?? ModuleConfig.RemoteHardwareConfig()}
set {_uniqueStorage()._remoteHardware = newValue}
}
/// Returns true if `remoteHardware` has been explicitly set.
var hasRemoteHardware: Bool {return _storage._remoteHardware != nil}
public var hasRemoteHardware: Bool {return _storage._remoteHardware != nil}
/// Clears the value of `remoteHardware`. Subsequent reads from it will return its default value.
mutating func clearRemoteHardware() {_uniqueStorage()._remoteHardware = nil}
public mutating func clearRemoteHardware() {_uniqueStorage()._remoteHardware = nil}
///
/// The part of the config that is specific to the Neighbor Info module
var neighborInfo: ModuleConfig.NeighborInfoConfig {
public var neighborInfo: ModuleConfig.NeighborInfoConfig {
get {return _storage._neighborInfo ?? ModuleConfig.NeighborInfoConfig()}
set {_uniqueStorage()._neighborInfo = newValue}
}
/// Returns true if `neighborInfo` has been explicitly set.
var hasNeighborInfo: Bool {return _storage._neighborInfo != nil}
public var hasNeighborInfo: Bool {return _storage._neighborInfo != nil}
/// Clears the value of `neighborInfo`. Subsequent reads from it will return its default value.
mutating func clearNeighborInfo() {_uniqueStorage()._neighborInfo = nil}
public mutating func clearNeighborInfo() {_uniqueStorage()._neighborInfo = nil}
///
/// The part of the config that is specific to the Ambient Lighting module
var ambientLighting: ModuleConfig.AmbientLightingConfig {
public var ambientLighting: ModuleConfig.AmbientLightingConfig {
get {return _storage._ambientLighting ?? ModuleConfig.AmbientLightingConfig()}
set {_uniqueStorage()._ambientLighting = newValue}
}
/// Returns true if `ambientLighting` has been explicitly set.
var hasAmbientLighting: Bool {return _storage._ambientLighting != nil}
public var hasAmbientLighting: Bool {return _storage._ambientLighting != nil}
/// Clears the value of `ambientLighting`. Subsequent reads from it will return its default value.
mutating func clearAmbientLighting() {_uniqueStorage()._ambientLighting = nil}
public mutating func clearAmbientLighting() {_uniqueStorage()._ambientLighting = nil}
///
/// The part of the config that is specific to the Detection Sensor module
var detectionSensor: ModuleConfig.DetectionSensorConfig {
public var detectionSensor: ModuleConfig.DetectionSensorConfig {
get {return _storage._detectionSensor ?? ModuleConfig.DetectionSensorConfig()}
set {_uniqueStorage()._detectionSensor = newValue}
}
/// Returns true if `detectionSensor` has been explicitly set.
var hasDetectionSensor: Bool {return _storage._detectionSensor != nil}
public var hasDetectionSensor: Bool {return _storage._detectionSensor != nil}
/// Clears the value of `detectionSensor`. Subsequent reads from it will return its default value.
mutating func clearDetectionSensor() {_uniqueStorage()._detectionSensor = nil}
public mutating func clearDetectionSensor() {_uniqueStorage()._detectionSensor = nil}
///
/// Paxcounter Config
var paxcounter: ModuleConfig.PaxcounterConfig {
public var paxcounter: ModuleConfig.PaxcounterConfig {
get {return _storage._paxcounter ?? ModuleConfig.PaxcounterConfig()}
set {_uniqueStorage()._paxcounter = newValue}
}
/// Returns true if `paxcounter` has been explicitly set.
var hasPaxcounter: Bool {return _storage._paxcounter != nil}
public var hasPaxcounter: Bool {return _storage._paxcounter != nil}
/// Clears the value of `paxcounter`. Subsequent reads from it will return its default value.
mutating func clearPaxcounter() {_uniqueStorage()._paxcounter = nil}
public mutating func clearPaxcounter() {_uniqueStorage()._paxcounter = nil}
///
/// A version integer used to invalidate old save files when we make
/// incompatible changes This integer is set at build time and is private to
/// NodeDB.cpp in the device code.
var version: UInt32 {
public var version: UInt32 {
get {return _storage._version}
set {_uniqueStorage()._version = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _storage = _StorageClass.defaultInstance
}
@ -292,8 +292,8 @@ extension LocalModuleConfig: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".LocalConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".LocalConfig"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "device"),
2: .same(proto: "position"),
3: .same(proto: "power"),
@ -345,7 +345,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
@ -367,7 +367,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
@ -401,7 +401,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: LocalConfig, rhs: LocalConfig) -> Bool {
public static func ==(lhs: LocalConfig, rhs: LocalConfig) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
@ -424,8 +424,8 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
}
extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".LocalModuleConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".LocalModuleConfig"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "mqtt"),
2: .same(proto: "serial"),
3: .standard(proto: "external_notification"),
@ -495,7 +495,7 @@ extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
return _storage
}
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
_ = _uniqueStorage()
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
while let fieldNumber = try decoder.nextFieldNumber() {
@ -523,7 +523,7 @@ extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
@ -575,7 +575,7 @@ extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: LocalModuleConfig, rhs: LocalModuleConfig) -> Bool {
public static func ==(lhs: LocalModuleConfig, rhs: LocalModuleConfig) -> Bool {
if lhs._storage !== rhs._storage {
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0

View file

@ -22,103 +22,103 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
///
/// This message wraps a MeshPacket with extra metadata about the sender and how it arrived.
struct ServiceEnvelope {
public struct ServiceEnvelope {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// The (probably encrypted) packet
var packet: MeshPacket {
public var packet: MeshPacket {
get {return _packet ?? MeshPacket()}
set {_packet = newValue}
}
/// Returns true if `packet` has been explicitly set.
var hasPacket: Bool {return self._packet != nil}
public var hasPacket: Bool {return self._packet != nil}
/// Clears the value of `packet`. Subsequent reads from it will return its default value.
mutating func clearPacket() {self._packet = nil}
public mutating func clearPacket() {self._packet = nil}
///
/// The global channel ID it was sent on
var channelID: String = String()
public var channelID: String = String()
///
/// The sending gateway node ID. Can we use this to authenticate/prevent fake
/// nodeid impersonation for senders? - i.e. use gateway/mesh id (which is authenticated) + local node id as
/// the globally trusted nodenum
var gatewayID: String = String()
public var gatewayID: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
fileprivate var _packet: MeshPacket? = nil
}
///
/// Information about a node intended to be reported unencrypted to a map using MQTT.
struct MapReport {
public struct MapReport {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// A full name for this user, i.e. "Kevin Hester"
var longName: String = String()
public var longName: String = String()
///
/// A VERY short name, ideally two characters.
/// Suitable for a tiny OLED screen
var shortName: String = String()
public var shortName: String = String()
///
/// Role of the node that applies specific settings for a particular use-case
var role: Config.DeviceConfig.Role = .client
public var role: Config.DeviceConfig.Role = .client
///
/// Hardware model of the node, i.e. T-Beam, Heltec V3, etc...
var hwModel: HardwareModel = .unset
public var hwModel: HardwareModel = .unset
///
/// Device firmware version string
var firmwareVersion: String = String()
public var firmwareVersion: String = String()
///
/// The region code for the radio (US, CN, EU433, etc...)
var region: Config.LoRaConfig.RegionCode = .unset
public var region: Config.LoRaConfig.RegionCode = .unset
///
/// Modem preset used by the radio (LongFast, MediumSlow, etc...)
var modemPreset: Config.LoRaConfig.ModemPreset = .longFast
public var modemPreset: Config.LoRaConfig.ModemPreset = .longFast
///
/// Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...)
/// and it uses the default frequency slot given the region and modem preset.
var hasDefaultChannel_p: Bool = false
public var hasDefaultChannel_p: Bool = false
///
/// Latitude: multiply by 1e-7 to get degrees in floating point
var latitudeI: Int32 = 0
public var latitudeI: Int32 = 0
///
/// Longitude: multiply by 1e-7 to get degrees in floating point
var longitudeI: Int32 = 0
public var longitudeI: Int32 = 0
///
/// Altitude in meters above MSL
var altitude: Int32 = 0
public var altitude: Int32 = 0
///
/// Indicates the bits of precision for latitude and longitude set by the sending node
var positionPrecision: UInt32 = 0
public var positionPrecision: UInt32 = 0
///
/// Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT)
var numOnlineLocalNodes: UInt32 = 0
public var numOnlineLocalNodes: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
public var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
public init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -131,14 +131,14 @@ extension MapReport: @unchecked Sendable {}
fileprivate let _protobuf_package = "meshtastic"
extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".ServiceEnvelope"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".ServiceEnvelope"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "packet"),
2: .standard(proto: "channel_id"),
3: .standard(proto: "gateway_id"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -152,7 +152,7 @@ extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
@ -169,7 +169,7 @@ extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: ServiceEnvelope, rhs: ServiceEnvelope) -> Bool {
public static func ==(lhs: ServiceEnvelope, rhs: ServiceEnvelope) -> Bool {
if lhs._packet != rhs._packet {return false}
if lhs.channelID != rhs.channelID {return false}
if lhs.gatewayID != rhs.gatewayID {return false}
@ -179,8 +179,8 @@ extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
extension MapReport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".MapReport"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
public static let protoMessageName: String = _protobuf_package + ".MapReport"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "long_name"),
2: .standard(proto: "short_name"),
3: .same(proto: "role"),
@ -196,7 +196,7 @@ extension MapReport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
13: .standard(proto: "num_online_local_nodes"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
@ -220,7 +220,7 @@ extension MapReport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.longName.isEmpty {
try visitor.visitSingularStringField(value: self.longName, fieldNumber: 1)
}
@ -263,7 +263,7 @@ extension MapReport: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: MapReport, rhs: MapReport) -> Bool {
public static func ==(lhs: MapReport, rhs: MapReport) -> Bool {
if lhs.longName != rhs.longName {return false}
if lhs.shortName != rhs.shortName {return false}
if lhs.role != rhs.role {return false}

Some files were not shown because too many files have changed in this diff Show more