Merge pull request #66 from meshtastic/feature/protobufs_upgrade_1.3

Feature/protobufs upgrade 1.3
This commit is contained in:
Garth Vander Houwen 2022-05-25 22:58:34 -07:00 committed by GitHub
commit 05c5efa170
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 6737 additions and 2835 deletions

View file

@ -21,10 +21,13 @@
DD47E3D626F17ED900029299 /* CircleText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D526F17ED900029299 /* CircleText.swift */; };
DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD47E3D826F3093800029299 /* MessageBubble.swift */; };
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4A911D2708C65400501B7E /* AppSettings.swift */; };
DD4C158C2824A91E0032668E /* module_config.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4C158B2824A91E0032668E /* module_config.pb.swift */; };
DD4C158E2824AA7E0032668E /* config.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4C158D2824AA7E0032668E /* config.pb.swift */; };
DD4DED9027AD2975004BA27E /* cannedmessages.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4DED8F27AD2975004BA27E /* cannedmessages.pb.swift */; };
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; };
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
DD539502276DAA6A00AD86B1 /* MapLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD539501276DAA6A00AD86B1 /* MapLocation.swift */; };
DD6B85A828009258000ACD6B /* ShareChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B85A728009258000ACD6B /* ShareChannel.swift */; };
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */; };
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */; };
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FE272476C700F4AB02 /* LogDocument.swift */; };
@ -43,8 +46,8 @@
DDAF8C6526ED0A490058C060 /* channel.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6426ED0A490058C060 /* channel.pb.swift */; };
DDAF8C6726ED0C8C0058C060 /* remote_hardware.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6626ED0C8C0058C060 /* remote_hardware.pb.swift */; };
DDAF8C6926ED0D070058C060 /* deviceonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6826ED0D070058C060 /* deviceonly.pb.swift */; };
DDAF8C6B26ED0DD80058C060 /* environmental_measurement.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6A26ED0DD80058C060 /* environmental_measurement.pb.swift */; };
DDAF8C6E26ED19040058C060 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6D26ED19040058C060 /* Extensions.swift */; };
DDB2CC6E27F3EB47009C5FCC /* telemetry.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */; };
DDC2E15826CE248E0042C5E4 /* MeshtasticClientApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E15726CE248E0042C5E4 /* MeshtasticClientApp.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 */; };
@ -52,7 +55,9 @@
DDC2E17A26CE248F0042C5E4 /* MeshtasticClientUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E17926CE248F0042C5E4 /* MeshtasticClientUITests.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 */; };
DDC4D568275499A500A4208E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC4D567275499A500A4208E /* Persistence.swift */; };
DDCA31322826009C00207175 /* PassKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDCA31312826009C00207175 /* PassKit.framework */; };
DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF924C926FBB953009FE055 /* ConnectedDevice.swift */; };
/* End PBXBuildFile section */
@ -88,9 +93,12 @@
DD47E3D526F17ED900029299 /* CircleText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleText.swift; sourceTree = "<group>"; };
DD47E3D826F3093800029299 /* MessageBubble.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageBubble.swift; sourceTree = "<group>"; };
DD4A911D2708C65400501B7E /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
DD4C158B2824A91E0032668E /* module_config.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = module_config.pb.swift; sourceTree = "<group>"; };
DD4C158D2824AA7E0032668E /* config.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = config.pb.swift; sourceTree = "<group>"; };
DD4DED8F27AD2975004BA27E /* cannedmessages.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = cannedmessages.pb.swift; sourceTree = "<group>"; };
DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = "<group>"; };
DD539501276DAA6A00AD86B1 /* MapLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLocation.swift; sourceTree = "<group>"; };
DD6B85A728009258000ACD6B /* ShareChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannel.swift; sourceTree = "<group>"; };
DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = "<group>"; };
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = "<group>"; };
DD8169FE272476C700F4AB02 /* LogDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogDocument.swift; sourceTree = "<group>"; };
@ -110,8 +118,9 @@
DDAF8C6426ED0A490058C060 /* channel.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = channel.pb.swift; sourceTree = "<group>"; };
DDAF8C6626ED0C8C0058C060 /* remote_hardware.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = remote_hardware.pb.swift; sourceTree = "<group>"; };
DDAF8C6826ED0D070058C060 /* deviceonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = deviceonly.pb.swift; sourceTree = "<group>"; };
DDAF8C6A26ED0DD80058C060 /* environmental_measurement.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = environmental_measurement.pb.swift; sourceTree = "<group>"; };
DDAF8C6D26ED19040058C060 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = telemetry.pb.swift; sourceTree = "<group>"; };
DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 3.xcdatamodel"; sourceTree = "<group>"; };
DDC2E15426CE248E0042C5E4 /* MeshtasticClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeshtasticClient.app; sourceTree = BUILT_PRODUCTS_DIR; };
DDC2E15726CE248E0042C5E4 /* MeshtasticClientApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticClientApp.swift; sourceTree = "<group>"; };
DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../Assets.xcassets; sourceTree = "<group>"; };
@ -125,7 +134,9 @@
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>"; };
DDC4D567275499A500A4208E /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
DDCA31312826009C00207175 /* PassKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PassKit.framework; path = System/Library/Frameworks/PassKit.framework; sourceTree = SDKROOT; };
DDF924C926FBB953009FE055 /* ConnectedDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectedDevice.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -134,6 +145,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
DDCA31322826009C00207175 /* PassKit.framework in Frameworks */,
C9697FA527933B8C00250207 /* SQLite in Frameworks */,
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */,
);
@ -199,6 +211,7 @@
DD4A911D2708C65400501B7E /* AppSettings.swift */,
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */,
DD8169FE272476C700F4AB02 /* LogDocument.swift */,
DD6B85A728009258000ACD6B /* ShareChannel.swift */,
);
path = Settings;
sourceTree = "<group>";
@ -206,6 +219,7 @@
DD8EDE9226F97A2B00A5A10B /* Frameworks */ = {
isa = PBXGroup;
children = (
DDCA31312826009C00207175 /* PassKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -217,14 +231,16 @@
DDAF8C6126ED0A230058C060 /* admin.pb.swift */,
C9A88B56278B559900BD810A /* apponly.pb.swift */,
DDAF8C6426ED0A490058C060 /* channel.pb.swift */,
DD4C158D2824AA7E0032668E /* config.pb.swift */,
DDAF8C6826ED0D070058C060 /* deviceonly.pb.swift */,
DDAF8C6A26ED0DD80058C060 /* environmental_measurement.pb.swift */,
DDAF8C5726ED07FD0058C060 /* mesh.pb.swift */,
DD4C158B2824A91E0032668E /* module_config.pb.swift */,
DDAF8C6026ED0A230058C060 /* mqtt.pb.swift */,
DDAF8C5C26ED09490058C060 /* portnums.pb.swift */,
DDAF8C5E26ED09B50058C060 /* radioconfig.pb.swift */,
DDAF8C6626ED0C8C0058C060 /* remote_hardware.pb.swift */,
DD17E5DC277D49D400010EC2 /* storeforward.pb.swift */,
DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */,
);
path = Protobufs;
sourceTree = "<group>";
@ -342,6 +358,7 @@
DD47E3D826F3093800029299 /* MessageBubble.swift */,
DD90860B26F684AF00DC5189 /* BatteryIcon.swift */,
DDF924C926FBB953009FE055 /* ConnectedDevice.swift */,
DDC3B273283F411B00AC321C /* LastHeardText.swift */,
);
path = Helpers;
sourceTree = "<group>";
@ -533,12 +550,13 @@
DDAF8C5F26ED09B50058C060 /* radioconfig.pb.swift in Sources */,
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */,
DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */,
DD4C158C2824A91E0032668E /* module_config.pb.swift in Sources */,
DD6B85A828009258000ACD6B /* ShareChannel.swift in Sources */,
DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */,
DDC4D568275499A500A4208E /* Persistence.swift in Sources */,
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */,
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */,
DDAF8C6926ED0D070058C060 /* deviceonly.pb.swift in Sources */,
DDAF8C6B26ED0DD80058C060 /* environmental_measurement.pb.swift in Sources */,
DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */,
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */,
DDAF8C6226ED0A230058C060 /* mqtt.pb.swift in Sources */,
@ -546,6 +564,7 @@
DDAF8C5D26ED09490058C060 /* portnums.pb.swift in Sources */,
DD9D8F2F2764403B00080993 /* Meshtastic.xcdatamodeld in Sources */,
DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */,
DDB2CC6E27F3EB47009C5FCC /* telemetry.pb.swift in Sources */,
DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */,
C9A7BC1027759A9600760B50 /* PositionAnnotationView.swift in Sources */,
DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */,
@ -558,8 +577,10 @@
C9483F6D2773017500998F6B /* MapView.swift in Sources */,
DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */,
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */,
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
C9A88B57278B559900BD810A /* apponly.pb.swift in Sources */,
DD4C158E2824AA7E0032668E /* config.pb.swift in Sources */,
DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */,
C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */,
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */,
@ -730,17 +751,18 @@
CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 6;
DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\"";
DEVELOPMENT_TEAM = GCH7VS5Y9R;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = MeshtasticClient/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.53;
MARKETING_VERSION = 1.3.1;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -761,17 +783,18 @@
CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 6;
DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\"";
DEVELOPMENT_TEAM = GCH7VS5Y9R;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = MeshtasticClient/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.2;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.2.53;
MARKETING_VERSION = 1.3.1;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
@ -786,6 +809,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = GCH7VS5Y9R;
INFOPLIST_FILE = MeshtasticClientTests/Info.plist;
@ -808,6 +832,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = GCH7VS5Y9R;
INFOPLIST_FILE = MeshtasticClientTests/Info.plist;
@ -920,7 +945,7 @@
repositoryURL = "https://github.com/apple/swift-protobuf.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.0.0;
minimumVersion = 1.19.0;
};
};
/* End XCRemoteSwiftPackageReference section */
@ -942,10 +967,11 @@
DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */,
DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */,
DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */,
);
currentVersion = DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */;
currentVersion = DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */;
name = Meshtastic.xcdatamodeld;
path = MeshtasticClient/Meshtastic.xcdatamodeld;
sourceTree = "<group>";

View file

@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/apple/swift-protobuf.git",
"state": {
"branch": null,
"revision": "7e2c5f3cbbeea68e004915e3a8961e20bd11d824",
"version": "1.18.0"
"revision": "e1499bc69b9040b29184f7f2996f7bab467c1639",
"version": "1.19.0"
}
}
]

View file

