diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 209100f1..8a8b8ba3 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -193,6 +193,7 @@ /* Begin PBXFileReference section */ A65FA974296876BF00A97686 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalMBTileOverlay.swift; sourceTree = ""; }; + DD0E9C222A30CE3A00580CBB /* MeshtasticDataModelV14.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV14.xcdatamodel; sourceTree = ""; }; DD0F791A28713C8A00A6FDAD /* AdminMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminMessageList.swift; sourceTree = ""; }; DD1925B628CDA5A400720036 /* CannedMessagesConfigEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfigEnums.swift; sourceTree = ""; }; DD1925B828CDA93900720036 /* SerialConfigEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfigEnums.swift; sourceTree = ""; }; @@ -1587,6 +1588,7 @@ DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DD0E9C222A30CE3A00580CBB /* MeshtasticDataModelV14.xcdatamodel */, DDB75A1F2A10766D006ED576 /* MeshtasticDataModelV13.xcdatamodel */, DDB759E12A04B264006ED576 /* MeshtasticDataModelV12.xcdatamodel */, DDDEE5E229DBE43E00A8E078 /* MeshtasticDataModelV11.xcdatamodel */, @@ -1601,7 +1603,7 @@ DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */, DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */, ); - currentVersion = DDB75A1F2A10766D006ED576 /* MeshtasticDataModelV13.xcdatamodel */; + currentVersion = DD0E9C222A30CE3A00580CBB /* MeshtasticDataModelV14.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index e1f20743..517456df 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -423,7 +423,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { if myInfo != nil { connectedPeripheral.num = myInfo!.myNodeNum - connectedPeripheral.firmwareVersion = myInfo?.firmwareVersion ?? "unknown".localized connectedPeripheral.name = myInfo?.bleName ?? "unknown".localized connectedPeripheral.longName = myInfo?.bleName ?? "unknown".localized } @@ -472,6 +471,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { if decodedInfo.metadata.firmwareVersion.count > 0 && !invalidVersion { nowKnown = true deviceMetadataPacket(metadata: decodedInfo.metadata, fromNum: connectedPeripheral.num, context: context!) + connectedPeripheral.firmwareVersion = decodedInfo.metadata.firmwareVersion ?? "unknown".localized } // Log any other unknownApp calls if !nowKnown { MeshLogger.log("🕸️ MESH PACKET received for Unknown App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") } diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index ba393038..d24e5bb0 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -89,17 +89,8 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO let myInfoEntity = MyInfoEntity(context: context) myInfoEntity.peripheralId = peripheralId myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum) - myInfoEntity.hasGps = myInfo.hasGps_p - myInfoEntity.hasWifi = myInfo.hasWifi_p - myInfoEntity.bitrate = myInfo.bitrate - // Swift does strings weird, this does work to get the version without the github hash - let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".") - var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: myInfo.firmwareVersion))] - version = version.dropLast() - myInfoEntity.firmwareVersion = String(version) - myInfoEntity.messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec) + myInfoEntity.rebootCount = Int32(myInfo.rebootCount) myInfoEntity.minAppVersion = Int32(bitPattern: myInfo.minAppVersion) - myInfoEntity.maxChannels = Int32(bitPattern: myInfo.maxChannels) do { try context.save() print("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))") @@ -113,15 +104,8 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO fetchedMyInfo[0].peripheralId = peripheralId fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum) - fetchedMyInfo[0].hasGps = myInfo.hasGps_p - fetchedMyInfo[0].bitrate = myInfo.bitrate - let lastDotIndex = myInfo.firmwareVersion.lastIndex(of: ".")// .lastIndex(of: ".", offsetBy: -1) - var version = myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: myInfo.firmwareVersion))] - version = version.dropLast() - fetchedMyInfo[0].firmwareVersion = String(version) - fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec) + fetchedMyInfo[0].rebootCount = Int32(myInfo.rebootCount) fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion) - fetchedMyInfo[0].maxChannels = Int32(bitPattern: myInfo.maxChannels) do { try context.save() @@ -214,6 +198,11 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS newMetadata.hasEthernet = metadata.hasEthernet_p newMetadata.role = Int32(metadata.role.rawValue) newMetadata.positionFlags = Int32(metadata.positionFlags) + // Swift does strings weird, this does work to get the version without the github hash + let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".") + var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))] + version = version.dropLast() + newMetadata.firmwareVersion = String(version) fetchedNode[0].metadata = newMetadata do { @@ -272,7 +261,6 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje newUser.num = Int64(nodeInfo.num) newUser.longName = nodeInfo.user.longName newUser.shortName = nodeInfo.user.shortName - newUser.macaddr = nodeInfo.user.macaddr newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased() newNode.user = newUser } @@ -329,7 +317,6 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje fetchedNode[0].user!.num = Int64(nodeInfo.num) fetchedNode[0].user!.longName = nodeInfo.user.longName fetchedNode[0].user!.shortName = nodeInfo.user.shortName - fetchedNode[0].user!.macaddr = nodeInfo.user.macaddr fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased() } diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 17b97ce6..9235346e 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModelV13.xcdatamodel + MeshtasticDataModelV14.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV14.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV14.xcdatamodel/contents new file mode 100644 index 00000000..200820dd --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV14.xcdatamodel/contents @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index f28fb5d5..2430d577 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -129,7 +129,6 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) newUser.num = Int64(packet.from) newUser.longName = newUserMessage.longName newUser.shortName = newUserMessage.shortName - newUser.macaddr = newUserMessage.macaddr newUser.hwModel = String(describing: newUserMessage.hwModel).uppercased() newNode.user = newUser } @@ -159,7 +158,6 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) fetchedNode[0].user!.num = Int64(nodeInfoMessage.num) fetchedNode[0].user!.longName = nodeInfoMessage.user.longName fetchedNode[0].user!.shortName = nodeInfoMessage.user.shortName - fetchedNode[0].user!.macaddr = nodeInfoMessage.user.macaddr fetchedNode[0].user!.hwModel = String(describing: nodeInfoMessage.user.hwModel).uppercased() } } diff --git a/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift b/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift index 6a9448c3..5d931be9 100644 --- a/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/deviceonly.pb.swift @@ -109,7 +109,8 @@ struct DeviceState { mutating func clearOwner() {_uniqueStorage()._owner = nil} /// - /// TODO: REPLACE + /// Deprecated in 2.1.x + /// Old node_db. See NodeInfoLite node_db_lite var nodeDb: [NodeInfo] { get {return _storage._nodeDb} set {_uniqueStorage()._nodeDb = newValue} @@ -179,6 +180,13 @@ struct DeviceState { set {_uniqueStorage()._nodeRemoteHardwarePins = newValue} } + /// + /// New lite version of NodeDB to decrease + var nodeDbLite: [NodeInfoLite] { + get {return _storage._nodeDbLite} + set {_uniqueStorage()._nodeDbLite = newValue} + } + var unknownFields = SwiftProtobuf.UnknownStorage() init() {} @@ -186,6 +194,118 @@ struct DeviceState { fileprivate var _storage = _StorageClass.defaultInstance } +struct NodeInfoLite { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// + /// The node number + var num: UInt32 { + get {return _storage._num} + set {_uniqueStorage()._num = newValue} + } + + /// + /// The user info for this node + var user: User { + get {return _storage._user ?? User()} + set {_uniqueStorage()._user = newValue} + } + /// Returns true if `user` has been explicitly set. + var hasUser: Bool {return _storage._user != nil} + /// Clears the value of `user`. Subsequent reads from it will return its default value. + mutating func clearUser() {_uniqueStorage()._user = nil} + + /// + /// This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true. + /// Position.time now indicates the last time we received a POSITION from that node. + var position: PositionLite { + get {return _storage._position ?? PositionLite()} + 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} + + /// + /// Returns the Signal-to-noise ratio (SNR) of the last received message, + /// as measured by the receiver. Return SNR of the last received message in dB + var snr: Float { + get {return _storage._snr} + set {_uniqueStorage()._snr = newValue} + } + + /// + /// Set to indicate the last time we received a packet from this node + var lastHeard: UInt32 { + get {return _storage._lastHeard} + set {_uniqueStorage()._lastHeard = newValue} + } + + /// + /// The latest device metrics for the node. + var deviceMetrics: DeviceMetrics { + get {return _storage._deviceMetrics ?? DeviceMetrics()} + set {_uniqueStorage()._deviceMetrics = newValue} + } + /// Returns true if `deviceMetrics` has been explicitly set. + var hasDeviceMetrics: Bool {return _storage._deviceMetrics != nil} + /// Clears the value of `deviceMetrics`. Subsequent reads from it will return its default value. + mutating func clearDeviceMetrics() {_uniqueStorage()._deviceMetrics = nil} + + /// + /// local channel index we heard that node on. Only populated if its not the default channel. + var channel: UInt32 { + get {return _storage._channel} + set {_uniqueStorage()._channel = newValue} + } + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _storage = _StorageClass.defaultInstance +} + +/// +/// Position with static location information only for NodeDBLite +struct PositionLite { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// + /// The new preferred location encoding, multiply by 1e-7 to get degrees + /// in floating point + var latitudeI: Int32 = 0 + + /// + /// TODO: REPLACE + var longitudeI: Int32 = 0 + + /// + /// In meters above MSL (but see issue #359) + var altitude: Int32 = 0 + + /// + /// This is usually not sent over the mesh (to save space), but it is sent + /// from the phone so that the local device can set its RTC If it is sent over + /// the mesh (because there are devices on the mesh without GPS), it will only + /// be sent by devices which has a hardware GPS clock. + /// seconds since 1970 + var time: UInt32 = 0 + + /// + /// TODO: REPLACE + var locationSource: Position.LocSource = .locUnset + + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} +} + /// /// The on-disk saved channels struct ChannelFile { @@ -302,6 +422,8 @@ struct NodeRemoteHardwarePin { #if swift(>=5.5) && canImport(_Concurrency) extension ScreenFonts: @unchecked Sendable {} extension DeviceState: @unchecked Sendable {} +extension NodeInfoLite: @unchecked Sendable {} +extension PositionLite: @unchecked Sendable {} extension ChannelFile: @unchecked Sendable {} extension OEMStore: @unchecked Sendable {} extension NodeRemoteHardwarePin: @unchecked Sendable {} @@ -332,6 +454,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati 11: .standard(proto: "did_gps_reset"), 12: .standard(proto: "rx_waypoint"), 13: .standard(proto: "node_remote_hardware_pins"), + 14: .standard(proto: "node_db_lite"), ] fileprivate class _StorageClass { @@ -345,6 +468,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati var _didGpsReset: Bool = false var _rxWaypoint: MeshPacket? = nil var _nodeRemoteHardwarePins: [NodeRemoteHardwarePin] = [] + var _nodeDbLite: [NodeInfoLite] = [] static let defaultInstance = _StorageClass() @@ -361,6 +485,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati _didGpsReset = source._didGpsReset _rxWaypoint = source._rxWaypoint _nodeRemoteHardwarePins = source._nodeRemoteHardwarePins + _nodeDbLite = source._nodeDbLite } } @@ -389,6 +514,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 11: try { try decoder.decodeSingularBoolField(value: &_storage._didGpsReset) }() case 12: try { try decoder.decodeSingularMessageField(value: &_storage._rxWaypoint) }() case 13: try { try decoder.decodeRepeatedMessageField(value: &_storage._nodeRemoteHardwarePins) }() + case 14: try { try decoder.decodeRepeatedMessageField(value: &_storage._nodeDbLite) }() default: break } } @@ -431,6 +557,9 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if !_storage._nodeRemoteHardwarePins.isEmpty { try visitor.visitRepeatedMessageField(value: _storage._nodeRemoteHardwarePins, fieldNumber: 13) } + if !_storage._nodeDbLite.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._nodeDbLite, fieldNumber: 14) + } } try unknownFields.traverse(visitor: &visitor) } @@ -450,6 +579,7 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if _storage._didGpsReset != rhs_storage._didGpsReset {return false} if _storage._rxWaypoint != rhs_storage._rxWaypoint {return false} if _storage._nodeRemoteHardwarePins != rhs_storage._nodeRemoteHardwarePins {return false} + if _storage._nodeDbLite != rhs_storage._nodeDbLite {return false} return true } if !storagesAreEqual {return false} @@ -459,6 +589,178 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati } } +extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".NodeInfoLite" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "num"), + 2: .same(proto: "user"), + 3: .same(proto: "position"), + 4: .same(proto: "snr"), + 5: .standard(proto: "last_heard"), + 6: .standard(proto: "device_metrics"), + 7: .same(proto: "channel"), + ] + + fileprivate class _StorageClass { + var _num: UInt32 = 0 + var _user: User? = nil + var _position: PositionLite? = nil + var _snr: Float = 0 + var _lastHeard: UInt32 = 0 + var _deviceMetrics: DeviceMetrics? = nil + var _channel: UInt32 = 0 + + static let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _num = source._num + _user = source._user + _position = source._position + _snr = source._snr + _lastHeard = source._lastHeard + _deviceMetrics = source._deviceMetrics + _channel = source._channel + } + } + + 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._num) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._user) }() + case 3: try { try decoder.decodeSingularMessageField(value: &_storage._position) }() + case 4: try { try decoder.decodeSingularFloatField(value: &_storage._snr) }() + case 5: try { try decoder.decodeSingularFixed32Field(value: &_storage._lastHeard) }() + case 6: try { try decoder.decodeSingularMessageField(value: &_storage._deviceMetrics) }() + case 7: try { try decoder.decodeSingularUInt32Field(value: &_storage._channel) }() + 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 + if _storage._num != 0 { + try visitor.visitSingularUInt32Field(value: _storage._num, fieldNumber: 1) + } + try { if let v = _storage._user { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._position { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + if _storage._snr != 0 { + try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) + } + if _storage._lastHeard != 0 { + try visitor.visitSingularFixed32Field(value: _storage._lastHeard, fieldNumber: 5) + } + try { if let v = _storage._deviceMetrics { + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + } }() + if _storage._channel != 0 { + try visitor.visitSingularUInt32Field(value: _storage._channel, fieldNumber: 7) + } + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: NodeInfoLite, rhs: NodeInfoLite) -> Bool { + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._num != rhs_storage._num {return false} + if _storage._user != rhs_storage._user {return false} + if _storage._position != rhs_storage._position {return false} + if _storage._snr != rhs_storage._snr {return false} + if _storage._lastHeard != rhs_storage._lastHeard {return false} + if _storage._deviceMetrics != rhs_storage._deviceMetrics {return false} + if _storage._channel != rhs_storage._channel {return false} + return true + } + if !storagesAreEqual {return false} + } + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".PositionLite" + static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "latitude_i"), + 2: .standard(proto: "longitude_i"), + 3: .same(proto: "altitude"), + 4: .same(proto: "time"), + 5: .standard(proto: "location_source"), + ] + + 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.decodeSingularSFixed32Field(value: &self.latitudeI) }() + case 2: try { try decoder.decodeSingularSFixed32Field(value: &self.longitudeI) }() + case 3: try { try decoder.decodeSingularInt32Field(value: &self.altitude) }() + case 4: try { try decoder.decodeSingularFixed32Field(value: &self.time) }() + case 5: try { try decoder.decodeSingularEnumField(value: &self.locationSource) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + if self.latitudeI != 0 { + try visitor.visitSingularSFixed32Field(value: self.latitudeI, fieldNumber: 1) + } + if self.longitudeI != 0 { + try visitor.visitSingularSFixed32Field(value: self.longitudeI, fieldNumber: 2) + } + if self.altitude != 0 { + try visitor.visitSingularInt32Field(value: self.altitude, fieldNumber: 3) + } + if self.time != 0 { + try visitor.visitSingularFixed32Field(value: self.time, fieldNumber: 4) + } + if self.locationSource != .locUnset { + try visitor.visitSingularEnumField(value: self.locationSource, fieldNumber: 5) + } + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: PositionLite, rhs: PositionLite) -> Bool { + if lhs.latitudeI != rhs.latitudeI {return false} + if lhs.longitudeI != rhs.longitudeI {return false} + if lhs.altitude != rhs.altitude {return false} + if lhs.time != rhs.time {return false} + if lhs.locationSource != rhs.locationSource {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension ChannelFile: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".ChannelFile" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ diff --git a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift index 8d164bac..e68d65a1 100644 --- a/Meshtastic/Protobufs/meshtastic/mesh.pb.swift +++ b/Meshtastic/Protobufs/meshtastic/mesh.pb.swift @@ -855,6 +855,7 @@ struct User { var shortName: String = String() /// + /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting var macaddr: Data = Data() @@ -1629,15 +1630,18 @@ struct MyNodeInfo { var myNodeNum: UInt32 = 0 /// + /// Deprecated in 2.1.x (Source from device_metadata) /// Note: This flag merely means we detected a hardware GPS in our node. /// Not the same as UserPreferences.location_sharing var hasGps_p: Bool = false /// + /// Deprecated in 2.1.x /// The maximum number of 'software' channels that can be set on this node. var maxChannels: UInt32 = 0 /// + /// Deprecated in 2.1.x (Source from device_metadata) /// 0.0.5 etc... var firmwareVersion: String = String() @@ -1665,10 +1669,12 @@ struct MyNodeInfo { var rebootCount: UInt32 = 0 /// + /// Deprecated in 2.1.x /// Calculated bitrate of the current channel (in Bytes Per Second) var bitrate: Float = 0 /// + /// Deprecated in 2.1.x /// How long before we consider a message abandoned and we can clear our /// caches of any messages in flight Normally quite large to handle the worst case /// message delivery time, 5 minutes. @@ -1681,22 +1687,27 @@ struct MyNodeInfo { var minAppVersion: UInt32 = 0 /// + /// Deprecated in 2.1.x (Only used on device to keep track of utilization) /// 24 time windows of 1hr each with the airtime transmitted out of the device per hour. var airPeriodTx: [UInt32] = [] /// + /// Deprecated in 2.1.x (Only used on device to keep track of utilization) /// 24 time windows of 1hr each with the airtime of valid packets for your mesh. var airPeriodRx: [UInt32] = [] /// + /// Deprecated in 2.1.x (Source from DeviceMetadata instead) /// Is the device wifi capable? var hasWifi_p: Bool = false /// + /// Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads) /// Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). var channelUtilization: Float = 0 /// + /// Deprecated in 2.1.x (Source from DeviceMetrics telemetry payloads) /// Percent of airtime for transmission used within the last hour. var airUtilTx: Float = 0 diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 70fb6101..fd11b1c4 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -60,7 +60,7 @@ struct Connect: View { Text("ble.name").font(.callout)+Text(": \(bleManager.connectedPeripheral.peripheral.name ?? "unknown".localized)") .font(.callout).foregroundColor(Color.gray) if node != nil { - Text("firmware.version").font(.callout)+Text(": \(node?.myInfo?.firmwareVersion ?? "unknown".localized)") + Text("firmware.version").font(.callout)+Text(": \(node?.metadata?.firmwareVersion ?? "unknown".localized)") .font(.callout).foregroundColor(Color.gray) } if bleManager.isSubscribed { @@ -110,8 +110,6 @@ struct Connect: View { Text("Num: \(String(node!.num))") Text("Short Name: \(node?.user?.shortName ?? "????")") Text("Long Name: \(node?.user?.longName ?? "unknown".localized)") - Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))") - Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))") Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") } } diff --git a/Meshtastic/Views/Helpers/Node/NodeInfoView.swift b/Meshtastic/Views/Helpers/Node/NodeInfoView.swift index 701adb38..8a8758df 100644 --- a/Meshtastic/Views/Helpers/Node/NodeInfoView.swift +++ b/Meshtastic/Views/Helpers/Node/NodeInfoView.swift @@ -104,20 +104,6 @@ struct NodeInfoView: View { Text(String(node.num)).font(.title).foregroundColor(.gray) } Divider() - VStack { - HStack { - Image(systemName: "globe") - .font(.title) - .foregroundColor(.accentColor) - .symbolRenderingMode(.hierarchical) - Text("MAC Address: ").font(.title) - - } - Text(String(node.user?.macaddr?.macAddressString ?? "not a valid mac address")) - .font(.title) - .foregroundColor(.gray) - } - Divider() VStack { HStack { Image(systemName: "clock.badge.checkmark.fill") @@ -208,16 +194,6 @@ struct NodeInfoView: View { } } Divider() - HStack { - Image(systemName: "globe") - .font(.headline) - .foregroundColor(.accentColor) - .symbolRenderingMode(.hierarchical) - Text("MAC Address: ") - Text(String(node.user?.macaddr?.macAddressString ?? "not a valid mac address")).foregroundColor(.gray) - } - .padding([.bottom], 10) - Divider() } VStack { diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index 14a07c1e..0e5f13fe 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -72,7 +72,7 @@ struct EnvironmentMetricsLog: View { .chartXAxis(content: { AxisMarks(position: .top) }) - .chartYScale(domain: format == .celsius ? -20...50 : 0...125) + .chartYScale(domain: format == .celsius ? -20...55 : 0...125) .chartForegroundStyleScale([ "Temperature" : .clear ]) diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 3fa24d14..e0a6b5cd 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -91,7 +91,7 @@ struct Settings: View { let connectedNode = nodes.first(where: { $0.num == connectedNodeNum }) connectedNodeNum = Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0) - if connectedNode != nil && node?.metadata == nil { + if connectedNode != nil && connectedNode?.user != nil && connectedNode?.myInfo != nil && node?.user != nil && node?.metadata == nil { let adminMessageId = bleManager.requestDeviceMetadata(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode!.myInfo!.adminIndex, context: context) if adminMessageId > 0 {