From fff3b6e8df7fa25ffed9a00c8158a69c94c1fab7 Mon Sep 17 00:00:00 2001 From: Blake McAnally Date: Mon, 15 Jul 2024 20:42:47 -0500 Subject: [PATCH 01/17] Update App Icon to support iOS 18 dark & tinted mode --- .../AppIcon.appiconset/Contents.json | 24 ++++++++++++++++++ .../AppIcon.appiconset/logo-dark.png | Bin 0 -> 29213 bytes .../AppIcon.appiconset/logo-tinted.png | Bin 0 -> 22823 bytes 3 files changed, 24 insertions(+) create mode 100644 Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-dark.png create mode 100644 Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-tinted.png diff --git a/Meshtastic/Assets.xcassets/AppIcon.appiconset/Contents.json b/Meshtastic/Assets.xcassets/AppIcon.appiconset/Contents.json index 937092d6..241cfb2b 100644 --- a/Meshtastic/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Meshtastic/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -5,6 +5,30 @@ "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "logo-dark.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "filename" : "logo-tinted.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" } ], "info" : { diff --git a/Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-dark.png b/Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..9942a312f00dac9ba4fca00c0a5a438bfb50a099 GIT binary patch literal 29213 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 &v&@NbnS~xqbjq9ajx-hVn2Ourc`KfnFBjh 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 D31RPq literal 0 HcmV?d00001 diff --git a/Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-tinted.png b/Meshtastic/Assets.xcassets/AppIcon.appiconset/logo-tinted.png new file mode 100644 index 0000000000000000000000000000000000000000..8591564379d0de5908f89c2e2f6d0a1b45d7f4f8 GIT binary patch literal 22823 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 Date: Tue, 3 Sep 2024 22:50:08 -0700 Subject: [PATCH 02/17] Actionable Notifs --- .../xcshareddata/swiftpm/Package.resolved | 4 +- Meshtastic/Helpers/BLEManager.swift | 12 ++-- .../Helpers/LocalNotificationManager.swift | 33 +++++++++ Meshtastic/Helpers/MeshPackets.swift | 44 +++++++----- Meshtastic/MeshtasticAppDelegate.swift | 68 +++++++++++++++++-- 5 files changed, 132 insertions(+), 29 deletions(-) diff --git a/Meshtastic.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Meshtastic.xcworkspace/xcshareddata/swiftpm/Package.resolved index c47a9058..3465793d 100644 --- a/Meshtastic.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Meshtastic.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -42,8 +42,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "d57a5aecf24a25b32ec4a74be2f5d0a995a47c4b", - "version" : "1.27.0" + "revision" : "edb6ed4919f7756157fe02f2552b7e3850a538e5", + "version" : "1.28.1" } } ], diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 08b53801..71e78fc8 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -3299,7 +3299,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate // MARK: - CB Central Manager implmentation extension BLEManager: CBCentralManagerDelegate { - + // MARK: Bluetooth enabled/disabled func centralManagerDidUpdateState(_ central: CBCentralManager) { if central.state == CBManagerState.poweredOn { @@ -3309,9 +3309,9 @@ extension BLEManager: CBCentralManagerDelegate { } else { isSwitchedOn = false } - + var status = "" - + switch central.state { case .poweredOff: status = "BLE is powered off" @@ -3330,10 +3330,10 @@ extension BLEManager: CBCentralManagerDelegate { } Logger.services.info("📜 [BLE] Bluetooth status: \(status)") } - + // Called each time a peripheral is discovered func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { - + if self.automaticallyReconnect && peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" { self.connectTo(peripheral: peripheral) Logger.services.info("✅ [BLE] Reconnecting to prefered peripheral: \(peripheral.name ?? "Unknown", privacy: .public)") @@ -3341,7 +3341,7 @@ extension BLEManager: CBCentralManagerDelegate { let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String let device = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: name ?? "Unknown", shortName: "?", longName: name ?? "Unknown", firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral) let index = peripherals.map { $0.peripheral }.firstIndex(of: peripheral) - + if let peripheralIndex = index { peripherals[peripheralIndex] = device } else { diff --git a/Meshtastic/Helpers/LocalNotificationManager.swift b/Meshtastic/Helpers/LocalNotificationManager.swift index 3e41c8f3..1260f20c 100644 --- a/Meshtastic/Helpers/LocalNotificationManager.swift +++ b/Meshtastic/Helpers/LocalNotificationManager.swift @@ -5,6 +5,16 @@ import OSLog class LocalNotificationManager { var notifications = [Notification]() + + let thumbsUpAction = UNNotificationAction(identifier: "messageNotification.thumbsUpAction", title: + "👍 \(Tapbacks.thumbsUp.description)", options: []) + let thumbsDownAction = UNNotificationAction(identifier: "messageNotification.thumbsDownAction", title: + "👎 \(Tapbacks.thumbsDown.description)", options: []) + let replyInputAction = UNTextInputNotificationAction( + identifier: "messageNotification.replyInputAction", + title: "reply".localized, + options: []) + // Step 1 Request Permissions for notifications private func requestAuthorization() { @@ -31,6 +41,15 @@ class LocalNotificationManager { // This function iterates over the Notification objects in the notifications array and schedules them for delivery in the future private func scheduleNotifications() { + let messageNotificationCategory = UNNotificationCategory( + identifier: "messageNotificationCategory", + actions: [thumbsUpAction, thumbsDownAction,replyInputAction], + intentIdentifiers: [], + options: .customDismissAction + ) + + UNUserNotificationCenter.current().setNotificationCategories([messageNotificationCategory]) + for notification in notifications { let content = UNMutableNotificationContent() content.subtitle = notification.subtitle @@ -45,6 +64,17 @@ class LocalNotificationManager { if notification.path != nil { content.userInfo["path"] = notification.path } + if notification.messageId != nil { + content.categoryIdentifier = "messageNotificationCategory" + content.userInfo["messageId"] = notification.messageId + } + if notification.channel != nil { + content.userInfo["channel"] = notification.channel + } + if notification.userNum != nil { + content.userInfo["userNum"] = notification.userNum + } + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) let request = UNNotificationRequest(identifier: notification.id, content: content, trigger: trigger) @@ -76,4 +106,7 @@ struct Notification { var content: String var target: String? var path: String? + var messageId: Int64? + var channel: Int32? + var userNum: Int64? } diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index efd80d72..a41fec2d 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -815,12 +815,10 @@ func textMessageAppPacket( context: NSManagedObjectContext, appState: AppState ) { - var messageText = String(bytes: packet.decoded.payload, encoding: .utf8) let rangeRef = Reference(Int.self) let rangeTestRegex = Regex { "seq " - TryCapture(as: rangeRef) { OneOrMore(.digit) } transform: { match in @@ -828,7 +826,7 @@ func textMessageAppPacket( } } let rangeTest = messageText?.contains(rangeTestRegex) ?? false && messageText?.starts(with: "seq ") ?? false - + if !wantRangeTestPackets && rangeTest { return } @@ -841,15 +839,16 @@ func textMessageAppPacket( } } } - + if messageText?.count ?? 0 > 0 { - MeshLogger.log("💬 \("mesh.log.textmessage.received".localized)") - + let messageUsers = UserEntity.fetchRequest() messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from]) + do { let fetchedUsers = try context.fetch(messageUsers) + let newMessage = MessageEntity(context: context) newMessage.messageId = Int64(packet.id) if packet.rxTime > 0 { @@ -865,54 +864,60 @@ func textMessageAppPacket( newMessage.portNum = Int32(packet.decoded.portnum.rawValue) newMessage.publicKey = packet.publicKey newMessage.pkiEncrypted = packet.pkiEncrypted + if packet.decoded.portnum == PortNum.detectionSensorApp { if !UserDefaults.enableDetectionNotifications { newMessage.read = true } } + if packet.decoded.replyID > 0 { newMessage.replyID = Int64(packet.decoded.replyID) } - + if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != Constants.maximumNodeNum { if !storeForwardBroadcast { newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to }) } } + if fetchedUsers.first(where: { $0.num == packet.from }) != nil { newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) + if !(newMessage.fromUser?.publicKey?.isEmpty ?? true) { - /// We have a key, check if it matches + // We have a key, check if it matches if newMessage.fromUser?.publicKey != newMessage.publicKey { newMessage.fromUser?.keyMatch = false newMessage.fromUser?.newPublicKey = newMessage.publicKey } } else { - /// We have no key, set it + // We have no key, set it newMessage.fromUser?.publicKey = packet.publicKey newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted } + if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) } else { newMessage.fromUser?.userNode?.lastHeard = Date() } } + newMessage.messagePayload = messageText newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText!) + if packet.to != Constants.maximumNodeNum && newMessage.fromUser != nil { newMessage.fromUser?.lastMessage = Date() } + var messageSaved = false - + do { - try context.save() Logger.data.info("💾 Saved a new message for \(newMessage.messageId)") messageSaved = true if messageSaved { - if packet.decoded.portnum == PortNum.detectionSensorApp && !UserDefaults.enableDetectionNotifications { return } @@ -931,14 +936,16 @@ func textMessageAppPacket( subtitle: "AKA \(newMessage.fromUser?.shortName ?? "?")", content: messageText!, target: "messages", - path: "meshtastic:///messages?userNum=\(newMessage.fromUser?.num ?? 0)&messageId=\(newMessage.messageId)" + path: "meshtastic:///messages?userNum=\(newMessage.fromUser?.num ?? 0)&messageId=\(newMessage.messageId)", + messageId: newMessage.messageId, + channel: newMessage.channel, + userNum: Int64(packet.from) ) ] manager.schedule() Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)") } } else if newMessage.fromUser != nil && newMessage.toUser == nil { - let fetchMyInfoRequest = MyInfoEntity.fetchRequest() fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode)) @@ -961,7 +968,11 @@ func textMessageAppPacket( subtitle: "AKA \(newMessage.fromUser?.shortName ?? "?")", content: messageText!, target: "messages", - path: "meshtastic:///messages?channelId=\(newMessage.channel)&messageId=\(newMessage.messageId)") + path: "meshtastic:///messages?channelId=\(newMessage.channel)&messageId=\(newMessage.messageId)", + messageId: newMessage.messageId, + channel: newMessage.channel, + userNum: Int64(newMessage.fromUser?.userId ?? "0") + ) ] manager.schedule() Logger.services.debug("iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)") @@ -969,7 +980,7 @@ func textMessageAppPacket( } } } catch { - + // Handle error } } } @@ -984,6 +995,7 @@ func textMessageAppPacket( } } + func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.waypoint.received %@".localized, String(packet.from)) diff --git a/Meshtastic/MeshtasticAppDelegate.swift b/Meshtastic/MeshtasticAppDelegate.swift index 06d290e9..d38557bc 100644 --- a/Meshtastic/MeshtasticAppDelegate.swift +++ b/Meshtastic/MeshtasticAppDelegate.swift @@ -9,9 +9,9 @@ import SwiftUI import OSLog class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject { - + var router: Router? - + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { Logger.services.info("🚀 [App] Meshtstic Apple App launched!") // Default User Default Values @@ -22,7 +22,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat if #available(iOS 17.0, macOS 14.0, *) { let locationsHandler = LocationsHandler.shared locationsHandler.startLocationUpdates() - + // If a background activity session was previously active, reinstantiate it after the background launch. if locationsHandler.backgroundActivity { locationsHandler.backgroundActivity = true @@ -38,7 +38,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat ) { completionHandler([.list, .banner, .sound]) } - + // This method is called when a user clicks on the notification func userNotificationCenter( _ center: UNUserNotificationCenter, @@ -46,6 +46,64 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat withCompletionHandler completionHandler: @escaping () -> Void ) { let userInfo = response.notification.request.content.userInfo + + switch response.actionIdentifier { + case UNNotificationDefaultActionIdentifier: + break + + case "messageNotification.thumbsUpAction": + if let channel = userInfo["channel"] as? Int32, + let replyID = userInfo["messageId"] as? Int64 { + let tapbackResponse = !BLEManager.shared.sendMessage( + message: Tapbacks.thumbsUp.emojiString, + toUserNum: userInfo["userNum"] as? Int64 ?? 0, + channel: channel, + isEmoji: true, + replyID: replyID + ) + Logger.services.info("Tapback response sent") + } else { + Logger.services.error("Failed to retrieve channel or messageId from userInfo") + } + break + + case "messageNotification.thumbsDownAction": + if let channel = userInfo["channel"] as? Int32, + let replyID = userInfo["messageId"] as? Int64 { + let tapbackResponse = !BLEManager.shared.sendMessage( + message: Tapbacks.thumbsDown.emojiString, + toUserNum: userInfo["userNum"] as? Int64 ?? 0, + channel: channel, + isEmoji: true, + replyID: replyID + ) + Logger.services.info("Tapback response sent") + } else { + Logger.services.error("Failed to retrieve channel or messageId from userInfo") + } + break + + case "messageNotification.replyInputAction": + if let userInput = (response as? UNTextInputNotificationResponse)?.userText, + let channel = userInfo["channel"] as? Int32, + let replyID = userInfo["messageId"] as? Int64 { + let tapbackResponse = !BLEManager.shared.sendMessage( + message: userInput, + toUserNum: userInfo["userNum"] as? Int64 ?? 0, + channel: channel, + isEmoji: false, + replyID: replyID + ) + Logger.services.info("Actionable notification reply sent") + } else { + Logger.services.error("Failed to retrieve user input, channel, or messageId from userInfo") + } + break + + default: + break + } + if let targetValue = userInfo["target"] as? String, let deepLink = userInfo["path"] as? String, let url = URL(string: deepLink) { @@ -54,7 +112,7 @@ class MeshtasticAppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificat } else { Logger.services.error("Failed to handle notification response: \(userInfo)") } - + completionHandler() } } From 8954b21faa15b212e66350621e51f12eb89f428b Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 6 Sep 2024 09:21:40 -0700 Subject: [PATCH 03/17] stop unwrapping nuilable positon --- Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift index 7906f8b5..14df3986 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift @@ -130,7 +130,9 @@ struct NodeMapSwiftUI: View { if node.positions?.count ?? 0 > 1 { position = .automatic } else { - position = .camera(MapCamera(centerCoordinate: mostRecent!.coordinate, distance: 8000, heading: 0, pitch: 60)) + if let mr = mostRecent?.coordinate { + position = .camera(MapCamera(centerCoordinate: mr.coordinate, distance: 8000, heading: 0, pitch: 60)) + } } if self.scene == nil { Task { From 10751e374cffe21ae9f2c574ea08117ea2cbcd10 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 6 Sep 2024 09:23:54 -0700 Subject: [PATCH 04/17] Dont be dumb --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 43f27393..1e63593b 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1686,7 +1686,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1721,7 +1721,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1753,7 +1753,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1786,7 +1786,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.3; + MARKETING_VERSION = 2.5.4; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift index 14df3986..340117ac 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/NodeMapSwiftUI.swift @@ -130,8 +130,8 @@ struct NodeMapSwiftUI: View { if node.positions?.count ?? 0 > 1 { position = .automatic } else { - if let mr = mostRecent?.coordinate { - position = .camera(MapCamera(centerCoordinate: mr.coordinate, distance: 8000, heading: 0, pitch: 60)) + if let mrCoord = mostRecent?.coordinate { + position = .camera(MapCamera(centerCoordinate: mrCoord, distance: 8000, heading: 0, pitch: 60)) } } if self.scene == nil { From 4f813c12d335db38de58dbdc6e600e2290ea7eab Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 6 Sep 2024 17:05:25 -0700 Subject: [PATCH 05/17] Clean up precision ranges for locations on the map report and public key --- Meshtastic/Views/Messages/UserList.swift | 46 +++++++++++++----- Meshtastic/Views/Settings/Channels.swift | 6 +-- .../Views/Settings/Channels/ChannelForm.swift | 2 +- .../Settings/Config/Module/MQTTConfig.swift | 48 ++++++------------- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 4e09859f..4db57180 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -35,7 +35,6 @@ struct UserList: View { var boolFilters: [Bool] {[ isFavorite, isOnline, - isPkiEncrypted, isEnvironment, distanceFilter, roleFilter @@ -45,11 +44,12 @@ struct UserList: View { sortDescriptors: [NSSortDescriptor(key: "lastMessage", ascending: false), NSSortDescriptor(key: "userNode.favorite", ascending: false), NSSortDescriptor(key: "pkiEncrypted", ascending: false), + NSSortDescriptor(key: "userNode.lastHeard", ascending: false), NSSortDescriptor(key: "longName", ascending: true)], - predicate: NSPredicate(format: "hwModelId != nil"), + predicate: NSPredicate(format: "longName != ''"), animation: .default ) - private var users: FetchedResults + var users: FetchedResults @Binding var node: NodeInfoEntity? @Binding var userSelection: UserEntity? @@ -202,34 +202,55 @@ struct UserList: View { DirectMessagesHelp() } .onChange(of: searchText) { _ in - searchUserList() + Task { + await searchUserList() + } } .onChange(of: viaLora) { _ in if !viaLora && !viaMqtt { viaMqtt = true } - searchUserList() + Task { + await searchUserList() + } } .onChange(of: viaMqtt) { _ in if !viaLora && !viaMqtt { viaLora = true } - searchUserList() + Task { + await searchUserList() + } } .onChange(of: [deviceRoles]) { _ in - searchUserList() + Task { + await searchUserList() + } } .onChange(of: hopsAway) { _ in - searchUserList() + Task { + await searchUserList() + } } .onChange(of: [boolFilters]) { _ in - searchUserList() + Task { + await searchUserList() + } } .onChange(of: maxDistance) { _ in - searchUserList() + Task { + await searchUserList() + } + } + .onChange(of: isPkiEncrypted) { _ in + Task { + await searchUserList() + } } .onAppear { - searchUserList() + Task { + await searchUserList() + } } .safeAreaInset(edge: .bottom, alignment: .leading) { HStack { @@ -267,8 +288,7 @@ struct UserList: View { .scrollDismissesKeyboard(.immediately) } } - - private func searchUserList() { + private func searchUserList() async { /// Case Insensitive Search Text Predicates let searchPredicates = ["userId", "numString", "hwModel", "hwDisplayName", "longName", "shortName"].map { property in diff --git a/Meshtastic/Views/Settings/Channels.swift b/Meshtastic/Views/Settings/Channels.swift index f039534c..ca55b95d 100644 --- a/Meshtastic/Views/Settings/Channels.swift +++ b/Meshtastic/Views/Settings/Channels.swift @@ -93,7 +93,7 @@ struct Channels: View { preciseLocation = true positionsEnabled = true if channelKey == "AQ==" { - positionPrecision = 13 + positionPrecision = 14 preciseLocation = false } } else if !supportedVersion && channelRole == 2 { @@ -103,8 +103,8 @@ struct Channels: View { } else { if channelKey == "AQ==" { preciseLocation = false - if (positionPrecision > 0 && positionPrecision < 10) || positionPrecision > 16 { - positionPrecision = 13 + if (positionPrecision > 0 && positionPrecision < 11) || positionPrecision > 14 { + positionPrecision = 14 } } else if positionPrecision == 32 { preciseLocation = true diff --git a/Meshtastic/Views/Settings/Channels/ChannelForm.swift b/Meshtastic/Views/Settings/Channels/ChannelForm.swift index d21e0f42..51cb8dfc 100644 --- a/Meshtastic/Views/Settings/Channels/ChannelForm.swift +++ b/Meshtastic/Views/Settings/Channels/ChannelForm.swift @@ -158,7 +158,7 @@ struct ChannelForm: View { VStack(alignment: .leading) { Label("Approximate Location", systemImage: "location.slash.circle.fill") - Slider(value: $positionPrecision, in: 10...16, step: 1) { + Slider(value: $positionPrecision, in: 11...14, step: 1) { } minimumValueLabel: { Image(systemName: "minus") } maximumValueLabel: { diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index d6cbbf2b..0caf3625 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -32,7 +32,6 @@ struct MQTTConfig: View { @State var nearbyTopics = [String]() @State var mapReportingEnabled = false @State var mapPublishIntervalSecs = 3600 - @State var preciseLocation: Bool = false @State var mapPositionPrecision: Double = 13.0 let locale = Locale.current @@ -105,35 +104,17 @@ struct MQTTConfig: View { } } .pickerStyle(DefaultPickerStyle()) - VStack(alignment: .leading) { - Toggle(isOn: $preciseLocation) { - Label("Precise Location", systemImage: "scope") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - .listRowSeparator(.visible) - .onChange(of: preciseLocation) { pl in - if pl == false { - mapPositionPrecision = 12 - } else { - mapPositionPrecision = 32 - } - } - } - - if !preciseLocation { - VStack(alignment: .leading) { - Label("Approximate Location", systemImage: "location.slash.circle.fill") - Slider(value: $mapPositionPrecision, in: 11...16, step: 1) { - } minimumValueLabel: { - Image(systemName: "minus") - } maximumValueLabel: { - Image(systemName: "plus") - } - Text(PositionPrecision(rawValue: Int(mapPositionPrecision))?.description ?? "") - .foregroundColor(.gray) - .font(.callout) + Label("Approximate Location", systemImage: "location.slash.circle.fill") + Slider(value: $mapPositionPrecision, in: 11...14, step: 1) { + } minimumValueLabel: { + Image(systemName: "minus") + } maximumValueLabel: { + Image(systemName: "plus") } + Text(PositionPrecision(rawValue: Int(mapPositionPrecision))?.description ?? "") + .foregroundColor(.gray) + .font(.callout) } } } @@ -429,11 +410,12 @@ struct MQTTConfig: View { self.mqttConnected = bleManager.mqttProxyConnected self.mapReportingEnabled = node?.mqttConfig?.mapReportingEnabled ?? false self.mapPublishIntervalSecs = Int(node?.mqttConfig?.mapPublishIntervalSecs ?? 3600) - self.mapPositionPrecision = Double(node?.mqttConfig?.mapPositionPrecision ?? 12) - if mapPositionPrecision == 0.0 { - self.mapPositionPrecision = 12 + self.mapPositionPrecision = Double(node?.mqttConfig?.mapPositionPrecision ?? 14) + if mapPositionPrecision < 11 || mapPositionPrecision > 14 { + self.mapPositionPrecision = 14 + self.hasChanges = true + } else { + self.hasChanges = false } - self.preciseLocation = mapPositionPrecision == 32 - self.hasChanges = false } } From adab69dab7adcdbb19f7e117e3669d724e9cf3e7 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 8 Sep 2024 11:10:58 -0700 Subject: [PATCH 06/17] Default precision of 14 --- Meshtastic/Views/Settings/Channels/ChannelForm.swift | 6 +++--- Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Views/Settings/Channels/ChannelForm.swift b/Meshtastic/Views/Settings/Channels/ChannelForm.swift index 51cb8dfc..e4930b7a 100644 --- a/Meshtastic/Views/Settings/Channels/ChannelForm.swift +++ b/Meshtastic/Views/Settings/Channels/ChannelForm.swift @@ -149,7 +149,7 @@ struct ChannelForm: View { .listRowSeparator(.visible) .onChange(of: preciseLocation) { pl in if pl == false { - positionPrecision = 13 + positionPrecision = 14 } } } @@ -220,7 +220,7 @@ struct ChannelForm: View { } positionPrecision = 32 } else { - positionPrecision = 13 + positionPrecision = 14 } hasChanges = true } @@ -230,7 +230,7 @@ struct ChannelForm: View { .onChange(of: positionsEnabled) { pe in if pe { if positionPrecision == 0 { - positionPrecision = 13 + positionPrecision = 14 } } else { positionPrecision = 0 diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 0caf3625..1996c744 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -32,7 +32,7 @@ struct MQTTConfig: View { @State var nearbyTopics = [String]() @State var mapReportingEnabled = false @State var mapPublishIntervalSecs = 3600 - @State var mapPositionPrecision: Double = 13.0 + @State var mapPositionPrecision: Double = 14.0 let locale = Locale.current From 374924eb8229bcbd5cca64e471bd99586129acdc Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 8 Sep 2024 12:56:52 -0700 Subject: [PATCH 07/17] Clean up the live activity --- Widgets/WidgetsLiveActivity.swift | 53 ++++++++++++++----------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/Widgets/WidgetsLiveActivity.swift b/Widgets/WidgetsLiveActivity.swift index e6177129..e574b642 100644 --- a/Widgets/WidgetsLiveActivity.swift +++ b/Widgets/WidgetsLiveActivity.swift @@ -38,7 +38,7 @@ struct WidgetsLiveActivity: Widget { .fixedSize() Spacer() } - if context.state.nodesOnline >= 100 { + if context.state.totalNodes >= 100 { Text("100+ online") .font(.caption) .foregroundStyle(.secondary) @@ -81,7 +81,7 @@ struct WidgetsLiveActivity: Widget { .font(.caption) .foregroundStyle(.secondary) .fixedSize() - Text("Bad \(context.state.badReceivedPackets)") + Text("Bad: \(context.state.badReceivedPackets)") .font(.caption) .foregroundStyle(.secondary) .fixedSize() @@ -97,7 +97,7 @@ struct WidgetsLiveActivity: Widget { } compactLeading: { Image("m-logo-black") .resizable() - .frame(width: 30.0) + .frame(width: 25) .padding(4) .background(.green.gradient, in: ContainerRelativeShape()) } compactTrailing: { @@ -120,26 +120,25 @@ struct WidgetsLiveActivity: Widget { } } -//struct WidgetsLiveActivity_Previews: PreviewProvider { -// static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "RAK Compact Rotary Handset Gray 8E6G") -// static let state = MeshActivityAttributes.ContentState( -// timerRange: Date.now...Date(timeIntervalSinceNow: 60), connected: true, channelUtilization: 25.84, airtime: 10.01, batteryLevel: 39, nodes: 17, nodesOnline: 9) -// -// static var previews: some View { -// attributes -// .previewContext(state, viewKind: .dynamicIsland(.compact)) -// .previewDisplayName("Compact") -// attributes -// .previewContext(state, viewKind: .dynamicIsland(.minimal)) -// .previewDisplayName("Minimal") -// attributes -// .previewContext(state, viewKind: .dynamicIsland(.expanded)) -// .previewDisplayName("Expanded") -// attributes -// .previewContext(state, viewKind: .content) -// .previewDisplayName("Notification") -// } -//} +struct WidgetsLiveActivity_Previews: PreviewProvider { + static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "RAK Compact Rotary Handset Gray 8E6G") + static let state = MeshActivityAttributes.ContentState(uptimeSeconds: 600, channelUtilization: 1.2, airtime: 3.5, sentPackets: 12587, receivedPackets: 12555, badReceivedPackets: 800, nodesOnline: 99, totalNodes: 100, timerRange: Date.now...Date(timeIntervalSinceNow: 300)) + + static var previews: some View { + attributes + .previewContext(state, viewKind: .dynamicIsland(.compact)) + .previewDisplayName("Compact") + attributes + .previewContext(state, viewKind: .dynamicIsland(.minimal)) + .previewDisplayName("Minimal") + attributes + .previewContext(state, viewKind: .dynamicIsland(.expanded)) + .previewDisplayName("Expanded") + attributes + .previewContext(state, viewKind: .content) + .previewDisplayName("Notification") + } +} struct LiveActivityView: View { @Environment(\.colorScheme) private var colorScheme @@ -203,13 +202,7 @@ struct NodeInfoView: View { .foregroundStyle(.secondary) .opacity(isLuminanceReduced ? 0.8 : 1.0) .fixedSize() - Text("Packets Sent: \(sentPackets)") - .font(.caption) - .fontWeight(.medium) - .foregroundStyle(.secondary) - .opacity(isLuminanceReduced ? 0.8 : 1.0) - .fixedSize() - Text("Packets Received: \(receivedPackets)") + Text("Packets: Sent \(sentPackets) Rec. \(receivedPackets)") .font(.caption) .fontWeight(.medium) .foregroundStyle(.secondary) From f52a0918d04db07d9a39818b5aa63d6805fa64ed Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 8 Sep 2024 13:06:21 -0700 Subject: [PATCH 08/17] Add error rate to live activity --- Widgets/WidgetsLiveActivity.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Widgets/WidgetsLiveActivity.swift b/Widgets/WidgetsLiveActivity.swift index e574b642..7b9a9846 100644 --- a/Widgets/WidgetsLiveActivity.swift +++ b/Widgets/WidgetsLiveActivity.swift @@ -208,7 +208,8 @@ struct NodeInfoView: View { .foregroundStyle(.secondary) .opacity(isLuminanceReduced ? 0.8 : 1.0) .fixedSize() - Text("Bad Packets: \(badReceivedPackets)") + let errorRate = (Double(badReceivedPackets) / Double(receivedPackets)) * 100 + Text("Bad: \(badReceivedPackets) \(String(format: "Error Rate: %.2f", errorRate))%") .font(.caption) .fontWeight(.medium) .foregroundStyle(.secondary) From 050a02712de9e9e6953e0dc4014a1af573db0529 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 9 Sep 2024 11:38:07 -0700 Subject: [PATCH 09/17] Merge from main --- protobufs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobufs b/protobufs index b6237629..4da558d0 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit b623762940ebdb1887a3b31b86f4d9cdaa7e6ecf +Subproject commit 4da558d0f73c46ef91b74431facee73c09affbfc From 2daf3e353622480dd56faed0626a8bfe8b3b9377 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 10 Sep 2024 15:05:13 -0700 Subject: [PATCH 10/17] Fix incoming keys --- Localizable.xcstrings | 28 +++++++++++++++------ Meshtastic/Helpers/MeshPackets.swift | 14 +++++++---- Meshtastic/Persistence/UpdateCoreData.swift | 21 ++++++++++------ Meshtastic/Views/Bluetooth/Connect.swift | 19 ++++++++------ Widgets/WidgetsLiveActivity.swift | 2 +- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 05c2bbb8..b447989f 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -1429,8 +1429,15 @@ "Bad" : { }, - "Bad Packets: %d" : { - + "Bad Packets: %d %@%%" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Bad Packets: %1$d %2$@%%" + } + } + } }, "Bandwidth" : { @@ -16079,11 +16086,15 @@ "Override automatic OLED screen detection." : { }, - "Packets Received: %d" : { - - }, - "Packets Sent: %d" : { - + "Packets: Sent: %d Received: %d" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Packets: Sent: %1$d Received: %2$d" + } + } + } }, "password" : { "localizations" : { @@ -22314,6 +22325,9 @@ } } } + }, + "Uptime: %@" : { + }, "Use a PWM output (like the RAK Buzzer) for tunes instead of an on/off output. This will ignore the output, output duration and active settings and use the device config buzzer GPIO option instead." : { diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 3b6b2b65..d9801699 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -864,8 +864,10 @@ func textMessageAppPacket( newMessage.isEmoji = packet.decoded.emoji == 1 newMessage.channel = Int32(packet.channel) newMessage.portNum = Int32(packet.decoded.portnum.rawValue) - newMessage.publicKey = packet.publicKey - newMessage.pkiEncrypted = packet.pkiEncrypted + if newMessage.toUser?.pkiEncrypted ?? false { + newMessage.pkiEncrypted = true + newMessage.publicKey = packet.publicKey + } if packet.decoded.portnum == PortNum.detectionSensorApp { if !UserDefaults.enableDetectionNotifications { newMessage.read = true @@ -889,9 +891,11 @@ func textMessageAppPacket( newMessage.fromUser?.newPublicKey = newMessage.publicKey } } else { - /// We have no key, set it - newMessage.fromUser?.publicKey = packet.publicKey - newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted + /// We have no key, set it if it is not empty + if !packet.publicKey.isEmpty { + newMessage.fromUser?.pkiEncrypted = true + newMessage.fromUser?.publicKey = packet.publicKey + } } if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 624dbb20..c1ee8470 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -181,8 +181,11 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) newUser.role = Int32(newUserMessage.role.rawValue) newUser.hwModel = String(describing: newUserMessage.hwModel).uppercased() newUser.hwModelId = Int32(newUserMessage.hwModel.rawValue) - newUser.pkiEncrypted = packet.pkiEncrypted - newUser.publicKey = packet.publicKey + if !newUserMessage.publicKey.isEmpty { + newUser.pkiEncrypted = true + newUser.publicKey = newUserMessage.publicKey + } + Task { Api().loadDeviceHardwareData { (hw) in let dh = hw.first(where: { $0.hwModel == newUser.hwModelId }) @@ -209,8 +212,10 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) } else { if packet.from > Constants.minimumNodeNum { let newUser = createUser(num: Int64(packet.from), context: context) - newNode.user?.pkiEncrypted = packet.pkiEncrypted - newNode.user?.publicKey = packet.publicKey + if !packet.publicKey.isEmpty { + newNode.user?.pkiEncrypted = true + newNode.user?.publicKey = packet.publicKey + } newNode.user = newUser } } @@ -224,6 +229,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) myInfoEntity.rebootCount = 0 do { try context.save() + Logger.data.info("💾 [NodeInfo] Saved a NodeInfo for node number: \(packet.from.toHex(), privacy: .public)") Logger.data.info("💾 [MyInfoEntity] Saved a new myInfo for node number: \(packet.from.toHex(), privacy: .public)") } catch { context.rollback() @@ -271,10 +277,9 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) fetchedNode[0].user!.role = Int32(nodeInfoMessage.user.role.rawValue) fetchedNode[0].user!.hwModel = String(describing: nodeInfoMessage.user.hwModel).uppercased() fetchedNode[0].user!.hwModelId = Int32(nodeInfoMessage.user.hwModel.rawValue) - - if !packet.publicKey.isEmpty { - fetchedNode[0].user!.pkiEncrypted = packet.pkiEncrypted - fetchedNode[0].user!.publicKey = packet.publicKey + if !nodeInfoMessage.user.publicKey.isEmpty { + fetchedNode[0].user!.pkiEncrypted = true + fetchedNode[0].user!.publicKey = nodeInfoMessage.user.publicKey } Task { Api().loadDeviceHardwareData { (hw) in diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 2a1eea84..3fdab7fd 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -92,6 +92,7 @@ struct Connect: View { } VStack { let localStats = node?.telemetries?.filtered(using: NSPredicate(format: "metricsType == 6")).lastObject as? TelemetryEntity + if localStats != nil { Divider() if localStats?.numTotalNodes ?? 0 >= 100 { @@ -111,25 +112,29 @@ struct Connect: View { .font(.caption) .fontWeight(.medium) .foregroundStyle(.secondary) - Text("Packets Sent: \(localStats?.numPacketsTx ?? 0)") + Text("Packets: Sent: \(localStats?.numPacketsTx ?? 0) Received: \(localStats?.numPacketsRx ?? 0)") .font(.caption) .fontWeight(.medium) .foregroundStyle(.secondary) - Text("Packets Received: \(localStats?.numPacketsRx ?? 0)") - .font(.caption) - .fontWeight(.medium) - .foregroundStyle(.secondary) - Text("Bad Packets: \(localStats?.numPacketsRxBad ?? 0)") + let errorRate = (Double(localStats?.numPacketsRxBad ?? -1) / Double(localStats?.numPacketsRx ?? -1)) * 100 + Text("Bad Packets: \(localStats?.numPacketsRxBad ?? 0) \(String(format: "Error Rate: %.2f", errorRate))%") .font(.caption) .fontWeight(.medium) .foregroundStyle(.secondary) .fixedSize() + let now = Date.now + let later = now + TimeInterval(Double(localStats?.numPacketsRxBad ?? 0)) + let uptime = (now.. var body: some View { + let errorRate = (Double(badReceivedPackets) / Double(receivedPackets)) * 100 VStack(alignment: .leading, spacing: 0) { Text(nodeName) .font(nodeName.count > 14 ? .callout : .title3) @@ -208,7 +209,6 @@ struct NodeInfoView: View { .foregroundStyle(.secondary) .opacity(isLuminanceReduced ? 0.8 : 1.0) .fixedSize() - let errorRate = (Double(badReceivedPackets) / Double(receivedPackets)) * 100 Text("Bad: \(badReceivedPackets) \(String(format: "Error Rate: %.2f", errorRate))%") .font(.caption) .fontWeight(.medium) From 68475b0fef1e48ef49743c08e7c68e814a11282e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 12 Sep 2024 12:11:42 -0500 Subject: [PATCH 11/17] Update protos --- .../Sources/meshtastic/admin.pb.swift | 276 ++------- .../Sources/meshtastic/apponly.pb.swift | 6 +- .../Sources/meshtastic/atak.pb.swift | 64 +- .../meshtastic/cannedmessages.pb.swift | 6 +- .../Sources/meshtastic/channel.pb.swift | 37 +- .../Sources/meshtastic/clientonly.pb.swift | 6 +- .../Sources/meshtastic/config.pb.swift | 555 ++++++++--------- .../meshtastic/connection_status.pb.swift | 21 +- .../Sources/meshtastic/deviceonly.pb.swift | 38 +- .../Sources/meshtastic/localonly.pb.swift | 9 +- .../Sources/meshtastic/mesh.pb.swift | 566 ++++++------------ .../Sources/meshtastic/module_config.pb.swift | 263 +++----- .../Sources/meshtastic/mqtt.pb.swift | 9 +- .../Sources/meshtastic/paxcount.pb.swift | 6 +- .../Sources/meshtastic/portnums.pb.swift | 14 +- .../Sources/meshtastic/powermon.pb.swift | 115 ++-- .../meshtastic/remote_hardware.pb.swift | 35 +- .../Sources/meshtastic/rtttl.pb.swift | 6 +- .../Sources/meshtastic/storeforward.pb.swift | 93 +-- .../Sources/meshtastic/telemetry.pb.swift | 82 +-- .../Sources/meshtastic/xmodem.pb.swift | 39 +- protobufs | 2 +- 22 files changed, 731 insertions(+), 1517 deletions(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 0f1c3586..d9ecbe22 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -24,7 +24,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /// This message is used to do settings operations to both remote AND local nodes. /// (Prior to 1.2 these operations were done via special ToRadio operations) -public struct AdminMessage { +public struct AdminMessage: @unchecked Sendable { // 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. @@ -483,7 +483,7 @@ public struct AdminMessage { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send the specified channel in the response to this message /// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) @@ -624,193 +624,11 @@ public struct AdminMessage { /// Tell the node to reset the nodedb. case nodedbReset(Int32) - #if !swift(>=4.1) - public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.getChannelRequest, .getChannelRequest): return { - guard case .getChannelRequest(let l) = lhs, case .getChannelRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getChannelResponse, .getChannelResponse): return { - guard case .getChannelResponse(let l) = lhs, case .getChannelResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerRequest, .getOwnerRequest): return { - guard case .getOwnerRequest(let l) = lhs, case .getOwnerRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerResponse, .getOwnerResponse): return { - guard case .getOwnerResponse(let l) = lhs, case .getOwnerResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigRequest, .getConfigRequest): return { - guard case .getConfigRequest(let l) = lhs, case .getConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigResponse, .getConfigResponse): return { - guard case .getConfigResponse(let l) = lhs, case .getConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigRequest, .getModuleConfigRequest): return { - guard case .getModuleConfigRequest(let l) = lhs, case .getModuleConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigResponse, .getModuleConfigResponse): return { - guard case .getModuleConfigResponse(let l) = lhs, case .getModuleConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesRequest, .getCannedMessageModuleMessagesRequest): return { - guard case .getCannedMessageModuleMessagesRequest(let l) = lhs, case .getCannedMessageModuleMessagesRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesResponse, .getCannedMessageModuleMessagesResponse): return { - guard case .getCannedMessageModuleMessagesResponse(let l) = lhs, case .getCannedMessageModuleMessagesResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataRequest, .getDeviceMetadataRequest): return { - guard case .getDeviceMetadataRequest(let l) = lhs, case .getDeviceMetadataRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataResponse, .getDeviceMetadataResponse): return { - guard case .getDeviceMetadataResponse(let l) = lhs, case .getDeviceMetadataResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneRequest, .getRingtoneRequest): return { - guard case .getRingtoneRequest(let l) = lhs, case .getRingtoneRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneResponse, .getRingtoneResponse): return { - guard case .getRingtoneResponse(let l) = lhs, case .getRingtoneResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusRequest, .getDeviceConnectionStatusRequest): return { - guard case .getDeviceConnectionStatusRequest(let l) = lhs, case .getDeviceConnectionStatusRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusResponse, .getDeviceConnectionStatusResponse): return { - guard case .getDeviceConnectionStatusResponse(let l) = lhs, case .getDeviceConnectionStatusResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setHamMode, .setHamMode): return { - guard case .setHamMode(let l) = lhs, case .setHamMode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsRequest, .getNodeRemoteHardwarePinsRequest): return { - guard case .getNodeRemoteHardwarePinsRequest(let l) = lhs, case .getNodeRemoteHardwarePinsRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsResponse, .getNodeRemoteHardwarePinsResponse): return { - guard case .getNodeRemoteHardwarePinsResponse(let l) = lhs, case .getNodeRemoteHardwarePinsResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.enterDfuModeRequest, .enterDfuModeRequest): return { - guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.deleteFileRequest, .deleteFileRequest): return { - guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setScale, .setScale): return { - guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setOwner, .setOwner): return { - guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setChannel, .setChannel): return { - guard case .setChannel(let l) = lhs, case .setChannel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setConfig, .setConfig): return { - guard case .setConfig(let l) = lhs, case .setConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setModuleConfig, .setModuleConfig): return { - guard case .setModuleConfig(let l) = lhs, case .setModuleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setCannedMessageModuleMessages, .setCannedMessageModuleMessages): return { - guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setRingtoneMessage, .setRingtoneMessage): return { - guard case .setRingtoneMessage(let l) = lhs, case .setRingtoneMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeByNodenum, .removeByNodenum): return { - guard case .removeByNodenum(let l) = lhs, case .removeByNodenum(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFavoriteNode, .setFavoriteNode): return { - guard case .setFavoriteNode(let l) = lhs, case .setFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFavoriteNode, .removeFavoriteNode): return { - guard case .removeFavoriteNode(let l) = lhs, case .removeFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFixedPosition, .setFixedPosition): return { - guard case .setFixedPosition(let l) = lhs, case .setFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFixedPosition, .removeFixedPosition): return { - guard case .removeFixedPosition(let l) = lhs, case .removeFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setTimeOnly, .setTimeOnly): return { - guard case .setTimeOnly(let l) = lhs, case .setTimeOnly(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.beginEditSettings, .beginEditSettings): return { - guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.commitEditSettings, .commitEditSettings): return { - guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetDevice, .factoryResetDevice): return { - guard case .factoryResetDevice(let l) = lhs, case .factoryResetDevice(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootOtaSeconds, .rebootOtaSeconds): return { - guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.exitSimulator, .exitSimulator): return { - guard case .exitSimulator(let l) = lhs, case .exitSimulator(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootSeconds, .rebootSeconds): return { - guard case .rebootSeconds(let l) = lhs, case .rebootSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.shutdownSeconds, .shutdownSeconds): return { - guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetConfig, .factoryResetConfig): return { - guard case .factoryResetConfig(let l) = lhs, case .factoryResetConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodedbReset, .nodedbReset): return { - guard case .nodedbReset(let l) = lhs, case .nodedbReset(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// TODO: REPLACE - public enum ConfigType: SwiftProtobuf.Enum { + public enum ConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -844,6 +662,7 @@ public struct AdminMessage { /// /// TODO: REPLACE case securityConfig // = 7 + case sessionkeyConfig // = 8 case UNRECOGNIZED(Int) public init() { @@ -860,6 +679,7 @@ public struct AdminMessage { case 5: self = .loraConfig case 6: self = .bluetoothConfig case 7: self = .securityConfig + case 8: self = .sessionkeyConfig default: self = .UNRECOGNIZED(rawValue) } } @@ -874,15 +694,29 @@ public struct AdminMessage { case .loraConfig: return 5 case .bluetoothConfig: return 6 case .securityConfig: return 7 + case .sessionkeyConfig: return 8 case .UNRECOGNIZED(let i): return i } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ConfigType] = [ + .deviceConfig, + .positionConfig, + .powerConfig, + .networkConfig, + .displayConfig, + .loraConfig, + .bluetoothConfig, + .securityConfig, + .sessionkeyConfig, + ] + } /// /// TODO: REPLACE - public enum ModuleConfigType: SwiftProtobuf.Enum { + public enum ModuleConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -980,51 +814,31 @@ public struct AdminMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ModuleConfigType] = [ + .mqttConfig, + .serialConfig, + .extnotifConfig, + .storeforwardConfig, + .rangetestConfig, + .telemetryConfig, + .cannedmsgConfig, + .audioConfig, + .remotehardwareConfig, + .neighborinfoConfig, + .ambientlightingConfig, + .detectionsensorConfig, + .paxcounterConfig, + ] + } public init() {} } -#if swift(>=4.2) - -extension AdminMessage.ConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ConfigType] = [ - .deviceConfig, - .positionConfig, - .powerConfig, - .networkConfig, - .displayConfig, - .loraConfig, - .bluetoothConfig, - .securityConfig, - ] -} - -extension AdminMessage.ModuleConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ModuleConfigType] = [ - .mqttConfig, - .serialConfig, - .extnotifConfig, - .storeforwardConfig, - .rangetestConfig, - .telemetryConfig, - .cannedmsgConfig, - .audioConfig, - .remotehardwareConfig, - .neighborinfoConfig, - .ambientlightingConfig, - .detectionsensorConfig, - .paxcounterConfig, - ] -} - -#endif // swift(>=4.2) - /// /// Parameters for setting up Meshtastic for ameteur radio usage -public struct HamParameters { +public struct HamParameters: Sendable { // 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. @@ -1054,7 +868,7 @@ public struct HamParameters { /// /// Response envelope for node_remote_hardware_pins -public struct NodeRemoteHardwarePinsResponse { +public struct NodeRemoteHardwarePinsResponse: Sendable { // 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. @@ -1068,15 +882,6 @@ public struct NodeRemoteHardwarePinsResponse { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension AdminMessage: @unchecked Sendable {} -extension AdminMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension AdminMessage.ConfigType: @unchecked Sendable {} -extension AdminMessage.ModuleConfigType: @unchecked Sendable {} -extension HamParameters: @unchecked Sendable {} -extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1755,6 +1560,7 @@ extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding { 5: .same(proto: "LORA_CONFIG"), 6: .same(proto: "BLUETOOTH_CONFIG"), 7: .same(proto: "SECURITY_CONFIG"), + 8: .same(proto: "SESSIONKEY_CONFIG"), ] } @@ -1807,7 +1613,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 2) } - if self.frequency != 0 { + if self.frequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.frequency, fieldNumber: 3) } if !self.shortName.isEmpty { diff --git a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift index 0457077c..18e66d8e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift @@ -26,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// any SECONDARY channels. /// No DISABLED channels are included. /// This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL -public struct ChannelSet { +public struct ChannelSet: Sendable { // 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. @@ -53,10 +53,6 @@ public struct ChannelSet { fileprivate var _loraConfig: Config.LoRaConfig? = nil } -#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. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift index 4406deb3..1dd12469 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Team: SwiftProtobuf.Enum { +public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -130,11 +130,6 @@ public enum Team: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Team: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Team] = [ .unspecifedColor, @@ -153,13 +148,12 @@ extension Team: CaseIterable { .darkGreen, .brown, ] -} -#endif // swift(>=4.2) +} /// /// Role of the group member -public enum MemberRole: SwiftProtobuf.Enum { +public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -233,11 +227,6 @@ public enum MemberRole: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension MemberRole: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [MemberRole] = [ .unspecifed, @@ -250,13 +239,12 @@ extension MemberRole: CaseIterable { .rto, .k9, ] -} -#endif // swift(>=4.2) +} /// /// Packets for the official ATAK Plugin -public struct TAKPacket { +public struct TAKPacket: Sendable { // 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. @@ -326,7 +314,7 @@ public struct TAKPacket { /// /// The payload of the packet - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// TAK position report case pli(PLI) @@ -334,24 +322,6 @@ public struct TAKPacket { /// ATAK GeoChat message case chat(GeoChat) - #if !swift(>=4.1) - public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.pli, .pli): return { - guard case .pli(let l) = lhs, case .pli(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.chat, .chat): return { - guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -363,7 +333,7 @@ public struct TAKPacket { /// /// ATAK GeoChat message -public struct GeoChat { +public struct GeoChat: Sendable { // 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. @@ -405,7 +375,7 @@ public struct GeoChat { /// /// ATAK Group /// <__group role='Team Member' name='Cyan'/> -public struct Group { +public struct Group: Sendable { // 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. @@ -427,7 +397,7 @@ public struct Group { /// /// ATAK EUD Status /// -public struct Status { +public struct Status: Sendable { // 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. @@ -444,7 +414,7 @@ public struct Status { /// /// ATAK Contact /// -public struct Contact { +public struct Contact: Sendable { // 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. @@ -464,7 +434,7 @@ public struct Contact { /// /// Position Location Information from ATAK -public struct PLI { +public struct PLI: Sendable { // 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. @@ -496,18 +466,6 @@ public struct PLI { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Team: @unchecked Sendable {} -extension MemberRole: @unchecked Sendable {} -extension TAKPacket: @unchecked Sendable {} -extension TAKPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension GeoChat: @unchecked Sendable {} -extension Group: @unchecked Sendable {} -extension Status: @unchecked Sendable {} -extension Contact: @unchecked Sendable {} -extension PLI: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift index 1b8c84de..a43393e1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct CannedMessageModuleConfig { +public struct CannedMessageModuleConfig: Sendable { // 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. @@ -36,10 +36,6 @@ public struct CannedMessageModuleConfig { public 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. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift index 5b9c7e49..a8c96595 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift @@ -36,13 +36,15 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// FIXME: Add description of multi-channel support and how primary vs secondary channels are used. /// FIXME: explain how apps use channels for security. /// explain how remote settings and remote gpio are managed as an example -public struct ChannelSettings { +public struct ChannelSettings: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// Deprecated in favor of LoraConfig.channel_num + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var channelNum: UInt32 = 0 /// @@ -111,7 +113,7 @@ public struct ChannelSettings { /// /// This message is specifically for modules to store per-channel configuration data. -public struct ModuleSettings { +public struct ModuleSettings: Sendable { // 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. @@ -132,7 +134,7 @@ public struct ModuleSettings { /// /// A pair of a channel number, mode and the (sharable) settings for that channel -public struct Channel { +public struct Channel: Sendable { // 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. @@ -170,7 +172,7 @@ public struct Channel { /// cross band routing as needed. /// If a device has only a single radio (the common case) only one channel can be PRIMARY at a time /// (but any number of SECONDARY channels can't be sent received on that common frequency) - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -209,6 +211,13 @@ public struct Channel { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Channel.Role] = [ + .disabled, + .primary, + .secondary, + ] + } public init() {} @@ -216,26 +225,6 @@ public struct Channel { fileprivate var _settings: ChannelSettings? = nil } -#if swift(>=4.2) - -extension Channel.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Channel.Role] = [ - .disabled, - .primary, - .secondary, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension ChannelSettings: @unchecked Sendable {} -extension ModuleSettings: @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. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift index c3d93bf7..89370cc5 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift @@ -23,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This abstraction is used to contain any configuration for provisioning a node on any client. /// It is useful for importing and exporting configurations. -public struct DeviceProfile { +public struct DeviceProfile: Sendable { // 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. @@ -94,10 +94,6 @@ public struct DeviceProfile { fileprivate var _moduleConfig: LocalModuleConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceProfile: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index 4b953470..2bb116d3 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct Config { +public struct Config: Sendable { // 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. @@ -93,11 +93,19 @@ public struct Config { set {payloadVariant = .security(newValue)} } + public var sessionkey: Config.SessionkeyConfig { + get { + if case .sessionkey(let v)? = payloadVariant {return v} + return Config.SessionkeyConfig() + } + set {payloadVariant = .sessionkey(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() /// /// Payload Variant - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { case device(Config.DeviceConfig) case position(Config.PositionConfig) case power(Config.PowerConfig) @@ -106,54 +114,13 @@ public struct Config { case lora(Config.LoRaConfig) case bluetooth(Config.BluetoothConfig) case security(Config.SecurityConfig) + case sessionkey(Config.SessionkeyConfig) - #if !swift(>=4.1) - public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.device, .device): return { - guard case .device(let l) = lhs, case .device(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.position, .position): return { - guard case .position(let l) = lhs, case .position(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.power, .power): return { - guard case .power(let l) = lhs, case .power(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.network, .network): return { - guard case .network(let l) = lhs, case .network(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.display, .display): return { - guard case .display(let l) = lhs, case .display(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.lora, .lora): return { - guard case .lora(let l) = lhs, case .lora(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.bluetooth, .bluetooth): return { - guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.security, .security): return { - guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// Configuration - public struct DeviceConfig { + public struct DeviceConfig: Sendable { // 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. @@ -165,13 +132,9 @@ public struct Config { /// /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI /// Moved to SecurityConfig - public var serialEnabled: Bool = false - /// - /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - /// Set this to true to leave the debug log outputting even when API is active. - /// Moved to SecurityConfig - public var debugLogEnabled: Bool = false + /// NOTE: This field was marked as deprecated in the .proto file. + public var serialEnabled: Bool = false /// /// For boards without a hard wired button, this is the pin number that will be used @@ -200,6 +163,8 @@ public struct Config { /// If true, device is considered to be "managed" by a mesh administrator /// Clients should then limit available configuration and administrative options inside the user interface /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var isManaged: Bool = false /// @@ -218,7 +183,7 @@ public struct Config { /// /// Defines the device's role on the Mesh network - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -236,6 +201,8 @@ public struct Config { /// The wifi radio and the oled screen will be put to sleep. /// This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. case router // = 2 + + /// NOTE: This enum value was marked as deprecated in the .proto file case routerClient // = 3 /// @@ -326,11 +293,26 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.Role] = [ + .client, + .clientMute, + .router, + .routerClient, + .repeater, + .tracker, + .sensor, + .tak, + .clientHidden, + .lostAndFound, + .takTracker, + ] + } /// /// Defines the device's behavior for how messages are rebroadcast - public enum RebroadcastMode: SwiftProtobuf.Enum { + public enum RebroadcastMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -378,6 +360,14 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ + .all, + .allSkipDecoding, + .localOnly, + .knownOnly, + ] + } public init() {} @@ -385,7 +375,7 @@ public struct Config { /// /// Position Config - public struct PositionConfig { + public struct PositionConfig: Sendable { // 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. @@ -407,6 +397,8 @@ public struct Config { /// /// Is GPS enabled for this node? + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsEnabled: Bool = false /// @@ -417,6 +409,8 @@ public struct Config { /// /// Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsAttemptTime: UInt32 = 0 /// @@ -457,7 +451,7 @@ public struct Config { /// are always included (also time if GPS-synced) /// NOTE: the more fields are included, the larger the message will be - /// leading to longer airtime and a higher risk of packet loss - public enum PositionFlags: SwiftProtobuf.Enum { + public enum PositionFlags: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -547,9 +541,24 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.PositionFlags] = [ + .unset, + .altitude, + .altitudeMsl, + .geoidalSeparation, + .dop, + .hvdop, + .satinview, + .seqNo, + .timestamp, + .heading, + .speed, + ] + } - public enum GpsMode: SwiftProtobuf.Enum { + public enum GpsMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -587,6 +596,13 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.GpsMode] = [ + .disabled, + .enabled, + .notPresent, + ] + } public init() {} @@ -595,7 +611,7 @@ public struct Config { /// /// Power Config\ /// See [Power Config](/docs/settings/config/power) for additional power config details. - public struct PowerConfig { + public struct PowerConfig: Sendable { // 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. @@ -655,7 +671,7 @@ public struct Config { /// /// Network Config - public struct NetworkConfig { + public struct NetworkConfig: Sendable { // 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. @@ -702,7 +718,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum AddressMode: SwiftProtobuf.Enum { + public enum AddressMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -734,9 +750,15 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.NetworkConfig.AddressMode] = [ + .dhcp, + .static, + ] + } - public struct IpV4Config { + public struct IpV4Config: Sendable { // 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. @@ -769,7 +791,7 @@ public struct Config { /// /// Display Config - public struct DisplayConfig { + public struct DisplayConfig: Sendable { // 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. @@ -825,7 +847,7 @@ public struct Config { /// /// How the GPS coordinates are displayed on the OLED screen. - public enum GpsCoordinateFormat: SwiftProtobuf.Enum { + public enum GpsCoordinateFormat: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -888,11 +910,21 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ + .dec, + .dms, + .utm, + .mgrs, + .olc, + .osgr, + ] + } /// /// Unit display preference - public enum DisplayUnits: SwiftProtobuf.Enum { + public enum DisplayUnits: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -924,11 +956,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ + .metric, + .imperial, + ] + } /// /// Override OLED outo detect with this if it fails. - public enum OledType: SwiftProtobuf.Enum { + public enum OledType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -972,9 +1010,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.OledType] = [ + .oledAuto, + .oledSsd1306, + .oledSh1106, + .oledSh1107, + ] + } - public enum DisplayMode: SwiftProtobuf.Enum { + public enum DisplayMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1018,9 +1064,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayMode] = [ + .default, + .twocolor, + .inverted, + .color, + ] + } - public enum CompassOrientation: SwiftProtobuf.Enum { + public enum CompassOrientation: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1088,6 +1142,18 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ + .degrees0, + .degrees90, + .degrees180, + .degrees270, + .degrees0Inverted, + .degrees90Inverted, + .degrees180Inverted, + .degrees270Inverted, + ] + } public init() {} @@ -1095,7 +1161,7 @@ public struct Config { /// /// Lora Config - public struct LoRaConfig { + public struct LoRaConfig: @unchecked Sendable { // 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. @@ -1250,9 +1316,16 @@ public struct Config { set {_uniqueStorage()._ignoreMqtt = newValue} } + /// + /// Sets the ok_to_mqtt bit on outgoing packets + public var configOkToMqtt: Bool { + get {return _storage._configOkToMqtt} + set {_uniqueStorage()._configOkToMqtt = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum RegionCode: SwiftProtobuf.Enum { + public enum RegionCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1386,12 +1459,35 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.RegionCode] = [ + .unset, + .us, + .eu433, + .eu868, + .cn, + .jp, + .anz, + .kr, + .tw, + .ru, + .in, + .nz865, + .th, + .lora24, + .ua433, + .ua868, + .my433, + .my919, + .sg923, + ] + } /// /// Standard predefined channel settings /// Note: these mappings must match ModemPreset Choice in the device code. - public enum ModemPreset: SwiftProtobuf.Enum { + public enum ModemPreset: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1405,6 +1501,8 @@ public struct Config { /// /// Very Long Range - Slow /// Deprecated in 2.5: Works only with txco and is unusably slow + /// + /// NOTE: This enum value was marked as deprecated in the .proto file case veryLongSlow // = 2 /// @@ -1468,6 +1566,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.ModemPreset] = [ + .longFast, + .longSlow, + .veryLongSlow, + .mediumSlow, + .mediumFast, + .shortSlow, + .shortFast, + .longModerate, + .shortTurbo, + ] + } public init() {} @@ -1475,7 +1586,7 @@ public struct Config { fileprivate var _storage = _StorageClass.defaultInstance } - public struct BluetoothConfig { + public struct BluetoothConfig: Sendable { // 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. @@ -1492,14 +1603,9 @@ public struct Config { /// Specified PIN for PairingMode.FixedPin public var fixedPin: UInt32 = 0 - /// - /// Enables device (serial style logs) over Bluetooth - /// Moved to SecurityConfig - public var deviceLoggingEnabled: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum PairingMode: SwiftProtobuf.Enum { + public enum PairingMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1537,12 +1643,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.BluetoothConfig.PairingMode] = [ + .randomPin, + .fixedPin, + .noPin, + ] + } public init() {} } - public struct SecurityConfig { + public struct SecurityConfig: @unchecked Sendable { // 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. @@ -1559,7 +1672,7 @@ public struct Config { /// /// The public key authorized to send admin messages to this node. - public var adminKey: Data = Data() + public var adminKey: [Data] = [] /// /// If true, device is considered to be "managed" by a mesh administrator via admin messages @@ -1572,13 +1685,9 @@ public struct Config { /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - /// Output live debug logging over serial. + /// Output live debug logging over serial or bluetooth is set to true. public var debugLogApiEnabled: Bool = false - /// - /// Enables device (serial style logs) over Bluetooth - public var bluetoothLoggingEnabled: Bool = false - /// /// Allow incoming device control over the insecure legacy admin channel. public var adminChannelEnabled: Bool = false @@ -1588,204 +1697,21 @@ public struct Config { public init() {} } + /// + /// Blank config request, strictly for getting the session key + public struct SessionkeyConfig: Sendable { + // 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. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + } + public init() {} } -#if swift(>=4.2) - -extension Config.DeviceConfig.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.Role] = [ - .client, - .clientMute, - .router, - .routerClient, - .repeater, - .tracker, - .sensor, - .tak, - .clientHidden, - .lostAndFound, - .takTracker, - ] -} - -extension Config.DeviceConfig.RebroadcastMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ - .all, - .allSkipDecoding, - .localOnly, - .knownOnly, - ] -} - -extension Config.PositionConfig.PositionFlags: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.PositionFlags] = [ - .unset, - .altitude, - .altitudeMsl, - .geoidalSeparation, - .dop, - .hvdop, - .satinview, - .seqNo, - .timestamp, - .heading, - .speed, - ] -} - -extension Config.PositionConfig.GpsMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.GpsMode] = [ - .disabled, - .enabled, - .notPresent, - ] -} - -extension Config.NetworkConfig.AddressMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.NetworkConfig.AddressMode] = [ - .dhcp, - .static, - ] -} - -extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ - .dec, - .dms, - .utm, - .mgrs, - .olc, - .osgr, - ] -} - -extension Config.DisplayConfig.DisplayUnits: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ - .metric, - .imperial, - ] -} - -extension Config.DisplayConfig.OledType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.OledType] = [ - .oledAuto, - .oledSsd1306, - .oledSh1106, - .oledSh1107, - ] -} - -extension Config.DisplayConfig.DisplayMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayMode] = [ - .default, - .twocolor, - .inverted, - .color, - ] -} - -extension Config.DisplayConfig.CompassOrientation: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ - .degrees0, - .degrees90, - .degrees180, - .degrees270, - .degrees0Inverted, - .degrees90Inverted, - .degrees180Inverted, - .degrees270Inverted, - ] -} - -extension Config.LoRaConfig.RegionCode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - .lora24, - .ua433, - .ua868, - .my433, - .my919, - .sg923, - ] -} - -extension Config.LoRaConfig.ModemPreset: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.ModemPreset] = [ - .longFast, - .longSlow, - .veryLongSlow, - .mediumSlow, - .mediumFast, - .shortSlow, - .shortFast, - .longModerate, - .shortTurbo, - ] -} - -extension Config.BluetoothConfig.PairingMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.BluetoothConfig.PairingMode] = [ - .randomPin, - .fixedPin, - .noPin, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension Config: @unchecked Sendable {} -extension Config.OneOf_PayloadVariant: @unchecked Sendable {} -extension Config.DeviceConfig: @unchecked Sendable {} -extension Config.DeviceConfig.Role: @unchecked Sendable {} -extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {} -extension Config.PositionConfig: @unchecked Sendable {} -extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} -extension Config.PositionConfig.GpsMode: @unchecked Sendable {} -extension Config.PowerConfig: @unchecked Sendable {} -extension Config.NetworkConfig: @unchecked Sendable {} -extension Config.NetworkConfig.AddressMode: @unchecked Sendable {} -extension Config.NetworkConfig.IpV4Config: @unchecked Sendable {} -extension Config.DisplayConfig: @unchecked Sendable {} -extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} -extension Config.DisplayConfig.OledType: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayMode: @unchecked Sendable {} -extension Config.DisplayConfig.CompassOrientation: @unchecked Sendable {} -extension Config.LoRaConfig: @unchecked Sendable {} -extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} -extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} -extension Config.BluetoothConfig: @unchecked Sendable {} -extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} -extension Config.SecurityConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1801,6 +1727,7 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas 6: .same(proto: "lora"), 7: .same(proto: "bluetooth"), 8: .same(proto: "security"), + 9: .same(proto: "sessionkey"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -1913,6 +1840,19 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas self.payloadVariant = .security(v) } }() + case 9: try { + var v: Config.SessionkeyConfig? + var hadOneofValue = false + if let current = self.payloadVariant { + hadOneofValue = true + if case .sessionkey(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.payloadVariant = .sessionkey(v) + } + }() default: break } } @@ -1956,6 +1896,10 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas guard case .security(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 8) }() + case .sessionkey?: try { + guard case .sessionkey(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 9) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -1973,7 +1917,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "role"), 2: .standard(proto: "serial_enabled"), - 3: .standard(proto: "debug_log_enabled"), 4: .standard(proto: "button_gpio"), 5: .standard(proto: "buzzer_gpio"), 6: .standard(proto: "rebroadcast_mode"), @@ -1993,7 +1936,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.role) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() - case 3: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }() case 4: try { try decoder.decodeSingularUInt32Field(value: &self.buttonGpio) }() case 5: try { try decoder.decodeSingularUInt32Field(value: &self.buzzerGpio) }() case 6: try { try decoder.decodeSingularEnumField(value: &self.rebroadcastMode) }() @@ -2015,9 +1957,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl if self.serialEnabled != false { try visitor.visitSingularBoolField(value: self.serialEnabled, fieldNumber: 2) } - if self.debugLogEnabled != false { - try visitor.visitSingularBoolField(value: self.debugLogEnabled, fieldNumber: 3) - } if self.buttonGpio != 0 { try visitor.visitSingularUInt32Field(value: self.buttonGpio, fieldNumber: 4) } @@ -2051,7 +1990,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl public static func ==(lhs: Config.DeviceConfig, rhs: Config.DeviceConfig) -> Bool { if lhs.role != rhs.role {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} - if lhs.debugLogEnabled != rhs.debugLogEnabled {return false} if lhs.buttonGpio != rhs.buttonGpio {return false} if lhs.buzzerGpio != rhs.buzzerGpio {return false} if lhs.rebroadcastMode != rhs.rebroadcastMode {return false} @@ -2260,7 +2198,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 2) } - if self.adcMultiplierOverride != 0 { + if self.adcMultiplierOverride.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.adcMultiplierOverride, fieldNumber: 3) } if self.waitBluetoothSecs != 0 { @@ -2595,6 +2533,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem 15: .standard(proto: "pa_fan_disabled"), 103: .standard(proto: "ignore_incoming"), 104: .standard(proto: "ignore_mqtt"), + 105: .standard(proto: "config_ok_to_mqtt"), ] fileprivate class _StorageClass { @@ -2615,6 +2554,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem var _paFanDisabled: Bool = false var _ignoreIncoming: [UInt32] = [] var _ignoreMqtt: Bool = false + var _configOkToMqtt: Bool = false #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -2646,6 +2586,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem _paFanDisabled = source._paFanDisabled _ignoreIncoming = source._ignoreIncoming _ignoreMqtt = source._ignoreMqtt + _configOkToMqtt = source._configOkToMqtt } } @@ -2681,6 +2622,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem case 15: try { try decoder.decodeSingularBoolField(value: &_storage._paFanDisabled) }() case 103: try { try decoder.decodeRepeatedUInt32Field(value: &_storage._ignoreIncoming) }() case 104: try { try decoder.decodeSingularBoolField(value: &_storage._ignoreMqtt) }() + case 105: try { try decoder.decodeSingularBoolField(value: &_storage._configOkToMqtt) }() default: break } } @@ -2704,7 +2646,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._codingRate != 0 { try visitor.visitSingularUInt32Field(value: _storage._codingRate, fieldNumber: 5) } - if _storage._frequencyOffset != 0 { + if _storage._frequencyOffset.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 6) } if _storage._region != .unset { @@ -2728,7 +2670,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._sx126XRxBoostedGain != false { try visitor.visitSingularBoolField(value: _storage._sx126XRxBoostedGain, fieldNumber: 13) } - if _storage._overrideFrequency != 0 { + if _storage._overrideFrequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._overrideFrequency, fieldNumber: 14) } if _storage._paFanDisabled != false { @@ -2740,6 +2682,9 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._ignoreMqtt != false { try visitor.visitSingularBoolField(value: _storage._ignoreMqtt, fieldNumber: 104) } + if _storage._configOkToMqtt != false { + try visitor.visitSingularBoolField(value: _storage._configOkToMqtt, fieldNumber: 105) + } } try unknownFields.traverse(visitor: &visitor) } @@ -2766,6 +2711,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._paFanDisabled != rhs_storage._paFanDisabled {return false} if _storage._ignoreIncoming != rhs_storage._ignoreIncoming {return false} if _storage._ignoreMqtt != rhs_storage._ignoreMqtt {return false} + if _storage._configOkToMqtt != rhs_storage._configOkToMqtt {return false} return true } if !storagesAreEqual {return false} @@ -2819,7 +2765,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI 1: .same(proto: "enabled"), 2: .same(proto: "mode"), 3: .standard(proto: "fixed_pin"), - 4: .standard(proto: "device_logging_enabled"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -2831,7 +2776,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI case 1: try { try decoder.decodeSingularBoolField(value: &self.enabled) }() case 2: try { try decoder.decodeSingularEnumField(value: &self.mode) }() case 3: try { try decoder.decodeSingularUInt32Field(value: &self.fixedPin) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.deviceLoggingEnabled) }() default: break } } @@ -2847,9 +2791,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI if self.fixedPin != 0 { try visitor.visitSingularUInt32Field(value: self.fixedPin, fieldNumber: 3) } - if self.deviceLoggingEnabled != false { - try visitor.visitSingularBoolField(value: self.deviceLoggingEnabled, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } @@ -2857,7 +2798,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI if lhs.enabled != rhs.enabled {return false} if lhs.mode != rhs.mode {return false} if lhs.fixedPin != rhs.fixedPin {return false} - if lhs.deviceLoggingEnabled != rhs.deviceLoggingEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -2880,7 +2820,6 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 4: .standard(proto: "is_managed"), 5: .standard(proto: "serial_enabled"), 6: .standard(proto: "debug_log_api_enabled"), - 7: .standard(proto: "bluetooth_logging_enabled"), 8: .standard(proto: "admin_channel_enabled"), ] @@ -2892,11 +2831,10 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm switch fieldNumber { case 1: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }() case 2: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }() - case 3: try { try decoder.decodeSingularBytesField(value: &self.adminKey) }() + case 3: try { try decoder.decodeRepeatedBytesField(value: &self.adminKey) }() case 4: try { try decoder.decodeSingularBoolField(value: &self.isManaged) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() case 6: try { try decoder.decodeSingularBoolField(value: &self.debugLogApiEnabled) }() - case 7: try { try decoder.decodeSingularBoolField(value: &self.bluetoothLoggingEnabled) }() case 8: try { try decoder.decodeSingularBoolField(value: &self.adminChannelEnabled) }() default: break } @@ -2911,7 +2849,7 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 2) } if !self.adminKey.isEmpty { - try visitor.visitSingularBytesField(value: self.adminKey, fieldNumber: 3) + try visitor.visitRepeatedBytesField(value: self.adminKey, fieldNumber: 3) } if self.isManaged != false { try visitor.visitSingularBoolField(value: self.isManaged, fieldNumber: 4) @@ -2922,9 +2860,6 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if self.debugLogApiEnabled != false { try visitor.visitSingularBoolField(value: self.debugLogApiEnabled, fieldNumber: 6) } - if self.bluetoothLoggingEnabled != false { - try visitor.visitSingularBoolField(value: self.bluetoothLoggingEnabled, fieldNumber: 7) - } if self.adminChannelEnabled != false { try visitor.visitSingularBoolField(value: self.adminChannelEnabled, fieldNumber: 8) } @@ -2938,9 +2873,27 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if lhs.isManaged != rhs.isManaged {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} if lhs.debugLogApiEnabled != rhs.debugLogApiEnabled {return false} - if lhs.bluetoothLoggingEnabled != rhs.bluetoothLoggingEnabled {return false} if lhs.adminChannelEnabled != rhs.adminChannelEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } + +extension Config.SessionkeyConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Config.protoMessageName + ".SessionkeyConfig" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Config.SessionkeyConfig, rhs: Config.SessionkeyConfig) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift index a2ec180e..a4569714 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct DeviceConnectionStatus { +public struct DeviceConnectionStatus: Sendable { // 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. @@ -81,7 +81,7 @@ public struct DeviceConnectionStatus { /// /// WiFi connection status -public struct WifiConnectionStatus { +public struct WifiConnectionStatus: Sendable { // 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. @@ -114,7 +114,7 @@ public struct WifiConnectionStatus { /// /// Ethernet connection status -public struct EthernetConnectionStatus { +public struct EthernetConnectionStatus: Sendable { // 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. @@ -139,7 +139,7 @@ public struct EthernetConnectionStatus { /// /// Ethernet or WiFi connection status -public struct NetworkConnectionStatus { +public struct NetworkConnectionStatus: Sendable { // 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. @@ -167,7 +167,7 @@ public struct NetworkConnectionStatus { /// /// Bluetooth connection status -public struct BluetoothConnectionStatus { +public struct BluetoothConnectionStatus: Sendable { // 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. @@ -191,7 +191,7 @@ public struct BluetoothConnectionStatus { /// /// Serial connection status -public struct SerialConnectionStatus { +public struct SerialConnectionStatus: Sendable { // 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. @@ -209,15 +209,6 @@ public struct SerialConnectionStatus { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceConnectionStatus: @unchecked Sendable {} -extension WifiConnectionStatus: @unchecked Sendable {} -extension EthernetConnectionStatus: @unchecked Sendable {} -extension NetworkConnectionStatus: @unchecked Sendable {} -extension BluetoothConnectionStatus: @unchecked Sendable {} -extension SerialConnectionStatus: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift index 43506399..076e639e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Font sizes for the device screen -public enum ScreenFonts: SwiftProtobuf.Enum { +public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -60,24 +60,18 @@ public enum ScreenFonts: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension ScreenFonts: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [ScreenFonts] = [ .fontSmall, .fontMedium, .fontLarge, ] -} -#endif // swift(>=4.2) +} /// /// Position with static location information only for NodeDBLite -public struct PositionLite { +public struct PositionLite: Sendable { // 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. @@ -112,13 +106,15 @@ public struct PositionLite { public init() {} } -public struct UserLite { +public struct UserLite: @unchecked Sendable { // 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 the addr of the radio. + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -157,7 +153,7 @@ public struct UserLite { public init() {} } -public struct NodeInfoLite { +public struct NodeInfoLite: @unchecked Sendable { // 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. @@ -260,7 +256,7 @@ public struct NodeInfoLite { /// FIXME, since we write this each time we enter deep sleep (and have infinite /// flash) it would be better to use some sort of append only data structure for /// the receive queue and use the preferences store for the other stuff -public struct DeviceState { +public struct DeviceState: @unchecked Sendable { // 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. @@ -320,6 +316,8 @@ public struct DeviceState { /// Used only during development. /// Indicates developer is testing and changes should never be saved to flash. /// Deprecated in 2.3.1 + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var noSave: Bool { get {return _storage._noSave} set {_uniqueStorage()._noSave = newValue} @@ -368,7 +366,7 @@ public struct DeviceState { /// /// The on-disk saved channels -public struct ChannelFile { +public struct ChannelFile: Sendable { // 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. @@ -391,7 +389,7 @@ public struct ChannelFile { /// /// This can be used for customizing the firmware distribution. If populated, /// show a secondary bootup screen with custom logo and text for 2.5 seconds. -public struct OEMStore { +public struct OEMStore: @unchecked Sendable { // 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. @@ -450,16 +448,6 @@ public struct OEMStore { fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension ScreenFonts: @unchecked Sendable {} -extension PositionLite: @unchecked Sendable {} -extension UserLite: @unchecked Sendable {} -extension NodeInfoLite: @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. fileprivate let _protobuf_package = "meshtastic" @@ -695,7 +683,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index 0af27466..f2ef681d 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct LocalConfig { +public struct LocalConfig: @unchecked Sendable { // 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. @@ -129,7 +129,7 @@ public struct LocalConfig { fileprivate var _storage = _StorageClass.defaultInstance } -public struct LocalModuleConfig { +public struct LocalModuleConfig: @unchecked Sendable { // 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. @@ -293,11 +293,6 @@ public struct LocalModuleConfig { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=5.5) && canImport(_Concurrency) -extension LocalConfig: @unchecked Sendable {} -extension LocalModuleConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index ba12908d..a4dfa4cb 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -25,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// bin/build-all.sh script. /// Because they will be used to find firmware filenames in the android app for OTA updates. /// To match the old style filenames, _ is converted to -, p is converted to . -public enum HardwareModel: SwiftProtobuf.Enum { +public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -346,6 +346,19 @@ public enum HardwareModel: SwiftProtobuf.Enum { /// Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. case me25Ls014Y10Td // = 75 + /// + /// RP2040_FEATHER_RFM95 + /// Adafruit Feather RP2040 with RFM95 LoRa Radio RFM95 with SX1272, SSD1306 OLED + /// https://www.adafruit.com/product/5714 + /// https://www.adafruit.com/product/326 + /// https://www.adafruit.com/product/938 + /// ^^^ short A0 to switch to I2C address 0x3C + case rp2040FeatherRfm95 // = 76 + + /// M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ + case m5StackCorebasic // = 77 + case m5StackCore2 // = 78 + /// /// ------------------------------------------------------------------------------------------------------------------------------------------ /// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. @@ -434,6 +447,9 @@ public enum HardwareModel: SwiftProtobuf.Enum { case 73: self = .wioE5 case 74: self = .radiomaster900Bandit case 75: self = .me25Ls014Y10Td + case 76: self = .rp2040FeatherRfm95 + case 77: self = .m5StackCorebasic + case 78: self = .m5StackCore2 case 255: self = .privateHw default: self = .UNRECOGNIZED(rawValue) } @@ -516,16 +532,14 @@ public enum HardwareModel: SwiftProtobuf.Enum { case .wioE5: return 73 case .radiomaster900Bandit: return 74 case .me25Ls014Y10Td: return 75 + case .rp2040FeatherRfm95: return 76 + case .m5StackCorebasic: return 77 + case .m5StackCore2: return 78 case .privateHw: return 255 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension HardwareModel: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [HardwareModel] = [ .unset, @@ -603,15 +617,17 @@ extension HardwareModel: CaseIterable { .wioE5, .radiomaster900Bandit, .me25Ls014Y10Td, + .rp2040FeatherRfm95, + .m5StackCorebasic, + .m5StackCore2, .privateHw, ] -} -#endif // swift(>=4.2) +} /// /// Shared constants between device and phone -public enum Constants: SwiftProtobuf.Enum { +public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -646,26 +662,20 @@ public enum Constants: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Constants: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Constants] = [ .zero, .dataPayloadLen, ] -} -#endif // swift(>=4.2) +} /// /// Error codes for critical errors /// The device might report these fault codes on the screen. /// If you encounter a fault code, please post on the meshtastic.discourse.group /// and we'll try to help. -public enum CriticalErrorCode: SwiftProtobuf.Enum { +public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -774,11 +784,6 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension CriticalErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [CriticalErrorCode] = [ .none, @@ -796,13 +801,12 @@ extension CriticalErrorCode: CaseIterable { .flashCorruptionRecoverable, .flashCorruptionUnrecoverable, ] -} -#endif // swift(>=4.2) +} /// /// a gps position -public struct Position { +public struct Position: @unchecked Sendable { // 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. @@ -1019,7 +1023,7 @@ public struct Position { /// /// How the location was acquired: manual, onboard GPS, external (EUD) GPS - public enum LocSource: SwiftProtobuf.Enum { + public enum LocSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1063,12 +1067,20 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.LocSource] = [ + .locUnset, + .locManual, + .locInternal, + .locExternal, + ] + } /// /// How the altitude was acquired: manual, GPS int/ext, etc /// Default: same as location_source if present - public enum AltSource: SwiftProtobuf.Enum { + public enum AltSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1118,6 +1130,15 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.AltSource] = [ + .altUnset, + .altManual, + .altInternal, + .altExternal, + .altBarometric, + ] + } public init() {} @@ -1125,31 +1146,6 @@ public struct Position { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension Position.LocSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.LocSource] = [ - .locUnset, - .locManual, - .locInternal, - .locExternal, - ] -} - -extension Position.AltSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.AltSource] = [ - .altUnset, - .altManual, - .altInternal, - .altExternal, - .altBarometric, - ] -} - -#endif // swift(>=4.2) - /// /// Broadcast when a newly powered mesh node wants to find a node num it can use /// Sent from the phone over bluetooth to set the user id for the owner of this node. @@ -1171,7 +1167,7 @@ extension Position.AltSource: CaseIterable { /// A few nodenums are reserved and will never be requested: /// 0xff - broadcast /// 0 through 3 - for future use -public struct User { +public struct User: @unchecked Sendable { // 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. @@ -1196,6 +1192,8 @@ public struct User { /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -1227,7 +1225,7 @@ public struct User { /// /// A message used in a traceroute -public struct RouteDiscovery { +public struct RouteDiscovery: Sendable { // 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. @@ -1255,7 +1253,7 @@ public struct RouteDiscovery { /// /// A Routing control Data packet handled by the routing module -public struct Routing { +public struct Routing: Sendable { // 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. @@ -1295,7 +1293,7 @@ public struct Routing { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// A route request going from the requester case routeRequest(RouteDiscovery) @@ -1307,34 +1305,12 @@ public struct Routing { /// in addition to ack.fail_id to provide details on the type of failure). case errorReason(Routing.Error) - #if !swift(>=4.1) - public static func ==(lhs: Routing.OneOf_Variant, rhs: Routing.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 (.routeRequest, .routeRequest): return { - guard case .routeRequest(let l) = lhs, case .routeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.routeReply, .routeReply): return { - guard case .routeReply(let l) = lhs, case .routeReply(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.errorReason, .errorReason): return { - guard case .errorReason(let l) = lhs, case .errorReason(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide /// details on the type of failure). - public enum Error: SwiftProtobuf.Enum { + public enum Error: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1440,40 +1416,34 @@ public struct Routing { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Routing.Error] = [ + .none, + .noRoute, + .gotNak, + .timeout, + .noInterface, + .maxRetransmit, + .noChannel, + .tooLarge, + .noResponse, + .dutyCycleLimit, + .badRequest, + .notAuthorized, + .pkiFailed, + .pkiUnknownPubkey, + ] + } public init() {} } -#if swift(>=4.2) - -extension Routing.Error: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Routing.Error] = [ - .none, - .noRoute, - .gotNak, - .timeout, - .noInterface, - .maxRetransmit, - .noChannel, - .tooLarge, - .noResponse, - .dutyCycleLimit, - .badRequest, - .notAuthorized, - .pkiFailed, - .pkiUnknownPubkey, - ] -} - -#endif // swift(>=4.2) - /// /// (Formerly called SubPacket) /// The payload portion fo a packet, this is the actual bytes that are sent /// inside a radio packet (because from/to are broken out by the comms library) -public struct DataMessage { +public struct DataMessage: @unchecked Sendable { // 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. @@ -1520,14 +1490,27 @@ public struct DataMessage { /// a message a heart or poop emoji. public var emoji: UInt32 = 0 + /// + /// Bitfield for extra flags. First use is to indicate that user approves the packet being uploaded to MQTT. + public var bitfield: UInt32 { + get {return _bitfield ?? 0} + set {_bitfield = newValue} + } + /// Returns true if `bitfield` has been explicitly set. + public var hasBitfield: Bool {return self._bitfield != nil} + /// Clears the value of `bitfield`. Subsequent reads from it will return its default value. + public mutating func clearBitfield() {self._bitfield = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _bitfield: UInt32? = nil } /// /// Waypoint message, used to share arbitrary locations across the mesh -public struct Waypoint { +public struct Waypoint: Sendable { // 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. @@ -1589,7 +1572,7 @@ public struct Waypoint { /// /// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server -public struct MqttClientProxyMessage { +public struct MqttClientProxyMessage: @unchecked Sendable { // 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. @@ -1630,7 +1613,7 @@ public struct MqttClientProxyMessage { /// /// The actual service envelope payload or text for mqtt pub / sub - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// Bytes case data(Data) @@ -1638,24 +1621,6 @@ public struct MqttClientProxyMessage { /// Text case text(String) - #if !swift(>=4.1) - public static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.data, .data): return { - guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -1665,7 +1630,7 @@ public struct MqttClientProxyMessage { /// A packet envelope sent/received over the mesh /// only payload_variant is sent in the payload portion of the LORA packet. /// The other fields are either not sent at all, or sent in the special 16 byte LORA header. -public struct MeshPacket { +public struct MeshPacket: @unchecked Sendable { // 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. @@ -1799,6 +1764,8 @@ public struct MeshPacket { /// /// Describe if this message is delayed + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var delayed: MeshPacket.Delayed { get {return _storage._delayed} set {_uniqueStorage()._delayed = newValue} @@ -1835,7 +1802,7 @@ public struct MeshPacket { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case decoded(DataMessage) @@ -1843,24 +1810,6 @@ public struct MeshPacket { /// TODO: REPLACE case encrypted(Data) - #if !swift(>=4.1) - public static func ==(lhs: MeshPacket.OneOf_PayloadVariant, rhs: MeshPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.decoded, .decoded): return { - guard case .decoded(let l) = lhs, case .decoded(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.encrypted, .encrypted): return { - guard case .encrypted(let l) = lhs, case .encrypted(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// @@ -1882,7 +1831,7 @@ public struct MeshPacket { /// So I bit the bullet and implemented a new (internal - not sent over the air) /// field in MeshPacket called 'priority'. /// And the transmission queue in the router object is now a priority queue. - public enum Priority: SwiftProtobuf.Enum { + public enum Priority: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1907,6 +1856,15 @@ public struct MeshPacket { /// assume it is important and use a slightly higher priority case reliable // = 70 + /// + /// If priority is unset but the packet is a response to a request, we want it to get there relatively quickly. + /// Furthermore, responses stop relaying packets directed to a node early. + case response // = 80 + + /// + /// Higher priority for specific message types (portnums) to distinguish between other reliable packets. + case high // = 100 + /// /// Ack/naks are sent with very high priority to ensure that retransmission /// stops as soon as possible @@ -1928,6 +1886,8 @@ public struct MeshPacket { case 10: self = .background case 64: self = .default case 70: self = .reliable + case 80: self = .response + case 100: self = .high case 120: self = .ack case 127: self = .max default: self = .UNRECOGNIZED(rawValue) @@ -1941,17 +1901,32 @@ public struct MeshPacket { case .background: return 10 case .default: return 64 case .reliable: return 70 + case .response: return 80 + case .high: return 100 case .ack: return 120 case .max: return 127 case .UNRECOGNIZED(let i): return i } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Priority] = [ + .unset, + .min, + .background, + .default, + .reliable, + .response, + .high, + .ack, + .max, + ] + } /// /// Identify if this is a delayed packet - public enum Delayed: SwiftProtobuf.Enum { + public enum Delayed: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1989,6 +1964,13 @@ public struct MeshPacket { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Delayed] = [ + .noDelay, + .broadcast, + .direct, + ] + } public init() {} @@ -1996,32 +1978,6 @@ public struct MeshPacket { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension MeshPacket.Priority: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Priority] = [ - .unset, - .min, - .background, - .default, - .reliable, - .ack, - .max, - ] -} - -extension MeshPacket.Delayed: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Delayed] = [ - .noDelay, - .broadcast, - .direct, - ] -} - -#endif // swift(>=4.2) - /// /// The bluetooth to device link: /// Old BTLE protocol docs from TODO, merge in above and make real docs... @@ -2039,7 +1995,7 @@ extension MeshPacket.Delayed: CaseIterable { /// level etc) SET_CONFIG (switches device to a new set of radio params and /// preshared key, drops all existing nodes, force our node to rejoin this new group) /// Full information about a node on the mesh -public struct NodeInfo { +public struct NodeInfo: @unchecked Sendable { // 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. @@ -2140,7 +2096,7 @@ public struct NodeInfo { /// Unique local debugging info for this node /// Note: we don't include position or the user info, because that will come in the /// Sent to the phone in response to WantNodes. -public struct MyNodeInfo { +public struct MyNodeInfo: Sendable { // 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. @@ -2171,7 +2127,7 @@ public struct MyNodeInfo { /// on the message it is assumed to be a continuation of the previously sent message. /// This allows the device code to use fixed maxlen 64 byte strings for messages, /// and then extend as needed by emitting multiple records. -public struct LogRecord { +public struct LogRecord: Sendable { // 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. @@ -2196,7 +2152,7 @@ public struct LogRecord { /// /// Log levels, chosen to match python logging conventions. - public enum Level: SwiftProtobuf.Enum { + public enum Level: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -2258,29 +2214,23 @@ public struct LogRecord { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [LogRecord.Level] = [ + .unset, + .critical, + .error, + .warning, + .info, + .debug, + .trace, + ] + } public init() {} } -#if swift(>=4.2) - -extension LogRecord.Level: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [LogRecord.Level] = [ - .unset, - .critical, - .error, - .warning, - .info, - .debug, - .trace, - ] -} - -#endif // swift(>=4.2) - -public struct QueueStatus { +public struct QueueStatus: Sendable { // 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. @@ -2307,7 +2257,7 @@ public struct QueueStatus { /// It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? /// It will sit in that descriptor until consumed by the phone, /// at which point the next item in the FIFO will be populated. -public struct FromRadio { +public struct FromRadio: Sendable { // 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. @@ -2483,7 +2433,7 @@ public struct FromRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Log levels, chosen to match python logging conventions. case packet(MeshPacket) @@ -2538,76 +2488,6 @@ public struct FromRadio { /// Notification message to the client case clientNotification(ClientNotification) - #if !swift(>=4.1) - public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.myInfo, .myInfo): return { - guard case .myInfo(let l) = lhs, case .myInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodeInfo, .nodeInfo): return { - guard case .nodeInfo(let l) = lhs, case .nodeInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.config, .config): return { - guard case .config(let l) = lhs, case .config(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.logRecord, .logRecord): return { - guard case .logRecord(let l) = lhs, case .logRecord(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.configCompleteID, .configCompleteID): return { - guard case .configCompleteID(let l) = lhs, case .configCompleteID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebooted, .rebooted): return { - guard case .rebooted(let l) = lhs, case .rebooted(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.moduleConfig, .moduleConfig): return { - guard case .moduleConfig(let l) = lhs, case .moduleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.channel, .channel): return { - guard case .channel(let l) = lhs, case .channel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.queueStatus, .queueStatus): return { - guard case .queueStatus(let l) = lhs, case .queueStatus(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.metadata, .metadata): return { - guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.fileInfo, .fileInfo): return { - guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.clientNotification, .clientNotification): return { - guard case .clientNotification(let l) = lhs, case .clientNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -2618,7 +2498,7 @@ public struct FromRadio { /// To be used for important messages that should to be displayed to the user /// in the form of push notifications or validation messages when saving /// invalid configuration. -public struct ClientNotification { +public struct ClientNotification: Sendable { // 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. @@ -2655,7 +2535,7 @@ public struct ClientNotification { /// /// Individual File info for the device -public struct FileInfo { +public struct FileInfo: Sendable { // 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. @@ -2676,7 +2556,7 @@ public struct FileInfo { /// /// Packets/commands to the radio will be written (reliably) to the toRadio characteristic. /// Once the write completes the phone can assume it is handled. -public struct ToRadio { +public struct ToRadio: Sendable { // 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. @@ -2756,7 +2636,7 @@ public struct ToRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send this packet on the mesh case packet(MeshPacket) @@ -2783,40 +2663,6 @@ public struct ToRadio { /// Heartbeat message (used to keep the device connection awake on serial) case heartbeat(Heartbeat) - #if !swift(>=4.1) - public static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.wantConfigID, .wantConfigID): return { - guard case .wantConfigID(let l) = lhs, case .wantConfigID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.disconnect, .disconnect): return { - guard case .disconnect(let l) = lhs, case .disconnect(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -2824,7 +2670,7 @@ public struct ToRadio { /// /// Compressed message payload -public struct Compressed { +public struct Compressed: @unchecked Sendable { // 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. @@ -2844,7 +2690,7 @@ public struct Compressed { /// /// Full info on edges for a single node -public struct NeighborInfo { +public struct NeighborInfo: Sendable { // 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. @@ -2872,7 +2718,7 @@ public struct NeighborInfo { /// /// A single edge in the mesh -public struct Neighbor { +public struct Neighbor: Sendable { // 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. @@ -2902,7 +2748,7 @@ public struct Neighbor { /// /// Device metadata response -public struct DeviceMetadata { +public struct DeviceMetadata: Sendable { // 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. @@ -2955,7 +2801,7 @@ public struct DeviceMetadata { /// /// A heartbeat message is sent to the node from the client to keep the connection alive. /// This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. -public struct Heartbeat { +public struct Heartbeat: Sendable { // 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. @@ -2967,7 +2813,7 @@ public struct Heartbeat { /// /// RemoteHardwarePins associated with a node -public struct NodeRemoteHardwarePin { +public struct NodeRemoteHardwarePin: Sendable { // 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. @@ -2994,7 +2840,7 @@ public struct NodeRemoteHardwarePin { fileprivate var _pin: RemoteHardwarePin? = nil } -public struct ChunkedPayload { +public struct ChunkedPayload: @unchecked Sendable { // 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. @@ -3022,7 +2868,7 @@ public struct ChunkedPayload { /// /// Wrapper message for broken repeated oneof support -public struct resend_chunks { +public struct resend_chunks: Sendable { // 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. @@ -3036,7 +2882,7 @@ public struct resend_chunks { /// /// Responses to a ChunkedPayload request -public struct ChunkedPayloadResponse { +public struct ChunkedPayloadResponse: Sendable { // 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. @@ -3079,7 +2925,7 @@ public struct ChunkedPayloadResponse { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Request to transfer chunked payload case requestTransfer(Bool) @@ -3090,76 +2936,11 @@ public struct ChunkedPayloadResponse { /// Request missing indexes in the chunked payload case resendChunks(resend_chunks) - #if !swift(>=4.1) - public static func ==(lhs: ChunkedPayloadResponse.OneOf_PayloadVariant, rhs: ChunkedPayloadResponse.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.requestTransfer, .requestTransfer): return { - guard case .requestTransfer(let l) = lhs, case .requestTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.acceptTransfer, .acceptTransfer): return { - guard case .acceptTransfer(let l) = lhs, case .acceptTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.resendChunks, .resendChunks): return { - guard case .resendChunks(let l) = lhs, case .resendChunks(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension HardwareModel: @unchecked Sendable {} -extension Constants: @unchecked Sendable {} -extension CriticalErrorCode: @unchecked Sendable {} -extension Position: @unchecked Sendable {} -extension Position.LocSource: @unchecked Sendable {} -extension Position.AltSource: @unchecked Sendable {} -extension User: @unchecked Sendable {} -extension RouteDiscovery: @unchecked Sendable {} -extension Routing: @unchecked Sendable {} -extension Routing.OneOf_Variant: @unchecked Sendable {} -extension Routing.Error: @unchecked Sendable {} -extension DataMessage: @unchecked Sendable {} -extension Waypoint: @unchecked Sendable {} -extension MqttClientProxyMessage: @unchecked Sendable {} -extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket: @unchecked Sendable {} -extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket.Priority: @unchecked Sendable {} -extension MeshPacket.Delayed: @unchecked Sendable {} -extension NodeInfo: @unchecked Sendable {} -extension MyNodeInfo: @unchecked Sendable {} -extension LogRecord: @unchecked Sendable {} -extension LogRecord.Level: @unchecked Sendable {} -extension QueueStatus: @unchecked Sendable {} -extension FromRadio: @unchecked Sendable {} -extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension ClientNotification: @unchecked Sendable {} -extension FileInfo: @unchecked Sendable {} -extension ToRadio: @unchecked Sendable {} -extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension Compressed: @unchecked Sendable {} -extension NeighborInfo: @unchecked Sendable {} -extension Neighbor: @unchecked Sendable {} -extension DeviceMetadata: @unchecked Sendable {} -extension Heartbeat: @unchecked Sendable {} -extension NodeRemoteHardwarePin: @unchecked Sendable {} -extension ChunkedPayload: @unchecked Sendable {} -extension resend_chunks: @unchecked Sendable {} -extension ChunkedPayloadResponse: @unchecked Sendable {} -extension ChunkedPayloadResponse.OneOf_PayloadVariant: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -3241,6 +3022,9 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 73: .same(proto: "WIO_E5"), 74: .same(proto: "RADIOMASTER_900_BANDIT"), 75: .same(proto: "ME25LS01_4Y10TD"), + 76: .same(proto: "RP2040_FEATHER_RFM95"), + 77: .same(proto: "M5STACK_COREBASIC"), + 78: .same(proto: "M5STACK_CORE2"), 255: .same(proto: "PRIVATE_HW"), ] } @@ -3779,6 +3563,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati 6: .standard(proto: "request_id"), 7: .standard(proto: "reply_id"), 8: .same(proto: "emoji"), + 9: .same(proto: "bitfield"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3795,12 +3580,17 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 6: try { try decoder.decodeSingularFixed32Field(value: &self.requestID) }() case 7: try { try decoder.decodeSingularFixed32Field(value: &self.replyID) }() case 8: try { try decoder.decodeSingularFixed32Field(value: &self.emoji) }() + case 9: try { try decoder.decodeSingularUInt32Field(value: &self._bitfield) }() default: break } } } public func traverse(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.portnum != .unknownApp { try visitor.visitSingularEnumField(value: self.portnum, fieldNumber: 1) } @@ -3825,6 +3615,9 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if self.emoji != 0 { try visitor.visitSingularFixed32Field(value: self.emoji, fieldNumber: 8) } + try { if let v = self._bitfield { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9) + } }() try unknownFields.traverse(visitor: &visitor) } @@ -3837,6 +3630,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if lhs.requestID != rhs.requestID {return false} if lhs.replyID != rhs.replyID {return false} if lhs.emoji != rhs.emoji {return false} + if lhs._bitfield != rhs._bitfield {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4153,7 +3947,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._rxTime != 0 { try visitor.visitSingularFixed32Field(value: _storage._rxTime, fieldNumber: 7) } - if _storage._rxSnr != 0 { + if _storage._rxSnr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._rxSnr, fieldNumber: 8) } if _storage._hopLimit != 0 { @@ -4224,6 +4018,8 @@ extension MeshPacket.Priority: SwiftProtobuf._ProtoNameProviding { 10: .same(proto: "BACKGROUND"), 64: .same(proto: "DEFAULT"), 70: .same(proto: "RELIABLE"), + 80: .same(proto: "RESPONSE"), + 100: .same(proto: "HIGH"), 120: .same(proto: "ACK"), 127: .same(proto: "MAX"), ] @@ -4336,7 +4132,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -5181,7 +4977,7 @@ extension Neighbor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if self.nodeID != 0 { try visitor.visitSingularUInt32Field(value: self.nodeID, fieldNumber: 1) } - if self.snr != 0 { + if self.snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 2) } if self.lastRxTime != 0 { @@ -5294,8 +5090,8 @@ extension Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index 3186c349..d1de21cf 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum RemoteHardwarePinType: SwiftProtobuf.Enum { +public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -58,24 +58,18 @@ public enum RemoteHardwarePinType: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension RemoteHardwarePinType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [RemoteHardwarePinType] = [ .unknown, .digitalRead, .digitalWrite, ] -} -#endif // swift(>=4.2) +} /// /// Module Config -public struct ModuleConfig { +public struct ModuleConfig: Sendable { // 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. @@ -218,7 +212,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// TODO: REPLACE case mqtt(ModuleConfig.MQTTConfig) @@ -259,73 +253,11 @@ public struct ModuleConfig { /// TODO: REPLACE case paxcounter(ModuleConfig.PaxcounterConfig) - #if !swift(>=4.1) - public static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.mqtt, .mqtt): return { - guard case .mqtt(let l) = lhs, case .mqtt(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.serial, .serial): return { - guard case .serial(let l) = lhs, case .serial(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.externalNotification, .externalNotification): return { - guard case .externalNotification(let l) = lhs, case .externalNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.storeForward, .storeForward): return { - guard case .storeForward(let l) = lhs, case .storeForward(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rangeTest, .rangeTest): return { - guard case .rangeTest(let l) = lhs, case .rangeTest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.telemetry, .telemetry): return { - guard case .telemetry(let l) = lhs, case .telemetry(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.cannedMessage, .cannedMessage): return { - guard case .cannedMessage(let l) = lhs, case .cannedMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.audio, .audio): return { - guard case .audio(let l) = lhs, case .audio(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.remoteHardware, .remoteHardware): return { - guard case .remoteHardware(let l) = lhs, case .remoteHardware(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.neighborInfo, .neighborInfo): return { - guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.ambientLighting, .ambientLighting): return { - guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.detectionSensor, .detectionSensor): return { - guard case .detectionSensor(let l) = lhs, case .detectionSensor(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.paxcounter, .paxcounter): return { - guard case .paxcounter(let l) = lhs, case .paxcounter(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// MQTT Client Config - public struct MQTTConfig { + public struct MQTTConfig: Sendable { // 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. @@ -400,7 +332,7 @@ public struct ModuleConfig { /// /// Settings for reporting unencrypted information about our node to a map via MQTT - public struct MapReportSettings { + public struct MapReportSettings: Sendable { // 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. @@ -420,7 +352,7 @@ public struct ModuleConfig { /// /// RemoteHardwareModule Config - public struct RemoteHardwareConfig { + public struct RemoteHardwareConfig: Sendable { // 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. @@ -444,7 +376,7 @@ public struct ModuleConfig { /// /// NeighborInfoModule Config - public struct NeighborInfoConfig { + public struct NeighborInfoConfig: Sendable { // 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. @@ -465,7 +397,7 @@ public struct ModuleConfig { /// /// Detection Sensor Module Config - public struct DetectionSensorConfig { + public struct DetectionSensorConfig: Sendable { // 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. @@ -516,7 +448,7 @@ public struct ModuleConfig { /// /// Audio Config for codec2 voice - public struct AudioConfig { + public struct AudioConfig: Sendable { // 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. @@ -553,7 +485,7 @@ public struct ModuleConfig { /// /// Baudrate for codec2 voice - public enum Audio_Baud: SwiftProtobuf.Enum { + public enum Audio_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case codec2Default // = 0 case codec23200 // = 1 @@ -600,6 +532,19 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ + .codec2Default, + .codec23200, + .codec22400, + .codec21600, + .codec21400, + .codec21300, + .codec21200, + .codec2700, + .codec2700B, + ] + } public init() {} @@ -607,7 +552,7 @@ public struct ModuleConfig { /// /// Config for the Paxcounter Module - public struct PaxcounterConfig { + public struct PaxcounterConfig: Sendable { // 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. @@ -633,7 +578,7 @@ public struct ModuleConfig { /// /// Serial Config - public struct SerialConfig { + public struct SerialConfig: Sendable { // 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. @@ -676,7 +621,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum Serial_Baud: SwiftProtobuf.Enum { + public enum Serial_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case baudDefault // = 0 case baud110 // = 1 @@ -744,11 +689,31 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ + .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, + .baud2400, + .baud4800, + .baud9600, + .baud19200, + .baud38400, + .baud57600, + .baud115200, + .baud230400, + .baud460800, + .baud576000, + .baud921600, + ] + } /// /// TODO: REPLACE - public enum Serial_Mode: SwiftProtobuf.Enum { + public enum Serial_Mode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case `default` // = 0 case simple // = 1 @@ -793,6 +758,17 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ + .default, + .simple, + .proto, + .textmsg, + .nmea, + .caltopo, + .ws85, + ] + } public init() {} @@ -800,7 +776,7 @@ public struct ModuleConfig { /// /// External Notifications Config - public struct ExternalNotificationConfig { + public struct ExternalNotificationConfig: Sendable { // 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. @@ -883,7 +859,7 @@ public struct ModuleConfig { /// /// Store and Forward Module Config - public struct StoreForwardConfig { + public struct StoreForwardConfig: Sendable { // 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. @@ -919,7 +895,7 @@ public struct ModuleConfig { /// /// Preferences for the RangeTestModule - public struct RangeTestConfig { + public struct RangeTestConfig: Sendable { // 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. @@ -944,7 +920,7 @@ public struct ModuleConfig { /// /// Configuration for both device and environment metrics - public struct TelemetryConfig { + public struct TelemetryConfig: Sendable { // 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. @@ -1001,7 +977,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public struct CannedMessageConfig { + public struct CannedMessageConfig: Sendable { // 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. @@ -1056,7 +1032,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum InputEventChar: SwiftProtobuf.Enum { + public enum InputEventChar: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1124,6 +1100,18 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ + .none, + .up, + .down, + .left, + .right, + .select, + .back, + .cancel, + ] + } public init() {} @@ -1132,7 +1120,7 @@ public struct ModuleConfig { /// ///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. ///Initially created for the RAK14001 RGB LED module. - public struct AmbientLightingConfig { + public struct AmbientLightingConfig: Sendable { // 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. @@ -1165,77 +1153,9 @@ public struct ModuleConfig { public init() {} } -#if swift(>=4.2) - -extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ - .codec2Default, - .codec23200, - .codec22400, - .codec21600, - .codec21400, - .codec21300, - .codec21200, - .codec2700, - .codec2700B, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ - .baudDefault, - .baud110, - .baud300, - .baud600, - .baud1200, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ - .default, - .simple, - .proto, - .textmsg, - .nmea, - .caltopo, - .ws85, - ] -} - -extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ - .none, - .up, - .down, - .left, - .right, - .select, - .back, - .cancel, - ] -} - -#endif // swift(>=4.2) - /// /// A GPIO pin definition for remote hardware module -public struct RemoteHardwarePin { +public struct RemoteHardwarePin: Sendable { // 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. @@ -1257,31 +1177,6 @@ public struct RemoteHardwarePin { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RemoteHardwarePinType: @unchecked Sendable {} -extension ModuleConfig: @unchecked Sendable {} -extension ModuleConfig.OneOf_PayloadVariant: @unchecked Sendable {} -extension ModuleConfig.MQTTConfig: @unchecked Sendable {} -extension ModuleConfig.MapReportSettings: @unchecked Sendable {} -extension ModuleConfig.RemoteHardwareConfig: @unchecked Sendable {} -extension ModuleConfig.NeighborInfoConfig: @unchecked Sendable {} -extension ModuleConfig.DetectionSensorConfig: @unchecked Sendable {} -extension ModuleConfig.AudioConfig: @unchecked Sendable {} -extension ModuleConfig.AudioConfig.Audio_Baud: @unchecked Sendable {} -extension ModuleConfig.PaxcounterConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Baud: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Mode: @unchecked Sendable {} -extension ModuleConfig.ExternalNotificationConfig: @unchecked Sendable {} -extension ModuleConfig.StoreForwardConfig: @unchecked Sendable {} -extension ModuleConfig.RangeTestConfig: @unchecked Sendable {} -extension ModuleConfig.TelemetryConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {} -extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {} -extension RemoteHardwarePin: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift index efe6cdd5..fc5e37a1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This message wraps a MeshPacket with extra metadata about the sender and how it arrived. -public struct ServiceEnvelope { +public struct ServiceEnvelope: Sendable { // 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. @@ -57,7 +57,7 @@ public struct ServiceEnvelope { /// /// Information about a node intended to be reported unencrypted to a map using MQTT. -public struct MapReport { +public struct MapReport: Sendable { // 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. @@ -121,11 +121,6 @@ public struct MapReport { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension ServiceEnvelope: @unchecked Sendable {} -extension MapReport: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift index cf8aa463..f82b3c51 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct Paxcount { +public struct Paxcount: Sendable { // 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. @@ -44,10 +44,6 @@ public struct Paxcount { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Paxcount: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index dd7e036f..46455db7 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -33,7 +33,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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. -public enum PortNum: SwiftProtobuf.Enum { +public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -277,11 +277,6 @@ public enum PortNum: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension PortNum: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [PortNum] = [ .unknownApp, @@ -313,14 +308,9 @@ extension PortNum: CaseIterable { .atakForwarder, .max, ] + } -#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 { diff --git a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift index 5f51e948..9c61e6d0 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). ///But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) -public struct PowerMon { +public struct PowerMon: Sendable { // 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. @@ -31,7 +31,7 @@ public struct PowerMon { /// Any significant power changing event in meshtastic should be tagged with a powermon state transition. ///If you are making new meshtastic features feel free to add new entries at the end of this definition. - public enum State: SwiftProtobuf.Enum { + public enum State: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case none // = 0 case cpuDeepSleep // = 1 @@ -104,37 +104,31 @@ public struct PowerMon { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerMon.State] = [ + .none, + .cpuDeepSleep, + .cpuLightSleep, + .vext1On, + .loraRxon, + .loraTxon, + .loraRxactive, + .btOn, + .ledOn, + .screenOn, + .screenDrawing, + .wifiOn, + .gpsActive, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerMon.State: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerMon.State] = [ - .none, - .cpuDeepSleep, - .cpuLightSleep, - .vext1On, - .loraRxon, - .loraTxon, - .loraRxactive, - .btOn, - .ledOn, - .screenOn, - .screenDrawing, - .wifiOn, - .gpsActive, - ] -} - -#endif // swift(>=4.2) - /// /// PowerStress testing support via the C++ PowerStress module -public struct PowerStressMessage { +public struct PowerStressMessage: Sendable { // 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. @@ -151,7 +145,7 @@ public struct PowerStressMessage { /// What operation would we like the UUT to perform. ///note: senders should probably set want_response in their request packets, so that they can know when the state ///machine has started processing their request - public enum Opcode: SwiftProtobuf.Enum { + public enum Opcode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -272,48 +266,35 @@ public struct PowerStressMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerStressMessage.Opcode] = [ + .unset, + .printInfo, + .forceQuiet, + .endQuiet, + .screenOn, + .screenOff, + .cpuIdle, + .cpuDeepsleep, + .cpuFullon, + .ledOn, + .ledOff, + .loraOff, + .loraTx, + .loraRx, + .btOff, + .btOn, + .wifiOff, + .wifiOn, + .gpsOff, + .gpsOn, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerStressMessage.Opcode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerStressMessage.Opcode] = [ - .unset, - .printInfo, - .forceQuiet, - .endQuiet, - .screenOn, - .screenOff, - .cpuIdle, - .cpuDeepsleep, - .cpuFullon, - .ledOn, - .ledOff, - .loraOff, - .loraTx, - .loraRx, - .btOff, - .btOn, - .wifiOff, - .wifiOn, - .gpsOff, - .gpsOn, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension PowerMon: @unchecked Sendable {} -extension PowerMon.State: @unchecked Sendable {} -extension PowerStressMessage: @unchecked Sendable {} -extension PowerStressMessage.Opcode: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -323,8 +304,8 @@ extension PowerMon: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { @@ -379,7 +360,7 @@ extension PowerStressMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.cmd != .unset { try visitor.visitSingularEnumField(value: self.cmd, fieldNumber: 1) } - if self.numSeconds != 0 { + if self.numSeconds.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.numSeconds, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift index ac6eeb26..60f64504 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift @@ -30,7 +30,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// because no security yet (beyond the channel mechanism). /// It should be off by default and then protected based on some TBD mechanism /// (a special channel once multichannel support is included?) -public struct HardwareMessage { +public struct HardwareMessage: Sendable { // 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. @@ -52,7 +52,7 @@ public struct HardwareMessage { /// /// TODO: REPLACE - public enum TypeEnum: SwiftProtobuf.Enum { + public enum TypeEnum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -110,32 +110,21 @@ public struct HardwareMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [HardwareMessage.TypeEnum] = [ + .unset, + .writeGpios, + .watchGpios, + .gpiosChanged, + .readGpios, + .readGpiosReply, + ] + } public init() {} } -#if swift(>=4.2) - -extension HardwareMessage.TypeEnum: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [HardwareMessage.TypeEnum] = [ - .unset, - .writeGpios, - .watchGpios, - .gpiosChanged, - .readGpios, - .readGpiosReply, - ] -} - -#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. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift index 6fdf3208..c1f3f678 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct RTTTLConfig { +public struct RTTTLConfig: Sendable { // 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. @@ -36,10 +36,6 @@ public struct RTTTLConfig { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RTTTLConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift index 54efa77b..0b67eaf6 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct StoreAndForward { +public struct StoreAndForward: @unchecked Sendable { // 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. @@ -79,7 +79,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case stats(StoreAndForward.Statistics) @@ -93,38 +93,12 @@ public struct StoreAndForward { /// Text from history message. case text(Data) - #if !swift(>=4.1) - public static func ==(lhs: StoreAndForward.OneOf_Variant, rhs: StoreAndForward.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 (.stats, .stats): return { - guard case .stats(let l) = lhs, case .stats(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.history, .history): return { - guard case .history(let l) = lhs, case .history(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// 001 - 063 = From Router /// 064 - 127 = From Client - public enum RequestResponse: SwiftProtobuf.Enum { + public enum RequestResponse: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -242,11 +216,31 @@ public struct StoreAndForward { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [StoreAndForward.RequestResponse] = [ + .unset, + .routerError, + .routerHeartbeat, + .routerPing, + .routerPong, + .routerBusy, + .routerHistory, + .routerStats, + .routerTextDirect, + .routerTextBroadcast, + .clientError, + .clientHistory, + .clientStats, + .clientPing, + .clientPong, + .clientAbort, + ] + } /// /// TODO: REPLACE - public struct Statistics { + public struct Statistics: Sendable { // 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. @@ -294,7 +288,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct History { + public struct History: Sendable { // 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. @@ -319,7 +313,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct Heartbeat { + public struct Heartbeat: Sendable { // 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. @@ -340,41 +334,6 @@ public struct StoreAndForward { public init() {} } -#if swift(>=4.2) - -extension StoreAndForward.RequestResponse: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [StoreAndForward.RequestResponse] = [ - .unset, - .routerError, - .routerHeartbeat, - .routerPing, - .routerPong, - .routerBusy, - .routerHistory, - .routerStats, - .routerTextDirect, - .routerTextBroadcast, - .clientError, - .clientHistory, - .clientStats, - .clientPing, - .clientPong, - .clientAbort, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension StoreAndForward: @unchecked Sendable {} -extension StoreAndForward.OneOf_Variant: @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. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index e4b9ee08..44183031 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Supported I2C Sensors for telemetry in Meshtastic -public enum TelemetrySensorType: SwiftProtobuf.Enum { +public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -140,6 +140,10 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { /// /// MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) case max17048 // = 28 + + /// + /// Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor + case customSensor // = 29 case UNRECOGNIZED(Int) public init() { @@ -177,6 +181,7 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case 26: self = .bmp3Xx case 27: self = .icm20948 case 28: self = .max17048 + case 29: self = .customSensor default: self = .UNRECOGNIZED(rawValue) } } @@ -212,15 +217,11 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case .bmp3Xx: return 26 case .icm20948: return 27 case .max17048: return 28 + case .customSensor: return 29 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension TelemetrySensorType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [TelemetrySensorType] = [ .sensorUnset, @@ -252,14 +253,14 @@ extension TelemetrySensorType: CaseIterable { .bmp3Xx, .icm20948, .max17048, + .customSensor, ] -} -#endif // swift(>=4.2) +} /// /// Key native device metrics such as battery level -public struct DeviceMetrics { +public struct DeviceMetrics: Sendable { // 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. @@ -332,7 +333,7 @@ public struct DeviceMetrics { /// /// Weather station or other environmental metrics -public struct EnvironmentMetrics { +public struct EnvironmentMetrics: @unchecked Sendable { // 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. @@ -535,7 +536,7 @@ public struct EnvironmentMetrics { /// /// Power Metrics (voltage / current / etc) -public struct PowerMetrics { +public struct PowerMetrics: Sendable { // 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. @@ -620,7 +621,7 @@ public struct PowerMetrics { /// /// Air quality metrics -public struct AirQualityMetrics { +public struct AirQualityMetrics: Sendable { // 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. @@ -777,7 +778,7 @@ public struct AirQualityMetrics { /// /// Local device mesh statistics -public struct LocalStats { +public struct LocalStats: Sendable { // 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. @@ -821,7 +822,7 @@ public struct LocalStats { /// /// Types of Measurements the telemetry module is equipped to handle -public struct Telemetry { +public struct Telemetry: Sendable { // 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. @@ -884,7 +885,7 @@ public struct Telemetry { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// Key native device metrics such as battery level case deviceMetrics(DeviceMetrics) @@ -901,36 +902,6 @@ public struct Telemetry { /// Local device mesh statistics case localStats(LocalStats) - #if !swift(>=4.1) - public 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 - }() - case (.airQualityMetrics, .airQualityMetrics): return { - guard case .airQualityMetrics(let l) = lhs, case .airQualityMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.powerMetrics, .powerMetrics): return { - guard case .powerMetrics(let l) = lhs, case .powerMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.localStats, .localStats): return { - guard case .localStats(let l) = lhs, case .localStats(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -938,7 +909,7 @@ public struct Telemetry { /// /// NAU7802 Telemetry configuration, for saving to flash -public struct Nau7802Config { +public struct Nau7802Config: Sendable { // 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. @@ -956,18 +927,6 @@ public struct Nau7802Config { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension TelemetrySensorType: @unchecked Sendable {} -extension DeviceMetrics: @unchecked Sendable {} -extension EnvironmentMetrics: @unchecked Sendable {} -extension PowerMetrics: @unchecked Sendable {} -extension AirQualityMetrics: @unchecked Sendable {} -extension LocalStats: @unchecked Sendable {} -extension Telemetry: @unchecked Sendable {} -extension Telemetry.OneOf_Variant: @unchecked Sendable {} -extension Nau7802Config: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1003,6 +962,7 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding { 26: .same(proto: "BMP3XX"), 27: .same(proto: "ICM20948"), 28: .same(proto: "MAX17048"), + 29: .same(proto: "CUSTOM_SENSOR"), ] } @@ -1474,10 +1434,10 @@ extension LocalStats: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if self.uptimeSeconds != 0 { try visitor.visitSingularUInt32Field(value: self.uptimeSeconds, fieldNumber: 1) } - if self.channelUtilization != 0 { + if self.channelUtilization.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 2) } - if self.airUtilTx != 0 { + if self.airUtilTx.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 3) } if self.numPacketsTx != 0 { @@ -1666,7 +1626,7 @@ extension Nau7802Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.zeroOffset != 0 { try visitor.visitSingularInt32Field(value: self.zeroOffset, fieldNumber: 1) } - if self.calibrationFactor != 0 { + if self.calibrationFactor.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.calibrationFactor, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift index 1f41fe0b..89d0097c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct XModem { +public struct XModem: @unchecked Sendable { // 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. @@ -35,7 +35,7 @@ public struct XModem { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum Control: SwiftProtobuf.Enum { + public enum Control: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case nul // = 0 case soh // = 1 @@ -79,34 +79,23 @@ public struct XModem { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [XModem.Control] = [ + .nul, + .soh, + .stx, + .eot, + .ack, + .nak, + .can, + .ctrlz, + ] + } public init() {} } -#if swift(>=4.2) - -extension XModem.Control: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [XModem.Control] = [ - .nul, - .soh, - .stx, - .eot, - .ack, - .nak, - .can, - .ctrlz, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension XModem: @unchecked Sendable {} -extension XModem.Control: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/protobufs b/protobufs index b6237629..0acaec6e 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit b623762940ebdb1887a3b31b86f4d9cdaa7e6ecf +Subproject commit 0acaec6eff00e748beeae89148093221f131cd9c From 042c030cf65cbc6ef01b3868d9d329c4d34971c3 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 12 Sep 2024 11:25:51 -0700 Subject: [PATCH 12/17] Update config to use new protos --- Localizable.xcstrings | 6 +- Meshtastic.xcodeproj/project.pbxproj | 4 +- .../Meshtastic.xcdatamodeld/.xccurrentversion | 2 +- .../contents | 476 ++++++++++++++++++ Meshtastic/Persistence/UpdateCoreData.swift | 12 +- .../Views/Settings/Config/DeviceConfig.swift | 10 - .../Views/Settings/Config/LoRaConfig.swift | 10 + .../Settings/Config/SecurityConfig.swift | 2 +- 8 files changed, 500 insertions(+), 22 deletions(-) create mode 100644 Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 44.xcdatamodel/contents diff --git a/Localizable.xcstrings b/Localizable.xcstrings index b447989f..42554c57 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -5068,9 +5068,6 @@ }, "Debug" : { - }, - "Debug Log" : { - }, "Debug Logs" : { @@ -15914,6 +15911,9 @@ }, "OK" : { + }, + "Ok to MQTT" : { + }, "OLED Type" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 1e63593b..b70f45ca 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -376,6 +376,7 @@ DD77093C2AA1AFA3007A8BF0 /* ChannelTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelTips.swift; sourceTree = ""; }; DD77093E2AA1B146007A8BF0 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; DD798B062915928D005217CD /* ChannelMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelMessageList.swift; sourceTree = ""; }; + DD7CF8DA2C93663C008BD10E /* MeshtasticDataModelV 44.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 44.xcdatamodel"; sourceTree = ""; }; DD7E235F2C7AA3E50078ACDF /* MeshtasticDataModelV 43.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 43.xcdatamodel"; sourceTree = ""; }; DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = ""; }; DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = ""; }; @@ -1898,6 +1899,7 @@ DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DD7CF8DA2C93663C008BD10E /* MeshtasticDataModelV 44.xcdatamodel */, DD7E235F2C7AA3E50078ACDF /* MeshtasticDataModelV 43.xcdatamodel */, DD1BD0F12C61D3AD008C0C70 /* MeshtasticDataModelV 42.xcdatamodel */, DD2984A82C5AEF7500B1268D /* MeshtasticDataModelV 41.xcdatamodel */, @@ -1942,7 +1944,7 @@ DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */, DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */, ); - currentVersion = DD7E235F2C7AA3E50078ACDF /* MeshtasticDataModelV 43.xcdatamodel */; + currentVersion = DD7CF8DA2C93663C008BD10E /* MeshtasticDataModelV 44.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 04d3cc1a..8a88003b 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModelV 43.xcdatamodel + MeshtasticDataModelV 44.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 44.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 44.xcdatamodel/contents new file mode 100644 index 00000000..98de0347 --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 44.xcdatamodel/contents @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index c1ee8470..fec3fbe9 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -463,7 +463,6 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessi let newDeviceConfig = DeviceConfigEntity(context: context) newDeviceConfig.role = Int32(config.role.rawValue) newDeviceConfig.serialEnabled = config.serialEnabled - newDeviceConfig.debugLogEnabled = config.debugLogEnabled newDeviceConfig.buttonGpio = Int32(config.buttonGpio) newDeviceConfig.buzzerGpio = Int32(config.buzzerGpio) newDeviceConfig.rebroadcastMode = Int32(config.rebroadcastMode.rawValue) @@ -476,7 +475,6 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessi } else { fetchedNode[0].deviceConfig?.role = Int32(config.role.rawValue) fetchedNode[0].deviceConfig?.serialEnabled = config.serialEnabled - fetchedNode[0].deviceConfig?.debugLogEnabled = config.debugLogEnabled fetchedNode[0].deviceConfig?.buttonGpio = Int32(config.buttonGpio) fetchedNode[0].deviceConfig?.buzzerGpio = Int32(config.buzzerGpio) fetchedNode[0].deviceConfig?.rebroadcastMode = Int32(config.rebroadcastMode.rawValue) @@ -818,21 +816,23 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, s let newSecurityConfig = SecurityConfigEntity(context: context) newSecurityConfig.publicKey = config.publicKey newSecurityConfig.privateKey = config.privateKey - newSecurityConfig.adminKey = config.adminKey + if config.adminKey.count > 0 { + newSecurityConfig.adminKey = config.adminKey[0] + } newSecurityConfig.isManaged = config.isManaged newSecurityConfig.serialEnabled = config.serialEnabled newSecurityConfig.debugLogApiEnabled = config.debugLogApiEnabled - newSecurityConfig.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled newSecurityConfig.adminChannelEnabled = config.adminChannelEnabled fetchedNode[0].securityConfig = newSecurityConfig } else { fetchedNode[0].securityConfig?.publicKey = config.publicKey fetchedNode[0].securityConfig?.privateKey = config.privateKey - fetchedNode[0].securityConfig?.adminKey = config.adminKey + if config.adminKey.count > 0 { + fetchedNode[0].securityConfig?.adminKey = config.adminKey[0] + } fetchedNode[0].securityConfig?.isManaged = config.isManaged fetchedNode[0].securityConfig?.serialEnabled = config.serialEnabled fetchedNode[0].securityConfig?.debugLogApiEnabled = config.debugLogApiEnabled - fetchedNode[0].securityConfig?.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled fetchedNode[0].securityConfig?.adminChannelEnabled = config.adminChannelEnabled } if sessionPasskey?.count != 0 { diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index dc17446e..c78cb845 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -24,7 +24,6 @@ struct DeviceConfig: View { @State var buzzerGPIO = 0 @State var buttonGPIO = 0 @State var serialEnabled = true - @State var debugLogEnabled = false @State var rebroadcastMode = 0 @State var nodeInfoBroadcastSecs = 10800 @State var doubleTapAsButtonPress = false @@ -89,10 +88,6 @@ struct DeviceConfig: View { Label("Serial Console", systemImage: "terminal") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - Toggle(isOn: $debugLogEnabled) { - Label("Debug Log", systemImage: "ant.fill") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) VStack(alignment: .leading) { HStack { Label("Time Zone", systemImage: "clock.badge.exclamationmark") @@ -200,7 +195,6 @@ struct DeviceConfig: View { var dc = Config.DeviceConfig() dc.role = DeviceRoles(rawValue: deviceRole)!.protoEnumValue() dc.serialEnabled = serialEnabled - dc.debugLogEnabled = debugLogEnabled dc.buttonGpio = UInt32(buttonGPIO) dc.buzzerGpio = UInt32(buzzerGPIO) dc.rebroadcastMode = RebroadcastModes(rawValue: rebroadcastMode)?.protoEnumValue() ?? RebroadcastModes.all.protoEnumValue() @@ -259,9 +253,6 @@ struct DeviceConfig: View { .onChange(of: serialEnabled) { if $0 != node?.deviceConfig?.serialEnabled { hasChanges = true } } - .onChange(of: debugLogEnabled) { - if $0 != node?.deviceConfig?.debugLogEnabled { hasChanges = true } - } .onChange(of: buttonGPIO) { newButtonGPIO in if newButtonGPIO != node?.deviceConfig?.buttonGpio ?? -1 { hasChanges = true } } @@ -289,7 +280,6 @@ struct DeviceConfig: View { func setDeviceValues() { self.deviceRole = Int(node?.deviceConfig?.role ?? 0) self.serialEnabled = (node?.deviceConfig?.serialEnabled ?? true) - self.debugLogEnabled = node?.deviceConfig?.debugLogEnabled ?? false self.buttonGPIO = Int(node?.deviceConfig?.buttonGpio ?? 0) self.buzzerGPIO = Int(node?.deviceConfig?.buzzerGpio ?? 0) self.rebroadcastMode = Int(node?.deviceConfig?.rebroadcastMode ?? 0) diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 43729f86..13623ee3 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -45,6 +45,7 @@ struct LoRaConfig: View { @State var rxBoostedGain = false @State var overrideFrequency: Float = 0.0 @State var ignoreMqtt = false + @State var okToMqtt = false let floatFormatter: NumberFormatter = { let formatter = NumberFormatter() @@ -100,6 +101,10 @@ struct LoRaConfig: View { Label("Ignore MQTT", systemImage: "server.rack") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + Toggle(isOn: $okToMqtt) { + Label("Ok to MQTT", systemImage: "network") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) Toggle(isOn: $txEnabled) { Label("Transmit Enabled", systemImage: "waveform.path") @@ -209,6 +214,7 @@ struct LoRaConfig: View { lc.sx126XRxBoostedGain = rxBoostedGain lc.overrideFrequency = overrideFrequency lc.ignoreMqtt = ignoreMqtt + lc.configOkToMqtt = okToMqtt if connectedNode?.num ?? -1 == node?.user?.num ?? 0 { UserDefaults.modemPreset = modemPreset } @@ -292,6 +298,9 @@ struct LoRaConfig: View { .onChange(of: ignoreMqtt) { if $0 != node?.loRaConfig?.ignoreMqtt { hasChanges = true } } + .onChange(of: okToMqtt) { + if $0 != node?.loRaConfig?.okToMqtt { hasChanges = true } + } } func setLoRaValues() { self.hopLimit = Int(node?.loRaConfig?.hopLimit ?? 3) @@ -307,6 +316,7 @@ struct LoRaConfig: View { self.rxBoostedGain = node?.loRaConfig?.sx126xRxBoostedGain ?? false self.overrideFrequency = node?.loRaConfig?.overrideFrequency ?? 0.0 self.ignoreMqtt = node?.loRaConfig?.ignoreMqtt ?? false + self.okToMqtt = node?.loRaConfig?.okToMqtt ?? false self.hasChanges = false } } diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index e58de058..95a07dfb 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -186,7 +186,7 @@ struct SecurityConfig: View { var config = Config.SecurityConfig() config.publicKey = Data(base64Encoded: publicKey) ?? Data() config.privateKey = Data(base64Encoded: privateKey) ?? Data() - config.adminKey = Data(base64Encoded: adminKey) ?? Data() + config.adminKey = [Data(base64Encoded: adminKey) ?? Data()] config.isManaged = isManaged config.serialEnabled = serialEnabled config.debugLogApiEnabled = debugLogApiEnabled From f8e1d0bfe39c4838db19df1fa62faad36da428ab Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 12 Sep 2024 13:52:47 -0700 Subject: [PATCH 13/17] Save don't mqtt me bro --- Meshtastic/Persistence/UpdateCoreData.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index fec3fbe9..faa8e606 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -598,6 +598,7 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPa newLoRaConfig.channelNum = Int32(config.channelNum) newLoRaConfig.sx126xRxBoostedGain = config.sx126XRxBoostedGain newLoRaConfig.ignoreMqtt = config.ignoreMqtt + newLoRaConfig.okToMqtt = config.configOkToMqtt fetchedNode[0].loRaConfig = newLoRaConfig } else { fetchedNode[0].loRaConfig?.regionCode = Int32(config.region.rawValue) @@ -615,6 +616,7 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPa fetchedNode[0].loRaConfig?.channelNum = Int32(config.channelNum) fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain fetchedNode[0].loRaConfig?.ignoreMqtt = config.ignoreMqtt + fetchedNode[0].loRaConfig?.okToMqtt = config.configOkToMqtt fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain } if sessionPasskey != nil { From 37d652cb39ea3c19cda21c17dbdea184d4ac3990 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 14 Sep 2024 08:48:09 -0700 Subject: [PATCH 14/17] Update protobufs --- .../Sources/meshtastic/admin.pb.swift | 5 + .../Sources/meshtastic/config.pb.swift | 119 ++++++++++++------ .../Sources/meshtastic/mesh.pb.swift | 65 ++++++++++ .../Sources/meshtastic/telemetry.pb.swift | 8 ++ protobufs | 2 +- 5 files changed, 161 insertions(+), 38 deletions(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 0f1c3586..53d244d1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -844,6 +844,7 @@ public struct AdminMessage { /// /// TODO: REPLACE case securityConfig // = 7 + case sessionkeyConfig // = 8 case UNRECOGNIZED(Int) public init() { @@ -860,6 +861,7 @@ public struct AdminMessage { case 5: self = .loraConfig case 6: self = .bluetoothConfig case 7: self = .securityConfig + case 8: self = .sessionkeyConfig default: self = .UNRECOGNIZED(rawValue) } } @@ -874,6 +876,7 @@ public struct AdminMessage { case .loraConfig: return 5 case .bluetoothConfig: return 6 case .securityConfig: return 7 + case .sessionkeyConfig: return 8 case .UNRECOGNIZED(let i): return i } } @@ -998,6 +1001,7 @@ extension AdminMessage.ConfigType: CaseIterable { .loraConfig, .bluetoothConfig, .securityConfig, + .sessionkeyConfig, ] } @@ -1755,6 +1759,7 @@ extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding { 5: .same(proto: "LORA_CONFIG"), 6: .same(proto: "BLUETOOTH_CONFIG"), 7: .same(proto: "SECURITY_CONFIG"), + 8: .same(proto: "SESSIONKEY_CONFIG"), ] } diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index 4b953470..37832baa 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -93,6 +93,14 @@ public struct Config { set {payloadVariant = .security(newValue)} } + public var sessionkey: Config.SessionkeyConfig { + get { + if case .sessionkey(let v)? = payloadVariant {return v} + return Config.SessionkeyConfig() + } + set {payloadVariant = .sessionkey(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -106,6 +114,7 @@ public struct Config { case lora(Config.LoRaConfig) case bluetooth(Config.BluetoothConfig) case security(Config.SecurityConfig) + case sessionkey(Config.SessionkeyConfig) #if !swift(>=4.1) public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { @@ -145,6 +154,10 @@ public struct Config { guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } return l == r }() + case (.sessionkey, .sessionkey): return { + guard case .sessionkey(let l) = lhs, case .sessionkey(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -167,12 +180,6 @@ public struct Config { /// Moved to SecurityConfig public var serialEnabled: Bool = false - /// - /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - /// Set this to true to leave the debug log outputting even when API is active. - /// Moved to SecurityConfig - public var debugLogEnabled: Bool = false - /// /// For boards without a hard wired button, this is the pin number that will be used /// Boards that have more than one button can swap the function with this one. defaults to BUTTON_PIN if defined. @@ -1250,6 +1257,13 @@ public struct Config { set {_uniqueStorage()._ignoreMqtt = newValue} } + /// + /// Sets the ok_to_mqtt bit on outgoing packets + public var configOkToMqtt: Bool { + get {return _storage._configOkToMqtt} + set {_uniqueStorage()._configOkToMqtt = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum RegionCode: SwiftProtobuf.Enum { @@ -1492,11 +1506,6 @@ public struct Config { /// Specified PIN for PairingMode.FixedPin public var fixedPin: UInt32 = 0 - /// - /// Enables device (serial style logs) over Bluetooth - /// Moved to SecurityConfig - public var deviceLoggingEnabled: Bool = false - public var unknownFields = SwiftProtobuf.UnknownStorage() public enum PairingMode: SwiftProtobuf.Enum { @@ -1559,7 +1568,7 @@ public struct Config { /// /// The public key authorized to send admin messages to this node. - public var adminKey: Data = Data() + public var adminKey: [Data] = [] /// /// If true, device is considered to be "managed" by a mesh administrator via admin messages @@ -1572,13 +1581,9 @@ public struct Config { /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - /// Output live debug logging over serial. + /// Output live debug logging over serial or bluetooth is set to true. public var debugLogApiEnabled: Bool = false - /// - /// Enables device (serial style logs) over Bluetooth - public var bluetoothLoggingEnabled: Bool = false - /// /// Allow incoming device control over the insecure legacy admin channel. public var adminChannelEnabled: Bool = false @@ -1588,6 +1593,18 @@ public struct Config { public init() {} } + /// + /// Blank config request, strictly for getting the session key + public struct SessionkeyConfig { + // 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. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + } + public init() {} } @@ -1784,6 +1801,7 @@ extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} extension Config.BluetoothConfig: @unchecked Sendable {} extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} extension Config.SecurityConfig: @unchecked Sendable {} +extension Config.SessionkeyConfig: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. @@ -1801,6 +1819,7 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas 6: .same(proto: "lora"), 7: .same(proto: "bluetooth"), 8: .same(proto: "security"), + 9: .same(proto: "sessionkey"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -1913,6 +1932,19 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas self.payloadVariant = .security(v) } }() + case 9: try { + var v: Config.SessionkeyConfig? + var hadOneofValue = false + if let current = self.payloadVariant { + hadOneofValue = true + if case .sessionkey(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.payloadVariant = .sessionkey(v) + } + }() default: break } } @@ -1956,6 +1988,10 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas guard case .security(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 8) }() + case .sessionkey?: try { + guard case .sessionkey(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 9) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -1973,7 +2009,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "role"), 2: .standard(proto: "serial_enabled"), - 3: .standard(proto: "debug_log_enabled"), 4: .standard(proto: "button_gpio"), 5: .standard(proto: "buzzer_gpio"), 6: .standard(proto: "rebroadcast_mode"), @@ -1993,7 +2028,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.role) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() - case 3: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }() case 4: try { try decoder.decodeSingularUInt32Field(value: &self.buttonGpio) }() case 5: try { try decoder.decodeSingularUInt32Field(value: &self.buzzerGpio) }() case 6: try { try decoder.decodeSingularEnumField(value: &self.rebroadcastMode) }() @@ -2015,9 +2049,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl if self.serialEnabled != false { try visitor.visitSingularBoolField(value: self.serialEnabled, fieldNumber: 2) } - if self.debugLogEnabled != false { - try visitor.visitSingularBoolField(value: self.debugLogEnabled, fieldNumber: 3) - } if self.buttonGpio != 0 { try visitor.visitSingularUInt32Field(value: self.buttonGpio, fieldNumber: 4) } @@ -2051,7 +2082,6 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl public static func ==(lhs: Config.DeviceConfig, rhs: Config.DeviceConfig) -> Bool { if lhs.role != rhs.role {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} - if lhs.debugLogEnabled != rhs.debugLogEnabled {return false} if lhs.buttonGpio != rhs.buttonGpio {return false} if lhs.buzzerGpio != rhs.buzzerGpio {return false} if lhs.rebroadcastMode != rhs.rebroadcastMode {return false} @@ -2595,6 +2625,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem 15: .standard(proto: "pa_fan_disabled"), 103: .standard(proto: "ignore_incoming"), 104: .standard(proto: "ignore_mqtt"), + 105: .standard(proto: "config_ok_to_mqtt"), ] fileprivate class _StorageClass { @@ -2615,6 +2646,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem var _paFanDisabled: Bool = false var _ignoreIncoming: [UInt32] = [] var _ignoreMqtt: Bool = false + var _configOkToMqtt: Bool = false #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -2646,6 +2678,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem _paFanDisabled = source._paFanDisabled _ignoreIncoming = source._ignoreIncoming _ignoreMqtt = source._ignoreMqtt + _configOkToMqtt = source._configOkToMqtt } } @@ -2681,6 +2714,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem case 15: try { try decoder.decodeSingularBoolField(value: &_storage._paFanDisabled) }() case 103: try { try decoder.decodeRepeatedUInt32Field(value: &_storage._ignoreIncoming) }() case 104: try { try decoder.decodeSingularBoolField(value: &_storage._ignoreMqtt) }() + case 105: try { try decoder.decodeSingularBoolField(value: &_storage._configOkToMqtt) }() default: break } } @@ -2740,6 +2774,9 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._ignoreMqtt != false { try visitor.visitSingularBoolField(value: _storage._ignoreMqtt, fieldNumber: 104) } + if _storage._configOkToMqtt != false { + try visitor.visitSingularBoolField(value: _storage._configOkToMqtt, fieldNumber: 105) + } } try unknownFields.traverse(visitor: &visitor) } @@ -2766,6 +2803,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._paFanDisabled != rhs_storage._paFanDisabled {return false} if _storage._ignoreIncoming != rhs_storage._ignoreIncoming {return false} if _storage._ignoreMqtt != rhs_storage._ignoreMqtt {return false} + if _storage._configOkToMqtt != rhs_storage._configOkToMqtt {return false} return true } if !storagesAreEqual {return false} @@ -2819,7 +2857,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI 1: .same(proto: "enabled"), 2: .same(proto: "mode"), 3: .standard(proto: "fixed_pin"), - 4: .standard(proto: "device_logging_enabled"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -2831,7 +2868,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI case 1: try { try decoder.decodeSingularBoolField(value: &self.enabled) }() case 2: try { try decoder.decodeSingularEnumField(value: &self.mode) }() case 3: try { try decoder.decodeSingularUInt32Field(value: &self.fixedPin) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.deviceLoggingEnabled) }() default: break } } @@ -2847,9 +2883,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI if self.fixedPin != 0 { try visitor.visitSingularUInt32Field(value: self.fixedPin, fieldNumber: 3) } - if self.deviceLoggingEnabled != false { - try visitor.visitSingularBoolField(value: self.deviceLoggingEnabled, fieldNumber: 4) - } try unknownFields.traverse(visitor: &visitor) } @@ -2857,7 +2890,6 @@ extension Config.BluetoothConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageI if lhs.enabled != rhs.enabled {return false} if lhs.mode != rhs.mode {return false} if lhs.fixedPin != rhs.fixedPin {return false} - if lhs.deviceLoggingEnabled != rhs.deviceLoggingEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -2880,7 +2912,6 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 4: .standard(proto: "is_managed"), 5: .standard(proto: "serial_enabled"), 6: .standard(proto: "debug_log_api_enabled"), - 7: .standard(proto: "bluetooth_logging_enabled"), 8: .standard(proto: "admin_channel_enabled"), ] @@ -2892,11 +2923,10 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm switch fieldNumber { case 1: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }() case 2: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }() - case 3: try { try decoder.decodeSingularBytesField(value: &self.adminKey) }() + case 3: try { try decoder.decodeRepeatedBytesField(value: &self.adminKey) }() case 4: try { try decoder.decodeSingularBoolField(value: &self.isManaged) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() case 6: try { try decoder.decodeSingularBoolField(value: &self.debugLogApiEnabled) }() - case 7: try { try decoder.decodeSingularBoolField(value: &self.bluetoothLoggingEnabled) }() case 8: try { try decoder.decodeSingularBoolField(value: &self.adminChannelEnabled) }() default: break } @@ -2911,7 +2941,7 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 2) } if !self.adminKey.isEmpty { - try visitor.visitSingularBytesField(value: self.adminKey, fieldNumber: 3) + try visitor.visitRepeatedBytesField(value: self.adminKey, fieldNumber: 3) } if self.isManaged != false { try visitor.visitSingularBoolField(value: self.isManaged, fieldNumber: 4) @@ -2922,9 +2952,6 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if self.debugLogApiEnabled != false { try visitor.visitSingularBoolField(value: self.debugLogApiEnabled, fieldNumber: 6) } - if self.bluetoothLoggingEnabled != false { - try visitor.visitSingularBoolField(value: self.bluetoothLoggingEnabled, fieldNumber: 7) - } if self.adminChannelEnabled != false { try visitor.visitSingularBoolField(value: self.adminChannelEnabled, fieldNumber: 8) } @@ -2938,9 +2965,27 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if lhs.isManaged != rhs.isManaged {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} if lhs.debugLogApiEnabled != rhs.debugLogApiEnabled {return false} - if lhs.bluetoothLoggingEnabled != rhs.bluetoothLoggingEnabled {return false} if lhs.adminChannelEnabled != rhs.adminChannelEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } + +extension Config.SessionkeyConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Config.protoMessageName + ".SessionkeyConfig" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + while let _ = try decoder.nextFieldNumber() { + } + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Config.SessionkeyConfig, rhs: Config.SessionkeyConfig) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index ba12908d..c7e8dc07 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -346,6 +346,19 @@ public enum HardwareModel: SwiftProtobuf.Enum { /// Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. case me25Ls014Y10Td // = 75 + /// + /// RP2040_FEATHER_RFM95 + /// Adafruit Feather RP2040 with RFM95 LoRa Radio RFM95 with SX1272, SSD1306 OLED + /// https://www.adafruit.com/product/5714 + /// https://www.adafruit.com/product/326 + /// https://www.adafruit.com/product/938 + /// ^^^ short A0 to switch to I2C address 0x3C + case rp2040FeatherRfm95 // = 76 + + /// M5 esp32 based MCU modules with enclosure, TFT and LORA Shields. All Variants (Basic, Core, Fire, Core2, Paper) https://m5stack.com/ + case m5StackCorebasic // = 77 + case m5StackCore2 // = 78 + /// /// ------------------------------------------------------------------------------------------------------------------------------------------ /// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. @@ -434,6 +447,9 @@ public enum HardwareModel: SwiftProtobuf.Enum { case 73: self = .wioE5 case 74: self = .radiomaster900Bandit case 75: self = .me25Ls014Y10Td + case 76: self = .rp2040FeatherRfm95 + case 77: self = .m5StackCorebasic + case 78: self = .m5StackCore2 case 255: self = .privateHw default: self = .UNRECOGNIZED(rawValue) } @@ -516,6 +532,9 @@ public enum HardwareModel: SwiftProtobuf.Enum { case .wioE5: return 73 case .radiomaster900Bandit: return 74 case .me25Ls014Y10Td: return 75 + case .rp2040FeatherRfm95: return 76 + case .m5StackCorebasic: return 77 + case .m5StackCore2: return 78 case .privateHw: return 255 case .UNRECOGNIZED(let i): return i } @@ -603,6 +622,9 @@ extension HardwareModel: CaseIterable { .wioE5, .radiomaster900Bandit, .me25Ls014Y10Td, + .rp2040FeatherRfm95, + .m5StackCorebasic, + .m5StackCore2, .privateHw, ] } @@ -1520,9 +1542,22 @@ public struct DataMessage { /// a message a heart or poop emoji. public var emoji: UInt32 = 0 + /// + /// Bitfield for extra flags. First use is to indicate that user approves the packet being uploaded to MQTT. + public var bitfield: UInt32 { + get {return _bitfield ?? 0} + set {_bitfield = newValue} + } + /// Returns true if `bitfield` has been explicitly set. + public var hasBitfield: Bool {return self._bitfield != nil} + /// Clears the value of `bitfield`. Subsequent reads from it will return its default value. + public mutating func clearBitfield() {self._bitfield = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _bitfield: UInt32? = nil } /// @@ -1907,6 +1942,15 @@ public struct MeshPacket { /// assume it is important and use a slightly higher priority case reliable // = 70 + /// + /// If priority is unset but the packet is a response to a request, we want it to get there relatively quickly. + /// Furthermore, responses stop relaying packets directed to a node early. + case response // = 80 + + /// + /// Higher priority for specific message types (portnums) to distinguish between other reliable packets. + case high // = 100 + /// /// Ack/naks are sent with very high priority to ensure that retransmission /// stops as soon as possible @@ -1928,6 +1972,8 @@ public struct MeshPacket { case 10: self = .background case 64: self = .default case 70: self = .reliable + case 80: self = .response + case 100: self = .high case 120: self = .ack case 127: self = .max default: self = .UNRECOGNIZED(rawValue) @@ -1941,6 +1987,8 @@ public struct MeshPacket { case .background: return 10 case .default: return 64 case .reliable: return 70 + case .response: return 80 + case .high: return 100 case .ack: return 120 case .max: return 127 case .UNRECOGNIZED(let i): return i @@ -2006,6 +2054,8 @@ extension MeshPacket.Priority: CaseIterable { .background, .default, .reliable, + .response, + .high, .ack, .max, ] @@ -3241,6 +3291,9 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 73: .same(proto: "WIO_E5"), 74: .same(proto: "RADIOMASTER_900_BANDIT"), 75: .same(proto: "ME25LS01_4Y10TD"), + 76: .same(proto: "RP2040_FEATHER_RFM95"), + 77: .same(proto: "M5STACK_COREBASIC"), + 78: .same(proto: "M5STACK_CORE2"), 255: .same(proto: "PRIVATE_HW"), ] } @@ -3779,6 +3832,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati 6: .standard(proto: "request_id"), 7: .standard(proto: "reply_id"), 8: .same(proto: "emoji"), + 9: .same(proto: "bitfield"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3795,12 +3849,17 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 6: try { try decoder.decodeSingularFixed32Field(value: &self.requestID) }() case 7: try { try decoder.decodeSingularFixed32Field(value: &self.replyID) }() case 8: try { try decoder.decodeSingularFixed32Field(value: &self.emoji) }() + case 9: try { try decoder.decodeSingularUInt32Field(value: &self._bitfield) }() default: break } } } public func traverse(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.portnum != .unknownApp { try visitor.visitSingularEnumField(value: self.portnum, fieldNumber: 1) } @@ -3825,6 +3884,9 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if self.emoji != 0 { try visitor.visitSingularFixed32Field(value: self.emoji, fieldNumber: 8) } + try { if let v = self._bitfield { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9) + } }() try unknownFields.traverse(visitor: &visitor) } @@ -3837,6 +3899,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if lhs.requestID != rhs.requestID {return false} if lhs.replyID != rhs.replyID {return false} if lhs.emoji != rhs.emoji {return false} + if lhs._bitfield != rhs._bitfield {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -4224,6 +4287,8 @@ extension MeshPacket.Priority: SwiftProtobuf._ProtoNameProviding { 10: .same(proto: "BACKGROUND"), 64: .same(proto: "DEFAULT"), 70: .same(proto: "RELIABLE"), + 80: .same(proto: "RESPONSE"), + 100: .same(proto: "HIGH"), 120: .same(proto: "ACK"), 127: .same(proto: "MAX"), ] diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index e4b9ee08..dc1d6cce 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -140,6 +140,10 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { /// /// MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) case max17048 // = 28 + + /// + /// Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor + case customSensor // = 29 case UNRECOGNIZED(Int) public init() { @@ -177,6 +181,7 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case 26: self = .bmp3Xx case 27: self = .icm20948 case 28: self = .max17048 + case 29: self = .customSensor default: self = .UNRECOGNIZED(rawValue) } } @@ -212,6 +217,7 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case .bmp3Xx: return 26 case .icm20948: return 27 case .max17048: return 28 + case .customSensor: return 29 case .UNRECOGNIZED(let i): return i } } @@ -252,6 +258,7 @@ extension TelemetrySensorType: CaseIterable { .bmp3Xx, .icm20948, .max17048, + .customSensor, ] } @@ -1003,6 +1010,7 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding { 26: .same(proto: "BMP3XX"), 27: .same(proto: "ICM20948"), 28: .same(proto: "MAX17048"), + 29: .same(proto: "CUSTOM_SENSOR"), ] } diff --git a/protobufs b/protobufs index 4da558d0..0acaec6e 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 4da558d0f73c46ef91b74431facee73c09affbfc +Subproject commit 0acaec6eff00e748beeae89148093221f131cd9c From 5fd1a821b3577dbde0400d22af349f4f5788d9b5 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 14 Sep 2024 10:37:00 -0700 Subject: [PATCH 15/17] Bump version --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index b70f45ca..7d9209f1 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1687,7 +1687,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.4; + MARKETING_VERSION = 2.5.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1722,7 +1722,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.4; + MARKETING_VERSION = 2.5.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1754,7 +1754,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.4; + MARKETING_VERSION = 2.5.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1787,7 +1787,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.4; + MARKETING_VERSION = 2.5.5; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From 98c90d52900a51cf05cc6fc22ca30266fd37d542 Mon Sep 17 00:00:00 2001 From: Jacob Powers Date: Sat, 14 Sep 2024 19:25:40 +0000 Subject: [PATCH 16/17] fix signal quality display when rssi missing --- .../Helpers/LoRaSignalStrengthIndicator.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift index 4405e819..03735ae2 100644 --- a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift +++ b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift @@ -72,6 +72,20 @@ private func getColor(signalStrength: LoRaSignalStrength) -> Color { } func getLoRaSignalStrength(snr: Float, rssi: Int32, preset: ModemPresets) -> LoRaSignalStrength { + // rssi is 0 when not available + if rssi == 0 { + if snr > (preset.snrLimit()) { + return .good + } + if snr < (preset.snrLimit() - 7.5) { + return .none + } + if snr <= (preset.snrLimit() - 5.5) { + return .bad + } + return .fair + } + if rssi > -115 && snr > (preset.snrLimit()) { return .good } else if rssi < -126 && snr < (preset.snrLimit() - 7.5) { From 70b9a8de513f85455f86d4231cbff27b852fca27 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 15 Sep 2024 11:35:35 -0700 Subject: [PATCH 17/17] Better filter before setting mismatched key --- Meshtastic/Helpers/MeshPackets.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 0c270ac9..09683c0e 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -886,11 +886,12 @@ func textMessageAppPacket( if fetchedUsers.first(where: { $0.num == packet.from }) != nil { newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) - if !(newMessage.fromUser?.publicKey?.isEmpty ?? true) { - // We have a key, check if it matches + if !(newMessage.fromUser?.publicKey?.isEmpty ?? true) && newMessage.toUser != nil && packet.pkiEncrypted { + // We have a key and it is a PKC encrypted DM, check if it matches if newMessage.fromUser?.publicKey != newMessage.publicKey { newMessage.fromUser?.keyMatch = false newMessage.fromUser?.newPublicKey = newMessage.publicKey + Logger.data.error("🔑 Key Mismatch origninal key: \(newMessage.fromUser?.publicKey?.base64EncodedString() ?? "No Key") new key: \(newMessage.fromUser?.newPublicKey?.base64EncodedString() ?? "No Key") ") } } else { /// We have no key, set it if it is not empty