@ -176,7 +176,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
peripheralName = name
}
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: String(peripheralName.suffix(3)), longName: peripheralName, firmwareVersion: "Unknown", rssi: RSSI.intValue, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral)
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: String(peripheralName.suffix(3)), longName: peripheralName, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral)
let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id })
if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected {
@ -318,7 +318,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if meshLoggingEnabled { MeshLogger.log("✅ BLE did discover TORADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") }
TORADIO_characteristic = characteristic
var toRadio: ToRadio = ToRadio()
toRadio.wantConfigID = 32168
toRadio.wantConfigID = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
let binaryData: Data = try! toRadio.serializedData()
peripheral.writeValue(binaryData, for: characteristic, type: .withResponse)
@ -384,6 +384,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
switch characteristic.uuid {
case FROMRADIO_UUID:
if characteristic.value == nil || characteristic.value!.isEmpty {
return
}
@ -405,8 +406,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let myInfo = MyInfoEntity(context: context!)
myInfo.myNodeNum = Int64(decodedInfo.myInfo.myNodeNum)
myInfo.hasGps = decodedInfo.myInfo.hasGps_p
myInfo.channelUtilization = decodedInfo.myInfo.channelUtilization
myInfo.bitrate = decodedInfo.myInfo.bitrate
self.connectedPeripheral.bitrate = myInfo.bitrate
// Swift does strings weird, this does work to get the version without the github hash
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")
var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))]
@ -420,8 +422,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
self.connectedPeripheral.num = myInfo.myNodeNum
self.connectedPeripheral.firmwareVersion = myInfo.firmwareVersion ?? "Unknown"
self.connectedPeripheral.name = myInfo.bleName ?? "Unknown"
self.connectedPeripheral.channelUtilization = myInfo.channelUtilization
self.connectedPeripheral.airTime = myInfo.airUtilTx
let fetchBCUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
fetchBCUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.myInfo.myNodeNum))
@ -440,6 +440,18 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("💾 Saved the All - Broadcast User")
}
//var settingsCalled = self.getSettings()
if false {
print("💾 Called Get Settings")
} else {
print("💥 Get Settings Call Failed")
}
} catch {
print("💥 Error Saving the All - Broadcast User")
@ -449,7 +461,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
fetchedMyInfo[0].myNodeNum = Int64(decodedInfo.myInfo.myNodeNum)
fetchedMyInfo[0].hasGps = decodedInfo.myInfo.hasGps_p
fetchedMyInfo[0].channelUtilization = decodedInfo.myInfo.channelUtilization
fetchedMyInfo[0].bitrate = decodedInfo.myInfo.bitrate
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")//.lastIndex(of: ".", offsetBy: -1)
var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset:6, in: decodedInfo.myInfo.firmwareVersion))]
version = version.dropLast()
@ -461,8 +474,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
self.connectedPeripheral.num = fetchedMyInfo[0].myNodeNum
self.connectedPeripheral.firmwareVersion = fetchedMyInfo[0].firmwareVersion ?? "Unknown"
self.connectedPeripheral.name = fetchedMyInfo[0].bleName ?? "Unknown"
self.connectedPeripheral.channelUtilization = fetchedMyInfo[0].channelUtilization
self.connectedPeripheral.airTime = fetchedMyInfo[0].airUtilTx
self.connectedPeripheral.bitrate = fetchedMyInfo[0].bitrate
}
do {
@ -476,7 +488,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
context!.rollback()
let nsError = error as NSError
print("💥 Error Saving CoreData MyInfoEntity: \(nsError)")
print("💥 Error Saving Core Data MyInfoEntity: \(nsError)")
}
} catch {
@ -513,12 +525,24 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let newNode = NodeInfoEntity(context: context!)
newNode.id = Int64(decodedInfo.nodeInfo.num)
newNode.num = Int64(decodedInfo.nodeInfo.num)
if decodedInfo.nodeInfo.lastHeard > 0 {
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
}
else {
newNode.lastHeard = Date()
if decodedInfo.nodeInfo.hasDeviceMetrics {
let telemetry = TelemetryEntity(context: context!)
telemetry.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel)
telemetry.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage
telemetry.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
self.connectedPeripheral.channelUtilization = telemetry.channelUtilization
telemetry.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
var newTelemetries = [TelemetryEntity]()
newTelemetries.append(telemetry)
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
}
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
newNode.snr = decodedInfo.nodeInfo.snr
if self.connectedPeripheral != nil && self.connectedPeripheral.num == newNode.num {
@ -528,7 +552,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
connectedPeripheral.name = decodedInfo.nodeInfo.user.longName
}
}
if decodedInfo.nodeInfo.hasUser {
let newUser = UserEntity(context: context!)
@ -538,7 +562,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
newUser.shortName = decodedInfo.nodeInfo.user.shortName
newUser.macaddr = decodedInfo.nodeInfo.user.macaddr
newUser.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
newUser.team = (String(describing: decodedInfo.nodeInfo.user.team))
newNode.user = newUser
}
@ -546,15 +569,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
position.latitudeI = decodedInfo.nodeInfo.position.latitudeI
position.longitudeI = decodedInfo.nodeInfo.position.longitudeI
position.altitude = decodedInfo.nodeInfo.position.altitude
position.batteryLevel = decodedInfo.nodeInfo.position.batteryLevel
if decodedInfo.nodeInfo.position.time > 0 {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.position.time)))
}
else {
position.time = Date()
}
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.position.time)))
var newPostions = [PositionEntity]()
newPostions.append(position)
@ -580,15 +595,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
fetchedNode[0].id = Int64(decodedInfo.nodeInfo.num)
fetchedNode[0].num = Int64(decodedInfo.nodeInfo.num)
if decodedInfo.nodeInfo.lastHeard == 0 {
fetchedNode[0].lastHeard = Date()
} else {
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
}
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.lastHeard)))
fetchedNode[0].snr = decodedInfo.nodeInfo.snr
if self.connectedPeripheral != nil && self.connectedPeripheral.num == fetchedNode[0].num {
@ -607,25 +614,36 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
fetchedNode[0].user!.shortName = decodedInfo.nodeInfo.user.shortName
fetchedNode[0].user!.macaddr = decodedInfo.nodeInfo.user.macaddr
fetchedNode[0].user!.hwModel = String(describing: decodedInfo.nodeInfo.user.hwModel).uppercased()
fetchedNode[0].user!.team = (String(describing: decodedInfo.nodeInfo.user.team))
}
let position = PositionEntity(context: context!)
position.latitudeI = decodedInfo.nodeInfo.position.latitudeI
position.longitudeI = decodedInfo.nodeInfo.position.longitudeI
position.altitude = decodedInfo.nodeInfo.position.altitude
position.batteryLevel = decodedInfo.nodeInfo.position.batteryLevel
if decodedInfo.nodeInfo.position.time > 0 {
if decodedInfo.nodeInfo.hasDeviceMetrics {
let newTelemetry = TelemetryEntity(context: context!)
newTelemetry.batteryLevel = Int32(decodedInfo.nodeInfo.deviceMetrics.batteryLevel)
newTelemetry.voltage = decodedInfo.nodeInfo.deviceMetrics.voltage
newTelemetry.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
self.connectedPeripheral.channelUtilization = newTelemetry.channelUtilization
newTelemetry.airUtilTx = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as! NSMutableOrderedSet
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
}
if decodedInfo.nodeInfo.hasPosition {
let position = PositionEntity(context: context!)
position.latitudeI = decodedInfo.nodeInfo.position.latitudeI
position.longitudeI = decodedInfo.nodeInfo.position.longitudeI
position.altitude = decodedInfo.nodeInfo.position.altitude
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.nodeInfo.position.time)))
}
else {
position.time = Date()
}
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
}
// Look for a MyInfo
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
@ -653,7 +671,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
context!.rollback()
let nsError = error as NSError
print("💥 Error Saving CoreData NodeInfoEntity: \(nsError)")
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
}
} catch {
@ -694,19 +712,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let newMessage = MessageEntity(context: context!)
newMessage.messageId = Int64(decodedInfo.packet.id)
if decodedInfo.packet.rxTime == 0 {
newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970)
} else {
newMessage.messageTimestamp = Int32(bitPattern: decodedInfo.packet.rxTime)
}
newMessage.messageTimestamp = Int32(bitPattern: decodedInfo.packet.rxTime)
newMessage.receivedACK = false
newMessage.direction = "IN"
newMessage.isTapback = decodedInfo.packet.decoded.isTapback
newMessage.isEmoji = decodedInfo.packet.decoded.emoji == 1
if decodedInfo.packet.decoded.replyID > 0 {
@ -780,14 +789,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if fetchedNode.count == 1 {
fetchedNode[0].id = Int64(decodedInfo.packet.from)
fetchedNode[0].num = Int64(decodedInfo.packet.from)
if decodedInfo.packet.rxTime > 0 {
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
}
else {
fetchedNode[0].lastHeard = Date()
}
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
fetchedNode[0].snr = decodedInfo.packet.rxSnr
} else {
@ -815,7 +817,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// MARK: Incoming Packet from the POSITION_APP
} else if decodedInfo.packet.decoded.portnum == PortNum.positionApp {
let fetchNodePositionRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.packet.from))
@ -826,15 +827,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if fetchedNode.count == 1 {
fetchedNode[0].id = Int64(decodedInfo.packet.from)
fetchedNode[0].num = Int64(decodedInfo.packet.from)
if decodedInfo.packet.rxTime == 0 {
fetchedNode[0].lastHeard = Date()
} else {
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
}
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
fetchedNode[0].snr = decodedInfo.packet.rxSnr
if let positionMessage = try? Position(serializedData: decodedInfo.packet.decoded.payload) {
@ -843,16 +836,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
position.latitudeI = positionMessage.latitudeI
position.longitudeI = positionMessage.longitudeI
position.altitude = positionMessage.altitude
position.batteryLevel = positionMessage.batteryLevel
if positionMessage.time == 0 {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
position.time = Date()
} else {
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time)))
}
let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet
mutablePositions.add(position)
@ -940,15 +925,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if fetchedMessage != nil {
fetchedMessage!.receivedACK = true
fetchedMessage!.ackSNR = decodedInfo.packet.rxSnr
if decodedInfo.packet.rxTime <= 0 {
fetchedMessage!.ackTimestamp = Int32(Date().timeIntervalSince1970)
} else {
fetchedMessage!.ackTimestamp = Int32(decodedInfo.packet.rxTime)
}
fetchedMessage!.ackTimestamp = Int32(decodedInfo.packet.rxTime)
fetchedMessage!.objectWillChange.send()
}
@ -969,10 +948,20 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
}
} else if decodedInfo.packet.decoded.portnum == PortNum.environmentalMeasurementApp {
// MARK: Incoming TELEMETRY_APP Packet
} else if decodedInfo.packet.decoded.portnum == PortNum.telemetryApp {
if meshLoggingEnabled { MeshLogger.log(" MESH PACKET received for Environmental Measurement App UNHANDLED \(try decodedInfo.packet.jsonString())") }
print(" MESH PACKET received for Environmental Measurement App UNHANDLED \(try decodedInfo.packet.jsonString())")
if let telemetryMessage = try? Telemetry(serializedData: decodedInfo.packet.decoded.payload) {
let telemetry = TelemetryEntity(context: context!)
print(decodedInfo.packet.decoded.requestID)
print(telemetryMessage)
}
if meshLoggingEnabled { MeshLogger.log(" MESH PACKET received for Telemetry App UNHANDLED \(try decodedInfo.packet.jsonString())") }
print(" MESH PACKET received for Telemetry App UNHANDLED \(try decodedInfo.packet.jsonString())")
} else if decodedInfo.packet.decoded.portnum == PortNum.storeForwardApp {
@ -1004,15 +993,24 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected })
}
case FROMNUM_UUID :
print("🚨 FROMNUM Characteristic UUID: \(characteristic.uuid)")
if characteristic.value == nil || characteristic.value!.isEmpty {
return
}
var decodedInfo = FromRadio()
//decodedInfo = try! FromRadio(serializedData: characteristic.value!)
default:
// Likely FROMNUM_UUID
print("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)")
}
peripheral.readValue(for: FROMRADIO_characteristic)
}
// Send Message
public func sendMessage(message: String, toUserNum: Int64, isTapback: Bool, replyID: Int64) -> Bool {
public func sendMessage(message: String, toUserNum: Int64, isEmoji: Bool, replyID: Int64) -> Bool {
var success = false
@ -1063,7 +1061,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
newMessage.receivedACK = false
newMessage.direction = "IN"
newMessage.toUser = fetchedUsers.first(where: { $0.num == toUserNum })
newMessage.isTapback = isTapback
newMessage.isEmoji = isEmoji
if replyID > 0 {
@ -1095,7 +1093,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
meshPacket.to = UInt32(toUserNum)
meshPacket.from = UInt32(fromUserNum)
meshPacket.decoded = dataMessage
meshPacket.decoded.isTapback = isTapback
meshPacket.decoded.emoji = isEmoji ? 1 : 0
if replyID > 0 {
meshPacket.decoded.replyID = UInt32(replyID)
}
@ -1124,8 +1122,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
context!.rollback()
let nsError = error as NSError
print("🚫 Unresolved Core Data error in Send Message Function \(nsError)")
if meshLoggingEnabled { MeshLogger.log("🚫 Unresolved Core Data error \(nsError)") }
print("💥 Unresolved Core Data error in Send Message Function it is likely that your database is corrupted deleting and re-installing the app should clear the corrupted data. Error: \(nsError)")
if meshLoggingEnabled { MeshLogger.log("💥 Unresolved Core Data error \(nsError)") }
}
}
}
@ -1137,6 +1135,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
return success
}
// Send Position
public func sendPosition(destNum: Int64, wantResponse: Bool) -> Bool {
var success = false
@ -1154,16 +1153,15 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
do {
let fetchedNode = try context?.fetch(fetchNode) as! [NodeInfoEntity]
if fetchedNode.count == 1 {
var positionPacket = Position()
positionPacket.latitudeI = Int32(LocationHelper.currentLocation.latitude * 1e7)
positionPacket.longitudeI = Int32(LocationHelper.currentLocation.longitude * 1e7)
positionPacket.time = UInt32(Date().timeIntervalSince1970)
positionPacket.time = UInt32(LocationHelper.currentTimestamp.timeIntervalSince1970)
positionPacket.altitude = Int32(LocationHelper.currentAltitude)
let mostRecentPosition = fetchedNode[0].positions?.lastObject as! PositionEntity
positionPacket.batteryLevel = mostRecentPosition.batteryLevel
var meshPacket = MeshPacket()
meshPacket.to = UInt32(destNum)
@ -1185,10 +1183,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("📍 Sent a Position Packet from the phone to the device for node: \(fromNodeNum)")
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
success = true
}
}
@ -1216,4 +1213,40 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
}
}
// MARK: Device Settings
public func getSettings() -> Bool {
var adminPacket = AdminMessage()
//adminPacket.getRadioRequest = true
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(connectedPeripheral.num)
meshPacket.from = UInt32(connectedPeripheral.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.wantAck = true
meshPacket.hopLimit = 0
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
meshPacket.decoded = dataMessage
var toRadio: ToRadio!
toRadio = ToRadio()
toRadio.packet = meshPacket
let binaryData: Data = try! toRadio.serializedData()
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
return true
}
return false
}
}

