From 9057f77e48a46196715f53ffcf8ed94a7efebde2 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 27 May 2022 19:18:33 -0700 Subject: [PATCH 1/5] Refactor Packet Handlers out out BLE Manger for testing and potentially TCP connections on iOS and serial on macOS --- Meshtastic Client.xcodeproj/project.pbxproj | 8 +- MeshtasticClient/Helpers/BLEManager.swift | 415 +-- MeshtasticClient/Helpers/MeshPackets.swift | 283 +++ MeshtasticClient/Model/PeripheralModel.swift | 4 +- .../Persistence/Persistence.swift | 2 +- MeshtasticClient/Protobufs/config.pb.swift | 48 +- .../Protobufs/deviceonly.pb.swift | 393 +++ MeshtasticClient/Protobufs/mesh.pb.swift | 78 +- .../Protobufs/module_config.pb.swift | 128 +- MeshtasticClient/Protobufs/portnums.pb.swift | 16 +- .../Protobufs/radioconfig.pb.swift | 2241 ----------------- .../Views/Bluetooth/Connect.swift | 4 +- .../Views/Helpers/LastHeardText.swift | 3 +- .../Views/Messages/UserMessageList.swift | 2 +- MeshtasticClient/Views/Nodes/NodeDetail.swift | 16 +- MeshtasticClient/Views/Nodes/NodeList.swift | 5 +- MeshtasticClient/Views/Nodes/NodeMap.swift | 4 +- .../Views/Settings/AppSettings.swift | 2 +- .../Views/Settings/ShareChannel.swift | 2 +- gen_protos.sh | 2 +- 20 files changed, 902 insertions(+), 2754 deletions(-) create mode 100644 MeshtasticClient/Helpers/MeshPackets.swift delete mode 100644 MeshtasticClient/Protobufs/radioconfig.pb.swift diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index d2feb92c..e6ecaea9 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -37,10 +37,10 @@ DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90860D26F69BAE00DC5189 /* NodeMap.swift */; }; DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */; }; DD9D8F2F2764403B00080993 /* Meshtastic.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */; }; + DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */; }; DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C5226EB1DF10058C060 /* BLEManager.swift */; }; DDAF8C5826ED07FD0058C060 /* mesh.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C5726ED07FD0058C060 /* mesh.pb.swift */; }; DDAF8C5D26ED09490058C060 /* portnums.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C5C26ED09490058C060 /* portnums.pb.swift */; }; - DDAF8C5F26ED09B50058C060 /* radioconfig.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C5E26ED09B50058C060 /* radioconfig.pb.swift */; }; DDAF8C6226ED0A230058C060 /* mqtt.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6026ED0A230058C060 /* mqtt.pb.swift */; }; DDAF8C6326ED0A230058C060 /* admin.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6126ED0A230058C060 /* admin.pb.swift */; }; DDAF8C6526ED0A490058C060 /* channel.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6426ED0A490058C060 /* channel.pb.swift */; }; @@ -109,10 +109,10 @@ DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = ""; }; DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationManager.swift; sourceTree = ""; }; DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = CoreDataSample.xcdatamodel; sourceTree = ""; }; + DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshPackets.swift; sourceTree = ""; }; DDAF8C5226EB1DF10058C060 /* BLEManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLEManager.swift; sourceTree = ""; }; DDAF8C5726ED07FD0058C060 /* mesh.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = mesh.pb.swift; sourceTree = ""; }; DDAF8C5C26ED09490058C060 /* portnums.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = portnums.pb.swift; sourceTree = ""; }; - DDAF8C5E26ED09B50058C060 /* radioconfig.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = radioconfig.pb.swift; sourceTree = ""; }; DDAF8C6026ED0A230058C060 /* mqtt.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = mqtt.pb.swift; sourceTree = ""; }; DDAF8C6126ED0A230058C060 /* admin.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = admin.pb.swift; sourceTree = ""; }; DDAF8C6426ED0A490058C060 /* channel.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = channel.pb.swift; sourceTree = ""; }; @@ -237,7 +237,6 @@ DD4C158B2824A91E0032668E /* module_config.pb.swift */, DDAF8C6026ED0A230058C060 /* mqtt.pb.swift */, DDAF8C5C26ED09490058C060 /* portnums.pb.swift */, - DDAF8C5E26ED09B50058C060 /* radioconfig.pb.swift */, DDAF8C6626ED0C8C0058C060 /* remote_hardware.pb.swift */, DD17E5DC277D49D400010EC2 /* storeforward.pb.swift */, DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */, @@ -371,6 +370,7 @@ DDAF8C6D26ED19040058C060 /* Extensions.swift */, DD913638270DFF4C00D7ACF3 /* LocalNotificationManager.swift */, DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */, + DDA6B2E828419CF2003E8C16 /* MeshPackets.swift */, ); path = Helpers; sourceTree = ""; @@ -547,7 +547,6 @@ DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */, DDAF8C6E26ED19040058C060 /* Extensions.swift in Sources */, DDC2E1A726CEB3400042C5E4 /* LocationHelper.swift in Sources */, - DDAF8C5F26ED09B50058C060 /* radioconfig.pb.swift in Sources */, DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */, DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */, DD4C158C2824A91E0032668E /* module_config.pb.swift in Sources */, @@ -579,6 +578,7 @@ DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */, DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */, DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */, + DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */, C9A88B57278B559900BD810A /* apponly.pb.swift in Sources */, DD4C158E2824AA7E0032668E /* config.pb.swift in Sources */, DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */, diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 0ff0cb9d..a7220d4e 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -171,12 +171,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { var peripheralName: String = peripheral.name ?? "Unknown" + let last4Code: String = (peripheral.name != nil ? String(peripheral.name!.suffix(4)) : "Unknown") if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String { peripheralName = name } - let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: String(peripheralName.suffix(3)), longName: peripheralName, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral) + let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: String(peripheralName.suffix(3)), longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral) let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id }) if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected { @@ -390,9 +391,54 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } var decodedInfo = FromRadio() - decodedInfo = try! FromRadio(serializedData: characteristic.value!) + switch decodedInfo.packet.decoded.portnum { + + case .unknownApp: + print("MyInfo or NodeInfo") + print("Sending nodeinfo: num=0x3b9c2510, lastseen=0, id=!3b9c2510, name=Unknown 2510") + case .textMessageApp: + textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) + case .remoteHardwareApp: + print("remoteHardwareApp") + case .positionApp: + print("positionApp") + case .nodeinfoApp: + print("nodeinfoApp") + case .routingApp: + routingPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) + case .adminApp: + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") + case .replyApp: + print("replyApp") + case .ipTunnelApp: + print("ipTunnelApp") + case .serialApp: + print("serialApp") + case .storeForwardApp: + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Store Forward App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") + case .rangeTestApp: + print("rangeTestApp") + case .telemetryApp: + telemetryPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) + case .textMessageCompressedApp: + print("textMessageCompressedApp") + case .zpsApp: + print("zpsApp") + case .privateApp: + print("privateApp") + case .atakForwarder: + print("atakForwarder") + case .UNRECOGNIZED(_): + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for UNRECOGNIZED App UNHANDLED \(try! decodedInfo.packet.jsonString())") + case .max: + print("MAX PORT NUM OF 511") + } + // MARK: Incoming MyInfo Packet if decodedInfo.myInfo.myNodeNum != 0 { @@ -440,18 +486,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph print("💾 Saved the All - Broadcast User") } - //var settingsCalled = self.getSettings() - - if false { - - print("💾 Called Get Settings") - - } else { - - print("💥 Get Settings Call Failed") - } - - } catch { print("💥 Error Saving the All - Broadcast User") @@ -690,300 +724,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if meshLoggingEnabled { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.num)") } } } - // Handle other packet types - if decodedInfo.packet.id != 0 { - do { - - // MARK: Incoming Packet from the TEXTMESSAGE_APP - if decodedInfo.packet.decoded.portnum == PortNum.textMessageApp { - - if let messageText = String(bytes: decodedInfo.packet.decoded.payload, encoding: .utf8) { - - print("💬 BLE FROMRADIO received for text message app \(messageText)") - if meshLoggingEnabled { MeshLogger.log("💬 BLE FROMRADIO received for text message app \(messageText)") } - - let messageUsers: NSFetchRequest = NSFetchRequest.init(entityName: "UserEntity") - messageUsers.predicate = NSPredicate(format: "num IN %@", [decodedInfo.packet.to, decodedInfo.packet.from]) - - do { - - let fetchedUsers = try context?.fetch(messageUsers) as! [UserEntity] - - let newMessage = MessageEntity(context: context!) - newMessage.messageId = Int64(decodedInfo.packet.id) - newMessage.messageTimestamp = Int32(bitPattern: decodedInfo.packet.rxTime) - newMessage.receivedACK = false - newMessage.direction = "IN" - newMessage.isEmoji = decodedInfo.packet.decoded.emoji == 1 - - if decodedInfo.packet.decoded.replyID > 0 { - - newMessage.replyID = Int64(decodedInfo.packet.decoded.replyID) - } - - if decodedInfo.packet.to == broadcastNodeNum && fetchedUsers.count == 1 { - - // Save the broadcast user if it does not exist - let bcu: UserEntity = UserEntity(context: context!) - bcu.shortName = "ALL" - bcu.longName = "All - Broadcast" - bcu.hwModel = "UNSET" - bcu.num = Int64(broadcastNodeNum) - bcu.userId = "BROADCASTNODE" - newMessage.toUser = bcu - - } else { - - newMessage.toUser = fetchedUsers.first(where: { $0.num == decodedInfo.packet.to }) - } - - newMessage.fromUser = fetchedUsers.first(where: { $0.num == decodedInfo.packet.from }) - newMessage.messagePayload = messageText - - do { - - try context!.save() - print("💾 Saved a new message for \(decodedInfo.packet.id)") - if meshLoggingEnabled { MeshLogger.log("💾 Saved a new message for \(newMessage.messageId)") } - - if newMessage.toUser != nil && newMessage.toUser!.num == self.broadcastNodeNum || self.connectedPeripheral != nil && self.connectedPeripheral.num == newMessage.toUser!.num { - - // Create an iOS Notification for the received message and schedule it immediately - let manager = LocalNotificationManager() - - manager.notifications = [ - Notification( - id: ("notification.id.\(newMessage.messageId)"), - title: "\(newMessage.fromUser?.longName ?? "Unknown")", - subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")", - content: messageText) - ] - manager.schedule() - if meshLoggingEnabled { MeshLogger.log("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "Unknown") \(messageText)") } - - } - } catch { - - context!.rollback() - - let nsError = error as NSError - print("💥 Failed to save new MessageEntity \(nsError)") - } - - } catch { - - print("💥 Fetch Message To and From Users Error") - } - } - // MARK: Incoming NODEINFO_APP Packet - } else if decodedInfo.packet.decoded.portnum == PortNum.nodeinfoApp { - - let fetchNodeInfoAppRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") - fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.packet.from)) - - do { - - let fetchedNode = try context?.fetch(fetchNodeInfoAppRequest) as! [NodeInfoEntity] - - if fetchedNode.count == 1 { - fetchedNode[0].id = Int64(decodedInfo.packet.from) - fetchedNode[0].num = Int64(decodedInfo.packet.from) - fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime))) - fetchedNode[0].snr = decodedInfo.packet.rxSnr - - } else { - return - } - do { - - try context!.save() - - if meshLoggingEnabled { MeshLogger.log("💾 Updated NodeInfo SNR \(decodedInfo.packet.rxSnr) and Time from Node Info App Packet For: \(fetchedNode[0].num)")} - print("💾 Updated NodeInfo SNR \(decodedInfo.packet.rxSnr) and Time from Packet For: \(fetchedNode[0].num)") - - } catch { - - context!.rollback() - - let nsError = error as NSError - print("💥 Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") - - } - } catch { - - print("💥 Error Fetching NodeInfoEntity for NODEINFO_APP") - } - - // MARK: Incoming Packet from the POSITION_APP - } else if decodedInfo.packet.decoded.portnum == PortNum.positionApp { - let fetchNodePositionRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") - fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(decodedInfo.packet.from)) - - do { - - let fetchedNode = try context?.fetch(fetchNodePositionRequest) as! [NodeInfoEntity] - - if fetchedNode.count == 1 { - fetchedNode[0].id = Int64(decodedInfo.packet.from) - fetchedNode[0].num = Int64(decodedInfo.packet.from) - fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime))) - fetchedNode[0].snr = decodedInfo.packet.rxSnr - - if let positionMessage = try? Position(serializedData: decodedInfo.packet.decoded.payload) { - - let position = PositionEntity(context: context!) - position.latitudeI = positionMessage.latitudeI - position.longitudeI = positionMessage.longitudeI - position.altitude = positionMessage.altitude - position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time))) - - let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet - mutablePositions.add(position) - - fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet - } - - } else { - - return - } - do { - - try context!.save() - - if meshLoggingEnabled { - MeshLogger.log("💾 Updated NodeInfo Position Coordinates, SNR \(decodedInfo.packet.rxSnr) and Time from Position App Packet For: \(fetchedNode[0].num)") - } - print("💾 Updated NodeInfo Position Coordinates, SNR \(decodedInfo.packet.rxSnr) and Time from Position App Packet For:: \(fetchedNode[0].num)") - - } catch { - - context!.rollback() - - let nsError = error as NSError - print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)") - } - } catch { - - print("💥 Error Fetching NodeInfoEntity for POSITION_APP") - } - // MARK: Incoming ROUTING_APP Packet - } else if decodedInfo.packet.decoded.portnum == PortNum.routingApp { - - - if let routingMessage = try? Routing(serializedData: decodedInfo.packet.decoded.payload) { - print(decodedInfo.packet.decoded.requestID) - print(routingMessage) - - let error = routingMessage.errorReason - - var errorExplanation = "Unknown Routing Error" - - switch error { - case Routing.Error.none: - errorExplanation = "This message is not a failure" - case Routing.Error.noRoute: - errorExplanation = "Our node doesn't have a route to the requested destination anymore." - case Routing.Error.gotNak: - errorExplanation = "We received a nak while trying to forward on your behalf" - case Routing.Error.timeout: - errorExplanation = "Timeout" - case Routing.Error.noInterface: - errorExplanation = "No suitable interface could be found for delivering this packet" - case Routing.Error.maxRetransmit: - errorExplanation = "We reached the max retransmission count (typically for naive flood routing)" - case Routing.Error.noChannel: - errorExplanation = "No suitable channel was found for sending this packet (i.e. was requested channel index disabled?)" - case Routing.Error.tooLarge: - errorExplanation = "The packet was too big for sending (exceeds interface MTU after encoding)" - case Routing.Error.noResponse: - errorExplanation = "The request had want_response set, the request reached the destination node, but no service on that node wants to send a response (possibly due to bad channel permissions)" - case Routing.Error.badRequest: - errorExplanation = "The application layer service on the remote node received your request, but considered your request somehow invalid" - case Routing.Error.notAuthorized: - errorExplanation = "The application layer service on the remote node received your request, but considered your request not authorized (i.e you did not send the request on the required bound channel)" - fallthrough - default: - print(error) - } - - if meshLoggingEnabled { MeshLogger.log("🕸️ ROUTING PACKET received for RequestID: \(decodedInfo.packet.decoded.requestID) Error: \(errorExplanation)") } - print("🕸️ ROUTING PACKET received for RequestID: \(decodedInfo.packet.decoded.requestID) Error: \(errorExplanation)") - - - if routingMessage.errorReason == Routing.Error.none { - - print("Priority ACK no Error") - - let fetchMessageRequest: NSFetchRequest = NSFetchRequest.init(entityName: "MessageEntity") - fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(decodedInfo.packet.decoded.requestID)) - - do { - - let fetchedMessage = try context?.fetch(fetchMessageRequest)[0] as? MessageEntity - - if fetchedMessage != nil { - - fetchedMessage!.receivedACK = true - fetchedMessage!.ackSNR = decodedInfo.packet.rxSnr - fetchedMessage!.ackTimestamp = Int32(decodedInfo.packet.rxTime) - fetchedMessage!.objectWillChange.send() - } - - try context!.save() - - if meshLoggingEnabled { - MeshLogger.log("💾 ACK Received and saved for MessageID \(decodedInfo.packet.decoded.requestID)") - } - print("💾 ACK Received and saved for MessageID \(decodedInfo.packet.decoded.requestID)") - - } catch { - - context!.rollback() - - let nsError = error as NSError - print("💥 Error Saving ACK for message MessageID \(decodedInfo.packet.id) Error: \(nsError)") - } - } - } - - // MARK: Incoming TELEMETRY_APP Packet - } else if decodedInfo.packet.decoded.portnum == PortNum.telemetryApp { - - - if let telemetryMessage = try? Telemetry(serializedData: decodedInfo.packet.decoded.payload) { - - let telemetry = TelemetryEntity(context: context!) - print(decodedInfo.packet.decoded.requestID) - print(telemetryMessage) - } - - - if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(try decodedInfo.packet.jsonString())") - - } else if decodedInfo.packet.decoded.portnum == PortNum.storeForwardApp { - - if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Store Forward App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") - - } else if decodedInfo.packet.decoded.portnum == PortNum.adminApp { - - if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try decodedInfo.packet.jsonString())") - - } else { - - if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Other App UNHANDLED \(try decodedInfo.packet.jsonString())") - } - - } catch { - if meshLoggingEnabled { MeshLogger.log("⚰️ Fatal Error: Failed to decode json") } - print("⚰️ Fatal Error: Failed to decode json") - } - } if decodedInfo.configCompleteID != 0 { @@ -994,20 +735,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } case FROMNUM_UUID : - print("🚨 FROMNUM Characteristic UUID: \(characteristic.uuid)") - if characteristic.value == nil || characteristic.value!.isEmpty { - return - } + + print("FROMNUM Notification, value will be read below") - var decodedInfo = FromRadio() - - //decodedInfo = try! FromRadio(serializedData: characteristic.value!) - default: print("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)") } - peripheral.readValue(for: FROMRADIO_characteristic) - } + peripheral.readValue(for: FROMRADIO_characteristic) + } // Send Message public func sendMessage(message: String, toUserNum: Int64, isEmoji: Bool, replyID: Int64) -> Bool { @@ -1116,6 +851,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph print("💾 Saved a new sent message to \(toUserNum)") if meshLoggingEnabled { MeshLogger.log("💾 Saved a new sent message from \(connectedPeripheral.num) to \(toUserNum)") } success = true + //sendShutdown(destNum: connectedPeripheral.num, wantResponse: true) } catch { @@ -1165,7 +901,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph var meshPacket = MeshPacket() meshPacket.to = UInt32(destNum) - meshPacket.from = UInt32(connectedPeripheral.num) + meshPacket.from = 0 //UInt32(connectedPeripheral.num) meshPacket.wantAck = wantResponse var dataMessage = DataMessage() @@ -1179,13 +915,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph toRadio.packet = meshPacket let binaryData: Data = try! toRadio.serializedData() - if meshLoggingEnabled { MeshLogger.log("📍 Sent a Position Packet from the phone to the device for node: \(fromNodeNum)") } - print("📍 Sent a Position Packet from the phone to the device for node: \(fromNodeNum)") + if meshLoggingEnabled { MeshLogger.log("📍 Sent a Position Packet from the Apple device GPS to node: \(fromNodeNum)") } + print("📍 Sent a Position Packet from the Apple device GPS to node: \(fromNodeNum)") if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) success = true + } } @@ -1218,7 +955,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph public func getSettings() -> Bool { var adminPacket = AdminMessage() - //adminPacket.getRadioRequest = true var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(connectedPeripheral.num) @@ -1249,4 +985,41 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph return false } + + // Send Position + public func sendShutdown(destNum: Int64, wantResponse: Bool) -> Bool { + + var adminPacket = AdminMessage() + adminPacket.rebootSeconds = 30 + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(connectedPeripheral.num) + meshPacket.from = UInt32(connectedPeripheral.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from)) + + do { + + let fetchedNode = try context.fetch(fetchNodeInfoAppRequest) as! [NodeInfoEntity] + + if fetchedNode.count == 1 { + fetchedNode[0].id = Int64(packet.from) + fetchedNode[0].num = Int64(packet.from) + fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + fetchedNode[0].snr = packet.rxSnr + + } else { + return + } + do { + + try context.save() + + if meshLogging { MeshLogger.log("💾 Updated NodeInfo SNR \(packet.rxSnr) and Time from Node Info App Packet For: \(fetchedNode[0].num)")} + print("💾 Updated NodeInfo SNR \(packet.rxSnr) and Time from Packet For: \(fetchedNode[0].num)") + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Saving NodeInfoEntity from NODEINFO_APP \(nsError)") + + } + } catch { + + print("💥 Error Fetching NodeInfoEntity for NODEINFO_APP") + } +} + +func positionPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) { + + let fetchNodePositionRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNodePositionRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from)) + + do { + + let fetchedNode = try context.fetch(fetchNodePositionRequest) as! [NodeInfoEntity] + + if fetchedNode.count == 1 { + + fetchedNode[0].id = Int64(packet.from) + fetchedNode[0].num = Int64(packet.from) + fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + fetchedNode[0].snr = packet.rxSnr + + if let positionMessage = try? Position(serializedData: packet.decoded.payload) { + + let position = PositionEntity(context: context) + position.latitudeI = positionMessage.latitudeI + position.longitudeI = positionMessage.longitudeI + position.altitude = positionMessage.altitude + position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time))) + + let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet + mutablePositions.add(position) + + fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet + } + + } else { + + return + } + do { + + try context.save() + + if meshLogging { + MeshLogger.log("💾 Updated NodeInfo Position Coordinates, SNR \(packet.rxSnr) and Time from Position App Packet For: \(fetchedNode[0].num)") + } + print("💾 Updated NodeInfo Position Coordinates, SNR \(packet.rxSnr) and Time from Position App Packet For: \(fetchedNode[0].num)") + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)") + } + } catch { + + print("💥 Error Fetching NodeInfoEntity for POSITION_APP") + } + +} + +func routingPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) { + + if let routingMessage = try? Routing(serializedData: packet.decoded.payload) { + print(packet.decoded.requestID) + print(routingMessage) + + let error = routingMessage.errorReason + + var errorExplanation = "Unknown Routing Error" + + switch error { + case Routing.Error.none: + errorExplanation = "This message is not a failure" + case Routing.Error.noRoute: + errorExplanation = "Our node doesn't have a route to the requested destination anymore." + case Routing.Error.gotNak: + errorExplanation = "We received a nak while trying to forward on your behalf" + case Routing.Error.timeout: + errorExplanation = "Timeout" + case Routing.Error.noInterface: + errorExplanation = "No suitable interface could be found for delivering this packet" + case Routing.Error.maxRetransmit: + errorExplanation = "We reached the max retransmission count (typically for naive flood routing)" + case Routing.Error.noChannel: + errorExplanation = "No suitable channel was found for sending this packet (i.e. was requested channel index disabled?)" + case Routing.Error.tooLarge: + errorExplanation = "The packet was too big for sending (exceeds interface MTU after encoding)" + case Routing.Error.noResponse: + errorExplanation = "The request had want_response set, the request reached the destination node, but no service on that node wants to send a response (possibly due to bad channel permissions)" + case Routing.Error.badRequest: + errorExplanation = "The application layer service on the remote node received your request, but considered your request somehow invalid" + case Routing.Error.notAuthorized: + errorExplanation = "The application layer service on the remote node received your request, but considered your request not authorized (i.e you did not send the request on the required bound channel)" + fallthrough + default: + print(error) + } + + if meshLogging { MeshLogger.log("🕸️ ROUTING PACKET received for RequestID: \(packet.decoded.requestID) Error: \(errorExplanation)") } + print("🕸️ ROUTING PACKET received for RequestID: \(packet.decoded.requestID) Error: \(errorExplanation)") + + if routingMessage.errorReason == Routing.Error.none { + + print("Priority ACK no Error") + + let fetchMessageRequest: NSFetchRequest = NSFetchRequest.init(entityName: "MessageEntity") + fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID)) + + do { + + let fetchedMessage = try context.fetch(fetchMessageRequest)[0] as? MessageEntity + + if fetchedMessage != nil { + + fetchedMessage!.receivedACK = true + fetchedMessage!.ackSNR = packet.rxSnr + fetchedMessage!.ackTimestamp = Int32(packet.rxTime) + fetchedMessage!.objectWillChange.send() + } + + try context.save() + + if meshLogging { + MeshLogger.log("💾 ACK Received and saved for MessageID \(packet.decoded.requestID)") + } + print("💾 ACK Received and saved for MessageID \(packet.decoded.requestID)") + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Saving ACK for message MessageID \(packet.id) Error: \(nsError)") + } + } + } +} + +func telemetryPacket(packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) { + + if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) { + + let telemetry = TelemetryEntity(context: context) + print(packet.decoded.requestID) + + if meshLogging { MeshLogger.log("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(telemetryMessage)") } + print("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(telemetryMessage)") + + } else { + + } +} + +func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, meshLogging: Bool, context: NSManagedObjectContext) { + + let broadcastNodeNum: UInt32 = 4294967295 + + if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) { + + print("💬 BLE FROMRADIO received for text message app \(messageText)") + if meshLogging { MeshLogger.log("💬 BLE FROMRADIO received for text message app \(messageText)") } + + let messageUsers: NSFetchRequest = NSFetchRequest.init(entityName: "UserEntity") + messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from]) + + do { + + let fetchedUsers = try context.fetch(messageUsers) as! [UserEntity] + + let newMessage = MessageEntity(context: context) + newMessage.messageId = Int64(packet.id) + newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime) + newMessage.receivedACK = false + newMessage.direction = "IN" + newMessage.isEmoji = packet.decoded.emoji == 1 + + if packet.decoded.replyID > 0 { + + newMessage.replyID = Int64(packet.decoded.replyID) + } + + if packet.to == broadcastNodeNum && fetchedUsers.count == 1 { + + // Save the broadcast user if it does not exist + let bcu: UserEntity = UserEntity(context: context) + bcu.shortName = "ALL" + bcu.longName = "All - Broadcast" + bcu.hwModel = "UNSET" + bcu.num = Int64(broadcastNodeNum) + bcu.userId = "BROADCASTNODE" + newMessage.toUser = bcu + + } else { + + newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to }) + } + + newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) + newMessage.messagePayload = messageText + + do { + + try context.save() + print("💾 Saved a new message for \(packet.id)") + if meshLogging { MeshLogger.log("💾 Saved a new message for \(newMessage.messageId)") } + + if newMessage.toUser != nil && newMessage.toUser!.num == broadcastNodeNum || connectedNode == newMessage.toUser!.num { + + // Create an iOS Notification for the received message and schedule it immediately + let manager = LocalNotificationManager() + + manager.notifications = [ + Notification( + id: ("notification.id.\(newMessage.messageId)"), + title: "\(newMessage.fromUser?.longName ?? "Unknown")", + subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")", + content: messageText) + ] + manager.schedule() + if meshLogging { MeshLogger.log("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "Unknown") \(messageText)") } + + } + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Failed to save new MessageEntity \(nsError)") + } + + } catch { + + print("💥 Fetch Message To and From Users Error") + } + } +} diff --git a/MeshtasticClient/Model/PeripheralModel.swift b/MeshtasticClient/Model/PeripheralModel.swift index 18f00d6b..cfdadc44 100644 --- a/MeshtasticClient/Model/PeripheralModel.swift +++ b/MeshtasticClient/Model/PeripheralModel.swift @@ -7,6 +7,7 @@ struct Peripheral: Identifiable { var name: String var shortName: String var longName: String + var lastFourCode: String var firmwareVersion: String var rssi: Int var bitrate: Float? @@ -16,12 +17,13 @@ struct Peripheral: Identifiable { var subscribed: Bool var peripheral: CBPeripheral - init(id: String, num: Int64, name: String, shortName: String, longName: String, firmwareVersion: String, rssi: Int, bitrate: Float?, channelUtilization: Float?, airTime: Float?, lastUpdate: Date, subscribed: Bool, peripheral: CBPeripheral) { + init(id: String, num: Int64, name: String, shortName: String, longName: String, lastFourCode: String, firmwareVersion: String, rssi: Int, bitrate: Float?, channelUtilization: Float?, airTime: Float?, lastUpdate: Date, subscribed: Bool, peripheral: CBPeripheral) { self.id = id self.num = num self.name = name self.shortName = shortName self.longName = longName + self.lastFourCode = lastFourCode self.firmwareVersion = firmwareVersion self.rssi = rssi self.bitrate = bitrate diff --git a/MeshtasticClient/Persistence/Persistence.swift b/MeshtasticClient/Persistence/Persistence.swift index c37af6e4..855b407f 100644 --- a/MeshtasticClient/Persistence/Persistence.swift +++ b/MeshtasticClient/Persistence/Persistence.swift @@ -34,7 +34,7 @@ class PersistenceController { init(inMemory: Bool = false) { container = NSPersistentContainer(name: "Meshtastic") - //self.clearDatabase() + //Likeself.clearDatabase() if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") diff --git a/MeshtasticClient/Protobufs/config.pb.swift b/MeshtasticClient/Protobufs/config.pb.swift index b2d08a49..e411e8ea 100644 --- a/MeshtasticClient/Protobufs/config.pb.swift +++ b/MeshtasticClient/Protobufs/config.pb.swift @@ -257,7 +257,7 @@ struct Config { var positionBroadcastSecs: UInt32 = 0 /// - /// We should send our position this often (but only if it has changed significantly) + /// Disable adaptive position braoadcast, which is now the default. var positionBroadcastSmartDisabled: Bool = false /// @@ -266,10 +266,6 @@ struct Config { /// The lat/lon/alt can be set by an internal GPS or with the help of the app. var fixedPosition: Bool = false - /// - /// Should we disbale location sharing with other nodes (or the local phone) - var locationShareDisabled: Bool = false - /// /// Should the GPS be disabled for this node? var gpsDisabled: Bool = false @@ -618,6 +614,10 @@ struct Config { /// will be a station var apMode: Bool = false + /// + /// If set, the node AP will broadcast as a hidden SSID + var apHidden: Bool = false + var unknownFields = SwiftProtobuf.UnknownStorage() init() {} @@ -738,7 +738,7 @@ struct Config { /// Because protobufs take ZERO space when the value is zero this works out nicely. /// This value is replaced by bandwidth/spread_factor/coding_rate. /// If you'd like to experiment with other options add them to MeshRadio.cpp in the device code. - var modemPreset: Config.LoRaConfig.ModemPreset = .vlongSlow + var modemPreset: Config.LoRaConfig.ModemPreset = .longFast /// /// Bandwidth in MHz @@ -898,7 +898,7 @@ struct Config { /// /// TODO: REPLACE - case vlongSlow // = 0 + case longFast // = 0 /// /// TODO: REPLACE @@ -906,7 +906,7 @@ struct Config { /// /// TODO: REPLACE - case longFast // = 2 + case vlongSlow // = 2 /// /// TODO: REPLACE @@ -926,14 +926,14 @@ struct Config { case UNRECOGNIZED(Int) init() { - self = .vlongSlow + self = .longFast } init?(rawValue: Int) { switch rawValue { - case 0: self = .vlongSlow + case 0: self = .longFast case 1: self = .longSlow - case 2: self = .longFast + case 2: self = .vlongSlow case 3: self = .midSlow case 4: self = .midFast case 5: self = .shortSlow @@ -944,9 +944,9 @@ struct Config { var rawValue: Int { switch self { - case .vlongSlow: return 0 + case .longFast: return 0 case .longSlow: return 1 - case .longFast: return 2 + case .vlongSlow: return 2 case .midSlow: return 3 case .midFast: return 4 case .shortSlow: return 5 @@ -1047,9 +1047,9 @@ extension Config.LoRaConfig.RegionCode: CaseIterable { extension Config.LoRaConfig.ModemPreset: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. static var allCases: [Config.LoRaConfig.ModemPreset] = [ - .vlongSlow, - .longSlow, .longFast, + .longSlow, + .vlongSlow, .midSlow, .midFast, .shortSlow, @@ -1291,7 +1291,6 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 1: .standard(proto: "position_broadcast_secs"), 2: .standard(proto: "position_broadcast_smart_disabled"), 3: .standard(proto: "fixed_position"), - 4: .standard(proto: "location_share_disabled"), 5: .standard(proto: "gps_disabled"), 6: .standard(proto: "gps_update_interval"), 7: .standard(proto: "gps_attempt_time"), @@ -1309,7 +1308,6 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm case 1: try { try decoder.decodeSingularUInt32Field(value: &self.positionBroadcastSecs) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.positionBroadcastSmartDisabled) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.fixedPosition) }() - case 4: try { try decoder.decodeSingularBoolField(value: &self.locationShareDisabled) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.gpsDisabled) }() case 6: try { try decoder.decodeSingularUInt32Field(value: &self.gpsUpdateInterval) }() case 7: try { try decoder.decodeSingularUInt32Field(value: &self.gpsAttemptTime) }() @@ -1331,9 +1329,6 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if self.fixedPosition != false { try visitor.visitSingularBoolField(value: self.fixedPosition, fieldNumber: 3) } - if self.locationShareDisabled != false { - try visitor.visitSingularBoolField(value: self.locationShareDisabled, fieldNumber: 4) - } if self.gpsDisabled != false { try visitor.visitSingularBoolField(value: self.gpsDisabled, fieldNumber: 5) } @@ -1359,7 +1354,6 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if lhs.positionBroadcastSecs != rhs.positionBroadcastSecs {return false} if lhs.positionBroadcastSmartDisabled != rhs.positionBroadcastSmartDisabled {return false} if lhs.fixedPosition != rhs.fixedPosition {return false} - if lhs.locationShareDisabled != rhs.locationShareDisabled {return false} if lhs.gpsDisabled != rhs.gpsDisabled {return false} if lhs.gpsUpdateInterval != rhs.gpsUpdateInterval {return false} if lhs.gpsAttemptTime != rhs.gpsAttemptTime {return false} @@ -1511,6 +1505,7 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem 1: .same(proto: "ssid"), 2: .same(proto: "psk"), 3: .standard(proto: "ap_mode"), + 4: .standard(proto: "ap_hidden"), ] mutating func decodeMessage(decoder: inout D) throws { @@ -1522,6 +1517,7 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem case 1: try { try decoder.decodeSingularStringField(value: &self.ssid) }() case 2: try { try decoder.decodeSingularStringField(value: &self.psk) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.apMode) }() + case 4: try { try decoder.decodeSingularBoolField(value: &self.apHidden) }() default: break } } @@ -1537,6 +1533,9 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if self.apMode != false { try visitor.visitSingularBoolField(value: self.apMode, fieldNumber: 3) } + if self.apHidden != false { + try visitor.visitSingularBoolField(value: self.apHidden, fieldNumber: 4) + } try unknownFields.traverse(visitor: &visitor) } @@ -1544,6 +1543,7 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if lhs.ssid != rhs.ssid {return false} if lhs.psk != rhs.psk {return false} if lhs.apMode != rhs.apMode {return false} + if lhs.apHidden != rhs.apHidden {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -1644,7 +1644,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 1) } - if self.modemPreset != .vlongSlow { + if self.modemPreset != .longFast { try visitor.visitSingularEnumField(value: self.modemPreset, fieldNumber: 2) } if self.bandwidth != 0 { @@ -1710,9 +1710,9 @@ extension Config.LoRaConfig.RegionCode: SwiftProtobuf._ProtoNameProviding { extension Config.LoRaConfig.ModemPreset: SwiftProtobuf._ProtoNameProviding { static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "VLongSlow"), + 0: .same(proto: "LongFast"), 1: .same(proto: "LongSlow"), - 2: .same(proto: "LongFast"), + 2: .same(proto: "VLongSlow"), 3: .same(proto: "MidSlow"), 4: .same(proto: "MidFast"), 5: .same(proto: "ShortSlow"), diff --git a/MeshtasticClient/Protobufs/deviceonly.pb.swift b/MeshtasticClient/Protobufs/deviceonly.pb.swift index 52a31d33..95139c11 100644 --- a/MeshtasticClient/Protobufs/deviceonly.pb.swift +++ b/MeshtasticClient/Protobufs/deviceonly.pb.swift @@ -215,11 +215,180 @@ struct OEMStore { init() {} } +struct LocalConfig { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// + /// TODO: REPLACE + var device: Config.DeviceConfig { + get {return _storage._device ?? Config.DeviceConfig()} + set {_uniqueStorage()._device = newValue} + } + /// Returns true if `device` has been explicitly set. + var hasDevice: Bool {return _storage._device != nil} + /// Clears the value of `device`. Subsequent reads from it will return its default value. + mutating func clearDevice() {_uniqueStorage()._device = nil} + + /// + /// TODO: REPLACE + var position: Config.PositionConfig { + get {return _storage._position ?? Config.PositionConfig()} + set {_uniqueStorage()._position = newValue} + } + /// Returns true if `position` has been explicitly set. + var hasPosition: Bool {return _storage._position != nil} + /// Clears the value of `position`. Subsequent reads from it will return its default value. + mutating func clearPosition() {_uniqueStorage()._position = nil} + + /// + /// TODO: REPLACE + var power: Config.PowerConfig { + get {return _storage._power ?? Config.PowerConfig()} + set {_uniqueStorage()._power = newValue} + } + /// Returns true if `power` has been explicitly set. + var hasPower: Bool {return _storage._power != nil} + /// Clears the value of `power`. Subsequent reads from it will return its default value. + mutating func clearPower() {_uniqueStorage()._power = nil} + + /// + /// TODO: REPLACE + var wifi: Config.WiFiConfig { + get {return _storage._wifi ?? Config.WiFiConfig()} + set {_uniqueStorage()._wifi = newValue} + } + /// Returns true if `wifi` has been explicitly set. + var hasWifi: Bool {return _storage._wifi != nil} + /// Clears the value of `wifi`. Subsequent reads from it will return its default value. + mutating func clearWifi() {_uniqueStorage()._wifi = nil} + + /// + /// TODO: REPLACE + var display: Config.DisplayConfig { + get {return _storage._display ?? Config.DisplayConfig()} + set {_uniqueStorage()._display = newValue} + } + /// Returns true if `display` has been explicitly set. + var hasDisplay: Bool {return _storage._display != nil} + /// Clears the value of `display`. Subsequent reads from it will return its default value. + mutating func clearDisplay() {_uniqueStorage()._display = nil} + + /// + /// TODO: REPLACE + var lora: Config.LoRaConfig { + get {return _storage._lora ?? Config.LoRaConfig()} + set {_uniqueStorage()._lora = newValue} + } + /// Returns true if `lora` has been explicitly set. + var hasLora: Bool {return _storage._lora != nil} + /// Clears the value of `lora`. Subsequent reads from it will return its default value. + mutating func clearLora() {_uniqueStorage()._lora = nil} + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _storage = _StorageClass.defaultInstance +} + +struct LocalModuleConfig { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// + /// TODO: REPLACE + var mqtt: ModuleConfig.MQTTConfig { + get {return _storage._mqtt ?? ModuleConfig.MQTTConfig()} + set {_uniqueStorage()._mqtt = newValue} + } + /// Returns true if `mqtt` has been explicitly set. + var hasMqtt: Bool {return _storage._mqtt != nil} + /// Clears the value of `mqtt`. Subsequent reads from it will return its default value. + mutating func clearMqtt() {_uniqueStorage()._mqtt = nil} + + /// + /// TODO: REPLACE + var serial: ModuleConfig.SerialConfig { + get {return _storage._serial ?? ModuleConfig.SerialConfig()} + set {_uniqueStorage()._serial = newValue} + } + /// Returns true if `serial` has been explicitly set. + var hasSerial: Bool {return _storage._serial != nil} + /// Clears the value of `serial`. Subsequent reads from it will return its default value. + mutating func clearSerial() {_uniqueStorage()._serial = nil} + + /// + /// TODO: REPLACE + var externalNotification: ModuleConfig.ExternalNotificationConfig { + get {return _storage._externalNotification ?? ModuleConfig.ExternalNotificationConfig()} + set {_uniqueStorage()._externalNotification = newValue} + } + /// Returns true if `externalNotification` has been explicitly set. + var hasExternalNotification: Bool {return _storage._externalNotification != nil} + /// Clears the value of `externalNotification`. Subsequent reads from it will return its default value. + mutating func clearExternalNotification() {_uniqueStorage()._externalNotification = nil} + + /// + /// TODO: REPLACE + var storeForward: ModuleConfig.StoreForwardConfig { + get {return _storage._storeForward ?? ModuleConfig.StoreForwardConfig()} + set {_uniqueStorage()._storeForward = newValue} + } + /// Returns true if `storeForward` has been explicitly set. + var hasStoreForward: Bool {return _storage._storeForward != nil} + /// Clears the value of `storeForward`. Subsequent reads from it will return its default value. + mutating func clearStoreForward() {_uniqueStorage()._storeForward = nil} + + /// + /// TODO: REPLACE + var rangeTest: ModuleConfig.RangeTestConfig { + get {return _storage._rangeTest ?? ModuleConfig.RangeTestConfig()} + set {_uniqueStorage()._rangeTest = newValue} + } + /// Returns true if `rangeTest` has been explicitly set. + var hasRangeTest: Bool {return _storage._rangeTest != nil} + /// Clears the value of `rangeTest`. Subsequent reads from it will return its default value. + mutating func clearRangeTest() {_uniqueStorage()._rangeTest = nil} + + /// + /// TODO: REPLACE + var telemetry: ModuleConfig.TelemetryConfig { + get {return _storage._telemetry ?? ModuleConfig.TelemetryConfig()} + set {_uniqueStorage()._telemetry = newValue} + } + /// Returns true if `telemetry` has been explicitly set. + var hasTelemetry: Bool {return _storage._telemetry != nil} + /// Clears the value of `telemetry`. Subsequent reads from it will return its default value. + mutating func clearTelemetry() {_uniqueStorage()._telemetry = nil} + + /// + /// TODO: REPLACE + var cannedMessage: ModuleConfig.CannedMessageConfig { + get {return _storage._cannedMessage ?? ModuleConfig.CannedMessageConfig()} + set {_uniqueStorage()._cannedMessage = newValue} + } + /// Returns true if `cannedMessage` has been explicitly set. + var hasCannedMessage: Bool {return _storage._cannedMessage != nil} + /// Clears the value of `cannedMessage`. Subsequent reads from it will return its default value. + mutating func clearCannedMessage() {_uniqueStorage()._cannedMessage = nil} + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _storage = _StorageClass.defaultInstance +} + #if swift(>=5.5) && canImport(_Concurrency) extension ScreenFonts: @unchecked Sendable {} extension DeviceState: @unchecked Sendable {} extension ChannelFile: @unchecked Sendable {} extension OEMStore: @unchecked Sendable {} +extension LocalConfig: @unchecked Sendable {} +extension LocalModuleConfig: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. @@ -443,3 +612,227 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB return true } } + +extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = "LocalConfig" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "device"), + 2: .same(proto: "position"), + 3: .same(proto: "power"), + 4: .same(proto: "wifi"), + 5: .same(proto: "display"), + 6: .same(proto: "lora"), + ] + + fileprivate class _StorageClass { + var _device: Config.DeviceConfig? = nil + var _position: Config.PositionConfig? = nil + var _power: Config.PowerConfig? = nil + var _wifi: Config.WiFiConfig? = nil + var _display: Config.DisplayConfig? = nil + var _lora: Config.LoRaConfig? = nil + + static let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _device = source._device + _position = source._position + _power = source._power + _wifi = source._wifi + _display = source._display + _lora = source._lora + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + + mutating func decodeMessage(decoder: inout D) throws { + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._device) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._position) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._power) }() + case 4: try { try decoder.decodeSingularMessageField(value: &_storage._wifi) }() + case 5: try { try decoder.decodeSingularMessageField(value: &_storage._display) }() + case 6: try { try decoder.decodeSingularMessageField(value: &_storage._lora) }() + default: break + } + } + } + } + + func traverse(visitor: inout V) throws { + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._device { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._position { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._power { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + try { if let v = _storage._wifi { + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + } }() + try { if let v = _storage._display { + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + } }() + try { if let v = _storage._lora { + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + } }() + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: LocalConfig, rhs: LocalConfig) -> Bool { + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._device != rhs_storage._device {return false} + if _storage._position != rhs_storage._position {return false} + if _storage._power != rhs_storage._power {return false} + if _storage._wifi != rhs_storage._wifi {return false} + if _storage._display != rhs_storage._display {return false} + if _storage._lora != rhs_storage._lora {return false} + return true + } + if !storagesAreEqual {return false} + } + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = "LocalModuleConfig" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "mqtt"), + 2: .same(proto: "serial"), + 3: .standard(proto: "external_notification"), + 4: .standard(proto: "store_forward"), + 5: .standard(proto: "range_test"), + 6: .same(proto: "telemetry"), + 7: .standard(proto: "canned_message"), + ] + + fileprivate class _StorageClass { + var _mqtt: ModuleConfig.MQTTConfig? = nil + var _serial: ModuleConfig.SerialConfig? = nil + var _externalNotification: ModuleConfig.ExternalNotificationConfig? = nil + var _storeForward: ModuleConfig.StoreForwardConfig? = nil + var _rangeTest: ModuleConfig.RangeTestConfig? = nil + var _telemetry: ModuleConfig.TelemetryConfig? = nil + var _cannedMessage: ModuleConfig.CannedMessageConfig? = nil + + static let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _mqtt = source._mqtt + _serial = source._serial + _externalNotification = source._externalNotification + _storeForward = source._storeForward + _rangeTest = source._rangeTest + _telemetry = source._telemetry + _cannedMessage = source._cannedMessage + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + + mutating func decodeMessage(decoder: inout D) throws { + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._mqtt) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._serial) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._externalNotification) }() + case 4: try { try decoder.decodeSingularMessageField(value: &_storage._storeForward) }() + case 5: try { try decoder.decodeSingularMessageField(value: &_storage._rangeTest) }() + case 6: try { try decoder.decodeSingularMessageField(value: &_storage._telemetry) }() + case 7: try { try decoder.decodeSingularMessageField(value: &_storage._cannedMessage) }() + default: break + } + } + } + } + + func traverse(visitor: inout V) throws { + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._mqtt { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._serial { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._externalNotification { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + try { if let v = _storage._storeForward { + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + } }() + try { if let v = _storage._rangeTest { + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + } }() + try { if let v = _storage._telemetry { + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + } }() + try { if let v = _storage._cannedMessage { + try visitor.visitSingularMessageField(value: v, fieldNumber: 7) + } }() + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: LocalModuleConfig, rhs: LocalModuleConfig) -> Bool { + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._mqtt != rhs_storage._mqtt {return false} + if _storage._serial != rhs_storage._serial {return false} + if _storage._externalNotification != rhs_storage._externalNotification {return false} + if _storage._storeForward != rhs_storage._storeForward {return false} + if _storage._rangeTest != rhs_storage._rangeTest {return false} + if _storage._telemetry != rhs_storage._telemetry {return false} + if _storage._cannedMessage != rhs_storage._cannedMessage {return false} + return true + } + if !storagesAreEqual {return false} + } + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/MeshtasticClient/Protobufs/mesh.pb.swift b/MeshtasticClient/Protobufs/mesh.pb.swift index c53f4a8c..84ee16ce 100644 --- a/MeshtasticClient/Protobufs/mesh.pb.swift +++ b/MeshtasticClient/Protobufs/mesh.pb.swift @@ -1037,27 +1037,9 @@ struct DataMessage { /// Formerly named typ and of type Type var portnum: PortNum = .unknownApp - var payloadVariant: DataMessage.OneOf_PayloadVariant? = nil - /// /// TODO: REPLACE - var payload: Data { - get { - if case .payload(let v)? = payloadVariant {return v} - return Data() - } - set {payloadVariant = .payload(newValue)} - } - - /// - /// TODO: REPLACE - var payloadCompressed: Data { - get { - if case .payloadCompressed(let v)? = payloadVariant {return v} - return Data() - } - set {payloadVariant = .payloadCompressed(newValue)} - } + var payload: Data = Data() /// /// Not normally used, but for testing a sender can request that recipient @@ -1106,34 +1088,6 @@ struct DataMessage { var unknownFields = SwiftProtobuf.UnknownStorage() - enum OneOf_PayloadVariant: Equatable { - /// - /// TODO: REPLACE - case payload(Data) - /// - /// TODO: REPLACE - case payloadCompressed(Data) - - #if !swift(>=4.1) - static func ==(lhs: DataMessage.OneOf_PayloadVariant, rhs: DataMessage.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 (.payload, .payload): return { - guard case .payload(let l) = lhs, case .payload(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.payloadCompressed, .payloadCompressed): return { - guard case .payloadCompressed(let l) = lhs, case .payloadCompressed(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif - } - init() {} fileprivate var _location: Location? = nil @@ -2142,7 +2096,6 @@ extension Routing: @unchecked Sendable {} extension Routing.OneOf_Variant: @unchecked Sendable {} extension Routing.Error: @unchecked Sendable {} extension DataMessage: @unchecked Sendable {} -extension DataMessage.OneOf_PayloadVariant: @unchecked Sendable {} extension Location: @unchecked Sendable {} extension MeshPacket: @unchecked Sendable {} extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} @@ -2684,7 +2637,6 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "portnum"), 2: .same(proto: "payload"), - 10: .standard(proto: "payload_compressed"), 3: .standard(proto: "want_response"), 4: .same(proto: "dest"), 5: .same(proto: "source"), @@ -2701,14 +2653,7 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.portnum) }() - case 2: try { - var v: Data? - try decoder.decodeSingularBytesField(value: &v) - if let v = v { - if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} - self.payloadVariant = .payload(v) - } - }() + case 2: try { try decoder.decodeSingularBytesField(value: &self.payload) }() case 3: try { try decoder.decodeSingularBoolField(value: &self.wantResponse) }() case 4: try { try decoder.decodeSingularFixed32Field(value: &self.dest) }() case 5: try { try decoder.decodeSingularFixed32Field(value: &self.source) }() @@ -2716,14 +2661,6 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 7: try { try decoder.decodeSingularFixed32Field(value: &self.replyID) }() case 8: try { try decoder.decodeSingularFixed32Field(value: &self.emoji) }() case 9: try { try decoder.decodeSingularMessageField(value: &self._location) }() - case 10: try { - var v: Data? - try decoder.decodeSingularBytesField(value: &v) - if let v = v { - if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} - self.payloadVariant = .payloadCompressed(v) - } - }() default: break } } @@ -2737,9 +2674,9 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if self.portnum != .unknownApp { try visitor.visitSingularEnumField(value: self.portnum, fieldNumber: 1) } - try { if case .payload(let v)? = self.payloadVariant { - try visitor.visitSingularBytesField(value: v, fieldNumber: 2) - } }() + if !self.payload.isEmpty { + try visitor.visitSingularBytesField(value: self.payload, fieldNumber: 2) + } if self.wantResponse != false { try visitor.visitSingularBoolField(value: self.wantResponse, fieldNumber: 3) } @@ -2761,15 +2698,12 @@ extension DataMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati try { if let v = self._location { try visitor.visitSingularMessageField(value: v, fieldNumber: 9) } }() - try { if case .payloadCompressed(let v)? = self.payloadVariant { - try visitor.visitSingularBytesField(value: v, fieldNumber: 10) - } }() try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: DataMessage, rhs: DataMessage) -> Bool { if lhs.portnum != rhs.portnum {return false} - if lhs.payloadVariant != rhs.payloadVariant {return false} + if lhs.payload != rhs.payload {return false} if lhs.wantResponse != rhs.wantResponse {return false} if lhs.dest != rhs.dest {return false} if lhs.source != rhs.source {return false} diff --git a/MeshtasticClient/Protobufs/module_config.pb.swift b/MeshtasticClient/Protobufs/module_config.pb.swift index 56bf157d..66aea788 100644 --- a/MeshtasticClient/Protobufs/module_config.pb.swift +++ b/MeshtasticClient/Protobufs/module_config.pb.swift @@ -253,21 +253,21 @@ struct ModuleConfig { enum Serial_Baud: SwiftProtobuf.Enum { typealias RawValue = Int case baudDefault // = 0 - case baud2400 // = 1 - case baud4800 // = 2 - case baud9600 // = 3 - case baud19200 // = 4 - case baud38400 // = 5 - case baud57600 // = 6 - case baud115200 // = 7 - case baud230400 // = 8 - case baud460800 // = 9 - case baud576000 // = 10 - case baud921600 // = 11 - case baud110 // = 12 - case baud300 // = 13 - case baud600 // = 14 - case baud1200 // = 15 + case baud110 // = 1 + case baud300 // = 2 + case baud600 // = 3 + case baud1200 // = 4 + case baud2400 // = 5 + case baud4800 // = 6 + case baud9600 // = 7 + case baud19200 // = 8 + case baud38400 // = 9 + case baud57600 // = 10 + case baud115200 // = 11 + case baud230400 // = 12 + case baud460800 // = 13 + case baud576000 // = 14 + case baud921600 // = 15 case UNRECOGNIZED(Int) init() { @@ -277,21 +277,21 @@ struct ModuleConfig { init?(rawValue: Int) { switch rawValue { case 0: self = .baudDefault - case 1: self = .baud2400 - case 2: self = .baud4800 - case 3: self = .baud9600 - case 4: self = .baud19200 - case 5: self = .baud38400 - case 6: self = .baud57600 - case 7: self = .baud115200 - case 8: self = .baud230400 - case 9: self = .baud460800 - case 10: self = .baud576000 - case 11: self = .baud921600 - case 12: self = .baud110 - case 13: self = .baud300 - case 14: self = .baud600 - case 15: self = .baud1200 + case 1: self = .baud110 + case 2: self = .baud300 + case 3: self = .baud600 + case 4: self = .baud1200 + case 5: self = .baud2400 + case 6: self = .baud4800 + case 7: self = .baud9600 + case 8: self = .baud19200 + case 9: self = .baud38400 + case 10: self = .baud57600 + case 11: self = .baud115200 + case 12: self = .baud230400 + case 13: self = .baud460800 + case 14: self = .baud576000 + case 15: self = .baud921600 default: self = .UNRECOGNIZED(rawValue) } } @@ -299,21 +299,21 @@ struct ModuleConfig { var rawValue: Int { switch self { case .baudDefault: return 0 - case .baud2400: return 1 - case .baud4800: return 2 - case .baud9600: return 3 - case .baud19200: return 4 - case .baud38400: return 5 - case .baud57600: return 6 - case .baud115200: return 7 - case .baud230400: return 8 - case .baud460800: return 9 - case .baud576000: return 10 - case .baud921600: return 11 - case .baud110: return 12 - case .baud300: return 13 - case .baud600: return 14 - case .baud1200: return 15 + case .baud110: return 1 + case .baud300: return 2 + case .baud600: return 3 + case .baud1200: return 4 + case .baud2400: return 5 + case .baud4800: return 6 + case .baud9600: return 7 + case .baud19200: return 8 + case .baud38400: return 9 + case .baud57600: return 10 + case .baud115200: return 11 + case .baud230400: return 12 + case .baud460800: return 13 + case .baud576000: return 14 + case .baud921600: return 15 case .UNRECOGNIZED(let i): return i } } @@ -643,6 +643,10 @@ extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. static var allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, .baud2400, .baud4800, .baud9600, @@ -654,10 +658,6 @@ extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { .baud460800, .baud576000, .baud921600, - .baud110, - .baud300, - .baud600, - .baud1200, ] } @@ -990,21 +990,21 @@ extension ModuleConfig.SerialConfig: SwiftProtobuf.Message, SwiftProtobuf._Messa extension ModuleConfig.SerialConfig.Serial_Baud: SwiftProtobuf._ProtoNameProviding { static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 0: .same(proto: "BAUD_Default"), - 1: .same(proto: "BAUD_2400"), - 2: .same(proto: "BAUD_4800"), - 3: .same(proto: "BAUD_9600"), - 4: .same(proto: "BAUD_19200"), - 5: .same(proto: "BAUD_38400"), - 6: .same(proto: "BAUD_57600"), - 7: .same(proto: "BAUD_115200"), - 8: .same(proto: "BAUD_230400"), - 9: .same(proto: "BAUD_460800"), - 10: .same(proto: "BAUD_576000"), - 11: .same(proto: "BAUD_921600"), - 12: .same(proto: "BAUD_110"), - 13: .same(proto: "BAUD_300"), - 14: .same(proto: "BAUD_600"), - 15: .same(proto: "BAUD_1200"), + 1: .same(proto: "BAUD_110"), + 2: .same(proto: "BAUD_300"), + 3: .same(proto: "BAUD_600"), + 4: .same(proto: "BAUD_1200"), + 5: .same(proto: "BAUD_2400"), + 6: .same(proto: "BAUD_4800"), + 7: .same(proto: "BAUD_9600"), + 8: .same(proto: "BAUD_19200"), + 9: .same(proto: "BAUD_38400"), + 10: .same(proto: "BAUD_57600"), + 11: .same(proto: "BAUD_115200"), + 12: .same(proto: "BAUD_230400"), + 13: .same(proto: "BAUD_460800"), + 14: .same(proto: "BAUD_576000"), + 15: .same(proto: "BAUD_921600"), ] } diff --git a/MeshtasticClient/Protobufs/portnums.pb.swift b/MeshtasticClient/Protobufs/portnums.pb.swift index db2d73bd..1f63debc 100644 --- a/MeshtasticClient/Protobufs/portnums.pb.swift +++ b/MeshtasticClient/Protobufs/portnums.pb.swift @@ -73,6 +73,10 @@ enum PortNum: SwiftProtobuf.Enum { /// Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message case adminApp // = 6 + /// + /// Compressed TEXT_MESSAGE payloads. + case textMessageCompressedApp // = 7 + /// /// Provides a 'ping' service that replies to any packet it receives. /// Also serves as a small example module. @@ -110,10 +114,6 @@ enum PortNum: SwiftProtobuf.Enum { /// Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS case zpsApp // = 68 - /// - /// Compressed payloads. - case compressionApp // = 69 - /// /// Private applications should use portnums >= 256. /// To simplify initial development and testing you can use "PRIVATE_APP" @@ -142,6 +142,7 @@ enum PortNum: SwiftProtobuf.Enum { case 4: self = .nodeinfoApp case 5: self = .routingApp case 6: self = .adminApp + case 7: self = .textMessageCompressedApp case 32: self = .replyApp case 33: self = .ipTunnelApp case 64: self = .serialApp @@ -149,7 +150,6 @@ enum PortNum: SwiftProtobuf.Enum { case 66: self = .rangeTestApp case 67: self = .telemetryApp case 68: self = .zpsApp - case 69: self = .compressionApp case 256: self = .privateApp case 257: self = .atakForwarder case 511: self = .max @@ -166,6 +166,7 @@ enum PortNum: SwiftProtobuf.Enum { case .nodeinfoApp: return 4 case .routingApp: return 5 case .adminApp: return 6 + case .textMessageCompressedApp: return 7 case .replyApp: return 32 case .ipTunnelApp: return 33 case .serialApp: return 64 @@ -173,7 +174,6 @@ enum PortNum: SwiftProtobuf.Enum { case .rangeTestApp: return 66 case .telemetryApp: return 67 case .zpsApp: return 68 - case .compressionApp: return 69 case .privateApp: return 256 case .atakForwarder: return 257 case .max: return 511 @@ -195,6 +195,7 @@ extension PortNum: CaseIterable { .nodeinfoApp, .routingApp, .adminApp, + .textMessageCompressedApp, .replyApp, .ipTunnelApp, .serialApp, @@ -202,7 +203,6 @@ extension PortNum: CaseIterable { .rangeTestApp, .telemetryApp, .zpsApp, - .compressionApp, .privateApp, .atakForwarder, .max, @@ -226,6 +226,7 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding { 4: .same(proto: "NODEINFO_APP"), 5: .same(proto: "ROUTING_APP"), 6: .same(proto: "ADMIN_APP"), + 7: .same(proto: "TEXT_MESSAGE_COMPRESSED_APP"), 32: .same(proto: "REPLY_APP"), 33: .same(proto: "IP_TUNNEL_APP"), 64: .same(proto: "SERIAL_APP"), @@ -233,7 +234,6 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding { 66: .same(proto: "RANGE_TEST_APP"), 67: .same(proto: "TELEMETRY_APP"), 68: .same(proto: "ZPS_APP"), - 69: .same(proto: "COMPRESSION_APP"), 256: .same(proto: "PRIVATE_APP"), 257: .same(proto: "ATAK_FORWARDER"), 511: .same(proto: "MAX"), diff --git a/MeshtasticClient/Protobufs/radioconfig.pb.swift b/MeshtasticClient/Protobufs/radioconfig.pb.swift deleted file mode 100644 index 53e39e75..00000000 --- a/MeshtasticClient/Protobufs/radioconfig.pb.swift +++ /dev/null @@ -1,2241 +0,0 @@ -// DO NOT EDIT. -// swift-format-ignore-file -// -// Generated by the Swift generator plugin for the protocol buffer compiler. -// Source: radioconfig.proto -// -// For information on using the generated types, please see the documentation: -// https://github.com/apple/swift-protobuf/ - -import Foundation -import SwiftProtobuf - -// If the compiler emits an error on this type, it is because this file -// was generated by a version of the `protoc` Swift plug-in that is -// incompatible with the version of SwiftProtobuf to which you are linking. -// Please ensure that you are building against the same version of the API -// that was used to generate this file. -fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck { - struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {} - typealias Version = _2 -} - -/// -/// The frequency/regulatory region the user has selected. -/// Note: In 1.0 builds (which must still be supported by the android app for a -/// long time) this field will be unpopulated. -/// If firmware is ever upgraded from an old 1.0ish build, the old -/// MyNodeInfo.region string will be used to set UserPreferences.region and the -/// old value will be no longer set. -enum RegionCode: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// TODO: REPLACE - case unset // = 0 - - /// - /// TODO: REPLACE - case us // = 1 - - /// - /// TODO: REPLACE - case eu433 // = 2 - - /// - /// TODO: REPLACE - case eu868 // = 3 - - /// - /// TODO: REPLACE - case cn // = 4 - - /// - /// TODO: REPLACE - case jp // = 5 - - /// - /// TODO: REPLACE - case anz // = 6 - - /// - /// TODO: REPLACE - case kr // = 7 - - /// - /// TODO: REPLACE - case tw // = 8 - - /// - /// TODO: REPLACE - case ru // = 9 - - /// - /// TODO: REPLACE - case `in` // = 10 - - /// - /// TODO: REPLACE - case nz865 // = 11 - - /// - /// TODO: REPLACE - case th // = 12 - case UNRECOGNIZED(Int) - - init() { - self = .unset - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .unset - case 1: self = .us - case 2: self = .eu433 - case 3: self = .eu868 - case 4: self = .cn - case 5: self = .jp - case 6: self = .anz - case 7: self = .kr - case 8: self = .tw - case 9: self = .ru - case 10: self = .in - case 11: self = .nz865 - case 12: self = .th - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .unset: return 0 - case .us: return 1 - case .eu433: return 2 - case .eu868: return 3 - case .cn: return 4 - case .jp: return 5 - case .anz: return 6 - case .kr: return 7 - case .tw: return 8 - case .ru: return 9 - case .in: return 10 - case .nz865: return 11 - case .th: return 12 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension RegionCode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - ] -} - -#endif // swift(>=4.2) - -/// -/// Defines the device's role on the Mesh network -/// unset -/// Behave normally. -/// Router -/// Functions as a router -enum Role: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// Client device role - case client // = 0 - - /// - /// ClientMute device role - /// This is like the client but packets will not hop over this node. Would be - /// useful if you want to save power by not contributing to the mesh. - case clientMute // = 1 - - /// - /// Router device role. - /// Uses an agressive algirithem for the flood networking so packets will - /// prefer to be routed over this node. Also assume that this will be generally - /// unattended and so will turn off the wifi/ble radio as well as the oled screen. - case router // = 2 - - /// - /// RouterClient device role - /// Uses an agressive algirithem for the flood networking so packets will - /// prefer to be routed over this node. Similiar power management as a regular - /// client, so the RouterClient can be used as both a Router and a Client. Useful - /// as a well placed base station that you could also use to send messages. - case routerClient // = 3 - case UNRECOGNIZED(Int) - - init() { - self = .client - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .client - case 1: self = .clientMute - case 2: self = .router - case 3: self = .routerClient - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .client: return 0 - case .clientMute: return 1 - case .router: return 2 - case .routerClient: return 3 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [Role] = [ - .client, - .clientMute, - .router, - .routerClient, - ] -} - -#endif // swift(>=4.2) - -/// -/// Sets the charge control current of devices with a battery charger that can be -/// configured. This is passed into the axp power management chip like on the tbeam. -enum ChargeCurrent: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// TODO: REPLACE - case maunset // = 0 - - /// - /// TODO: REPLACE - case ma100 // = 1 - - /// - /// TODO: REPLACE - case ma190 // = 2 - - /// - /// TODO: REPLACE - case ma280 // = 3 - - /// - /// TODO: REPLACE - case ma360 // = 4 - - /// - /// TODO: REPLACE - case ma450 // = 5 - - /// - /// TODO: REPLACE - case ma550 // = 6 - - /// - /// TODO: REPLACE - case ma630 // = 7 - - /// - /// TODO: REPLACE - case ma700 // = 8 - - /// - /// TODO: REPLACE - case ma780 // = 9 - - /// - /// TODO: REPLACE - case ma880 // = 10 - - /// - /// TODO: REPLACE - case ma960 // = 11 - - /// - /// TODO: REPLACE - case ma1000 // = 12 - - /// - /// TODO: REPLACE - case ma1080 // = 13 - - /// - /// TODO: REPLACE - case ma1160 // = 14 - - /// - /// TODO: REPLACE - case ma1240 // = 15 - - /// - /// TODO: REPLACE - case ma1320 // = 16 - case UNRECOGNIZED(Int) - - init() { - self = .maunset - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .maunset - case 1: self = .ma100 - case 2: self = .ma190 - case 3: self = .ma280 - case 4: self = .ma360 - case 5: self = .ma450 - case 6: self = .ma550 - case 7: self = .ma630 - case 8: self = .ma700 - case 9: self = .ma780 - case 10: self = .ma880 - case 11: self = .ma960 - case 12: self = .ma1000 - case 13: self = .ma1080 - case 14: self = .ma1160 - case 15: self = .ma1240 - case 16: self = .ma1320 - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .maunset: return 0 - case .ma100: return 1 - case .ma190: return 2 - case .ma280: return 3 - case .ma360: return 4 - case .ma450: return 5 - case .ma550: return 6 - case .ma630: return 7 - case .ma700: return 8 - case .ma780: return 9 - case .ma880: return 10 - case .ma960: return 11 - case .ma1000: return 12 - case .ma1080: return 13 - case .ma1160: return 14 - case .ma1240: return 15 - case .ma1320: return 16 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension ChargeCurrent: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [ChargeCurrent] = [ - .maunset, - .ma100, - .ma190, - .ma280, - .ma360, - .ma450, - .ma550, - .ma630, - .ma700, - .ma780, - .ma880, - .ma960, - .ma1000, - .ma1080, - .ma1160, - .ma1240, - .ma1320, - ] -} - -#endif // swift(>=4.2) - -/// -/// How the GPS coordinates are displayed on the OLED screen. -enum GpsCoordinateFormat: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// GPS coordinates are displayed in the normal decimal degrees format: - /// DD.DDDDDD DDD.DDDDDD - case gpsFormatDec // = 0 - - /// - /// GPS coordinates are displayed in the degrees minutes seconds format: - /// DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant - case gpsFormatDms // = 1 - - /// - /// GPS coordinates are displayed in Universal Transverse Mercator format: - /// ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing - case gpsFormatUtm // = 2 - - /// - /// GPS coordinates are displayed in Military Grid Reference System format: - /// ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, - /// E is easting, N is northing - case gpsFormatMgrs // = 3 - - /// - /// GPS coordinates are displayed in Open Location Code (aka Plus Codes). - case gpsFormatOlc // = 4 - - /// - /// GPS coordinates are displayed in Ordnance Survey Grid Reference (the National Grid System of the UK). - /// Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, E is the easting, - /// N is the northing - case gpsFormatOsgr // = 5 - case UNRECOGNIZED(Int) - - init() { - self = .gpsFormatDec - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .gpsFormatDec - case 1: self = .gpsFormatDms - case 2: self = .gpsFormatUtm - case 3: self = .gpsFormatMgrs - case 4: self = .gpsFormatOlc - case 5: self = .gpsFormatOsgr - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .gpsFormatDec: return 0 - case .gpsFormatDms: return 1 - case .gpsFormatUtm: return 2 - case .gpsFormatMgrs: return 3 - case .gpsFormatOlc: return 4 - case .gpsFormatOsgr: return 5 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension GpsCoordinateFormat: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [GpsCoordinateFormat] = [ - .gpsFormatDec, - .gpsFormatDms, - .gpsFormatUtm, - .gpsFormatMgrs, - .gpsFormatOlc, - .gpsFormatOsgr, - ] -} - -#endif // swift(>=4.2) - -/// -/// Bit field of boolean configuration options, indicating which optional -/// fields to include when assembling POSITION messages -/// Longitude and latitude 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 -enum PositionFlags: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// Required for compilation - case posUndefined // = 0 - - /// - /// Include an altitude value (if available) - case posAltitude // = 1 - - /// - /// Altitude value is MSL - case posAltMsl // = 2 - - /// - /// Include geoidal separation - case posGeoSep // = 4 - - /// - /// Include the DOP value ; PDOP used by default, see below - case posDop // = 8 - - /// - /// If POS_DOP set, send separate HDOP / VDOP values instead of PDOP - case posHvdop // = 16 - - /// - /// Include battery level - case posBattery // = 32 - - /// - /// Include number of "satellites in view" - case posSatinview // = 64 - - /// - /// Include a sequence number incremented per packet - case posSeqNos // = 128 - - /// - /// Include positional timestamp (from GPS solution) - case posTimestamp // = 256 - case UNRECOGNIZED(Int) - - init() { - self = .posUndefined - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .posUndefined - case 1: self = .posAltitude - case 2: self = .posAltMsl - case 4: self = .posGeoSep - case 8: self = .posDop - case 16: self = .posHvdop - case 32: self = .posBattery - case 64: self = .posSatinview - case 128: self = .posSeqNos - case 256: self = .posTimestamp - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .posUndefined: return 0 - case .posAltitude: return 1 - case .posAltMsl: return 2 - case .posGeoSep: return 4 - case .posDop: return 8 - case .posHvdop: return 16 - case .posBattery: return 32 - case .posSatinview: return 64 - case .posSeqNos: return 128 - case .posTimestamp: return 256 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension PositionFlags: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [PositionFlags] = [ - .posUndefined, - .posAltitude, - .posAltMsl, - .posGeoSep, - .posDop, - .posHvdop, - .posBattery, - .posSatinview, - .posSeqNos, - .posTimestamp, - ] -} - -#endif // swift(>=4.2) - -/// -/// TODO: REPLACE -enum InputEventChar: SwiftProtobuf.Enum { - typealias RawValue = Int - - /// - /// TODO: REPLACE - case keyNone // = 0 - - /// - /// TODO: REPLACE - case keyUp // = 17 - - /// - /// TODO: REPLACE - case keyDown // = 18 - - /// - /// TODO: REPLACE - case keyLeft // = 19 - - /// - /// TODO: REPLACE - case keyRight // = 20 - - /// - /// '\n' - case keySelect // = 10 - - /// - /// TODO: REPLACE - case keyBack // = 27 - - /// - /// TODO: REPLACE - case keyCancel // = 24 - case UNRECOGNIZED(Int) - - init() { - self = .keyNone - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .keyNone - case 10: self = .keySelect - case 17: self = .keyUp - case 18: self = .keyDown - case 19: self = .keyLeft - case 20: self = .keyRight - case 24: self = .keyCancel - case 27: self = .keyBack - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .keyNone: return 0 - case .keySelect: return 10 - case .keyUp: return 17 - case .keyDown: return 18 - case .keyLeft: return 19 - case .keyRight: return 20 - case .keyCancel: return 24 - case .keyBack: return 27 - case .UNRECOGNIZED(let i): return i - } - } - -} - -#if swift(>=4.2) - -extension InputEventChar: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [InputEventChar] = [ - .keyNone, - .keyUp, - .keyDown, - .keyLeft, - .keyRight, - .keySelect, - .keyBack, - .keyCancel, - ] -} - -#endif // swift(>=4.2) - -/// -/// The entire set of user settable/readable settings for our radio device. -/// Includes both the current channel settings and any preferences the user has -/// set for behavior of their node -struct RadioConfig { - // SwiftProtobuf.Message conformance is added in an extension below. See the - // `Message` and `Message+*Additions` files in the SwiftProtobuf library for - // methods supported on all messages. - - /// - /// TODO: REPLACE - var preferences: RadioConfig.UserPreferences { - get {return _preferences ?? RadioConfig.UserPreferences()} - set {_preferences = newValue} - } - /// Returns true if `preferences` has been explicitly set. - var hasPreferences: Bool {return self._preferences != nil} - /// Clears the value of `preferences`. Subsequent reads from it will return its default value. - mutating func clearPreferences() {self._preferences = nil} - - var unknownFields = SwiftProtobuf.UnknownStorage() - - /// - /// See [software design](/docs/software/other/sw-design) for more information on these preferences - struct UserPreferences { - // 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. - - /// - /// We should send our position this often (but only if it has changed significantly) - /// Defaults to 15 minutes - var positionBroadcastSecs: UInt32 { - get {return _storage._positionBroadcastSecs} - set {_uniqueStorage()._positionBroadcastSecs = newValue} - } - - /// - /// We should send our position this often (but only if it has changed significantly) - var positionBroadcastSmartDisabled: Bool { - get {return _storage._positionBroadcastSmartDisabled} - set {_uniqueStorage()._positionBroadcastSmartDisabled = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of 1 minute - var waitBluetoothSecs: UInt32 { - get {return _storage._waitBluetoothSecs} - set {_uniqueStorage()._waitBluetoothSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of one minute - var screenOnSecs: UInt32 { - get {return _storage._screenOnSecs} - set {_uniqueStorage()._screenOnSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of 15 minutes - /// IMPORTANT NOTE FOR DEVICE CLIENTS: YOU MUST SEND SOME SORT OF PACKET TO THE PHONE AT LEAST THIS OFTEN OR THE DEVICE WILL DECIDE YOU ARE GONE! - var phoneTimeoutSecs: UInt32 { - get {return _storage._phoneTimeoutSecs} - set {_uniqueStorage()._phoneTimeoutSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of two hours, MAXUINT for disabled - var meshSdsTimeoutSecs: UInt32 { - get {return _storage._meshSdsTimeoutSecs} - set {_uniqueStorage()._meshSdsTimeoutSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of one year - var sdsSecs: UInt32 { - get {return _storage._sdsSecs} - set {_uniqueStorage()._sdsSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of 3600 - var lsSecs: UInt32 { - get {return _storage._lsSecs} - set {_uniqueStorage()._lsSecs = newValue} - } - - /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of 10 seconds - var minWakeSecs: UInt32 { - get {return _storage._minWakeSecs} - set {_uniqueStorage()._minWakeSecs = newValue} - } - - /// - /// If set, this node will try to join the specified wifi network and - /// acquire an address via DHCP - var wifiSsid: String { - get {return _storage._wifiSsid} - set {_uniqueStorage()._wifiSsid = newValue} - } - - /// - /// If set, will be use to authenticate to the named wifi - var wifiPassword: String { - get {return _storage._wifiPassword} - set {_uniqueStorage()._wifiPassword = newValue} - } - - /// - /// If set, the node will operate as an AP (and DHCP server), otherwise it - /// will be a station - var wifiApMode: Bool { - get {return _storage._wifiApMode} - set {_uniqueStorage()._wifiApMode = newValue} - } - - /// - /// The region code for my radio (US, CN, EU433, etc...) - var region: RegionCode { - get {return _storage._region} - set {_uniqueStorage()._region = newValue} - } - - /// - /// Sets the current of the battery charger - var chargeCurrent: ChargeCurrent { - get {return _storage._chargeCurrent} - set {_uniqueStorage()._chargeCurrent = newValue} - } - - /// - /// Sets the role of node - var role: Role { - get {return _storage._role} - set {_uniqueStorage()._role = newValue} - } - - /// - /// If set, we are powered from a low-current source (i.e. solar), so even if it looks like we have power flowing in - /// we should try to minimize power consumption as much as possible. - /// YOU DO NOT NEED TO SET THIS IF YOU'VE set is_router (it is implied in that case). - var isLowPower: Bool { - get {return _storage._isLowPower} - set {_uniqueStorage()._isLowPower = newValue} - } - - /// - /// If set, this node is at a fixed position. - /// We will generate GPS position updates at the regular interval, but use whatever the last lat/lon/alt we have for the node. - /// The lat/lon/alt can be set by an internal GPS or with the help of the app. - var fixedPosition: Bool { - get {return _storage._fixedPosition} - set {_uniqueStorage()._fixedPosition = newValue} - } - - /// - /// If set, this will disable the SerialConsole by not initilizing the StreamAPI - var serialDisabled: Bool { - get {return _storage._serialDisabled} - set {_uniqueStorage()._serialDisabled = newValue} - } - - /// - /// Should we disbale location sharing with other nodes (or the local phone) - var locationShareDisabled: Bool { - get {return _storage._locationShareDisabled} - set {_uniqueStorage()._locationShareDisabled = newValue} - } - - /// - /// Should the GPS be disabled for this node? - var gpsDisabled: Bool { - get {return _storage._gpsDisabled} - set {_uniqueStorage()._gpsDisabled = newValue} - } - - /// - /// How often should we try to get GPS position (in seconds) - /// or zero for the default of once every 30 seconds - /// or a very large value (maxint) to update only once at boot. - var gpsUpdateInterval: UInt32 { - get {return _storage._gpsUpdateInterval} - set {_uniqueStorage()._gpsUpdateInterval = newValue} - } - - /// - /// How long should we try to get our position during each gps_update_interval attempt? (in seconds) - /// Or if zero, use the default of 30 seconds. - /// If we don't get a new gps fix in that time, the gps will be put into sleep until the next gps_update_rate - /// window. - var gpsAttemptTime: UInt32 { - get {return _storage._gpsAttemptTime} - set {_uniqueStorage()._gpsAttemptTime = newValue} - } - - /// - /// Shall we accept 2D GPS fixes? By default, only 3D fixes are accepted - /// (during a 2D fix, altitude values are unreliable and will be excluded) - var gpsAccept2D: Bool { - get {return _storage._gpsAccept2D} - set {_uniqueStorage()._gpsAccept2D = newValue} - } - - /// - /// GPS maximum DOP accepted (dilution of precision) - /// Set a rejection threshold for GPS readings based on their precision, - /// relative to the GPS rated accuracy (which is typically ~3m) - /// Solutions above this value will be treated as retryable errors! - /// Useful range is between 1 - 64 (3m - <~200m) - /// By default (if zero), accept all GPS readings - var gpsMaxDop: UInt32 { - get {return _storage._gpsMaxDop} - set {_uniqueStorage()._gpsMaxDop = newValue} - } - - /// - /// This parameter is for advanced users with advanced test equipment, we do not recommend most users use it. - /// A frequency offset that is added to to the calculated band center frequency. - /// Used to correct for crystal calibration errors. - var frequencyOffset: Float { - get {return _storage._frequencyOffset} - set {_uniqueStorage()._frequencyOffset = newValue} - } - - /// - /// The server to use for our MQTT global message gateway feature. - /// If not set, the default server will be used - var mqttServer: String { - get {return _storage._mqttServer} - set {_uniqueStorage()._mqttServer = newValue} - } - - /// - /// If a meshtastic node is able to reach the internet it will normally attempt to gateway any channels that are marked as - /// is_uplink_enabled or is_downlink_enabled. - /// But if this flag is set, all MQTT features will be disabled and no servers will be contacted. - var mqttDisabled: Bool { - get {return _storage._mqttDisabled} - set {_uniqueStorage()._mqttDisabled = newValue} - } - - /// - /// How the GPS coordinates are displayed on the OLED screen. - var gpsFormat: GpsCoordinateFormat { - get {return _storage._gpsFormat} - set {_uniqueStorage()._gpsFormat = newValue} - } - - /// - /// This setting is never saved to disk, but if set, all device settings will be returned to factory defaults. - /// (Region, serial number etc... will be preserved) - var factoryReset: Bool { - get {return _storage._factoryReset} - set {_uniqueStorage()._factoryReset = newValue} - } - - /// - /// 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. - var debugLogEnabled: Bool { - get {return _storage._debugLogEnabled} - set {_uniqueStorage()._debugLogEnabled = newValue} - } - - /// - /// If true, radio should not try to be smart about what packets to queue to - /// the phone - /// bool keep_all_packets = 101; - /// If true, we will try to capture all the packets sent on the mesh, not just the ones destined to our node. - /// bool promiscuous_mode = 102; - /// For testing it is useful sometimes to force a node to never listen to - /// particular other nodes (simulating radio out of range). All nodenums listed - /// in ignore_incoming will have packets they send droped on receive (by router.cpp) - var ignoreIncoming: [UInt32] { - get {return _storage._ignoreIncoming} - set {_uniqueStorage()._ignoreIncoming = newValue} - } - - /// - /// Preferences for the SerialModule - /// FIXME - Move this out of UserPreferences and into a section for module configuration. - var serialModuleEnabled: Bool { - get {return _storage._serialModuleEnabled} - set {_uniqueStorage()._serialModuleEnabled = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleEcho: Bool { - get {return _storage._serialModuleEcho} - set {_uniqueStorage()._serialModuleEcho = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleRxd: UInt32 { - get {return _storage._serialModuleRxd} - set {_uniqueStorage()._serialModuleRxd = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleTxd: UInt32 { - get {return _storage._serialModuleTxd} - set {_uniqueStorage()._serialModuleTxd = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleBaud: RadioConfig.UserPreferences.Serial_Baud { - get {return _storage._serialModuleBaud} - set {_uniqueStorage()._serialModuleBaud = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleTimeout: UInt32 { - get {return _storage._serialModuleTimeout} - set {_uniqueStorage()._serialModuleTimeout = newValue} - } - - /// - /// TODO: REPLACE - var serialModuleMode: RadioConfig.UserPreferences.Serial_Mode { - get {return _storage._serialModuleMode} - set {_uniqueStorage()._serialModuleMode = newValue} - } - - /// - /// Preferences for the ExternalNotificationModule - /// FIXME - Move this out of UserPreferences and into a section for module configuration. - var extNotificationModuleEnabled: Bool { - get {return _storage._extNotificationModuleEnabled} - set {_uniqueStorage()._extNotificationModuleEnabled = newValue} - } - - /// - /// TODO: REPLACE - var extNotificationModuleOutputMs: UInt32 { - get {return _storage._extNotificationModuleOutputMs} - set {_uniqueStorage()._extNotificationModuleOutputMs = newValue} - } - - /// - /// TODO: REPLACE - var extNotificationModuleOutput: UInt32 { - get {return _storage._extNotificationModuleOutput} - set {_uniqueStorage()._extNotificationModuleOutput = newValue} - } - - /// - /// TODO: REPLACE - var extNotificationModuleActive: Bool { - get {return _storage._extNotificationModuleActive} - set {_uniqueStorage()._extNotificationModuleActive = newValue} - } - - /// - /// TODO: REPLACE - var extNotificationModuleAlertMessage: Bool { - get {return _storage._extNotificationModuleAlertMessage} - set {_uniqueStorage()._extNotificationModuleAlertMessage = newValue} - } - - /// - /// TODO: REPLACE - var extNotificationModuleAlertBell: Bool { - get {return _storage._extNotificationModuleAlertBell} - set {_uniqueStorage()._extNotificationModuleAlertBell = newValue} - } - - /// - /// Preferences for the RangeTestModule - /// FIXME - Move this out of UserPreferences and into a section for module configuration. - var rangeTestModuleEnabled: Bool { - get {return _storage._rangeTestModuleEnabled} - set {_uniqueStorage()._rangeTestModuleEnabled = newValue} - } - - /// - /// TODO: REPLACE - var rangeTestModuleSender: UInt32 { - get {return _storage._rangeTestModuleSender} - set {_uniqueStorage()._rangeTestModuleSender = newValue} - } - - /// - /// TODO: REPLACE - var rangeTestModuleSave: Bool { - get {return _storage._rangeTestModuleSave} - set {_uniqueStorage()._rangeTestModuleSave = newValue} - } - - /// - /// Preferences for the StoreForwardModule - ///FIXME - Move this out of UserPreferences and into a section for module configuration. (was 136) - var storeForwardModuleEnabled: Bool { - get {return _storage._storeForwardModuleEnabled} - set {_uniqueStorage()._storeForwardModuleEnabled = newValue} - } - - /// - /// TODO: REPLACE - var storeForwardModuleHeartbeat: Bool { - get {return _storage._storeForwardModuleHeartbeat} - set {_uniqueStorage()._storeForwardModuleHeartbeat = newValue} - } - - /// - /// TODO: REPLACE - var storeForwardModuleRecords: UInt32 { - get {return _storage._storeForwardModuleRecords} - set {_uniqueStorage()._storeForwardModuleRecords = newValue} - } - - /// - /// TODO: REPLACE - var storeForwardModuleHistoryReturnMax: UInt32 { - get {return _storage._storeForwardModuleHistoryReturnMax} - set {_uniqueStorage()._storeForwardModuleHistoryReturnMax = newValue} - } - - /// - /// TODO: REPLACE - var storeForwardModuleHistoryReturnWindow: UInt32 { - get {return _storage._storeForwardModuleHistoryReturnWindow} - set {_uniqueStorage()._storeForwardModuleHistoryReturnWindow = newValue} - } - - /// - /// Bit field of boolean configuration options for POSITION messages - /// (bitwise OR of PositionFlags) - var positionFlags: UInt32 { - get {return _storage._positionFlags} - set {_uniqueStorage()._positionFlags = newValue} - } - - /// - /// Circumvents the logic block for determining whether the device is powered or not. - /// Useful for devices with finicky ADC issues on the battery sense pins. - var isAlwaysPowered: Bool { - get {return _storage._isAlwaysPowered} - set {_uniqueStorage()._isAlwaysPowered = newValue} - } - - /// - /// Automatically toggles to the next page on the screen like a carousel, based the specified interval in seconds. - /// Potentially useful for devices without user buttons. - var autoScreenCarouselSecs: UInt32 { - get {return _storage._autoScreenCarouselSecs} - set {_uniqueStorage()._autoScreenCarouselSecs = newValue} - } - - /// - /// If non-zero, the device will fully power off this many seconds after external power is removed. - var onBatteryShutdownAfterSecs: UInt32 { - get {return _storage._onBatteryShutdownAfterSecs} - set {_uniqueStorage()._onBatteryShutdownAfterSecs = newValue} - } - - /// - /// Overrides HOPS_RELIABLE and sets the maximum number of hops. This can't be greater than 7. - var hopLimit: UInt32 { - get {return _storage._hopLimit} - set {_uniqueStorage()._hopLimit = newValue} - } - - /// - /// MQTT username to use (most useful for a custom MQTT server). - /// If using a custom server, this will be honoured even if empty. - /// If using the default server, this will only be honoured if set, otherwise the device will use the default username - var mqttUsername: String { - get {return _storage._mqttUsername} - set {_uniqueStorage()._mqttUsername = newValue} - } - - /// - /// MQTT password to use (most useful for a custom MQTT server). - /// If using a custom server, this will be honoured even if empty. - /// If using the default server, this will only be honoured if set, otherwise the device will use the default password - var mqttPassword: String { - get {return _storage._mqttPassword} - set {_uniqueStorage()._mqttPassword = newValue} - } - - /// - /// Disable TX from the LoRa radio. Useful for hot-swapping antennas and other tests. - /// Defaults to false - var isLoraTxDisabled: Bool { - get {return _storage._isLoraTxDisabled} - set {_uniqueStorage()._isLoraTxDisabled = newValue} - } - - /// - /// If set to true, enable power saving features of the esp32 - var isPowerSaving: Bool { - get {return _storage._isPowerSaving} - set {_uniqueStorage()._isPowerSaving = newValue} - } - - /// - /// Enable the rotary encoder #1. This is a 'dumb' encoder sending pulses on both A and B pins while rotating. - var rotary1Enabled: Bool { - get {return _storage._rotary1Enabled} - set {_uniqueStorage()._rotary1Enabled = newValue} - } - - /// - /// GPIO pin for rotary encoder A port. - var inputbrokerPinA: UInt32 { - get {return _storage._inputbrokerPinA} - set {_uniqueStorage()._inputbrokerPinA = newValue} - } - - /// - /// GPIO pin for rotary encoder B port. - var inputbrokerPinB: UInt32 { - get {return _storage._inputbrokerPinB} - set {_uniqueStorage()._inputbrokerPinB = newValue} - } - - /// - /// GPIO pin for rotary encoder Press port. - var inputbrokerPinPress: UInt32 { - get {return _storage._inputbrokerPinPress} - set {_uniqueStorage()._inputbrokerPinPress = newValue} - } - - /// - /// Generate input event on CW of this kind. - var inputbrokerEventCw: InputEventChar { - get {return _storage._inputbrokerEventCw} - set {_uniqueStorage()._inputbrokerEventCw = newValue} - } - - /// - /// Generate input event on CCW of this kind. - var inputbrokerEventCcw: InputEventChar { - get {return _storage._inputbrokerEventCcw} - set {_uniqueStorage()._inputbrokerEventCcw = newValue} - } - - /// - /// Generate input event on Press of this kind. - var inputbrokerEventPress: InputEventChar { - get {return _storage._inputbrokerEventPress} - set {_uniqueStorage()._inputbrokerEventPress = newValue} - } - - /// - /// Enable the Up/Down/Select input device. Can be RAK rotary encoder or 3 buttons. Uses the a/b/press definitions from inputbroker. - var updown1Enabled: Bool { - get {return _storage._updown1Enabled} - set {_uniqueStorage()._updown1Enabled = newValue} - } - - /// - /// Enable/disable CannedMessageModule. - var cannedMessageModuleEnabled: Bool { - get {return _storage._cannedMessageModuleEnabled} - set {_uniqueStorage()._cannedMessageModuleEnabled = newValue} - } - - /// - /// Input event origin accepted by the canned message module. - /// Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any" - var cannedMessageModuleAllowInputSource: String { - get {return _storage._cannedMessageModuleAllowInputSource} - set {_uniqueStorage()._cannedMessageModuleAllowInputSource = newValue} - } - - /// - /// CannedMessageModule also sends a bell character with the messages. - /// ExternalNotificationModule can benefit from this feature. - var cannedMessageModuleSendBell: Bool { - get {return _storage._cannedMessageModuleSendBell} - set {_uniqueStorage()._cannedMessageModuleSendBell = newValue} - } - - /// - /// Whether to send encrypted or decrypted packets to MQTT. - /// This parameter is only honoured if you also set mqtt_server - /// (the default official mqtt.meshtastic.org server can handle encrypted packets) - /// Decrypted packets may be useful for external systems that want to consume meshtastic packets - var mqttEncryptionEnabled: Bool { - get {return _storage._mqttEncryptionEnabled} - set {_uniqueStorage()._mqttEncryptionEnabled = newValue} - } - - /// - /// Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k) - /// Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation. - var adcMultiplierOverride: Float { - get {return _storage._adcMultiplierOverride} - set {_uniqueStorage()._adcMultiplierOverride = newValue} - } - - var unknownFields = SwiftProtobuf.UnknownStorage() - - /// - /// TODO: REPLACE - enum Serial_Baud: SwiftProtobuf.Enum { - typealias RawValue = Int - case baudDefault // = 0 - case baud2400 // = 1 - case baud4800 // = 2 - case baud9600 // = 3 - case baud19200 // = 4 - case baud38400 // = 5 - case baud57600 // = 6 - case baud115200 // = 7 - case baud230400 // = 8 - case baud460800 // = 9 - case baud576000 // = 10 - case baud921600 // = 11 - case baud110 // = 12 - case baud300 // = 13 - case baud600 // = 14 - case baud1200 // = 15 - case UNRECOGNIZED(Int) - - init() { - self = .baudDefault - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .baudDefault - case 1: self = .baud2400 - case 2: self = .baud4800 - case 3: self = .baud9600 - case 4: self = .baud19200 - case 5: self = .baud38400 - case 6: self = .baud57600 - case 7: self = .baud115200 - case 8: self = .baud230400 - case 9: self = .baud460800 - case 10: self = .baud576000 - case 11: self = .baud921600 - case 12: self = .baud110 - case 13: self = .baud300 - case 14: self = .baud600 - case 15: self = .baud1200 - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .baudDefault: return 0 - case .baud2400: return 1 - case .baud4800: return 2 - case .baud9600: return 3 - case .baud19200: return 4 - case .baud38400: return 5 - case .baud57600: return 6 - case .baud115200: return 7 - case .baud230400: return 8 - case .baud460800: return 9 - case .baud576000: return 10 - case .baud921600: return 11 - case .baud110: return 12 - case .baud300: return 13 - case .baud600: return 14 - case .baud1200: return 15 - case .UNRECOGNIZED(let i): return i - } - } - - } - - /// - /// TODO: REPLACE - enum Serial_Mode: SwiftProtobuf.Enum { - typealias RawValue = Int - case modeDefault // = 0 - case modeSimple // = 1 - case modeProto // = 2 - case UNRECOGNIZED(Int) - - init() { - self = .modeDefault - } - - init?(rawValue: Int) { - switch rawValue { - case 0: self = .modeDefault - case 1: self = .modeSimple - case 2: self = .modeProto - default: self = .UNRECOGNIZED(rawValue) - } - } - - var rawValue: Int { - switch self { - case .modeDefault: return 0 - case .modeSimple: return 1 - case .modeProto: return 2 - case .UNRECOGNIZED(let i): return i - } - } - - } - - init() {} - - fileprivate var _storage = _StorageClass.defaultInstance - } - - init() {} - - fileprivate var _preferences: RadioConfig.UserPreferences? = nil -} - -#if swift(>=4.2) - -extension RadioConfig.UserPreferences.Serial_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [RadioConfig.UserPreferences.Serial_Baud] = [ - .baudDefault, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - .baud110, - .baud300, - .baud600, - .baud1200, - ] -} - -extension RadioConfig.UserPreferences.Serial_Mode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - static var allCases: [RadioConfig.UserPreferences.Serial_Mode] = [ - .modeDefault, - .modeSimple, - .modeProto, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension RegionCode: @unchecked Sendable {} -extension Role: @unchecked Sendable {} -extension ChargeCurrent: @unchecked Sendable {} -extension GpsCoordinateFormat: @unchecked Sendable {} -extension PositionFlags: @unchecked Sendable {} -extension InputEventChar: @unchecked Sendable {} -extension RadioConfig: @unchecked Sendable {} -extension RadioConfig.UserPreferences: @unchecked Sendable {} -extension RadioConfig.UserPreferences.Serial_Baud: @unchecked Sendable {} -extension RadioConfig.UserPreferences.Serial_Mode: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - -// MARK: - Code below here is support for the SwiftProtobuf runtime. - -extension RegionCode: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "Unset"), - 1: .same(proto: "US"), - 2: .same(proto: "EU433"), - 3: .same(proto: "EU868"), - 4: .same(proto: "CN"), - 5: .same(proto: "JP"), - 6: .same(proto: "ANZ"), - 7: .same(proto: "KR"), - 8: .same(proto: "TW"), - 9: .same(proto: "RU"), - 10: .same(proto: "IN"), - 11: .same(proto: "NZ865"), - 12: .same(proto: "TH"), - ] -} - -extension Role: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "Client"), - 1: .same(proto: "ClientMute"), - 2: .same(proto: "Router"), - 3: .same(proto: "RouterClient"), - ] -} - -extension ChargeCurrent: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "MAUnset"), - 1: .same(proto: "MA100"), - 2: .same(proto: "MA190"), - 3: .same(proto: "MA280"), - 4: .same(proto: "MA360"), - 5: .same(proto: "MA450"), - 6: .same(proto: "MA550"), - 7: .same(proto: "MA630"), - 8: .same(proto: "MA700"), - 9: .same(proto: "MA780"), - 10: .same(proto: "MA880"), - 11: .same(proto: "MA960"), - 12: .same(proto: "MA1000"), - 13: .same(proto: "MA1080"), - 14: .same(proto: "MA1160"), - 15: .same(proto: "MA1240"), - 16: .same(proto: "MA1320"), - ] -} - -extension GpsCoordinateFormat: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "GpsFormatDec"), - 1: .same(proto: "GpsFormatDMS"), - 2: .same(proto: "GpsFormatUTM"), - 3: .same(proto: "GpsFormatMGRS"), - 4: .same(proto: "GpsFormatOLC"), - 5: .same(proto: "GpsFormatOSGR"), - ] -} - -extension PositionFlags: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "POS_UNDEFINED"), - 1: .same(proto: "POS_ALTITUDE"), - 2: .same(proto: "POS_ALT_MSL"), - 4: .same(proto: "POS_GEO_SEP"), - 8: .same(proto: "POS_DOP"), - 16: .same(proto: "POS_HVDOP"), - 32: .same(proto: "POS_BATTERY"), - 64: .same(proto: "POS_SATINVIEW"), - 128: .same(proto: "POS_SEQ_NOS"), - 256: .same(proto: "POS_TIMESTAMP"), - ] -} - -extension InputEventChar: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "KEY_NONE"), - 10: .same(proto: "KEY_SELECT"), - 17: .same(proto: "KEY_UP"), - 18: .same(proto: "KEY_DOWN"), - 19: .same(proto: "KEY_LEFT"), - 20: .same(proto: "KEY_RIGHT"), - 24: .same(proto: "KEY_CANCEL"), - 27: .same(proto: "KEY_BACK"), - ] -} - -extension RadioConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = "RadioConfig" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "preferences"), - ] - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._preferences) }() - default: break - } - } - } - - 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 - try { if let v = self._preferences { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: RadioConfig, rhs: RadioConfig) -> Bool { - if lhs._preferences != rhs._preferences {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension RadioConfig.UserPreferences: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = RadioConfig.protoMessageName + ".UserPreferences" - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "position_broadcast_secs"), - 17: .standard(proto: "position_broadcast_smart_disabled"), - 4: .standard(proto: "wait_bluetooth_secs"), - 5: .standard(proto: "screen_on_secs"), - 6: .standard(proto: "phone_timeout_secs"), - 8: .standard(proto: "mesh_sds_timeout_secs"), - 9: .standard(proto: "sds_secs"), - 10: .standard(proto: "ls_secs"), - 11: .standard(proto: "min_wake_secs"), - 12: .standard(proto: "wifi_ssid"), - 13: .standard(proto: "wifi_password"), - 14: .standard(proto: "wifi_ap_mode"), - 15: .same(proto: "region"), - 16: .standard(proto: "charge_current"), - 18: .same(proto: "role"), - 38: .standard(proto: "is_low_power"), - 39: .standard(proto: "fixed_position"), - 40: .standard(proto: "serial_disabled"), - 32: .standard(proto: "location_share_disabled"), - 33: .standard(proto: "gps_disabled"), - 34: .standard(proto: "gps_update_interval"), - 36: .standard(proto: "gps_attempt_time"), - 45: .standard(proto: "gps_accept_2d"), - 46: .standard(proto: "gps_max_dop"), - 41: .standard(proto: "frequency_offset"), - 42: .standard(proto: "mqtt_server"), - 43: .standard(proto: "mqtt_disabled"), - 44: .standard(proto: "gps_format"), - 100: .standard(proto: "factory_reset"), - 101: .standard(proto: "debug_log_enabled"), - 103: .standard(proto: "ignore_incoming"), - 120: .standard(proto: "serial_module_enabled"), - 121: .standard(proto: "serial_module_echo"), - 122: .standard(proto: "serial_module_rxd"), - 123: .standard(proto: "serial_module_txd"), - 176: .standard(proto: "serial_module_baud"), - 124: .standard(proto: "serial_module_timeout"), - 125: .standard(proto: "serial_module_mode"), - 126: .standard(proto: "ext_notification_module_enabled"), - 127: .standard(proto: "ext_notification_module_output_ms"), - 128: .standard(proto: "ext_notification_module_output"), - 129: .standard(proto: "ext_notification_module_active"), - 130: .standard(proto: "ext_notification_module_alert_message"), - 131: .standard(proto: "ext_notification_module_alert_bell"), - 132: .standard(proto: "range_test_module_enabled"), - 133: .standard(proto: "range_test_module_sender"), - 134: .standard(proto: "range_test_module_save"), - 148: .standard(proto: "store_forward_module_enabled"), - 149: .standard(proto: "store_forward_module_heartbeat"), - 137: .standard(proto: "store_forward_module_records"), - 138: .standard(proto: "store_forward_module_history_return_max"), - 139: .standard(proto: "store_forward_module_history_return_window"), - 150: .standard(proto: "position_flags"), - 151: .standard(proto: "is_always_powered"), - 152: .standard(proto: "auto_screen_carousel_secs"), - 153: .standard(proto: "on_battery_shutdown_after_secs"), - 154: .standard(proto: "hop_limit"), - 155: .standard(proto: "mqtt_username"), - 156: .standard(proto: "mqtt_password"), - 157: .standard(proto: "is_lora_tx_disabled"), - 158: .standard(proto: "is_power_saving"), - 160: .standard(proto: "rotary1_enabled"), - 161: .standard(proto: "inputbroker_pin_a"), - 162: .standard(proto: "inputbroker_pin_b"), - 163: .standard(proto: "inputbroker_pin_press"), - 164: .standard(proto: "inputbroker_event_cw"), - 165: .standard(proto: "inputbroker_event_ccw"), - 166: .standard(proto: "inputbroker_event_press"), - 167: .standard(proto: "updown1_enabled"), - 170: .standard(proto: "canned_message_module_enabled"), - 171: .standard(proto: "canned_message_module_allow_input_source"), - 173: .standard(proto: "canned_message_module_send_bell"), - 174: .standard(proto: "mqtt_encryption_enabled"), - 175: .standard(proto: "adc_multiplier_override"), - ] - - fileprivate class _StorageClass { - var _positionBroadcastSecs: UInt32 = 0 - var _positionBroadcastSmartDisabled: Bool = false - var _waitBluetoothSecs: UInt32 = 0 - var _screenOnSecs: UInt32 = 0 - var _phoneTimeoutSecs: UInt32 = 0 - var _meshSdsTimeoutSecs: UInt32 = 0 - var _sdsSecs: UInt32 = 0 - var _lsSecs: UInt32 = 0 - var _minWakeSecs: UInt32 = 0 - var _wifiSsid: String = String() - var _wifiPassword: String = String() - var _wifiApMode: Bool = false - var _region: RegionCode = .unset - var _chargeCurrent: ChargeCurrent = .maunset - var _role: Role = .client - var _isLowPower: Bool = false - var _fixedPosition: Bool = false - var _serialDisabled: Bool = false - var _locationShareDisabled: Bool = false - var _gpsDisabled: Bool = false - var _gpsUpdateInterval: UInt32 = 0 - var _gpsAttemptTime: UInt32 = 0 - var _gpsAccept2D: Bool = false - var _gpsMaxDop: UInt32 = 0 - var _frequencyOffset: Float = 0 - var _mqttServer: String = String() - var _mqttDisabled: Bool = false - var _gpsFormat: GpsCoordinateFormat = .gpsFormatDec - var _factoryReset: Bool = false - var _debugLogEnabled: Bool = false - var _ignoreIncoming: [UInt32] = [] - var _serialModuleEnabled: Bool = false - var _serialModuleEcho: Bool = false - var _serialModuleRxd: UInt32 = 0 - var _serialModuleTxd: UInt32 = 0 - var _serialModuleBaud: RadioConfig.UserPreferences.Serial_Baud = .baudDefault - var _serialModuleTimeout: UInt32 = 0 - var _serialModuleMode: RadioConfig.UserPreferences.Serial_Mode = .modeDefault - var _extNotificationModuleEnabled: Bool = false - var _extNotificationModuleOutputMs: UInt32 = 0 - var _extNotificationModuleOutput: UInt32 = 0 - var _extNotificationModuleActive: Bool = false - var _extNotificationModuleAlertMessage: Bool = false - var _extNotificationModuleAlertBell: Bool = false - var _rangeTestModuleEnabled: Bool = false - var _rangeTestModuleSender: UInt32 = 0 - var _rangeTestModuleSave: Bool = false - var _storeForwardModuleEnabled: Bool = false - var _storeForwardModuleHeartbeat: Bool = false - var _storeForwardModuleRecords: UInt32 = 0 - var _storeForwardModuleHistoryReturnMax: UInt32 = 0 - var _storeForwardModuleHistoryReturnWindow: UInt32 = 0 - var _positionFlags: UInt32 = 0 - var _isAlwaysPowered: Bool = false - var _autoScreenCarouselSecs: UInt32 = 0 - var _onBatteryShutdownAfterSecs: UInt32 = 0 - var _hopLimit: UInt32 = 0 - var _mqttUsername: String = String() - var _mqttPassword: String = String() - var _isLoraTxDisabled: Bool = false - var _isPowerSaving: Bool = false - var _rotary1Enabled: Bool = false - var _inputbrokerPinA: UInt32 = 0 - var _inputbrokerPinB: UInt32 = 0 - var _inputbrokerPinPress: UInt32 = 0 - var _inputbrokerEventCw: InputEventChar = .keyNone - var _inputbrokerEventCcw: InputEventChar = .keyNone - var _inputbrokerEventPress: InputEventChar = .keyNone - var _updown1Enabled: Bool = false - var _cannedMessageModuleEnabled: Bool = false - var _cannedMessageModuleAllowInputSource: String = String() - var _cannedMessageModuleSendBell: Bool = false - var _mqttEncryptionEnabled: Bool = false - var _adcMultiplierOverride: Float = 0 - - static let defaultInstance = _StorageClass() - - private init() {} - - init(copying source: _StorageClass) { - _positionBroadcastSecs = source._positionBroadcastSecs - _positionBroadcastSmartDisabled = source._positionBroadcastSmartDisabled - _waitBluetoothSecs = source._waitBluetoothSecs - _screenOnSecs = source._screenOnSecs - _phoneTimeoutSecs = source._phoneTimeoutSecs - _meshSdsTimeoutSecs = source._meshSdsTimeoutSecs - _sdsSecs = source._sdsSecs - _lsSecs = source._lsSecs - _minWakeSecs = source._minWakeSecs - _wifiSsid = source._wifiSsid - _wifiPassword = source._wifiPassword - _wifiApMode = source._wifiApMode - _region = source._region - _chargeCurrent = source._chargeCurrent - _role = source._role - _isLowPower = source._isLowPower - _fixedPosition = source._fixedPosition - _serialDisabled = source._serialDisabled - _locationShareDisabled = source._locationShareDisabled - _gpsDisabled = source._gpsDisabled - _gpsUpdateInterval = source._gpsUpdateInterval - _gpsAttemptTime = source._gpsAttemptTime - _gpsAccept2D = source._gpsAccept2D - _gpsMaxDop = source._gpsMaxDop - _frequencyOffset = source._frequencyOffset - _mqttServer = source._mqttServer - _mqttDisabled = source._mqttDisabled - _gpsFormat = source._gpsFormat - _factoryReset = source._factoryReset - _debugLogEnabled = source._debugLogEnabled - _ignoreIncoming = source._ignoreIncoming - _serialModuleEnabled = source._serialModuleEnabled - _serialModuleEcho = source._serialModuleEcho - _serialModuleRxd = source._serialModuleRxd - _serialModuleTxd = source._serialModuleTxd - _serialModuleBaud = source._serialModuleBaud - _serialModuleTimeout = source._serialModuleTimeout - _serialModuleMode = source._serialModuleMode - _extNotificationModuleEnabled = source._extNotificationModuleEnabled - _extNotificationModuleOutputMs = source._extNotificationModuleOutputMs - _extNotificationModuleOutput = source._extNotificationModuleOutput - _extNotificationModuleActive = source._extNotificationModuleActive - _extNotificationModuleAlertMessage = source._extNotificationModuleAlertMessage - _extNotificationModuleAlertBell = source._extNotificationModuleAlertBell - _rangeTestModuleEnabled = source._rangeTestModuleEnabled - _rangeTestModuleSender = source._rangeTestModuleSender - _rangeTestModuleSave = source._rangeTestModuleSave - _storeForwardModuleEnabled = source._storeForwardModuleEnabled - _storeForwardModuleHeartbeat = source._storeForwardModuleHeartbeat - _storeForwardModuleRecords = source._storeForwardModuleRecords - _storeForwardModuleHistoryReturnMax = source._storeForwardModuleHistoryReturnMax - _storeForwardModuleHistoryReturnWindow = source._storeForwardModuleHistoryReturnWindow - _positionFlags = source._positionFlags - _isAlwaysPowered = source._isAlwaysPowered - _autoScreenCarouselSecs = source._autoScreenCarouselSecs - _onBatteryShutdownAfterSecs = source._onBatteryShutdownAfterSecs - _hopLimit = source._hopLimit - _mqttUsername = source._mqttUsername - _mqttPassword = source._mqttPassword - _isLoraTxDisabled = source._isLoraTxDisabled - _isPowerSaving = source._isPowerSaving - _rotary1Enabled = source._rotary1Enabled - _inputbrokerPinA = source._inputbrokerPinA - _inputbrokerPinB = source._inputbrokerPinB - _inputbrokerPinPress = source._inputbrokerPinPress - _inputbrokerEventCw = source._inputbrokerEventCw - _inputbrokerEventCcw = source._inputbrokerEventCcw - _inputbrokerEventPress = source._inputbrokerEventPress - _updown1Enabled = source._updown1Enabled - _cannedMessageModuleEnabled = source._cannedMessageModuleEnabled - _cannedMessageModuleAllowInputSource = source._cannedMessageModuleAllowInputSource - _cannedMessageModuleSendBell = source._cannedMessageModuleSendBell - _mqttEncryptionEnabled = source._mqttEncryptionEnabled - _adcMultiplierOverride = source._adcMultiplierOverride - } - } - - fileprivate mutating func _uniqueStorage() -> _StorageClass { - if !isKnownUniquelyReferenced(&_storage) { - _storage = _StorageClass(copying: _storage) - } - return _storage - } - - mutating func decodeMessage(decoder: inout D) throws { - _ = _uniqueStorage() - try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularUInt32Field(value: &_storage._positionBroadcastSecs) }() - case 4: try { try decoder.decodeSingularUInt32Field(value: &_storage._waitBluetoothSecs) }() - case 5: try { try decoder.decodeSingularUInt32Field(value: &_storage._screenOnSecs) }() - case 6: try { try decoder.decodeSingularUInt32Field(value: &_storage._phoneTimeoutSecs) }() - case 8: try { try decoder.decodeSingularUInt32Field(value: &_storage._meshSdsTimeoutSecs) }() - case 9: try { try decoder.decodeSingularUInt32Field(value: &_storage._sdsSecs) }() - case 10: try { try decoder.decodeSingularUInt32Field(value: &_storage._lsSecs) }() - case 11: try { try decoder.decodeSingularUInt32Field(value: &_storage._minWakeSecs) }() - case 12: try { try decoder.decodeSingularStringField(value: &_storage._wifiSsid) }() - case 13: try { try decoder.decodeSingularStringField(value: &_storage._wifiPassword) }() - case 14: try { try decoder.decodeSingularBoolField(value: &_storage._wifiApMode) }() - case 15: try { try decoder.decodeSingularEnumField(value: &_storage._region) }() - case 16: try { try decoder.decodeSingularEnumField(value: &_storage._chargeCurrent) }() - case 17: try { try decoder.decodeSingularBoolField(value: &_storage._positionBroadcastSmartDisabled) }() - case 18: try { try decoder.decodeSingularEnumField(value: &_storage._role) }() - case 32: try { try decoder.decodeSingularBoolField(value: &_storage._locationShareDisabled) }() - case 33: try { try decoder.decodeSingularBoolField(value: &_storage._gpsDisabled) }() - case 34: try { try decoder.decodeSingularUInt32Field(value: &_storage._gpsUpdateInterval) }() - case 36: try { try decoder.decodeSingularUInt32Field(value: &_storage._gpsAttemptTime) }() - case 38: try { try decoder.decodeSingularBoolField(value: &_storage._isLowPower) }() - case 39: try { try decoder.decodeSingularBoolField(value: &_storage._fixedPosition) }() - case 40: try { try decoder.decodeSingularBoolField(value: &_storage._serialDisabled) }() - case 41: try { try decoder.decodeSingularFloatField(value: &_storage._frequencyOffset) }() - case 42: try { try decoder.decodeSingularStringField(value: &_storage._mqttServer) }() - case 43: try { try decoder.decodeSingularBoolField(value: &_storage._mqttDisabled) }() - case 44: try { try decoder.decodeSingularEnumField(value: &_storage._gpsFormat) }() - case 45: try { try decoder.decodeSingularBoolField(value: &_storage._gpsAccept2D) }() - case 46: try { try decoder.decodeSingularUInt32Field(value: &_storage._gpsMaxDop) }() - case 100: try { try decoder.decodeSingularBoolField(value: &_storage._factoryReset) }() - case 101: try { try decoder.decodeSingularBoolField(value: &_storage._debugLogEnabled) }() - case 103: try { try decoder.decodeRepeatedUInt32Field(value: &_storage._ignoreIncoming) }() - case 120: try { try decoder.decodeSingularBoolField(value: &_storage._serialModuleEnabled) }() - case 121: try { try decoder.decodeSingularBoolField(value: &_storage._serialModuleEcho) }() - case 122: try { try decoder.decodeSingularUInt32Field(value: &_storage._serialModuleRxd) }() - case 123: try { try decoder.decodeSingularUInt32Field(value: &_storage._serialModuleTxd) }() - case 124: try { try decoder.decodeSingularUInt32Field(value: &_storage._serialModuleTimeout) }() - case 125: try { try decoder.decodeSingularEnumField(value: &_storage._serialModuleMode) }() - case 126: try { try decoder.decodeSingularBoolField(value: &_storage._extNotificationModuleEnabled) }() - case 127: try { try decoder.decodeSingularUInt32Field(value: &_storage._extNotificationModuleOutputMs) }() - case 128: try { try decoder.decodeSingularUInt32Field(value: &_storage._extNotificationModuleOutput) }() - case 129: try { try decoder.decodeSingularBoolField(value: &_storage._extNotificationModuleActive) }() - case 130: try { try decoder.decodeSingularBoolField(value: &_storage._extNotificationModuleAlertMessage) }() - case 131: try { try decoder.decodeSingularBoolField(value: &_storage._extNotificationModuleAlertBell) }() - case 132: try { try decoder.decodeSingularBoolField(value: &_storage._rangeTestModuleEnabled) }() - case 133: try { try decoder.decodeSingularUInt32Field(value: &_storage._rangeTestModuleSender) }() - case 134: try { try decoder.decodeSingularBoolField(value: &_storage._rangeTestModuleSave) }() - case 137: try { try decoder.decodeSingularUInt32Field(value: &_storage._storeForwardModuleRecords) }() - case 138: try { try decoder.decodeSingularUInt32Field(value: &_storage._storeForwardModuleHistoryReturnMax) }() - case 139: try { try decoder.decodeSingularUInt32Field(value: &_storage._storeForwardModuleHistoryReturnWindow) }() - case 148: try { try decoder.decodeSingularBoolField(value: &_storage._storeForwardModuleEnabled) }() - case 149: try { try decoder.decodeSingularBoolField(value: &_storage._storeForwardModuleHeartbeat) }() - case 150: try { try decoder.decodeSingularUInt32Field(value: &_storage._positionFlags) }() - case 151: try { try decoder.decodeSingularBoolField(value: &_storage._isAlwaysPowered) }() - case 152: try { try decoder.decodeSingularUInt32Field(value: &_storage._autoScreenCarouselSecs) }() - case 153: try { try decoder.decodeSingularUInt32Field(value: &_storage._onBatteryShutdownAfterSecs) }() - case 154: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopLimit) }() - case 155: try { try decoder.decodeSingularStringField(value: &_storage._mqttUsername) }() - case 156: try { try decoder.decodeSingularStringField(value: &_storage._mqttPassword) }() - case 157: try { try decoder.decodeSingularBoolField(value: &_storage._isLoraTxDisabled) }() - case 158: try { try decoder.decodeSingularBoolField(value: &_storage._isPowerSaving) }() - case 160: try { try decoder.decodeSingularBoolField(value: &_storage._rotary1Enabled) }() - case 161: try { try decoder.decodeSingularUInt32Field(value: &_storage._inputbrokerPinA) }() - case 162: try { try decoder.decodeSingularUInt32Field(value: &_storage._inputbrokerPinB) }() - case 163: try { try decoder.decodeSingularUInt32Field(value: &_storage._inputbrokerPinPress) }() - case 164: try { try decoder.decodeSingularEnumField(value: &_storage._inputbrokerEventCw) }() - case 165: try { try decoder.decodeSingularEnumField(value: &_storage._inputbrokerEventCcw) }() - case 166: try { try decoder.decodeSingularEnumField(value: &_storage._inputbrokerEventPress) }() - case 167: try { try decoder.decodeSingularBoolField(value: &_storage._updown1Enabled) }() - case 170: try { try decoder.decodeSingularBoolField(value: &_storage._cannedMessageModuleEnabled) }() - case 171: try { try decoder.decodeSingularStringField(value: &_storage._cannedMessageModuleAllowInputSource) }() - case 173: try { try decoder.decodeSingularBoolField(value: &_storage._cannedMessageModuleSendBell) }() - case 174: try { try decoder.decodeSingularBoolField(value: &_storage._mqttEncryptionEnabled) }() - case 175: try { try decoder.decodeSingularFloatField(value: &_storage._adcMultiplierOverride) }() - case 176: try { try decoder.decodeSingularEnumField(value: &_storage._serialModuleBaud) }() - default: break - } - } - } - } - - func traverse(visitor: inout V) throws { - try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - if _storage._positionBroadcastSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._positionBroadcastSecs, fieldNumber: 1) - } - if _storage._waitBluetoothSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._waitBluetoothSecs, fieldNumber: 4) - } - if _storage._screenOnSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._screenOnSecs, fieldNumber: 5) - } - if _storage._phoneTimeoutSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._phoneTimeoutSecs, fieldNumber: 6) - } - if _storage._meshSdsTimeoutSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._meshSdsTimeoutSecs, fieldNumber: 8) - } - if _storage._sdsSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._sdsSecs, fieldNumber: 9) - } - if _storage._lsSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._lsSecs, fieldNumber: 10) - } - if _storage._minWakeSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._minWakeSecs, fieldNumber: 11) - } - if !_storage._wifiSsid.isEmpty { - try visitor.visitSingularStringField(value: _storage._wifiSsid, fieldNumber: 12) - } - if !_storage._wifiPassword.isEmpty { - try visitor.visitSingularStringField(value: _storage._wifiPassword, fieldNumber: 13) - } - if _storage._wifiApMode != false { - try visitor.visitSingularBoolField(value: _storage._wifiApMode, fieldNumber: 14) - } - if _storage._region != .unset { - try visitor.visitSingularEnumField(value: _storage._region, fieldNumber: 15) - } - if _storage._chargeCurrent != .maunset { - try visitor.visitSingularEnumField(value: _storage._chargeCurrent, fieldNumber: 16) - } - if _storage._positionBroadcastSmartDisabled != false { - try visitor.visitSingularBoolField(value: _storage._positionBroadcastSmartDisabled, fieldNumber: 17) - } - if _storage._role != .client { - try visitor.visitSingularEnumField(value: _storage._role, fieldNumber: 18) - } - if _storage._locationShareDisabled != false { - try visitor.visitSingularBoolField(value: _storage._locationShareDisabled, fieldNumber: 32) - } - if _storage._gpsDisabled != false { - try visitor.visitSingularBoolField(value: _storage._gpsDisabled, fieldNumber: 33) - } - if _storage._gpsUpdateInterval != 0 { - try visitor.visitSingularUInt32Field(value: _storage._gpsUpdateInterval, fieldNumber: 34) - } - if _storage._gpsAttemptTime != 0 { - try visitor.visitSingularUInt32Field(value: _storage._gpsAttemptTime, fieldNumber: 36) - } - if _storage._isLowPower != false { - try visitor.visitSingularBoolField(value: _storage._isLowPower, fieldNumber: 38) - } - if _storage._fixedPosition != false { - try visitor.visitSingularBoolField(value: _storage._fixedPosition, fieldNumber: 39) - } - if _storage._serialDisabled != false { - try visitor.visitSingularBoolField(value: _storage._serialDisabled, fieldNumber: 40) - } - if _storage._frequencyOffset != 0 { - try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 41) - } - if !_storage._mqttServer.isEmpty { - try visitor.visitSingularStringField(value: _storage._mqttServer, fieldNumber: 42) - } - if _storage._mqttDisabled != false { - try visitor.visitSingularBoolField(value: _storage._mqttDisabled, fieldNumber: 43) - } - if _storage._gpsFormat != .gpsFormatDec { - try visitor.visitSingularEnumField(value: _storage._gpsFormat, fieldNumber: 44) - } - if _storage._gpsAccept2D != false { - try visitor.visitSingularBoolField(value: _storage._gpsAccept2D, fieldNumber: 45) - } - if _storage._gpsMaxDop != 0 { - try visitor.visitSingularUInt32Field(value: _storage._gpsMaxDop, fieldNumber: 46) - } - if _storage._factoryReset != false { - try visitor.visitSingularBoolField(value: _storage._factoryReset, fieldNumber: 100) - } - if _storage._debugLogEnabled != false { - try visitor.visitSingularBoolField(value: _storage._debugLogEnabled, fieldNumber: 101) - } - if !_storage._ignoreIncoming.isEmpty { - try visitor.visitPackedUInt32Field(value: _storage._ignoreIncoming, fieldNumber: 103) - } - if _storage._serialModuleEnabled != false { - try visitor.visitSingularBoolField(value: _storage._serialModuleEnabled, fieldNumber: 120) - } - if _storage._serialModuleEcho != false { - try visitor.visitSingularBoolField(value: _storage._serialModuleEcho, fieldNumber: 121) - } - if _storage._serialModuleRxd != 0 { - try visitor.visitSingularUInt32Field(value: _storage._serialModuleRxd, fieldNumber: 122) - } - if _storage._serialModuleTxd != 0 { - try visitor.visitSingularUInt32Field(value: _storage._serialModuleTxd, fieldNumber: 123) - } - if _storage._serialModuleTimeout != 0 { - try visitor.visitSingularUInt32Field(value: _storage._serialModuleTimeout, fieldNumber: 124) - } - if _storage._serialModuleMode != .modeDefault { - try visitor.visitSingularEnumField(value: _storage._serialModuleMode, fieldNumber: 125) - } - if _storage._extNotificationModuleEnabled != false { - try visitor.visitSingularBoolField(value: _storage._extNotificationModuleEnabled, fieldNumber: 126) - } - if _storage._extNotificationModuleOutputMs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._extNotificationModuleOutputMs, fieldNumber: 127) - } - if _storage._extNotificationModuleOutput != 0 { - try visitor.visitSingularUInt32Field(value: _storage._extNotificationModuleOutput, fieldNumber: 128) - } - if _storage._extNotificationModuleActive != false { - try visitor.visitSingularBoolField(value: _storage._extNotificationModuleActive, fieldNumber: 129) - } - if _storage._extNotificationModuleAlertMessage != false { - try visitor.visitSingularBoolField(value: _storage._extNotificationModuleAlertMessage, fieldNumber: 130) - } - if _storage._extNotificationModuleAlertBell != false { - try visitor.visitSingularBoolField(value: _storage._extNotificationModuleAlertBell, fieldNumber: 131) - } - if _storage._rangeTestModuleEnabled != false { - try visitor.visitSingularBoolField(value: _storage._rangeTestModuleEnabled, fieldNumber: 132) - } - if _storage._rangeTestModuleSender != 0 { - try visitor.visitSingularUInt32Field(value: _storage._rangeTestModuleSender, fieldNumber: 133) - } - if _storage._rangeTestModuleSave != false { - try visitor.visitSingularBoolField(value: _storage._rangeTestModuleSave, fieldNumber: 134) - } - if _storage._storeForwardModuleRecords != 0 { - try visitor.visitSingularUInt32Field(value: _storage._storeForwardModuleRecords, fieldNumber: 137) - } - if _storage._storeForwardModuleHistoryReturnMax != 0 { - try visitor.visitSingularUInt32Field(value: _storage._storeForwardModuleHistoryReturnMax, fieldNumber: 138) - } - if _storage._storeForwardModuleHistoryReturnWindow != 0 { - try visitor.visitSingularUInt32Field(value: _storage._storeForwardModuleHistoryReturnWindow, fieldNumber: 139) - } - if _storage._storeForwardModuleEnabled != false { - try visitor.visitSingularBoolField(value: _storage._storeForwardModuleEnabled, fieldNumber: 148) - } - if _storage._storeForwardModuleHeartbeat != false { - try visitor.visitSingularBoolField(value: _storage._storeForwardModuleHeartbeat, fieldNumber: 149) - } - if _storage._positionFlags != 0 { - try visitor.visitSingularUInt32Field(value: _storage._positionFlags, fieldNumber: 150) - } - if _storage._isAlwaysPowered != false { - try visitor.visitSingularBoolField(value: _storage._isAlwaysPowered, fieldNumber: 151) - } - if _storage._autoScreenCarouselSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._autoScreenCarouselSecs, fieldNumber: 152) - } - if _storage._onBatteryShutdownAfterSecs != 0 { - try visitor.visitSingularUInt32Field(value: _storage._onBatteryShutdownAfterSecs, fieldNumber: 153) - } - if _storage._hopLimit != 0 { - try visitor.visitSingularUInt32Field(value: _storage._hopLimit, fieldNumber: 154) - } - if !_storage._mqttUsername.isEmpty { - try visitor.visitSingularStringField(value: _storage._mqttUsername, fieldNumber: 155) - } - if !_storage._mqttPassword.isEmpty { - try visitor.visitSingularStringField(value: _storage._mqttPassword, fieldNumber: 156) - } - if _storage._isLoraTxDisabled != false { - try visitor.visitSingularBoolField(value: _storage._isLoraTxDisabled, fieldNumber: 157) - } - if _storage._isPowerSaving != false { - try visitor.visitSingularBoolField(value: _storage._isPowerSaving, fieldNumber: 158) - } - if _storage._rotary1Enabled != false { - try visitor.visitSingularBoolField(value: _storage._rotary1Enabled, fieldNumber: 160) - } - if _storage._inputbrokerPinA != 0 { - try visitor.visitSingularUInt32Field(value: _storage._inputbrokerPinA, fieldNumber: 161) - } - if _storage._inputbrokerPinB != 0 { - try visitor.visitSingularUInt32Field(value: _storage._inputbrokerPinB, fieldNumber: 162) - } - if _storage._inputbrokerPinPress != 0 { - try visitor.visitSingularUInt32Field(value: _storage._inputbrokerPinPress, fieldNumber: 163) - } - if _storage._inputbrokerEventCw != .keyNone { - try visitor.visitSingularEnumField(value: _storage._inputbrokerEventCw, fieldNumber: 164) - } - if _storage._inputbrokerEventCcw != .keyNone { - try visitor.visitSingularEnumField(value: _storage._inputbrokerEventCcw, fieldNumber: 165) - } - if _storage._inputbrokerEventPress != .keyNone { - try visitor.visitSingularEnumField(value: _storage._inputbrokerEventPress, fieldNumber: 166) - } - if _storage._updown1Enabled != false { - try visitor.visitSingularBoolField(value: _storage._updown1Enabled, fieldNumber: 167) - } - if _storage._cannedMessageModuleEnabled != false { - try visitor.visitSingularBoolField(value: _storage._cannedMessageModuleEnabled, fieldNumber: 170) - } - if !_storage._cannedMessageModuleAllowInputSource.isEmpty { - try visitor.visitSingularStringField(value: _storage._cannedMessageModuleAllowInputSource, fieldNumber: 171) - } - if _storage._cannedMessageModuleSendBell != false { - try visitor.visitSingularBoolField(value: _storage._cannedMessageModuleSendBell, fieldNumber: 173) - } - if _storage._mqttEncryptionEnabled != false { - try visitor.visitSingularBoolField(value: _storage._mqttEncryptionEnabled, fieldNumber: 174) - } - if _storage._adcMultiplierOverride != 0 { - try visitor.visitSingularFloatField(value: _storage._adcMultiplierOverride, fieldNumber: 175) - } - if _storage._serialModuleBaud != .baudDefault { - try visitor.visitSingularEnumField(value: _storage._serialModuleBaud, fieldNumber: 176) - } - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: RadioConfig.UserPreferences, rhs: RadioConfig.UserPreferences) -> Bool { - if lhs._storage !== rhs._storage { - let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in - let _storage = _args.0 - let rhs_storage = _args.1 - if _storage._positionBroadcastSecs != rhs_storage._positionBroadcastSecs {return false} - if _storage._positionBroadcastSmartDisabled != rhs_storage._positionBroadcastSmartDisabled {return false} - if _storage._waitBluetoothSecs != rhs_storage._waitBluetoothSecs {return false} - if _storage._screenOnSecs != rhs_storage._screenOnSecs {return false} - if _storage._phoneTimeoutSecs != rhs_storage._phoneTimeoutSecs {return false} - if _storage._meshSdsTimeoutSecs != rhs_storage._meshSdsTimeoutSecs {return false} - if _storage._sdsSecs != rhs_storage._sdsSecs {return false} - if _storage._lsSecs != rhs_storage._lsSecs {return false} - if _storage._minWakeSecs != rhs_storage._minWakeSecs {return false} - if _storage._wifiSsid != rhs_storage._wifiSsid {return false} - if _storage._wifiPassword != rhs_storage._wifiPassword {return false} - if _storage._wifiApMode != rhs_storage._wifiApMode {return false} - if _storage._region != rhs_storage._region {return false} - if _storage._chargeCurrent != rhs_storage._chargeCurrent {return false} - if _storage._role != rhs_storage._role {return false} - if _storage._isLowPower != rhs_storage._isLowPower {return false} - if _storage._fixedPosition != rhs_storage._fixedPosition {return false} - if _storage._serialDisabled != rhs_storage._serialDisabled {return false} - if _storage._locationShareDisabled != rhs_storage._locationShareDisabled {return false} - if _storage._gpsDisabled != rhs_storage._gpsDisabled {return false} - if _storage._gpsUpdateInterval != rhs_storage._gpsUpdateInterval {return false} - if _storage._gpsAttemptTime != rhs_storage._gpsAttemptTime {return false} - if _storage._gpsAccept2D != rhs_storage._gpsAccept2D {return false} - if _storage._gpsMaxDop != rhs_storage._gpsMaxDop {return false} - if _storage._frequencyOffset != rhs_storage._frequencyOffset {return false} - if _storage._mqttServer != rhs_storage._mqttServer {return false} - if _storage._mqttDisabled != rhs_storage._mqttDisabled {return false} - if _storage._gpsFormat != rhs_storage._gpsFormat {return false} - if _storage._factoryReset != rhs_storage._factoryReset {return false} - if _storage._debugLogEnabled != rhs_storage._debugLogEnabled {return false} - if _storage._ignoreIncoming != rhs_storage._ignoreIncoming {return false} - if _storage._serialModuleEnabled != rhs_storage._serialModuleEnabled {return false} - if _storage._serialModuleEcho != rhs_storage._serialModuleEcho {return false} - if _storage._serialModuleRxd != rhs_storage._serialModuleRxd {return false} - if _storage._serialModuleTxd != rhs_storage._serialModuleTxd {return false} - if _storage._serialModuleBaud != rhs_storage._serialModuleBaud {return false} - if _storage._serialModuleTimeout != rhs_storage._serialModuleTimeout {return false} - if _storage._serialModuleMode != rhs_storage._serialModuleMode {return false} - if _storage._extNotificationModuleEnabled != rhs_storage._extNotificationModuleEnabled {return false} - if _storage._extNotificationModuleOutputMs != rhs_storage._extNotificationModuleOutputMs {return false} - if _storage._extNotificationModuleOutput != rhs_storage._extNotificationModuleOutput {return false} - if _storage._extNotificationModuleActive != rhs_storage._extNotificationModuleActive {return false} - if _storage._extNotificationModuleAlertMessage != rhs_storage._extNotificationModuleAlertMessage {return false} - if _storage._extNotificationModuleAlertBell != rhs_storage._extNotificationModuleAlertBell {return false} - if _storage._rangeTestModuleEnabled != rhs_storage._rangeTestModuleEnabled {return false} - if _storage._rangeTestModuleSender != rhs_storage._rangeTestModuleSender {return false} - if _storage._rangeTestModuleSave != rhs_storage._rangeTestModuleSave {return false} - if _storage._storeForwardModuleEnabled != rhs_storage._storeForwardModuleEnabled {return false} - if _storage._storeForwardModuleHeartbeat != rhs_storage._storeForwardModuleHeartbeat {return false} - if _storage._storeForwardModuleRecords != rhs_storage._storeForwardModuleRecords {return false} - if _storage._storeForwardModuleHistoryReturnMax != rhs_storage._storeForwardModuleHistoryReturnMax {return false} - if _storage._storeForwardModuleHistoryReturnWindow != rhs_storage._storeForwardModuleHistoryReturnWindow {return false} - if _storage._positionFlags != rhs_storage._positionFlags {return false} - if _storage._isAlwaysPowered != rhs_storage._isAlwaysPowered {return false} - if _storage._autoScreenCarouselSecs != rhs_storage._autoScreenCarouselSecs {return false} - if _storage._onBatteryShutdownAfterSecs != rhs_storage._onBatteryShutdownAfterSecs {return false} - if _storage._hopLimit != rhs_storage._hopLimit {return false} - if _storage._mqttUsername != rhs_storage._mqttUsername {return false} - if _storage._mqttPassword != rhs_storage._mqttPassword {return false} - if _storage._isLoraTxDisabled != rhs_storage._isLoraTxDisabled {return false} - if _storage._isPowerSaving != rhs_storage._isPowerSaving {return false} - if _storage._rotary1Enabled != rhs_storage._rotary1Enabled {return false} - if _storage._inputbrokerPinA != rhs_storage._inputbrokerPinA {return false} - if _storage._inputbrokerPinB != rhs_storage._inputbrokerPinB {return false} - if _storage._inputbrokerPinPress != rhs_storage._inputbrokerPinPress {return false} - if _storage._inputbrokerEventCw != rhs_storage._inputbrokerEventCw {return false} - if _storage._inputbrokerEventCcw != rhs_storage._inputbrokerEventCcw {return false} - if _storage._inputbrokerEventPress != rhs_storage._inputbrokerEventPress {return false} - if _storage._updown1Enabled != rhs_storage._updown1Enabled {return false} - if _storage._cannedMessageModuleEnabled != rhs_storage._cannedMessageModuleEnabled {return false} - if _storage._cannedMessageModuleAllowInputSource != rhs_storage._cannedMessageModuleAllowInputSource {return false} - if _storage._cannedMessageModuleSendBell != rhs_storage._cannedMessageModuleSendBell {return false} - if _storage._mqttEncryptionEnabled != rhs_storage._mqttEncryptionEnabled {return false} - if _storage._adcMultiplierOverride != rhs_storage._adcMultiplierOverride {return false} - return true - } - if !storagesAreEqual {return false} - } - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension RadioConfig.UserPreferences.Serial_Baud: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "BAUD_Default"), - 1: .same(proto: "BAUD_2400"), - 2: .same(proto: "BAUD_4800"), - 3: .same(proto: "BAUD_9600"), - 4: .same(proto: "BAUD_19200"), - 5: .same(proto: "BAUD_38400"), - 6: .same(proto: "BAUD_57600"), - 7: .same(proto: "BAUD_115200"), - 8: .same(proto: "BAUD_230400"), - 9: .same(proto: "BAUD_460800"), - 10: .same(proto: "BAUD_576000"), - 11: .same(proto: "BAUD_921600"), - 12: .same(proto: "BAUD_110"), - 13: .same(proto: "BAUD_300"), - 14: .same(proto: "BAUD_600"), - 15: .same(proto: "BAUD_1200"), - ] -} - -extension RadioConfig.UserPreferences.Serial_Mode: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 0: .same(proto: "MODE_Default"), - 1: .same(proto: "MODE_SIMPLE"), - 2: .same(proto: "MODE_PROTO"), - ] -} diff --git a/MeshtasticClient/Views/Bluetooth/Connect.swift b/MeshtasticClient/Views/Bluetooth/Connect.swift index 84087dbe..7b4ce84a 100644 --- a/MeshtasticClient/Views/Bluetooth/Connect.swift +++ b/MeshtasticClient/Views/Bluetooth/Connect.swift @@ -265,8 +265,8 @@ struct Connect: View { ConnectedDevice( bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.shortName : - "???") + name: (bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.lastFourCode : + "????") } ) } diff --git a/MeshtasticClient/Views/Helpers/LastHeardText.swift b/MeshtasticClient/Views/Helpers/LastHeardText.swift index c17a423d..3d688264 100644 --- a/MeshtasticClient/Views/Helpers/LastHeardText.swift +++ b/MeshtasticClient/Views/Helpers/LastHeardText.swift @@ -7,6 +7,7 @@ import SwiftUI // struct LastHeardText: View { var lastHeard: Date? + let sixMonthsAgo = Calendar.current.date(byAdding: .month, value: -6, to: Date()) var body: some View { @@ -16,7 +17,7 @@ struct LastHeardText: View { } else { - Text("Last Heard: Unknown Age") + Text("Unknown Age") } } } diff --git a/MeshtasticClient/Views/Messages/UserMessageList.swift b/MeshtasticClient/Views/Messages/UserMessageList.swift index 1d64cb66..80ae8b81 100644 --- a/MeshtasticClient/Views/Messages/UserMessageList.swift +++ b/MeshtasticClient/Views/Messages/UserMessageList.swift @@ -470,7 +470,7 @@ struct UserMessageList: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") } } } diff --git a/MeshtasticClient/Views/Nodes/NodeDetail.swift b/MeshtasticClient/Views/Nodes/NodeDetail.swift index 637344a5..9c0f99d3 100644 --- a/MeshtasticClient/Views/Nodes/NodeDetail.swift +++ b/MeshtasticClient/Views/Nodes/NodeDetail.swift @@ -133,16 +133,18 @@ struct NodeDetail: View { BatteryIcon(batteryLevel: mostRecent.batteryLevel, font: .title, color: .accentColor) .padding(.bottom) - Text(String(mostRecent.batteryLevel) + "%") - .font(.title3) - .foregroundColor(.gray) - .fixedSize() + + if mostRecent.batteryLevel > 0 { + Text(String(mostRecent.batteryLevel) + "%") + .font(.title3) + .foregroundColor(.gray) + .fixedSize() + } + Text(String(format: "%.2f", mostRecent.voltage) + " V") .font(.title3) .foregroundColor(.gray) .fixedSize() - - } .padding(5) } @@ -281,7 +283,7 @@ struct NodeDetail: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") } ) .onAppear(perform: { diff --git a/MeshtasticClient/Views/Nodes/NodeList.swift b/MeshtasticClient/Views/Nodes/NodeList.swift index b608a3f3..a84e9e6b 100644 --- a/MeshtasticClient/Views/Nodes/NodeList.swift +++ b/MeshtasticClient/Views/Nodes/NodeList.swift @@ -68,7 +68,7 @@ struct NodeList: View { HStack(alignment: .bottom) { - Image(systemName: "repeat.circle.fill").font(.title3) + Image(systemName: "repeat.circle.fill").font(.title2) .foregroundColor(.accentColor).symbolRenderingMode(.hierarchical) if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { @@ -83,7 +83,8 @@ struct NodeList: View { HStack(alignment: .bottom) { - Image(systemName: "clock.badge.checkmark.fill").font(.title3).foregroundColor(.accentColor).symbolRenderingMode(.hierarchical) + Image(systemName: "clock.badge.checkmark.fill").font(.title3) + .foregroundColor(.accentColor).symbolRenderingMode(.hierarchical) if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { LastHeardText(lastHeard: node.lastHeard).font(.subheadline).foregroundColor(.gray) diff --git a/MeshtasticClient/Views/Nodes/NodeMap.swift b/MeshtasticClient/Views/Nodes/NodeMap.swift index e7d91c57..4c4d223c 100644 --- a/MeshtasticClient/Views/Nodes/NodeMap.swift +++ b/MeshtasticClient/Views/Nodes/NodeMap.swift @@ -126,8 +126,8 @@ struct NodeMap: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : - "???") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : + "????") }) .onAppear(perform: { diff --git a/MeshtasticClient/Views/Settings/AppSettings.swift b/MeshtasticClient/Views/Settings/AppSettings.swift index 769419db..661e2673 100644 --- a/MeshtasticClient/Views/Settings/AppSettings.swift +++ b/MeshtasticClient/Views/Settings/AppSettings.swift @@ -251,7 +251,7 @@ struct AppSettings: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") }) .onAppear { diff --git a/MeshtasticClient/Views/Settings/ShareChannel.swift b/MeshtasticClient/Views/Settings/ShareChannel.swift index 2fbab5d3..1756d719 100644 --- a/MeshtasticClient/Views/Settings/ShareChannel.swift +++ b/MeshtasticClient/Views/Settings/ShareChannel.swift @@ -81,7 +81,7 @@ struct ShareChannel: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "???") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") }) .onAppear { diff --git a/gen_protos.sh b/gen_protos.sh index a07c2b40..5c3244f2 100755 --- a/gen_protos.sh +++ b/gen_protos.sh @@ -15,7 +15,7 @@ fi pdir=$(realpath "../Meshtastic-protobufs") sdir=$(realpath "./MeshtasticClient/Protobufs") echo "pdir:$pdir sdir:$sdir" -pfiles="admin.proto apponly.proto cannedmessages.proto channel.proto config.proto deviceonly.proto mesh.proto module_config.proto mqtt.proto portnums.proto radioconfig.proto remote_hardware.proto storeforward.proto telemetry.proto" +pfiles="admin.proto apponly.proto cannedmessages.proto channel.proto config.proto deviceonly.proto mesh.proto module_config.proto mqtt.proto portnums.proto remote_hardware.proto storeforward.proto telemetry.proto" for pf in $pfiles do echo "Generating $pf..." From e4fd40701e0d7b90c8f9586f707a598f7a889a6d Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 27 May 2022 19:34:42 -0700 Subject: [PATCH 2/5] Add packet type functions to switch statement --- MeshtasticClient/Helpers/BLEManager.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index a7220d4e..89f4b986 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -355,7 +355,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // MARK: Data Read / Update Characteristic Event func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - if let e = error { print("🚫 didUpdateValueFor Characteristic error \(e)") @@ -365,7 +364,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if errorCode == 5 { // CBATTErrorDomain Code=5 "Authentication is insufficient." // BLE Pin connection error - // We will try and re-connect to this device lastConnectionError = "🚫 BLE \(e.localizedDescription) Please try connecting again and check the PIN carefully." if meshLoggingEnabled { MeshLogger.log("🚫 BLE \(e.localizedDescription) Please try connecting again and check the PIN carefully.") } self.centralManager?.cancelPeripheralConnection(peripheral) @@ -374,7 +372,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if errorCode == 15 { // CBATTErrorDomain Code=15 "Encryption is insufficient." // BLE Pin connection error - // We will try and re-connect to this device lastConnectionError = "🚫 BLE \(e.localizedDescription) This may be a Meshtastic Firmware bug affecting BLE 4.0 devices." if meshLoggingEnabled { MeshLogger.log("🚫 BLE \(e.localizedDescription) Please try connecting again. You may need to forget the device under Settings > General > Bluetooth.") } self.centralManager?.cancelPeripheralConnection(peripheral) @@ -397,15 +394,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph case .unknownApp: print("MyInfo or NodeInfo") - print("Sending nodeinfo: num=0x3b9c2510, lastseen=0, id=!3b9c2510, name=Unknown 2510") case .textMessageApp: textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) case .remoteHardwareApp: print("remoteHardwareApp") case .positionApp: - print("positionApp") + positionPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .nodeinfoApp: - print("nodeinfoApp") + nodeInfoPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .routingApp: routingPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .adminApp: @@ -725,22 +721,26 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } } - if decodedInfo.configCompleteID != 0 { if meshLoggingEnabled { MeshLogger.log("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)") } print("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)") self.connectedPeripheral.subscribed = true peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected }) + // Config conplete returns so we don't read the characteristic again + return } case FROMNUM_UUID : - print("FROMNUM Notification, value will be read below") + print("🗞️ FROMNUM Notification, value will be read below") default: + print("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)") } + + // Either Read the config complete value or from num notify value peripheral.readValue(for: FROMRADIO_characteristic) } From 39f7120a1337527972a823d6ff1a3c857249af55 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 27 May 2022 19:41:02 -0700 Subject: [PATCH 3/5] Handle all the ports --- MeshtasticClient/Helpers/BLEManager.swift | 27 +++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 89f4b986..5c21ecd0 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -397,7 +397,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph case .textMessageApp: textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) case .remoteHardwareApp: - print("remoteHardwareApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .positionApp: positionPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .nodeinfoApp: @@ -408,26 +409,34 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") } print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .replyApp: - print("replyApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Reply App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Reply App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .ipTunnelApp: - print("ipTunnelApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for IP Tunnel App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for IP Tunnel App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .serialApp: - print("serialApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Serial App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Serial App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .storeForwardApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Store Forward App UNHANDLED \(try! decodedInfo.packet.jsonString())") } print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .rangeTestApp: - print("rangeTestApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Range Test App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Range Test App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .telemetryApp: telemetryPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .textMessageCompressedApp: - print("textMessageCompressedApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Text Message Compressed App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Text Message Compressed App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .zpsApp: - print("zpsApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for ZPS App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for ZPS App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .privateApp: - print("privateApp") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Private App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for Private App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .atakForwarder: - print("atakForwarder") + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for ATAK Forwarder App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + print("ℹ️ MESH PACKET received for ATAK Forwarder App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .UNRECOGNIZED(_): if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try! decodedInfo.packet.jsonString())") } print("ℹ️ MESH PACKET received for UNRECOGNIZED App UNHANDLED \(try! decodedInfo.packet.jsonString())") From cfd07b227d9329dbe360ba2e5dc9f51420fd1274 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 27 May 2022 22:14:57 -0700 Subject: [PATCH 4/5] Consolidate mesh logging --- Meshtastic Client.xcodeproj/project.pbxproj | 4 +- MeshtasticClient/Helpers/BLEManager.swift | 63 ++++++--------------- MeshtasticClient/Helpers/MeshLogger.swift | 1 + MeshtasticClient/Helpers/MeshPackets.swift | 13 ++--- 4 files changed, 25 insertions(+), 56 deletions(-) diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index e6ecaea9..d93f6c14 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -751,7 +751,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; @@ -783,7 +783,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 7; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index 5c21ecd0..b4e1fd2e 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -124,14 +124,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.isConnected = false self.lastConnectionError = "🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(name)." - print("🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(name).") - if meshLoggingEnabled { MeshLogger.log("🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(String(name)). This can occur when a device has been taken out of BLE range, or if a device is already connected to another phone, tablet or computer.") } + + if meshLoggingEnabled { MeshLogger.log(self.lastConnectionError + " This can occur when a device has been taken out of BLE range, or if a device is already connected to another phone, tablet or computer.") } self.timeoutTimerCount = 0 self.timeoutTimer?.invalidate() } else { - print("🚨 BLE Connecting 2 Second Timeout Timer Fired \(timeoutTimerCount) Time(s): \(name)") + if meshLoggingEnabled { MeshLogger.log("🚨 BLE Connecting 2 Second Timeout Timer Fired \(timeoutTimerCount) Time(s): \(name)") } } } @@ -140,13 +140,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph func connectTo(peripheral: CBPeripheral) { if meshLoggingEnabled { MeshLogger.log("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") } - print("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") stopScanning() if self.connectedPeripheral != nil { + if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")") } - print("ℹ️ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")") self.disconnectPeripheral() } @@ -196,8 +195,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } let today = Date() - let fiveMinutesAgo = Calendar.current.date(byAdding: .minute, value: -5, to: today)! - peripherals.removeAll(where: { $0.lastUpdate <= fiveMinutesAgo}) + let oneMinuteAgo = Calendar.current.date(byAdding: .minute, value: -1, to: today)! + peripherals.removeAll(where: { $0.lastUpdate <= oneMinuteAgo}) } // Called when a peripheral is connected @@ -217,7 +216,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // Discover Services peripheral.discoverServices([meshtasticServiceCBUUID]) if meshLoggingEnabled { MeshLogger.log("✅ BLE Connected: \(peripheral.name ?? "Unknown")") } - print("✅ BLE Connected: \(peripheral.name ?? "Unknown")") } @@ -225,7 +223,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { if meshLoggingEnabled { MeshLogger.log("🚫 BLE Failed to Connect: \(peripheral.name ?? "Unknown")") } - print("🚫 BLE Failed to Connect: \(peripheral.name ?? "Unknown")") disconnectPeripheral() } @@ -248,27 +245,27 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph lastConnectionError = "🚨 \(e.localizedDescription) The app will automatically reconnect to the preferred radio if it reappears within 10 seconds." if peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" { if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Reconnecting: \(peripheral.name ?? "Unknown")") } - print("ℹ️ BLE Reconnecting: \(peripheral.name ?? "Unknown")") self.connectTo(peripheral: peripheral) } + } else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us. // Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work. lastConnectionError = e.localizedDescription - print("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") } + } else if errorCode == 14 { // Peer removed pairing information // Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that lastConnectionError = "🚨 \(e.localizedDescription) This error usually cannot be fixed without forgetting the device unders Settings > Bluetooth and re-connecting to the radio." if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(lastConnectionError)") } + } else { lastConnectionError = e.localizedDescription - print("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") } } } else { @@ -276,7 +273,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph // Disconnected without error which indicates user intent to disconnect // Happens when swiping to disconnect if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect") } - print("ℹ️ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect") } } @@ -293,7 +289,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph for service in services { if service.uuid == meshtasticServiceCBUUID { - print("✅ Meshtastic service discovered OK") + if meshLoggingEnabled { MeshLogger.log("✅ BLE Service for Meshtastic discovered by \(peripheral.name ?? "Unknown")") } //peripheral.discoverCharacteristics(nil, for: service) peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID], for: service) @@ -305,7 +301,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { if let e = error { - print("🚫 Discover Characteristics error \(e)") if meshLoggingEnabled { MeshLogger.log("🚫 BLE didDiscoverCharacteristicsFor error by \(peripheral.name ?? "Unknown") \(e)") } } @@ -315,7 +310,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph switch characteristic.uuid { case TORADIO_UUID: - print("✅ TORADIO characteristic OK") + if meshLoggingEnabled { MeshLogger.log("✅ BLE did discover TORADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") } TORADIO_characteristic = characteristic var toRadio: ToRadio = ToRadio() @@ -324,13 +319,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph peripheral.writeValue(binaryData, for: characteristic, type: .withResponse) case FROMRADIO_UUID: - print("✅ FROMRADIO characteristic OK") + if meshLoggingEnabled { MeshLogger.log("✅ BLE did discover FROMRADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") } FROMRADIO_characteristic = characteristic peripheral.readValue(for: FROMRADIO_characteristic) case FROMNUM_UUID: - print("✅ FROMNUM (Notify) characteristic OK") + if meshLoggingEnabled { MeshLogger.log("✅ BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") } FROMNUM_characteristic = characteristic peripheral.setNotifyValue(true, for: characteristic) @@ -344,11 +339,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) { - print("ℹ️ didUpdateNotificationStateFor char: \(characteristic.uuid.uuidString) \(characteristic.isNotifying)") - if meshLoggingEnabled { MeshLogger.log("ℹ️ didUpdateNotificationStateFor char: \(characteristic.uuid.uuidString) \(characteristic.isNotifying)") } - if let errorText = error?.localizedDescription { - print("🚫 didUpdateNotificationStateFor error: \(errorText)") + + if meshLoggingEnabled { MeshLogger.log("🚫 didUpdateNotificationStateFor error: \(errorText)") } } } @@ -398,7 +391,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) case .remoteHardwareApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .positionApp: positionPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .nodeinfoApp: @@ -407,39 +399,28 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph routingPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .adminApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .replyApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Reply App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Reply App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .ipTunnelApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for IP Tunnel App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for IP Tunnel App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .serialApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Serial App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Serial App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .storeForwardApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Store Forward App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Admin App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .rangeTestApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Range Test App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Range Test App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .telemetryApp: telemetryPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) case .textMessageCompressedApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Text Message Compressed App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Text Message Compressed App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .zpsApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for ZPS App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for ZPS App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .privateApp: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Private App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for Private App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .atakForwarder: if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for ATAK Forwarder App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for ATAK Forwarder App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .UNRECOGNIZED(_): if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try! decodedInfo.packet.jsonString())") } - print("ℹ️ MESH PACKET received for UNRECOGNIZED App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .max: print("MAX PORT NUM OF 511") } @@ -510,6 +491,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: decodedInfo.myInfo.messageTimeoutMsec) fetchedMyInfo[0].minAppVersion = Int32(bitPattern: decodedInfo.myInfo.minAppVersion) fetchedMyInfo[0].maxChannels = Int32(bitPattern: decodedInfo.myInfo.maxChannels) + self.connectedPeripheral.num = fetchedMyInfo[0].myNodeNum self.connectedPeripheral.firmwareVersion = fetchedMyInfo[0].firmwareVersion ?? "Unknown" self.connectedPeripheral.name = fetchedMyInfo[0].bleName ?? "Unknown" @@ -519,7 +501,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph do { try context!.save() - print("💾 Saved a myInfo for \(decodedInfo.myInfo.myNodeNum)") if meshLoggingEnabled { MeshLogger.log("💾 Saved a myInfo for \(peripheral.name ?? String(decodedInfo.myInfo.myNodeNum))") } } catch { @@ -720,12 +701,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if decodedInfo.nodeInfo.hasUser { - print("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.user.longName)") if meshLoggingEnabled { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.user.longName)") } } else { - print("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.num)") if meshLoggingEnabled { MeshLogger.log("💾 BLE FROMRADIO received and nodeInfo saved for \(decodedInfo.nodeInfo.num)") } } } @@ -733,7 +712,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if decodedInfo.configCompleteID != 0 { if meshLoggingEnabled { MeshLogger.log("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)") } - print("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)") self.connectedPeripheral.subscribed = true peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected }) // Config conplete returns so we don't read the characteristic again @@ -769,7 +747,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if preferredPeripheral != nil && preferredPeripheral?.peripheral != nil { connectTo(peripheral: preferredPeripheral!.peripheral) } - print("🚫 Message Send Failed, not properly connected to \(preferredPeripheral?.name ?? "Unknown")") if meshLoggingEnabled { MeshLogger.log("🚫 Message Send Failed, not properly connected to \(preferredPeripheral?.name ?? "Unknown")") } success = false @@ -850,25 +827,22 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph let binaryData: Data = try! toRadio.serializedData() if meshLoggingEnabled { MeshLogger.log("📲 New messageId \(newMessage.messageId) sent to \(newMessage.toUser?.longName! ?? "Unknown")") } - print("📲 New messageId \(newMessage.messageId) sent to \(newMessage.toUser?.longName! ?? "Unknown")") if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { + connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) do { try context!.save() - print("💾 Saved a new sent message to \(toUserNum)") if meshLoggingEnabled { MeshLogger.log("💾 Saved a new sent message from \(connectedPeripheral.num) to \(toUserNum)") } success = true - //sendShutdown(destNum: connectedPeripheral.num, wantResponse: true) } catch { context!.rollback() let nsError = error as NSError - print("💥 Unresolved Core Data error in Send Message Function it is likely that your database is corrupted deleting and re-installing the app should clear the corrupted data. Error: \(nsError)") - if meshLoggingEnabled { MeshLogger.log("💥 Unresolved Core Data error \(nsError)") } + if meshLoggingEnabled { MeshLogger.log("💥 Unresolved Core Data error in Send Message Function it is likely that your database is corrupted deleting and re-installing the app should clear the corrupted data. Error: \(nsError)") } } } } @@ -925,7 +899,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph let binaryData: Data = try! toRadio.serializedData() if meshLoggingEnabled { MeshLogger.log("📍 Sent a Position Packet from the Apple device GPS to node: \(fromNodeNum)") } - print("📍 Sent a Position Packet from the Apple device GPS to node: \(fromNodeNum)") if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { diff --git a/MeshtasticClient/Helpers/MeshLogger.swift b/MeshtasticClient/Helpers/MeshLogger.swift index 2dc383d6..8de54f48 100644 --- a/MeshtasticClient/Helpers/MeshLogger.swift +++ b/MeshtasticClient/Helpers/MeshLogger.swift @@ -17,6 +17,7 @@ class MeshLogger { formatter.dateFormat = "M/d/yy h:mm:ss.SSSS" let timestamp = formatter.string(from: Date()) guard let data = (message + " - " + timestamp + "\n").data(using: String.Encoding.utf8) else { return } + print(message) if FileManager.default.fileExists(atPath: logFile.path) { if let fileHandle = try? FileHandle(forWritingTo: logFile) { diff --git a/MeshtasticClient/Helpers/MeshPackets.swift b/MeshtasticClient/Helpers/MeshPackets.swift index 69c8289b..39c1e897 100644 --- a/MeshtasticClient/Helpers/MeshPackets.swift +++ b/MeshtasticClient/Helpers/MeshPackets.swift @@ -8,6 +8,8 @@ import Foundation import CoreData + + func nodeInfoPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObjectContext) { let fetchNodeInfoAppRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") @@ -31,7 +33,6 @@ func nodeInfoPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedOb try context.save() if meshLogging { MeshLogger.log("💾 Updated NodeInfo SNR \(packet.rxSnr) and Time from Node Info App Packet For: \(fetchedNode[0].num)")} - print("💾 Updated NodeInfo SNR \(packet.rxSnr) and Time from Packet For: \(fetchedNode[0].num)") } catch { @@ -86,9 +87,8 @@ func positionPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedOb try context.save() if meshLogging { - MeshLogger.log("💾 Updated NodeInfo Position Coordinates, SNR \(packet.rxSnr) and Time from Position App Packet For: \(fetchedNode[0].num)") + MeshLogger.log("💾 Updated Node Position Coordinates, SNR and Time from Position App Packet For: \(fetchedNode[0].num)") } - print("💾 Updated NodeInfo Position Coordinates, SNR \(packet.rxSnr) and Time from Position App Packet For: \(fetchedNode[0].num)") } catch { @@ -143,7 +143,6 @@ func routingPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObj } if meshLogging { MeshLogger.log("🕸️ ROUTING PACKET received for RequestID: \(packet.decoded.requestID) Error: \(errorExplanation)") } - print("🕸️ ROUTING PACKET received for RequestID: \(packet.decoded.requestID) Error: \(errorExplanation)") if routingMessage.errorReason == Routing.Error.none { @@ -169,7 +168,6 @@ func routingPacket (packet: MeshPacket, meshLogging: Bool, context: NSManagedObj if meshLogging { MeshLogger.log("💾 ACK Received and saved for MessageID \(packet.decoded.requestID)") } - print("💾 ACK Received and saved for MessageID \(packet.decoded.requestID)") } catch { @@ -187,10 +185,8 @@ func telemetryPacket(packet: MeshPacket, meshLogging: Bool, context: NSManagedOb if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) { let telemetry = TelemetryEntity(context: context) - print(packet.decoded.requestID) if meshLogging { MeshLogger.log("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(telemetryMessage)") } - print("ℹ️ MESH PACKET received for Telemetry App UNHANDLED \(telemetryMessage)") } else { @@ -203,8 +199,7 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, meshLogging: if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) { - print("💬 BLE FROMRADIO received for text message app \(messageText)") - if meshLogging { MeshLogger.log("💬 BLE FROMRADIO received for text message app \(messageText)") } + if meshLogging { MeshLogger.log("💬 Message received for text message app \(messageText)") } let messageUsers: NSFetchRequest = NSFetchRequest.init(entityName: "UserEntity") messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from]) From d601729852b1832962b979786d4adb8a9a390fa5 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 27 May 2022 23:56:34 -0700 Subject: [PATCH 5/5] Location updates for node details --- .../Persistence/Persistence.swift | 2 +- MeshtasticClient/Views/Nodes/NodeDetail.swift | 131 +++++++++--------- 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/MeshtasticClient/Persistence/Persistence.swift b/MeshtasticClient/Persistence/Persistence.swift index 855b407f..c37af6e4 100644 --- a/MeshtasticClient/Persistence/Persistence.swift +++ b/MeshtasticClient/Persistence/Persistence.swift @@ -34,7 +34,7 @@ class PersistenceController { init(inMemory: Bool = false) { container = NSPersistentContainer(name: "Meshtastic") - //Likeself.clearDatabase() + //self.clearDatabase() if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") diff --git a/MeshtasticClient/Views/Nodes/NodeDetail.swift b/MeshtasticClient/Views/Nodes/NodeDetail.swift index 9c0f99d3..5a52d5d3 100644 --- a/MeshtasticClient/Views/Nodes/NodeDetail.swift +++ b/MeshtasticClient/Views/Nodes/NodeDetail.swift @@ -37,17 +37,33 @@ struct NodeDetail: View { }, set: { _ in } ) - let annotations = [MapLocation(name: node.user!.shortName ?? "???", coordinate: mostRecent.coordinate!)] - - Map(coordinateRegion: regionBinding, showsUserLocation: true, userTrackingMode: .none, annotationItems: annotations) { location in - MapAnnotation( - coordinate: location.coordinate, - content: { - CircleText(text: node.user!.shortName ?? "???", color: .accentColor, circleSize: 32, fontSize: 14) - } + + ZStack { + + let annotations = node.positions?.array as! [PositionEntity] + + Map(coordinateRegion: regionBinding, + interactionModes: [.all], + showsUserLocation: true, + userTrackingMode: .constant(.follow), + annotationItems: annotations + ) + { location in + + return MapAnnotation( + coordinate: location.coordinate ?? CLLocationCoordinate2D(latitude: 0, longitude: 0), + + content: { + + CircleText(text: node.user!.shortName ?? "???", color: .accentColor) + } + ) + } + .frame(idealWidth: bounds.size.width, maxHeight: bounds.size.height / 2) + .ignoresSafeArea(.all, edges: [.leading, .trailing]) } - .frame(idealWidth: bounds.size.width, maxHeight: bounds.size.height / 3) + } else { Image(node.user?.hwModel ?? "UNSET") @@ -74,7 +90,6 @@ struct NodeDetail: View { .symbolRenderingMode(.hierarchical) LastHeardText(lastHeard: node.lastHeard).font(.title3) - } .padding() Divider() @@ -203,70 +218,50 @@ struct NodeDetail: View { .padding() Divider() + ForEach(node.positions!.array as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in if mappin.coordinate != nil { - + VStack { + + HStack { + + Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) // .font(.subheadline) + Text("Lat/Long:").font(.caption) + Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))") + .foregroundColor(.gray) + .font(.caption) + + Image(systemName: "arrow.up.arrow.down.circle") + .font(.subheadline) + .foregroundColor(.accentColor) + .symbolRenderingMode(.hierarchical) + + Text("Alt:") + .font(.caption) + + Text("\(String(mappin.altitude))m") + .foregroundColor(.gray) + .font(.caption) + } + + HStack { + + Image(systemName: "clock.badge.checkmark.fill") + .font(.subheadline) + .foregroundColor(.accentColor) + .symbolRenderingMode(.hierarchical) + Text("Time:") + .font(.caption) + Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)") + .foregroundColor(.gray) + .font(.caption) + Divider() + } + } } - } -// ForEach(node.positions!.array as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in -// -// if mappin.coordinate != nil { -// -// VStack { -// -// HStack { -// -// Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) // .font(.subheadline) -// Text("Lat/Long:").font(.caption) -// Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))") -// .foregroundColor(.gray) -// .font(.caption) -// -// Image(systemName: "arrow.up.arrow.down.circle") -// .font(.subheadline) -// .foregroundColor(.accentColor) -// .symbolRenderingMode(.hierarchical) -// -// Text("Alt:") -// .font(.caption) -// -// Text("\(String(mappin.altitude))m") -// .foregroundColor(.gray) -// .font(.caption) -// } -// HStack { -// -// Image(systemName: "clock.badge.checkmark.fill") -// .font(.subheadline) -// .foregroundColor(.accentColor) -// .symbolRenderingMode(.hierarchical) -// Text("Time:") -// .font(.caption) -// Text("\(mappin.time!, style: .date) \(mappin.time!, style: .time)") -// .foregroundColor(.gray) -// .font(.caption) -// Divider() -// -// HStack { -// -// BatteryIcon(batteryLevel: mappin.batteryLevel, font: .subheadline, color: .accentColor) -// -// if mappin.batteryLevel > 0 { -// -// Text(String(mappin.batteryLevel) + "%") -// .font(.caption2) -// .foregroundColor(.gray) -// } -// } -// } -// } -// .padding(1) -// Divider() -// } -// } } } }