View file

@ -24,6 +24,16 @@ class LocationHelper: NSObject, ObservableObject {
}
return altitude
}
static var currentTimestamp: Date {
guard let timestamp = shared.locationManager.location?.timestamp else {
return Date.now
}
return timestamp
}
private let locationManager = CLLocationManager()

View file

@ -45,6 +45,8 @@
<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>
<key>NSCameraUsageDescription</key>
<string>We use the camera to share channels using a QR Code</string>
<key>NSLocationUsageDescription</key>
<string>We use your location to display it on the mesh map as well as to have GPS coordinatess to send to the connected device.</string>
<key>NSLocationWhenInUseUsageDescription</key>

View file

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MeshtasticDataModel v2.xcdatamodel</string>
<string>MeshtasticDataModel v 3.xcdatamodel</string>
</dict>
</plist>

View file

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="19574" systemVersion="21E258" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="MessageEntity" representedClassName="MessageEntity" syncable="YES" codeGenerationType="class">
<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="direction" attributeType="String"/>
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="messagePayload" attributeType="String"/>
<attribute name="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="fromUser" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
<relationship name="toUser" 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="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="bitrate" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="errorCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="firmwareVersion" attributeType="String"/>
<attribute name="hasGps" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="maxChannels" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="messageTimeoutMsec" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="myNodeNum"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="lastHeard" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
<relationship name="positions" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PositionEntity" inverseName="nodePosition" inverseEntity="PositionEntity"/>
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
<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="PositionEntity" representedClassName="PositionEntity" 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="satsInView" 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="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="relativeHumidity" 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="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="UserEntity" representedClassName="UserEntity" syncable="YES" codeGenerationType="class">
<attribute name="hwModel" attributeType="String"/>
<attribute name="longName" attributeType="String"/>
<attribute name="macaddr" optional="YES" attributeType="Binary"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="shortName" attributeType="String"/>
<attribute name="team" optional="YES" 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="allMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND isEmoji == false"/>
</fetchedProperty>
</entity>
<elements>
<element name="MessageEntity" positionX="-36" positionY="63" width="128" height="215"/>
<element name="MyInfoEntity" positionX="-18" positionY="81" width="128" height="209"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="164"/>
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="194"/>
<element name="UserEntity" positionX="0" positionY="144" width="128" height="200"/>
</elements>
</model>

View file

@ -9,13 +9,14 @@ struct Peripheral: Identifiable {
var longName: String
var firmwareVersion: String
var rssi: Int
var bitrate: Float?
var channelUtilization: Float?
var airTime: Float?
var lastUpdate: Date
var subscribed: Bool
var peripheral: CBPeripheral
init(id: String, num: Int64, name: String, shortName: String, longName: String, firmwareVersion: String, rssi: Int, channelUtilization: Float?, airTime: Float?, lastUpdate: Date, subscribed: Bool, peripheral: CBPeripheral) {
init(id: String, num: Int64, name: String, shortName: String, longName: String, firmwareVersion: String, rssi: Int, bitrate: Float?, channelUtilization: Float?, airTime: Float?, lastUpdate: Date, subscribed: Bool, peripheral: CBPeripheral) {
self.id = id
self.num = num
self.name = name
@ -23,6 +24,7 @@ struct Peripheral: Identifiable {
self.longName = longName
self.firmwareVersion = firmwareVersion
self.rssi = rssi
self.bitrate = bitrate
self.channelUtilization = channelUtilization
self.airTime = airTime
self.lastUpdate = lastUpdate

View file

@ -34,6 +34,7 @@ class PersistenceController {
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Meshtastic")
//self.clearDatabase()
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,8 @@ struct ChannelSet {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// TODO: REPLACE
var settings: [ChannelSettings] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
@ -38,6 +40,10 @@ struct ChannelSet {
init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
extension ChannelSet: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {

View file

@ -7,25 +7,6 @@
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
///
/// Meshtastic protobufs
///
/// For more information on protobufs (and tools to use them with the language of your choice) see
/// https://developers.google.com/protocol-buffers/docs/proto3
///
/// We are not placing any of these defs inside a package, because if you do the
/// resulting nanopb version is super verbose package mesh.
///
/// Protobuf build instructions:
///
/// To build java classes for reading writing:
/// protoc -I=. --java_out /tmp mesh.proto
///
/// To generate Nanopb c code:
/// /home/kevinh/packages/nanopb-0.4.0-linux-x86/generator-bin/protoc --nanopb_out=/tmp -I=app/src/main/proto mesh.proto
///
/// Nanopb binaries available here: https://jpa.kapsi.fi/nanopb/download/ use nanopb 0.4.0
import Foundation
import SwiftProtobuf
@ -40,96 +21,46 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
}
///
/// Canned message plugin part 1
struct CannedMessagePluginMessagePart1 {
/// Canned message module configuration.
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 plugin separated by '|' characters.
/// This is part 1.
var text: String = String()
/// Predefined messages for canned message module separated by '|' characters.
var messagesPart1: String = String()
///
/// TODO: REPLACE
var messagesPart2: String = String()
///
/// TODO: REPLACE
var messagesPart3: String = String()
///
/// TODO: REPLACE
var messagesPart4: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Canned message plugin part 2
struct CannedMessagePluginMessagePart2 {
// 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 plugin separated by '|' characters.
/// This is part 2.
var text: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Canned message plugin part 3
struct CannedMessagePluginMessagePart3 {
// 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 plugin separated by '|' characters.
/// This is part 3.
var text: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Canned message plugin part 4
struct CannedMessagePluginMessagePart4 {
// 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 plugin separated by '|' characters.
/// This is part 4.
var text: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Canned message plugin part 5
struct CannedMessagePluginMessagePart5 {
// 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 plugin separated by '|' characters.
/// This is part 5.
var text: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
extension CannedMessageModuleConfig: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension CannedMessagePluginMessagePart1: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessagePluginMessagePart1"
extension CannedMessageModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessageModuleConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
11: .same(proto: "messagesPart1"),
12: .same(proto: "messagesPart2"),
13: .same(proto: "messagesPart3"),
14: .same(proto: "messagesPart4"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -138,149 +69,36 @@ extension CannedMessagePluginMessagePart1: SwiftProtobuf.Message, SwiftProtobuf.
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
case 11: try { try decoder.decodeSingularStringField(value: &self.messagesPart1) }()
case 12: try { try decoder.decodeSingularStringField(value: &self.messagesPart2) }()
case 13: try { try decoder.decodeSingularStringField(value: &self.messagesPart3) }()
case 14: try { try decoder.decodeSingularStringField(value: &self.messagesPart4) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
if !self.messagesPart1.isEmpty {
try visitor.visitSingularStringField(value: self.messagesPart1, fieldNumber: 11)
}
if !self.messagesPart2.isEmpty {
try visitor.visitSingularStringField(value: self.messagesPart2, fieldNumber: 12)
}
if !self.messagesPart3.isEmpty {
try visitor.visitSingularStringField(value: self.messagesPart3, fieldNumber: 13)
}
if !self.messagesPart4.isEmpty {
try visitor.visitSingularStringField(value: self.messagesPart4, fieldNumber: 14)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessagePluginMessagePart1, rhs: CannedMessagePluginMessagePart1) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension CannedMessagePluginMessagePart2: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessagePluginMessagePart2"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessagePluginMessagePart2, rhs: CannedMessagePluginMessagePart2) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension CannedMessagePluginMessagePart3: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessagePluginMessagePart3"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessagePluginMessagePart3, rhs: CannedMessagePluginMessagePart3) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension CannedMessagePluginMessagePart4: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessagePluginMessagePart4"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessagePluginMessagePart4, rhs: CannedMessagePluginMessagePart4) -> Bool {
if lhs.text != rhs.text {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension CannedMessagePluginMessagePart5: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "CannedMessagePluginMessagePart5"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "text"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularStringField(value: &self.text) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.text.isEmpty {
try visitor.visitSingularStringField(value: self.text, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: CannedMessagePluginMessagePart5, rhs: CannedMessagePluginMessagePart5) -> Bool {
if lhs.text != rhs.text {return false}
static func ==(lhs: CannedMessageModuleConfig, rhs: CannedMessageModuleConfig) -> Bool {
if lhs.messagesPart1 != rhs.messagesPart1 {return false}
if lhs.messagesPart2 != rhs.messagesPart2 {return false}
if lhs.messagesPart3 != rhs.messagesPart3 {return false}
if lhs.messagesPart4 != rhs.messagesPart4 {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -7,25 +7,6 @@
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
///
/// Meshtastic protobufs
///
/// For more information on protobufs (and tools to use them with the language of your choice) see
/// https://developers.google.com/protocol-buffers/docs/proto3
///
/// We are not placing any of these defs inside a package, because if you do the
/// resulting nanopb version is super verbose package mesh.
///
/// Protobuf build instructions:
///
/// To build java classes for reading writing:
/// protoc -I=. --java_out /tmp mesh.proto
///
/// To generate Nanopb c code:
/// /home/kevinh/packages/nanopb-0.4.0-linux-x86/generator-bin/protoc --nanopb_out=/tmp -I=app/src/main/proto mesh.proto
///
/// Nanopb binaries available here: https://jpa.kapsi.fi/nanopb/download/ use nanopb 0.4.0
import Foundation
import SwiftProtobuf
@ -56,7 +37,6 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
/// users COULD type in a channel name and be able to talk.
/// Y is a lower case letter from a-z that represents the channel 'speed' settings
/// (for some future definition of speed)
///
/// 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
@ -65,38 +45,6 @@ struct ChannelSettings {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// If zero then, use default max legal continuous power (ie. something that won't
/// burn out the radio hardware)
/// In most cases you should use zero here.
/// Units are in dBm.
var txPower: Int32 = 0
///
/// Note: This is the 'old' mechanism for specifying channel parameters.
/// Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH.
/// As a heuristic: If bandwidth is specified, do not use modem_config.
/// Because protobufs take ZERO space when the value is zero this works out nicely.
/// This value is replaced by bandwidth/spread_factor/coding_rate.
/// If you'd like to experiment with other options add them to MeshRadio.cpp in the device code.
var modemConfig: ChannelSettings.ModemConfig = .bw125Cr45Sf128
///
/// Bandwidth in MHz
/// Certain bandwidth numbers are 'special' and will be converted to the
/// appropriate floating point value: 31 -> 31.25MHz
var bandwidth: UInt32 = 0
///
/// A number from 7 to 12.
/// Indicates number of chirps per symbol as 1<<spread_factor.
var spreadFactor: UInt32 = 0
///
/// The denominator of the coding rate.
/// ie for 4/8, the value is 8. 5/8 the value is 5.
var codingRate: UInt32 = 0
///
/// NOTE: this field is _independent_ and unrelated to the concepts in channel.proto.
/// this is controlling the actual hardware frequency the radio is transmitting on.
@ -139,7 +87,7 @@ struct ChannelSettings {
/// is the special (minimally secure) "Default"channel.
/// 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 ModemConfig
/// Where "X" is selected based on the English words listed above for ModemPreset
var name: String = String()
///
@ -166,92 +114,9 @@ struct ChannelSettings {
var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// Standard predefined channel settings
/// Note: these mappings must match ModemConfigChoice in the device code.
enum ModemConfig: SwiftProtobuf.Enum {
typealias RawValue = Int
///
/// < Bw = 125 kHz, Cr = 4/5, Sf(7) = 128chips/symbol, CRC
/// < on. ShortSlow | Short Range / Slow (5.469 kbps)
case bw125Cr45Sf128 // = 0
///
/// < Bw = 500 kHz, Cr = 4/5, Sf(7) = 128chips/symbol, CRC
/// < on. ShortFast | Short Range / Fast (21.875 kbps)
case bw500Cr45Sf128 // = 1
///
/// < Bw = 31.25 kHz, Cr = 4/8, Sf(9) = 512chips/symbol,
/// < CRC on. LongFast | Long Range / Fast (275 bps)
case bw3125Cr48Sf512 // = 2
///
/// < Bw = 125 kHz, Cr = 4/8, Sf(12) = 4096chips/symbol, CRC
/// < on. LongSlow | Long Range / Slow (183 bps)
case bw125Cr48Sf4096 // = 3
///
/// < Bw = 250 kHz, Cr = 4/6, Sf(11) = 2048chips/symbol, CRC
/// < on. MediumSlow | Medium Range / Slow (895 bps)
case bw250Cr46Sf2048 // = 4
///
/// < Bw = 250 kHz, Cr = 4/7, Sf(10) = 1024chips/symbol, CRC
/// < on. MediumFast | Medium Range / Fast (1400 bps)
case bw250Cr47Sf1024 // = 5
case UNRECOGNIZED(Int)
init() {
self = .bw125Cr45Sf128
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .bw125Cr45Sf128
case 1: self = .bw500Cr45Sf128
case 2: self = .bw3125Cr48Sf512
case 3: self = .bw125Cr48Sf4096
case 4: self = .bw250Cr46Sf2048
case 5: self = .bw250Cr47Sf1024
default: self = .UNRECOGNIZED(rawValue)
}
}
var rawValue: Int {
switch self {
case .bw125Cr45Sf128: return 0
case .bw500Cr45Sf128: return 1
case .bw3125Cr48Sf512: return 2
case .bw125Cr48Sf4096: return 3
case .bw250Cr46Sf2048: return 4
case .bw250Cr47Sf1024: return 5
case .UNRECOGNIZED(let i): return i
}
}
}
init() {}
}
#if swift(>=4.2)
extension ChannelSettings.ModemConfig: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ChannelSettings.ModemConfig] = [
.bw125Cr45Sf128,
.bw500Cr45Sf128,
.bw3125Cr48Sf512,
.bw125Cr48Sf4096,
.bw250Cr46Sf2048,
.bw250Cr47Sf1024,
]
}
#endif // swift(>=4.2)
///
/// A pair of a channel number, mode and the (sharable) settings for that channel
struct Channel {
@ -276,18 +141,18 @@ struct Channel {
/// Clears the value of `settings`. Subsequent reads from it will return its default value.
mutating func clearSettings() {self._settings = nil}
///
/// TODO: REPLACE
var role: Channel.Role = .disabled
var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// How this channel is being used (or not).
///
/// Note: this field is an enum to give us options for the future.
/// In particular, someday we might make a 'SCANNING' option.
/// SCANNING channels could have different frequencies and the radio would
/// occasionally check that freq to see if anything is being transmitted.
///
/// For devices that have multiple physical radios attached, we could keep multiple PRIMARY/SCANNING channels active at once to allow
/// 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
@ -351,16 +216,17 @@ extension Channel.Role: CaseIterable {
#endif // swift(>=4.2)
#if swift(>=5.5) && canImport(_Concurrency)
extension ChannelSettings: @unchecked Sendable {}
extension Channel: @unchecked Sendable {}
extension Channel.Role: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "ChannelSettings"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "tx_power"),
3: .standard(proto: "modem_config"),
6: .same(proto: "bandwidth"),
7: .standard(proto: "spread_factor"),
8: .standard(proto: "coding_rate"),
9: .standard(proto: "channel_num"),
4: .same(proto: "psk"),
5: .same(proto: "name"),
@ -375,13 +241,8 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self.txPower) }()
case 3: try { try decoder.decodeSingularEnumField(value: &self.modemConfig) }()
case 4: try { try decoder.decodeSingularBytesField(value: &self.psk) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.name) }()
case 6: try { try decoder.decodeSingularUInt32Field(value: &self.bandwidth) }()
case 7: try { try decoder.decodeSingularUInt32Field(value: &self.spreadFactor) }()
case 8: try { try decoder.decodeSingularUInt32Field(value: &self.codingRate) }()
case 9: try { try decoder.decodeSingularUInt32Field(value: &self.channelNum) }()
case 10: try { try decoder.decodeSingularFixed32Field(value: &self.id) }()
case 16: try { try decoder.decodeSingularBoolField(value: &self.uplinkEnabled) }()
@ -392,27 +253,12 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.txPower != 0 {
try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 1)
}
if self.modemConfig != .bw125Cr45Sf128 {
try visitor.visitSingularEnumField(value: self.modemConfig, fieldNumber: 3)
}
if !self.psk.isEmpty {
try visitor.visitSingularBytesField(value: self.psk, fieldNumber: 4)
}
if !self.name.isEmpty {
try visitor.visitSingularStringField(value: self.name, fieldNumber: 5)
}
if self.bandwidth != 0 {
try visitor.visitSingularUInt32Field(value: self.bandwidth, fieldNumber: 6)
}
if self.spreadFactor != 0 {
try visitor.visitSingularUInt32Field(value: self.spreadFactor, fieldNumber: 7)
}
if self.codingRate != 0 {
try visitor.visitSingularUInt32Field(value: self.codingRate, fieldNumber: 8)
}
if self.channelNum != 0 {
try visitor.visitSingularUInt32Field(value: self.channelNum, fieldNumber: 9)
}
@ -429,11 +275,6 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
static func ==(lhs: ChannelSettings, rhs: ChannelSettings) -> Bool {
if lhs.txPower != rhs.txPower {return false}
if lhs.modemConfig != rhs.modemConfig {return false}
if lhs.bandwidth != rhs.bandwidth {return false}
if lhs.spreadFactor != rhs.spreadFactor {return false}
if lhs.codingRate != rhs.codingRate {return false}
if lhs.channelNum != rhs.channelNum {return false}
if lhs.psk != rhs.psk {return false}
if lhs.name != rhs.name {return false}
@ -445,17 +286,6 @@ extension ChannelSettings: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
}
extension ChannelSettings.ModemConfig: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "Bw125Cr45Sf128"),
1: .same(proto: "Bw500Cr45Sf128"),
2: .same(proto: "Bw31_25Cr48Sf512"),
3: .same(proto: "Bw125Cr48Sf4096"),
4: .same(proto: "Bw250Cr46Sf2048"),
5: .same(proto: "Bw250Cr47Sf1024"),
]
}
extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "Channel"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
@ -479,12 +309,16 @@ extension Channel: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBa
}
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
// https://github.com/apple/swift-protobuf/issues/1182
if self.index != 0 {
try visitor.visitSingularInt32Field(value: self.index, fieldNumber: 1)
}
if let v = self._settings {
try { if let v = self._settings {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
} }()
if self.role != .disabled {
try visitor.visitSingularEnumField(value: self.role, fieldNumber: 3)
}

File diff suppressed because it is too large Load diff

View file

@ -21,44 +21,60 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
}
///
/// This is a stub version of the old 1.1 representation of RadioConfig.
/// But only keeping the region info.
/// The device firmware uses this stub while migrating old nodes to the new preferences system.
struct LegacyRadioConfig {
// 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
enum ScreenFonts: SwiftProtobuf.Enum {
typealias RawValue = Int
var preferences: LegacyRadioConfig.LegacyPreferences {
get {return _preferences ?? LegacyRadioConfig.LegacyPreferences()}
set {_preferences = newValue}
}
/// Returns true if `preferences` has been explicitly set.
var hasPreferences: Bool {return self._preferences != nil}
/// Clears the value of `preferences`. Subsequent reads from it will return its default value.
mutating func clearPreferences() {self._preferences = nil}
///
/// TODO: REPLACE
case fontSmall // = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// TODO: REPLACE
case fontMedium // = 1
struct LegacyPreferences {
// 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
case fontLarge // = 2
case UNRECOGNIZED(Int)
///
/// The region code for my radio (US, CN, EU433, etc...)
var region: RegionCode = .unset
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
init() {
self = .fontSmall
}
init() {}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .fontSmall
case 1: self = .fontMedium
case 2: self = .fontLarge
default: self = .UNRECOGNIZED(rawValue)
}
}
var rawValue: Int {
switch self {
case .fontSmall: return 0
case .fontMedium: return 1
case .fontLarge: return 2
case .UNRECOGNIZED(let i): return i
}
}
fileprivate var _preferences: LegacyRadioConfig.LegacyPreferences? = nil
}
#if swift(>=4.2)
extension ScreenFonts: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ScreenFonts] = [
.fontSmall,
.fontMedium,
.fontLarge,
]
}
#endif // swift(>=4.2)
///
/// This message is never sent over the wire, but it is used for serializing DB
/// state to flash in the device code
@ -70,17 +86,6 @@ struct DeviceState {
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
///
/// Moved to its own file, but we keep this here so we can automatically migrate old radio.region settings
var legacyRadio: LegacyRadioConfig {
get {return _storage._legacyRadio ?? LegacyRadioConfig()}
set {_uniqueStorage()._legacyRadio = newValue}
}
/// Returns true if `legacyRadio` has been explicitly set.
var hasLegacyRadio: Bool {return _storage._legacyRadio != nil}
/// Clears the value of `legacyRadio`. Subsequent reads from it will return its default value.
mutating func clearLegacyRadio() {_uniqueStorage()._legacyRadio = nil}
///
/// Read only settings/info about this node
var myNode: MyNodeInfo {
@ -103,6 +108,8 @@ struct DeviceState {
/// Clears the value of `owner`. Subsequent reads from it will return its default value.
mutating func clearOwner() {_uniqueStorage()._owner = nil}
///
/// TODO: REPLACE
var nodeDb: [NodeInfo] {
get {return _storage._nodeDb}
set {_uniqueStorage()._nodeDb = newValue}
@ -152,41 +159,6 @@ struct DeviceState {
set {_uniqueStorage()._didGpsReset = newValue}
}
///
/// Canned Message Plugin message part1.
var cannedMessagePluginMessagePart1: String {
get {return _storage._cannedMessagePluginMessagePart1}
set {_uniqueStorage()._cannedMessagePluginMessagePart1 = newValue}
}
///
/// Canned Message Plugin message part2.
var cannedMessagePluginMessagePart2: String {
get {return _storage._cannedMessagePluginMessagePart2}
set {_uniqueStorage()._cannedMessagePluginMessagePart2 = newValue}
}
///
/// Canned Message Plugin message part3.
var cannedMessagePluginMessagePart3: String {
get {return _storage._cannedMessagePluginMessagePart3}
set {_uniqueStorage()._cannedMessagePluginMessagePart3 = newValue}
}
///
/// Canned Message Plugin message part4.
var cannedMessagePluginMessagePart4: String {
get {return _storage._cannedMessagePluginMessagePart4}
set {_uniqueStorage()._cannedMessagePluginMessagePart4 = newValue}
}
///
/// Canned Message Plugin message part5.
var cannedMessagePluginMessagePart5: String {
get {return _storage._cannedMessagePluginMessagePart5}
set {_uniqueStorage()._cannedMessagePluginMessagePart5 = newValue}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
@ -210,76 +182,59 @@ struct ChannelFile {
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
///
/// This can be used for customizing the firmware distribution. If populated,
/// show a secondary bootup screen with cuatom logo and text for 2.5 seconds.
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.
extension LegacyRadioConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "LegacyRadioConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "preferences"),
]
///
/// The Logo width in Px
var oemIconWidth: UInt32 = 0
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularMessageField(value: &self._preferences) }()
default: break
}
}
}
///
/// The Logo height in Px
var oemIconHeight: UInt32 = 0
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._preferences {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
///
/// The Logo in xbm bytechar format
var oemIconBits: Data = Data()
static func ==(lhs: LegacyRadioConfig, rhs: LegacyRadioConfig) -> Bool {
if lhs._preferences != rhs._preferences {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
///
/// Use this font for the OEM text.
var oemFont: ScreenFonts = .fontSmall
///
/// Use this font for the OEM text.
var oemText: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
extension LegacyRadioConfig.LegacyPreferences: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = LegacyRadioConfig.protoMessageName + ".LegacyPreferences"
#if swift(>=5.5) && canImport(_Concurrency)
extension ScreenFonts: @unchecked Sendable {}
extension DeviceState: @unchecked Sendable {}
extension ChannelFile: @unchecked Sendable {}
extension OEMStore: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension ScreenFonts: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
15: .same(proto: "region"),
0: .same(proto: "FONT_SMALL"),
1: .same(proto: "FONT_MEDIUM"),
2: .same(proto: "FONT_LARGE"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 15: try { try decoder.decodeSingularEnumField(value: &self.region) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.region != .unset {
try visitor.visitSingularEnumField(value: self.region, fieldNumber: 15)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: LegacyRadioConfig.LegacyPreferences, rhs: LegacyRadioConfig.LegacyPreferences) -> Bool {
if lhs.region != rhs.region {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "DeviceState"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "legacyRadio"),
2: .standard(proto: "my_node"),
3: .same(proto: "owner"),
4: .standard(proto: "node_db"),
@ -288,15 +243,9 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
7: .standard(proto: "rx_text_message"),
9: .standard(proto: "no_save"),
11: .standard(proto: "did_gps_reset"),
13: .standard(proto: "canned_message_plugin_message_part1"),
14: .standard(proto: "canned_message_plugin_message_part2"),
15: .standard(proto: "canned_message_plugin_message_part3"),
16: .standard(proto: "canned_message_plugin_message_part4"),
17: .standard(proto: "canned_message_plugin_message_part5"),
]
fileprivate class _StorageClass {
var _legacyRadio: LegacyRadioConfig? = nil
var _myNode: MyNodeInfo? = nil
var _owner: User? = nil
var _nodeDb: [NodeInfo] = []
@ -305,18 +254,12 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
var _rxTextMessage: MeshPacket? = nil
var _noSave: Bool = false
var _didGpsReset: Bool = false
var _cannedMessagePluginMessagePart1: String = String()
var _cannedMessagePluginMessagePart2: String = String()
var _cannedMessagePluginMessagePart3: String = String()
var _cannedMessagePluginMessagePart4: String = String()
var _cannedMessagePluginMessagePart5: String = String()
static let defaultInstance = _StorageClass()
private init() {}
init(copying source: _StorageClass) {
_legacyRadio = source._legacyRadio
_myNode = source._myNode
_owner = source._owner
_nodeDb = source._nodeDb
@ -325,11 +268,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
_rxTextMessage = source._rxTextMessage
_noSave = source._noSave
_didGpsReset = source._didGpsReset
_cannedMessagePluginMessagePart1 = source._cannedMessagePluginMessagePart1
_cannedMessagePluginMessagePart2 = source._cannedMessagePluginMessagePart2
_cannedMessagePluginMessagePart3 = source._cannedMessagePluginMessagePart3
_cannedMessagePluginMessagePart4 = source._cannedMessagePluginMessagePart4
_cannedMessagePluginMessagePart5 = source._cannedMessagePluginMessagePart5
}
}
@ -348,7 +286,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularMessageField(value: &_storage._legacyRadio) }()
case 2: try { try decoder.decodeSingularMessageField(value: &_storage._myNode) }()
case 3: try { try decoder.decodeSingularMessageField(value: &_storage._owner) }()
case 4: try { try decoder.decodeRepeatedMessageField(value: &_storage._nodeDb) }()
@ -357,11 +294,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
case 8: try { try decoder.decodeSingularUInt32Field(value: &_storage._version) }()
case 9: try { try decoder.decodeSingularBoolField(value: &_storage._noSave) }()
case 11: try { try decoder.decodeSingularBoolField(value: &_storage._didGpsReset) }()
case 13: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessagePluginMessagePart1) }()
case 14: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessagePluginMessagePart2) }()
case 15: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessagePluginMessagePart3) }()
case 16: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessagePluginMessagePart4) }()
case 17: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessagePluginMessagePart5) }()
default: break
}
}
@ -370,24 +302,25 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
try withExtendedLifetime(_storage) { (_storage: _StorageClass) in
if let v = _storage._legacyRadio {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
if let v = _storage._myNode {
// 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
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = _storage._myNode {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
if let v = _storage._owner {
} }()
try { if let v = _storage._owner {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
}
} }()
if !_storage._nodeDb.isEmpty {
try visitor.visitRepeatedMessageField(value: _storage._nodeDb, fieldNumber: 4)
}
if !_storage._receiveQueue.isEmpty {
try visitor.visitRepeatedMessageField(value: _storage._receiveQueue, fieldNumber: 5)
}
if let v = _storage._rxTextMessage {
try { if let v = _storage._rxTextMessage {
try visitor.visitSingularMessageField(value: v, fieldNumber: 7)
}
} }()
if _storage._version != 0 {
try visitor.visitSingularUInt32Field(value: _storage._version, fieldNumber: 8)
}
@ -397,21 +330,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
if _storage._didGpsReset != false {
try visitor.visitSingularBoolField(value: _storage._didGpsReset, fieldNumber: 11)
}
if !_storage._cannedMessagePluginMessagePart1.isEmpty {
try visitor.visitSingularStringField(value: _storage._cannedMessagePluginMessagePart1, fieldNumber: 13)
}
if !_storage._cannedMessagePluginMessagePart2.isEmpty {
try visitor.visitSingularStringField(value: _storage._cannedMessagePluginMessagePart2, fieldNumber: 14)
}
if !_storage._cannedMessagePluginMessagePart3.isEmpty {
try visitor.visitSingularStringField(value: _storage._cannedMessagePluginMessagePart3, fieldNumber: 15)
}
if !_storage._cannedMessagePluginMessagePart4.isEmpty {
try visitor.visitSingularStringField(value: _storage._cannedMessagePluginMessagePart4, fieldNumber: 16)
}
if !_storage._cannedMessagePluginMessagePart5.isEmpty {
try visitor.visitSingularStringField(value: _storage._cannedMessagePluginMessagePart5, fieldNumber: 17)
}
}
try unknownFields.traverse(visitor: &visitor)
}
@ -421,7 +339,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in
let _storage = _args.0
let rhs_storage = _args.1
if _storage._legacyRadio != rhs_storage._legacyRadio {return false}
if _storage._myNode != rhs_storage._myNode {return false}
if _storage._owner != rhs_storage._owner {return false}
if _storage._nodeDb != rhs_storage._nodeDb {return false}
@ -430,11 +347,6 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
if _storage._rxTextMessage != rhs_storage._rxTextMessage {return false}
if _storage._noSave != rhs_storage._noSave {return false}
if _storage._didGpsReset != rhs_storage._didGpsReset {return false}
if _storage._cannedMessagePluginMessagePart1 != rhs_storage._cannedMessagePluginMessagePart1 {return false}
if _storage._cannedMessagePluginMessagePart2 != rhs_storage._cannedMessagePluginMessagePart2 {return false}
if _storage._cannedMessagePluginMessagePart3 != rhs_storage._cannedMessagePluginMessagePart3 {return false}
if _storage._cannedMessagePluginMessagePart4 != rhs_storage._cannedMessagePluginMessagePart4 {return false}
if _storage._cannedMessagePluginMessagePart5 != rhs_storage._cannedMessagePluginMessagePart5 {return false}
return true
}
if !storagesAreEqual {return false}
@ -475,3 +387,59 @@ extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
return true
}
}
extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "OEMStore"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "oem_icon_width"),
2: .standard(proto: "oem_icon_height"),
3: .standard(proto: "oem_icon_bits"),
4: .standard(proto: "oem_font"),
5: .standard(proto: "oem_text"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularUInt32Field(value: &self.oemIconWidth) }()
case 2: try { try decoder.decodeSingularUInt32Field(value: &self.oemIconHeight) }()
case 3: try { try decoder.decodeSingularBytesField(value: &self.oemIconBits) }()
case 4: try { try decoder.decodeSingularEnumField(value: &self.oemFont) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.oemText) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.oemIconWidth != 0 {
try visitor.visitSingularUInt32Field(value: self.oemIconWidth, fieldNumber: 1)
}
if self.oemIconHeight != 0 {
try visitor.visitSingularUInt32Field(value: self.oemIconHeight, fieldNumber: 2)
}
if !self.oemIconBits.isEmpty {
try visitor.visitSingularBytesField(value: self.oemIconBits, fieldNumber: 3)
}
if self.oemFont != .fontSmall {
try visitor.visitSingularEnumField(value: self.oemFont, fieldNumber: 4)
}
if !self.oemText.isEmpty {
try visitor.visitSingularStringField(value: self.oemText, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
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}
if lhs.oemFont != rhs.oemFont {return false}
if lhs.oemText != rhs.oemText {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View file

@ -1,107 +0,0 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: environmental_measurement.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct EnvironmentalMeasurement {
// 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.
var temperature: Float = 0
var relativeHumidity: Float = 0
var barometricPressure: Float = 0
var gasResistance: Float = 0
var voltage: Float = 0
var current: Float = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension EnvironmentalMeasurement: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "EnvironmentalMeasurement"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "temperature"),
2: .standard(proto: "relative_humidity"),
3: .standard(proto: "barometric_pressure"),
4: .standard(proto: "gas_resistance"),
5: .same(proto: "voltage"),
6: .same(proto: "current"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularFloatField(value: &self.temperature) }()
case 2: try { try decoder.decodeSingularFloatField(value: &self.relativeHumidity) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.barometricPressure) }()
case 4: try { try decoder.decodeSingularFloatField(value: &self.gasResistance) }()
case 5: try { try decoder.decodeSingularFloatField(value: &self.voltage) }()
case 6: try { try decoder.decodeSingularFloatField(value: &self.current) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.temperature != 0 {
try visitor.visitSingularFloatField(value: self.temperature, fieldNumber: 1)
}
if self.relativeHumidity != 0 {
try visitor.visitSingularFloatField(value: self.relativeHumidity, fieldNumber: 2)
}
if self.barometricPressure != 0 {
try visitor.visitSingularFloatField(value: self.barometricPressure, fieldNumber: 3)
}
if self.gasResistance != 0 {
try visitor.visitSingularFloatField(value: self.gasResistance, fieldNumber: 4)
}
if self.voltage != 0 {
try visitor.visitSingularFloatField(value: self.voltage, fieldNumber: 5)
}
if self.current != 0 {
try visitor.visitSingularFloatField(value: self.current, fieldNumber: 6)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: EnvironmentalMeasurement, rhs: EnvironmentalMeasurement) -> Bool {
if lhs.temperature != rhs.temperature {return false}
if lhs.relativeHumidity != rhs.relativeHumidity {return false}
if lhs.barometricPressure != rhs.barometricPressure {return false}
if lhs.gasResistance != rhs.gasResistance {return false}
if lhs.voltage != rhs.voltage {return false}
if lhs.current != rhs.current {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -55,6 +55,10 @@ struct ServiceEnvelope {
fileprivate var _packet: MeshPacket? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
extension ServiceEnvelope: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
@ -80,9 +84,13 @@ extension ServiceEnvelope: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if let v = self._packet {
// 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
// https://github.com/apple/swift-protobuf/issues/1182
try { if let v = self._packet {
try visitor.visitSingularMessageField(value: v, fieldNumber: 1)
}
} }()
if !self.channelID.isEmpty {
try visitor.visitSingularStringField(value: self.channelID, fieldNumber: 2)
}

View file

@ -23,19 +23,14 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
///
/// For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a
/// unique 'portnum' for their application.
///
/// If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to this
/// master table.
/// PortNums should be assigned in the following range:
///
/// 0-63 Core Meshtastic use, do not use for third party apps
/// 64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application
/// 256-511 Use one of these portnums for your private applications that you don't want to register publically
///
/// All other values are reserved.
///
/// Note: This was formerly a Type enum named 'typ' with the same id #
///
/// We have change to this 'portnum' based scheme for specifying app handlers for particular payloads.
/// This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically.
enum PortNum: SwiftProtobuf.Enum {
@ -51,7 +46,6 @@ enum PortNum: SwiftProtobuf.Enum {
/// A simple UTF-8 text message, which even the little micros in the mesh
/// can understand and show on their screen eventually in some circumstances
/// even signal might send messages in this form (see below)
/// Formerly called CLEAR_TEXT
case textMessageApp // = 1
///
@ -61,27 +55,27 @@ enum PortNum: SwiftProtobuf.Enum {
///
/// The built-in position messaging app.
/// Payload is a [Position](/developers/protobufs/api.md#position) message
/// Payload is a [Position](/docs/developers/protobufs/api#position) message
case positionApp // = 3
///
/// The built-in user info app.
/// Payload is a [User](/developers/protobufs/api.md#user) message
/// Payload is a [User](/docs/developers/protobufs/api#user) message
case nodeinfoApp // = 4
///
/// Protocol control packets for mesh protocol use.
/// Payload is a [Routing](/developers/protobufs/api.md#routing) message
/// Payload is a [Routing](/docs/developers/protobufs/api#routing) message
case routingApp // = 5
///
/// Admin control packets.
/// Payload is a [AdminMessage](/developers/protobufs/api.md#adminmessage) message
/// Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
case adminApp // = 6
///
/// Provides a 'ping' service that replies to any packet it receives.
/// Also serves as a small example plugin.
/// Also serves as a small example module.
case replyApp // = 32
///
@ -93,8 +87,7 @@ enum PortNum: SwiftProtobuf.Enum {
/// Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
/// network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
/// Maximum packet size of 240 bytes.
/// Plugin is disabled by default can be turned on by setting SERIALPLUGIN_ENABLED = 1 in SerialPlugh.cpp.
/// Maintained by Jm Casler (MC Hamster) : jm@casler.org
/// Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
case serialApp // = 64
///
@ -103,14 +96,13 @@ enum PortNum: SwiftProtobuf.Enum {
case storeForwardApp // = 65
///
/// STORE_FORWARD_APP (Work in Progress)
/// Maintained by Jm Casler (MC Hamster) : jm@casler.org
/// Optional port for messages for the range test module.
case rangeTestApp // = 66
///
/// Provides a format to send and receive environmental data from the Meshtastic network.
/// Provides a format to send and receive telemetry data from the Meshtastic network.
/// Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
case environmentalMeasurementApp // = 67
case telemetryApp // = 67
///
/// Experimental tools for estimating node position without a GPS
@ -118,6 +110,10 @@ enum PortNum: SwiftProtobuf.Enum {
/// Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
case zpsApp // = 68
///
/// Compressed payloads.
case compressionApp // = 69
///
/// Private applications should use portnums >= 256.
/// To simplify initial development and testing you can use "PRIVATE_APP"
@ -125,7 +121,7 @@ enum PortNum: SwiftProtobuf.Enum {
case privateApp // = 256
///
/// ATAK Forwarder Plugin https://github.com/paulmandal/atak-forwarder
/// ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
case atakForwarder // = 257
///
@ -151,8 +147,9 @@ enum PortNum: SwiftProtobuf.Enum {
case 64: self = .serialApp
case 65: self = .storeForwardApp
case 66: self = .rangeTestApp
case 67: self = .environmentalMeasurementApp
case 67: self = .telemetryApp
case 68: self = .zpsApp
case 69: self = .compressionApp
case 256: self = .privateApp
case 257: self = .atakForwarder
case 511: self = .max
@ -174,8 +171,9 @@ enum PortNum: SwiftProtobuf.Enum {
case .serialApp: return 64
case .storeForwardApp: return 65
case .rangeTestApp: return 66
case .environmentalMeasurementApp: return 67
case .telemetryApp: return 67
case .zpsApp: return 68
case .compressionApp: return 69
case .privateApp: return 256
case .atakForwarder: return 257
case .max: return 511
@ -202,8 +200,9 @@ extension PortNum: CaseIterable {
.serialApp,
.storeForwardApp,
.rangeTestApp,
.environmentalMeasurementApp,
.telemetryApp,
.zpsApp,
.compressionApp,
.privateApp,
.atakForwarder,
.max,
@ -212,6 +211,10 @@ extension PortNum: CaseIterable {
#endif // swift(>=4.2)
#if swift(>=5.5) && canImport(_Concurrency)
extension PortNum: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension PortNum: SwiftProtobuf._ProtoNameProviding {
@ -228,8 +231,9 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding {
64: .same(proto: "SERIAL_APP"),
65: .same(proto: "STORE_FORWARD_APP"),
66: .same(proto: "RANGE_TEST_APP"),
67: .same(proto: "ENVIRONMENTAL_MEASUREMENT_APP"),
67: .same(proto: "TELEMETRY_APP"),
68: .same(proto: "ZPS_APP"),
69: .same(proto: "COMPRESSION_APP"),
256: .same(proto: "PRIVATE_APP"),
257: .same(proto: "ATAK_FORWARDER"),
511: .same(proto: "MAX"),

File diff suppressed because it is too large Load diff

View file

@ -21,14 +21,11 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
}
///
/// An example app to show off the plugin system. This message is used for
/// An example app to show off the module system. This message is used for
/// REMOTE_HARDWARE_APP PortNums.
///
/// Also provides easy remote access to any GPIO.
///
/// In the future other remote hardware operations can be added based on user interest
/// (i.e. serial output, spi/i2c input/output).
///
/// FIXME - currently this feature is turned on by default which is dangerous
/// because no security yet (beyond the channel mechanism).
/// It should be off by default and then protected based on some TBD mechanism
@ -53,6 +50,8 @@ struct HardwareMessage {
var unknownFields = SwiftProtobuf.UnknownStorage()
///
/// TODO: REPLACE
enum TypeEnum: SwiftProtobuf.Enum {
typealias RawValue = Int
@ -132,6 +131,11 @@ extension HardwareMessage.TypeEnum: CaseIterable {
#endif // swift(>=4.2)
#if swift(>=5.5) && canImport(_Concurrency)
extension HardwareMessage: @unchecked Sendable {}
extension HardwareMessage.TypeEnum: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension HardwareMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {

View file

@ -20,13 +20,19 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP
typealias Version = _2
}
///
/// TODO: REPLACE
struct StoreAndForward {
// 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 rr: StoreAndForward.RequestResponse = .unset
///
/// TODO: REPLACE
var stats: StoreAndForward.Statistics {
get {return _stats ?? StoreAndForward.Statistics()}
set {_stats = newValue}
@ -36,6 +42,8 @@ struct StoreAndForward {
/// Clears the value of `stats`. Subsequent reads from it will return its default value.
mutating func clearStats() {self._stats = nil}
///
/// TODO: REPLACE
var history: StoreAndForward.History {
get {return _history ?? StoreAndForward.History()}
set {_history = newValue}
@ -45,6 +53,8 @@ struct StoreAndForward {
/// Clears the value of `history`. Subsequent reads from it will return its default value.
mutating func clearHistory() {self._history = nil}
///
/// TODO: REPLACE
var heartbeat: StoreAndForward.Heartbeat {
get {return _heartbeat ?? StoreAndForward.Heartbeat()}
set {_heartbeat = newValue}
@ -161,6 +171,8 @@ struct StoreAndForward {
}
///
/// TODO: REPLACE
struct Statistics {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@ -207,6 +219,8 @@ struct StoreAndForward {
init() {}
}
///
/// TODO: REPLACE
struct History {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@ -229,6 +243,8 @@ struct StoreAndForward {
init() {}
}
///
/// TODO: REPLACE
struct Heartbeat {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
@ -277,6 +293,14 @@ extension StoreAndForward.RequestResponse: CaseIterable {
#endif // swift(>=4.2)
#if swift(>=5.5) && canImport(_Concurrency)
extension StoreAndForward: @unchecked Sendable {}
extension StoreAndForward.RequestResponse: @unchecked Sendable {}
extension StoreAndForward.Statistics: @unchecked Sendable {}
extension StoreAndForward.History: @unchecked Sendable {}
extension StoreAndForward.Heartbeat: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension StoreAndForward: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
@ -304,18 +328,22 @@ extension StoreAndForward: SwiftProtobuf.Message, SwiftProtobuf._MessageImplemen
}
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
// https://github.com/apple/swift-protobuf/issues/1182
if self.rr != .unset {
try visitor.visitSingularEnumField(value: self.rr, fieldNumber: 1)
}
if let v = self._stats {
try { if let v = self._stats {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}
if let v = self._history {
} }()
try { if let v = self._history {
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
}
if let v = self._heartbeat {
} }()
try { if let v = self._heartbeat {
try visitor.visitSingularMessageField(value: v, fieldNumber: 4)
}
} }()
try unknownFields.traverse(visitor: &visitor)
}

View file

@ -0,0 +1,472 @@
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: telemetry.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
///
/// TODO: REPLACE
enum TelemetrySensorType: SwiftProtobuf.Enum {
typealias RawValue = Int
///
/// No external telemetry sensor
case notSet // = 0
///
/// TODO: REPLACE
case dht11 // = 1
///
/// TODO: REPLACE
case ds18B20 // = 2
///
/// TODO: REPLACE
case dht12 // = 3
///
/// TODO: REPLACE
case dht21 // = 4
///
/// TODO: REPLACE
case dht22 // = 5
///
/// TODO: REPLACE
case bme280 // = 6
///
/// TODO: REPLACE
case bme680 // = 7
///
/// TODO: REPLACE
case mcp9808 // = 8
///
/// TODO: REPLACE
case shtc3 // = 9
case UNRECOGNIZED(Int)
init() {
self = .notSet
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .notSet
case 1: self = .dht11
case 2: self = .ds18B20
case 3: self = .dht12
case 4: self = .dht21
case 5: self = .dht22
case 6: self = .bme280
case 7: self = .bme680
case 8: self = .mcp9808
case 9: self = .shtc3
default: self = .UNRECOGNIZED(rawValue)
}
}
var rawValue: Int {
switch self {
case .notSet: return 0
case .dht11: return 1
case .ds18B20: return 2
case .dht12: return 3
case .dht21: return 4
case .dht22: return 5
case .bme280: return 6
case .bme680: return 7
case .mcp9808: return 8
case .shtc3: return 9
case .UNRECOGNIZED(let i): return i
}
}
}
#if swift(>=4.2)
extension TelemetrySensorType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [TelemetrySensorType] = [
.notSet,
.dht11,
.ds18B20,
.dht12,
.dht21,
.dht22,
.bme280,
.bme680,
.mcp9808,
.shtc3,
]
}
#endif // swift(>=4.2)
///
/// Key native device metrics such as battery level
struct DeviceMetrics {
// 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.
///
/// 1-100 (0 means powered)
var batteryLevel: UInt32 = 0
///
/// Voltage measured
var voltage: Float = 0
///
/// Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise).
var channelUtilization: Float = 0
///
/// Percent of airtime for transmission used within the last hour.
var airUtilTx: Float = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Weather station or other environmental metrics
struct EnvironmentMetrics {
// 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.
///
/// Temperature measured
var temperature: Float = 0
///
/// Relative humidity percent measured
var relativeHumidity: Float = 0
///
/// Barometric pressure in hPA measured
var barometricPressure: Float = 0
///
/// Gas resistance in mOhm measured
var gasResistance: Float = 0
///
/// Voltage measured
var voltage: Float = 0
///
/// Current measured
var current: Float = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
///
/// Types of Measurements the telemetry module is equipped to handle
struct Telemetry {
// 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.
///
/// This is usually not sent over the mesh (to save space), but it is sent
/// from the phone so that the local device can set its RTC If it is sent over
/// the mesh (because there are devices on the mesh without GPS), it will only
/// be sent by devices which has a hardware GPS clock (IE Mobile Phone).
/// seconds since 1970
var time: UInt32 = 0
var variant: Telemetry.OneOf_Variant? = nil
///
/// Key native device metrics such as battery level
var deviceMetrics: DeviceMetrics {
get {
if case .deviceMetrics(let v)? = variant {return v}
return DeviceMetrics()
}
set {variant = .deviceMetrics(newValue)}
}
///
/// Weather station or other environmental metrics
var environmentMetrics: EnvironmentMetrics {
get {
if case .environmentMetrics(let v)? = variant {return v}
return EnvironmentMetrics()
}
set {variant = .environmentMetrics(newValue)}
}
var unknownFields = SwiftProtobuf.UnknownStorage()
enum OneOf_Variant: Equatable {
///
/// Key native device metrics such as battery level
case deviceMetrics(DeviceMetrics)
///
/// Weather station or other environmental metrics
case environmentMetrics(EnvironmentMetrics)
#if !swift(>=4.1)
static func ==(lhs: Telemetry.OneOf_Variant, rhs: Telemetry.OneOf_Variant) -> 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
switch (lhs, rhs) {
case (.deviceMetrics, .deviceMetrics): return {
guard case .deviceMetrics(let l) = lhs, case .deviceMetrics(let r) = rhs else { preconditionFailure() }
return l == r
}()
case (.environmentMetrics, .environmentMetrics): return {
guard case .environmentMetrics(let l) = lhs, case .environmentMetrics(let r) = rhs else { preconditionFailure() }
return l == r
}()
default: return false
}
}
#endif
}
init() {}
}
#if swift(>=5.5) && canImport(_Concurrency)
extension TelemetrySensorType: @unchecked Sendable {}
extension DeviceMetrics: @unchecked Sendable {}
extension EnvironmentMetrics: @unchecked Sendable {}
extension Telemetry: @unchecked Sendable {}
extension Telemetry.OneOf_Variant: @unchecked Sendable {}
#endif // swift(>=5.5) && canImport(_Concurrency)
// MARK: - Code below here is support for the SwiftProtobuf runtime.
extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "NotSet"),
1: .same(proto: "DHT11"),
2: .same(proto: "DS18B20"),
3: .same(proto: "DHT12"),
4: .same(proto: "DHT21"),
5: .same(proto: "DHT22"),
6: .same(proto: "BME280"),
7: .same(proto: "BME680"),
8: .same(proto: "MCP9808"),
9: .same(proto: "SHTC3"),
]
}
extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "DeviceMetrics"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .standard(proto: "battery_level"),
2: .same(proto: "voltage"),
3: .standard(proto: "channel_utilization"),
4: .standard(proto: "air_util_tx"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularUInt32Field(value: &self.batteryLevel) }()
case 2: try { try decoder.decodeSingularFloatField(value: &self.voltage) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.channelUtilization) }()
case 4: try { try decoder.decodeSingularFloatField(value: &self.airUtilTx) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.batteryLevel != 0 {
try visitor.visitSingularUInt32Field(value: self.batteryLevel, fieldNumber: 1)
}
if self.voltage != 0 {
try visitor.visitSingularFloatField(value: self.voltage, fieldNumber: 2)
}
if self.channelUtilization != 0 {
try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 3)
}
if self.airUtilTx != 0 {
try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 4)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: DeviceMetrics, rhs: DeviceMetrics) -> Bool {
if lhs.batteryLevel != rhs.batteryLevel {return false}
if lhs.voltage != rhs.voltage {return false}
if lhs.channelUtilization != rhs.channelUtilization {return false}
if lhs.airUtilTx != rhs.airUtilTx {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "EnvironmentMetrics"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "temperature"),
2: .standard(proto: "relative_humidity"),
3: .standard(proto: "barometric_pressure"),
4: .standard(proto: "gas_resistance"),
5: .same(proto: "voltage"),
6: .same(proto: "current"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularFloatField(value: &self.temperature) }()
case 2: try { try decoder.decodeSingularFloatField(value: &self.relativeHumidity) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.barometricPressure) }()
case 4: try { try decoder.decodeSingularFloatField(value: &self.gasResistance) }()
case 5: try { try decoder.decodeSingularFloatField(value: &self.voltage) }()
case 6: try { try decoder.decodeSingularFloatField(value: &self.current) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.temperature != 0 {
try visitor.visitSingularFloatField(value: self.temperature, fieldNumber: 1)
}
if self.relativeHumidity != 0 {
try visitor.visitSingularFloatField(value: self.relativeHumidity, fieldNumber: 2)
}
if self.barometricPressure != 0 {
try visitor.visitSingularFloatField(value: self.barometricPressure, fieldNumber: 3)
}
if self.gasResistance != 0 {
try visitor.visitSingularFloatField(value: self.gasResistance, fieldNumber: 4)
}
if self.voltage != 0 {
try visitor.visitSingularFloatField(value: self.voltage, fieldNumber: 5)
}
if self.current != 0 {
try visitor.visitSingularFloatField(value: self.current, fieldNumber: 6)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: EnvironmentMetrics, rhs: EnvironmentMetrics) -> Bool {
if lhs.temperature != rhs.temperature {return false}
if lhs.relativeHumidity != rhs.relativeHumidity {return false}
if lhs.barometricPressure != rhs.barometricPressure {return false}
if lhs.gasResistance != rhs.gasResistance {return false}
if lhs.voltage != rhs.voltage {return false}
if lhs.current != rhs.current {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = "Telemetry"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "time"),
2: .standard(proto: "device_metrics"),
3: .standard(proto: "environment_metrics"),
]
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
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularFixed32Field(value: &self.time) }()
case 2: try {
var v: DeviceMetrics?
var hadOneofValue = false
if let current = self.variant {
hadOneofValue = true
if case .deviceMetrics(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {
if hadOneofValue {try decoder.handleConflictingOneOf()}
self.variant = .deviceMetrics(v)
}
}()
case 3: try {
var v: EnvironmentMetrics?
var hadOneofValue = false
if let current = self.variant {
hadOneofValue = true
if case .environmentMetrics(let m) = current {v = m}
}
try decoder.decodeSingularMessageField(value: &v)
if let v = v {
if hadOneofValue {try decoder.handleConflictingOneOf()}
self.variant = .environmentMetrics(v)
}
}()
default: break
}
}
}
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
// https://github.com/apple/swift-protobuf/issues/1182
if self.time != 0 {
try visitor.visitSingularFixed32Field(value: self.time, fieldNumber: 1)
}
switch self.variant {
case .deviceMetrics?: try {
guard case .deviceMetrics(let v)? = self.variant else { preconditionFailure() }
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
}()
case .environmentMetrics?: try {
guard case .environmentMetrics(let v)? = self.variant else { preconditionFailure() }
try visitor.visitSingularMessageField(value: v, fieldNumber: 3)
}()
case nil: break
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: Telemetry, rhs: Telemetry) -> Bool {
if lhs.time != rhs.time {return false}
if lhs.variant != rhs.variant {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

View file

@ -24,7 +24,7 @@ struct Connect: View {
var body: some View {
let firmwareVersion = bleManager.lastConnnectionVersion
let minimumVersion = "1.2.52"
let minimumVersion = "1.3.0"
let supportedVersion = firmwareVersion == "0.0.0" || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedSame
NavigationView {
@ -74,9 +74,13 @@ struct Connect: View {
if bleManager.connectedPeripheral != nil {
Text("FW Version: ").font(.caption)+Text(bleManager.connectedPeripheral.firmwareVersion)
.font(.caption).foregroundColor(Color.gray)
Text("Channel Utilization: ").font(.caption)+Text(String(bleManager.connectedPeripheral.channelUtilization ?? 0.00))
Text("Bitrate: ").font(.caption)+Text(String(format: "%.2f", bleManager.connectedPeripheral.bitrate ?? 0.00))
.font(.caption).foregroundColor(Color.gray)
Text("Air Time: ").font(.caption)+Text(String(bleManager.connectedPeripheral.airTime ?? 0.00))
Text("Channel Utilization: ").font(.caption)+Text(String(format: "%.2f", bleManager.connectedPeripheral.channelUtilization ?? 0.00))
.font(.caption).foregroundColor(Color.gray)
Text("Air Time: ").font(.caption)+Text(String(format: "%.2f", bleManager.connectedPeripheral.airTime ?? 0.00))
.font(.caption).foregroundColor(Color.gray)
}
if bleManager.connectedPeripheral.subscribed {

View file

@ -0,0 +1,22 @@
import SwiftUI
//
// LastHeardText.swift
// Meshtastic Apple
//
// Created by Garth Vander Houwen on 5/25/22.
//
struct LastHeardText: View {
var lastHeard: Date?
let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date())
var body: some View {
if (lastHeard != nil && lastHeard! >= sixMonthsAgo!){
Text("Last Heard: \(lastHeard!, style: .relative) ago")
} else {
Text("Last Heard: Unknown Age")
}
}
}

View file

@ -101,7 +101,7 @@ struct UserMessageList: View {
Button(action: {
if bleManager.sendMessage(message: "❤️", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "❤️", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent ❤️ Tapback")
self.context.refresh(user, mergeChanges: true)
@ -115,7 +115,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "👍", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "👍", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent 👍 Tapback")
self.context.refresh(user, mergeChanges: true)
@ -129,7 +129,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "👎", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "👎", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent 👎 Tapback")
self.context.refresh(user, mergeChanges: true)
@ -143,7 +143,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "🤣", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "🤣", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent 🤣 Tapback")
self.context.refresh(user, mergeChanges: true)
@ -157,7 +157,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "‼️", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "‼️", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent ‼️ Tapback")
self.context.refresh(user, mergeChanges: true)
@ -171,7 +171,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent ❓ Tapback")
self.context.refresh(user, mergeChanges: true)
@ -185,7 +185,7 @@ struct UserMessageList: View {
}
Button(action: {
if bleManager.sendMessage(message: "💩", toUserNum: user.num, isTapback: true, replyID: message.messageId) {
if bleManager.sendMessage(message: "💩", toUserNum: user.num, isEmoji: true, replyID: message.messageId) {
print("Sent 💩 Tapback")
self.context.refresh(user, mergeChanges: true)
@ -434,7 +434,7 @@ struct UserMessageList: View {
.padding(.bottom, 15)
Button(action: {
if bleManager.sendMessage(message: typingMessage, toUserNum: user.num, isTapback: false, replyID: replyMessageId) {
if bleManager.sendMessage(message: typingMessage, toUserNum: user.num, isEmoji: false, replyID: replyMessageId) {
typingMessage = ""
focusedField = nil
replyMessageId = 0

View file

@ -65,19 +65,19 @@ struct NodeDetail: View {
ScrollView {
if node.lastHeard != nil {
HStack {
HStack {
Image(systemName: "clock.badge.checkmark.fill")
.font(.title)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
Text("Last Heard: \(node.lastHeard!, style: .relative) ago").font(.title3)
}
.padding()
Divider()
Image(systemName: "clock.badge.checkmark.fill")
.font(.title)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
LastHeardText(lastHeard: node.lastHeard).font(.title3)
}
.padding()
Divider()
HStack {
@ -104,7 +104,8 @@ struct NodeDetail: View {
}
}
.padding(5)
if node.snr > 0 {
Divider()
VStack(alignment: .center) {
@ -122,9 +123,9 @@ struct NodeDetail: View {
.padding(5)
}
if node.positions?.count ?? 0 >= 1 {
if node.telemetries?.count ?? 0 >= 1 {
let mostRecent = node.positions?.lastObject as! PositionEntity
let mostRecent = node.telemetries?.lastObject as! TelemetryEntity
Divider()
@ -132,23 +133,16 @@ struct NodeDetail: View {
BatteryIcon(batteryLevel: mostRecent.batteryLevel, font: .title, color: .accentColor)
.padding(.bottom)
if mostRecent.batteryLevel > 0 {
Text("Battery")
.font(.title2)
.fixedSize()
.textCase(.uppercase)
Text(String(mostRecent.batteryLevel) + "%")
.font(.title2)
.foregroundColor(.gray)
.symbolRenderingMode(.hierarchical)
} else {
Text("Powered")
.font(.callout)
.fixedSize()
.textCase(.uppercase)
}
Text(String(mostRecent.batteryLevel) + "%")
.font(.title3)
.foregroundColor(.gray)
.fixedSize()
Text(String(format: "%.2f", mostRecent.voltage) + " V")
.font(.title3)
.foregroundColor(.gray)
.fixedSize()
}
.padding(5)
}
@ -207,63 +201,70 @@ struct NodeDetail: View {
.padding()
Divider()
ForEach(node.positions!.array as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in
if mappin.coordinate != nil {
VStack {
HStack {
Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) // .font(.subheadline)
Text("Lat/Long:").font(.caption)
Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))")
.foregroundColor(.gray)
.font(.caption)
Image(systemName: "arrow.up.arrow.down.circle")
.font(.subheadline)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
Text("Alt:")
.font(.caption)
Text("\(String(mappin.altitude))m")
.foregroundColor(.gray)
.font(.caption)
}
HStack {
Image(systemName: "clock.badge.checkmark.fill")
.font(.subheadline)
.foregroundColor(.accentColor)
.symbolRenderingMode(.hierarchical)
Text("Time:")
.font(.caption)
Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)")
.foregroundColor(.gray)
.font(.caption)
Divider()
HStack {
BatteryIcon(batteryLevel: mappin.batteryLevel, font: .subheadline, color: .accentColor)
if mappin.batteryLevel > 0 {
Text(String(mappin.batteryLevel) + "%")
.font(.caption2)
.foregroundColor(.gray)
}
}
}
}
.padding(1)
Divider()
}
}
// ForEach(node.positions!.array as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in
//
// if mappin.coordinate != nil {
//
// VStack {
//
// HStack {
//
// Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) // .font(.subheadline)
// Text("Lat/Long:").font(.caption)
// Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))")
// .foregroundColor(.gray)
// .font(.caption)
//
// Image(systemName: "arrow.up.arrow.down.circle")
// .font(.subheadline)
// .foregroundColor(.accentColor)
// .symbolRenderingMode(.hierarchical)
//
// Text("Alt:")
// .font(.caption)
//
// Text("\(String(mappin.altitude))m")
// .foregroundColor(.gray)
// .font(.caption)
// }
// HStack {
//
// Image(systemName: "clock.badge.checkmark.fill")
// .font(.subheadline)
// .foregroundColor(.accentColor)
// .symbolRenderingMode(.hierarchical)
// Text("Time:")
// .font(.caption)
// Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)")
// .foregroundColor(.gray)
// .font(.caption)
// Divider()
//
// HStack {
//
// BatteryIcon(batteryLevel: mappin.batteryLevel, font: .subheadline, color: .accentColor)
//
// if mappin.batteryLevel > 0 {
//
// Text(String(mappin.batteryLevel) + "%")
// .font(.caption2)
// .foregroundColor(.gray)
// }
// }
// }
// }
// .padding(1)
// Divider()
// }
// }
}
}
}

View file

@ -65,11 +65,18 @@ struct NodeList: View {
.padding(.bottom, 10)
if connected {
HStack(alignment: .bottom) {
Image(systemName: "repeat.circle.fill").font(.title3)
.foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
Text("Currently Connected").font(.title3).foregroundColor(Color.accentColor)
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
Text("Currently Connected").font(.headline).foregroundColor(Color.accentColor)
} else {
Text("Currently Connected").font(.title3).foregroundColor(Color.accentColor)
}
}
Spacer()
}
@ -77,44 +84,23 @@ struct NodeList: View {
HStack(alignment: .bottom) {
Image(systemName: "clock.badge.checkmark.fill").font(.title3).foregroundColor(.accentColor).symbolRenderingMode(.hierarchical)
if node.lastHeard != nil {
Text("Last Heard: \(node.lastHeard!, style: .relative) ago").font(.subheadline).foregroundColor(.gray)
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
LastHeardText(lastHeard: node.lastHeard).font(.subheadline).foregroundColor(.gray)
} else {
Text("Last Heard: Unknown").font(.subheadline).foregroundColor(.gray)
LastHeardText(lastHeard: node.lastHeard).font(.title3).foregroundColor(.gray)
}
}
}
.padding([.leading, .top, .bottom])
}
// .swipeActions {
//
// Button {
//
// context.delete(node)
//
// do {
//
// try context.save()
// print("Successfully Deleted NodeInfoEntiy: \(node.num)")
//
// } catch {
//
// print("Failed to save context after deleting NodeInfoEntity Num: \(node.num)")
// }
//
// } label: {
//
// Label("Delete from app", systemImage: "trash")
// }
// .tint(.red)
// }
}
}
}
.navigationTitle("All Nodes")
.onAppear {
// self.nodes.returnsObjectsAsFaults = false
self.bleManager.context = context
self.bleManager.userSettings = userSettings

View file

@ -158,7 +158,7 @@ struct AppSettings: View {
GeometryReader { _ in
List {
Form {
Section(header: Text("USER DETAILS")) {
HStack {
@ -206,6 +206,13 @@ struct AppSettings: View {
.listRowSeparator(.visible)
}
}
Section(header: Text("MESH OPTIONS")) {
NavigationLink(destination: ShareChannel()) {
Text("Share Your Channel vis QR Code")
}
}
Section(header: Text("MESSAGING OPTIONS")) {
Picker("Keyboard Type", selection: $userSettings.keyboardType) {

View file

@ -0,0 +1,94 @@
//
// ShareChannel.swift
// MeshtasticClient
//
// Created by Garth Vander Houwen on 4/8/22.
//
import SwiftUI
import CoreData
import CoreImage.CIFilterBuiltins
struct QrCodeImage {
let context = CIContext()
func generateQRCode(from text: String) -> UIImage {
var qrImage = UIImage(systemName: "xmark.circle") ?? UIImage()
let data = Data(text.utf8)
let filter = CIFilter.qrCodeGenerator()
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 20, y: 20)
if let outputImage = filter.outputImage?.transformed(by: transform) {
if let image = context.createCGImage(
outputImage,
from: outputImage.extent) {
qrImage = UIImage(cgImage: image)
}
}
return qrImage
}
}
struct ShareChannel: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var userSettings: UserSettings
@State private var text = "meshtastic.org"
var qrCodeImage = QrCodeImage()
var body: some View {
VStack {
GeometryReader { bounds in
let smallest = min(bounds.size.width, bounds.size.height)
ScrollView {
VStack {
Text("Scan the QR code below with the Apple or Android device you would like to share with your channel settings with.")
.fixedSize(horizontal: false, vertical: true)
.font(.callout)
.padding()
Spacer()
let image = qrCodeImage.generateQRCode(from: text)
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(
minWidth: smallest * 0.9,
maxWidth: smallest * 0.9,
minHeight: smallest * 0.9,
maxHeight: smallest * 0.9,
alignment: .center
)
Spacer()
Text("Channel Name (Long/Slow)").font(.title)
Spacer()
}
.frame(width: bounds.size.width, height: bounds.size.height)
}
}
.navigationTitle("Share Channel")
.navigationBarTitleDisplayMode(.automatic)
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???")
})
.onAppear {
self.bleManager.context = context
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

View file

@ -15,7 +15,7 @@ fi
pdir=$(realpath "../Meshtastic-protobufs")
sdir=$(realpath "./MeshtasticClient/Protobufs")
echo "pdir:$pdir sdir:$sdir"
pfiles="admin.proto apponly.proto cannedmessages.proto channel.proto deviceonly.proto environmental_measurement.proto mesh.proto mqtt.proto portnums.proto radioconfig.proto remote_hardware.proto storeforward.proto"
pfiles="admin.proto apponly.proto cannedmessages.proto channel.proto config.proto deviceonly.proto mesh.proto module_config.proto mqtt.proto portnums.proto radioconfig.proto remote_hardware.proto storeforward.proto telemetry.proto"
for pf in $pfiles
do
echo "Generating $pf..."