From 0ebaeac3ce7126a4d6b63f9052f9c9be70e311c1 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 7 Aug 2024 08:06:39 -0700 Subject: [PATCH 01/75] PKI Protos --- .../Sources/meshtastic/admin.pb.swift | 261 +++++++-- .../Sources/meshtastic/apponly.pb.swift | 6 +- .../Sources/meshtastic/atak.pb.swift | 64 ++- .../meshtastic/cannedmessages.pb.swift | 6 +- .../Sources/meshtastic/channel.pb.swift | 37 +- .../Sources/meshtastic/clientonly.pb.swift | 6 +- .../Sources/meshtastic/config.pb.swift | 426 +++++++++------ .../meshtastic/connection_status.pb.swift | 21 +- .../Sources/meshtastic/deviceonly.pb.swift | 33 +- .../Sources/meshtastic/localonly.pb.swift | 9 +- .../Sources/meshtastic/mesh.pb.swift | 509 ++++++++++++++---- .../Sources/meshtastic/module_config.pb.swift | 263 ++++++--- .../Sources/meshtastic/mqtt.pb.swift | 9 +- .../Sources/meshtastic/paxcount.pb.swift | 6 +- .../Sources/meshtastic/portnums.pb.swift | 14 +- .../Sources/meshtastic/powermon.pb.swift | 115 ++-- .../meshtastic/remote_hardware.pb.swift | 35 +- .../Sources/meshtastic/rtttl.pb.swift | 6 +- .../Sources/meshtastic/storeforward.pb.swift | 93 +++- .../Sources/meshtastic/telemetry.pb.swift | 111 ++-- .../Sources/meshtastic/xmodem.pb.swift | 39 +- protobufs | 2 +- 22 files changed, 1489 insertions(+), 582 deletions(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 37528079..ba263709 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -24,7 +24,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /// This message is used to do settings operations to both remote AND local nodes. /// (Prior to 1.2 these operations were done via special ToRadio operations) -public struct AdminMessage: Sendable { +public struct AdminMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -456,7 +456,7 @@ public struct AdminMessage: Sendable { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Send the specified channel in the response to this message /// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) @@ -590,11 +590,185 @@ public struct AdminMessage: Sendable { /// Tell the node to reset the nodedb. case nodedbReset(Int32) + #if !swift(>=4.1) + public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.getChannelRequest, .getChannelRequest): return { + guard case .getChannelRequest(let l) = lhs, case .getChannelRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getChannelResponse, .getChannelResponse): return { + guard case .getChannelResponse(let l) = lhs, case .getChannelResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getOwnerRequest, .getOwnerRequest): return { + guard case .getOwnerRequest(let l) = lhs, case .getOwnerRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getOwnerResponse, .getOwnerResponse): return { + guard case .getOwnerResponse(let l) = lhs, case .getOwnerResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getConfigRequest, .getConfigRequest): return { + guard case .getConfigRequest(let l) = lhs, case .getConfigRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getConfigResponse, .getConfigResponse): return { + guard case .getConfigResponse(let l) = lhs, case .getConfigResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getModuleConfigRequest, .getModuleConfigRequest): return { + guard case .getModuleConfigRequest(let l) = lhs, case .getModuleConfigRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getModuleConfigResponse, .getModuleConfigResponse): return { + guard case .getModuleConfigResponse(let l) = lhs, case .getModuleConfigResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getCannedMessageModuleMessagesRequest, .getCannedMessageModuleMessagesRequest): return { + guard case .getCannedMessageModuleMessagesRequest(let l) = lhs, case .getCannedMessageModuleMessagesRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getCannedMessageModuleMessagesResponse, .getCannedMessageModuleMessagesResponse): return { + guard case .getCannedMessageModuleMessagesResponse(let l) = lhs, case .getCannedMessageModuleMessagesResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceMetadataRequest, .getDeviceMetadataRequest): return { + guard case .getDeviceMetadataRequest(let l) = lhs, case .getDeviceMetadataRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceMetadataResponse, .getDeviceMetadataResponse): return { + guard case .getDeviceMetadataResponse(let l) = lhs, case .getDeviceMetadataResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getRingtoneRequest, .getRingtoneRequest): return { + guard case .getRingtoneRequest(let l) = lhs, case .getRingtoneRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getRingtoneResponse, .getRingtoneResponse): return { + guard case .getRingtoneResponse(let l) = lhs, case .getRingtoneResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceConnectionStatusRequest, .getDeviceConnectionStatusRequest): return { + guard case .getDeviceConnectionStatusRequest(let l) = lhs, case .getDeviceConnectionStatusRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceConnectionStatusResponse, .getDeviceConnectionStatusResponse): return { + guard case .getDeviceConnectionStatusResponse(let l) = lhs, case .getDeviceConnectionStatusResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setHamMode, .setHamMode): return { + guard case .setHamMode(let l) = lhs, case .setHamMode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getNodeRemoteHardwarePinsRequest, .getNodeRemoteHardwarePinsRequest): return { + guard case .getNodeRemoteHardwarePinsRequest(let l) = lhs, case .getNodeRemoteHardwarePinsRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getNodeRemoteHardwarePinsResponse, .getNodeRemoteHardwarePinsResponse): return { + guard case .getNodeRemoteHardwarePinsResponse(let l) = lhs, case .getNodeRemoteHardwarePinsResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.enterDfuModeRequest, .enterDfuModeRequest): return { + guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.deleteFileRequest, .deleteFileRequest): return { + guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setScale, .setScale): return { + guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setOwner, .setOwner): return { + guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setChannel, .setChannel): return { + guard case .setChannel(let l) = lhs, case .setChannel(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setConfig, .setConfig): return { + guard case .setConfig(let l) = lhs, case .setConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setModuleConfig, .setModuleConfig): return { + guard case .setModuleConfig(let l) = lhs, case .setModuleConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setCannedMessageModuleMessages, .setCannedMessageModuleMessages): return { + guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setRingtoneMessage, .setRingtoneMessage): return { + guard case .setRingtoneMessage(let l) = lhs, case .setRingtoneMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeByNodenum, .removeByNodenum): return { + guard case .removeByNodenum(let l) = lhs, case .removeByNodenum(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setFavoriteNode, .setFavoriteNode): return { + guard case .setFavoriteNode(let l) = lhs, case .setFavoriteNode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeFavoriteNode, .removeFavoriteNode): return { + guard case .removeFavoriteNode(let l) = lhs, case .removeFavoriteNode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setFixedPosition, .setFixedPosition): return { + guard case .setFixedPosition(let l) = lhs, case .setFixedPosition(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeFixedPosition, .removeFixedPosition): return { + guard case .removeFixedPosition(let l) = lhs, case .removeFixedPosition(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.beginEditSettings, .beginEditSettings): return { + guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.commitEditSettings, .commitEditSettings): return { + guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebootOtaSeconds, .rebootOtaSeconds): return { + guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.exitSimulator, .exitSimulator): return { + guard case .exitSimulator(let l) = lhs, case .exitSimulator(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebootSeconds, .rebootSeconds): return { + guard case .rebootSeconds(let l) = lhs, case .rebootSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.shutdownSeconds, .shutdownSeconds): return { + guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.factoryReset, .factoryReset): return { + guard case .factoryReset(let l) = lhs, case .factoryReset(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nodedbReset, .nodedbReset): return { + guard case .nodedbReset(let l) = lhs, case .nodedbReset(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// TODO: REPLACE - public enum ConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ConfigType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -656,22 +830,11 @@ public struct AdminMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ConfigType] = [ - .deviceConfig, - .positionConfig, - .powerConfig, - .networkConfig, - .displayConfig, - .loraConfig, - .bluetoothConfig, - ] - } /// /// TODO: REPLACE - public enum ModuleConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ModuleConfigType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -769,31 +932,50 @@ public struct AdminMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ModuleConfigType] = [ - .mqttConfig, - .serialConfig, - .extnotifConfig, - .storeforwardConfig, - .rangetestConfig, - .telemetryConfig, - .cannedmsgConfig, - .audioConfig, - .remotehardwareConfig, - .neighborinfoConfig, - .ambientlightingConfig, - .detectionsensorConfig, - .paxcounterConfig, - ] - } public init() {} } +#if swift(>=4.2) + +extension AdminMessage.ConfigType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ConfigType] = [ + .deviceConfig, + .positionConfig, + .powerConfig, + .networkConfig, + .displayConfig, + .loraConfig, + .bluetoothConfig, + ] +} + +extension AdminMessage.ModuleConfigType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ModuleConfigType] = [ + .mqttConfig, + .serialConfig, + .extnotifConfig, + .storeforwardConfig, + .rangetestConfig, + .telemetryConfig, + .cannedmsgConfig, + .audioConfig, + .remotehardwareConfig, + .neighborinfoConfig, + .ambientlightingConfig, + .detectionsensorConfig, + .paxcounterConfig, + ] +} + +#endif // swift(>=4.2) + /// /// Parameters for setting up Meshtastic for ameteur radio usage -public struct HamParameters: Sendable { +public struct HamParameters { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -823,7 +1005,7 @@ public struct HamParameters: Sendable { /// /// Response envelope for node_remote_hardware_pins -public struct NodeRemoteHardwarePinsResponse: Sendable { +public struct NodeRemoteHardwarePinsResponse { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -837,6 +1019,15 @@ public struct NodeRemoteHardwarePinsResponse: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension AdminMessage: @unchecked Sendable {} +extension AdminMessage.OneOf_PayloadVariant: @unchecked Sendable {} +extension AdminMessage.ConfigType: @unchecked Sendable {} +extension AdminMessage.ModuleConfigType: @unchecked Sendable {} +extension HamParameters: @unchecked Sendable {} +extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1534,7 +1725,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 2) } - if self.frequency.bitPattern != 0 { + if self.frequency != 0 { try visitor.visitSingularFloatField(value: self.frequency, fieldNumber: 3) } if !self.shortName.isEmpty { diff --git a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift index 18e66d8e..0457077c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift @@ -26,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// any SECONDARY channels. /// No DISABLED channels are included. /// This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL -public struct ChannelSet: Sendable { +public struct ChannelSet { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -53,6 +53,10 @@ public struct ChannelSet: Sendable { fileprivate var _loraConfig: Config.LoRaConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension ChannelSet: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift index 1dd12469..4406deb3 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum Team: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -130,6 +130,11 @@ public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension Team: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Team] = [ .unspecifedColor, @@ -148,12 +153,13 @@ public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { .darkGreen, .brown, ] - } +#endif // swift(>=4.2) + /// /// Role of the group member -public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum MemberRole: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -227,6 +233,11 @@ public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension MemberRole: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [MemberRole] = [ .unspecifed, @@ -239,12 +250,13 @@ public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { .rto, .k9, ] - } +#endif // swift(>=4.2) + /// /// Packets for the official ATAK Plugin -public struct TAKPacket: Sendable { +public struct TAKPacket { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -314,7 +326,7 @@ public struct TAKPacket: Sendable { /// /// The payload of the packet - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TAK position report case pli(PLI) @@ -322,6 +334,24 @@ public struct TAKPacket: Sendable { /// ATAK GeoChat message case chat(GeoChat) + #if !swift(>=4.1) + public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.pli, .pli): return { + guard case .pli(let l) = lhs, case .pli(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.chat, .chat): return { + guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -333,7 +363,7 @@ public struct TAKPacket: Sendable { /// /// ATAK GeoChat message -public struct GeoChat: Sendable { +public struct GeoChat { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -375,7 +405,7 @@ public struct GeoChat: Sendable { /// /// ATAK Group /// <__group role='Team Member' name='Cyan'/> -public struct Group: Sendable { +public struct Group { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -397,7 +427,7 @@ public struct Group: Sendable { /// /// ATAK EUD Status /// -public struct Status: Sendable { +public struct Status { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -414,7 +444,7 @@ public struct Status: Sendable { /// /// ATAK Contact /// -public struct Contact: Sendable { +public struct Contact { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -434,7 +464,7 @@ public struct Contact: Sendable { /// /// Position Location Information from ATAK -public struct PLI: Sendable { +public struct PLI { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -466,6 +496,18 @@ public struct PLI: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension Team: @unchecked Sendable {} +extension MemberRole: @unchecked Sendable {} +extension TAKPacket: @unchecked Sendable {} +extension TAKPacket.OneOf_PayloadVariant: @unchecked Sendable {} +extension GeoChat: @unchecked Sendable {} +extension Group: @unchecked Sendable {} +extension Status: @unchecked Sendable {} +extension Contact: @unchecked Sendable {} +extension PLI: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift index a43393e1..1b8c84de 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct CannedMessageModuleConfig: Sendable { +public struct CannedMessageModuleConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,6 +36,10 @@ public struct CannedMessageModuleConfig: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension CannedMessageModuleConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift index a8c96595..5b9c7e49 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift @@ -36,15 +36,13 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// FIXME: Add description of multi-channel support and how primary vs secondary channels are used. /// FIXME: explain how apps use channels for security. /// explain how remote settings and remote gpio are managed as an example -public struct ChannelSettings: @unchecked Sendable { +public struct ChannelSettings { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// Deprecated in favor of LoraConfig.channel_num - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var channelNum: UInt32 = 0 /// @@ -113,7 +111,7 @@ public struct ChannelSettings: @unchecked Sendable { /// /// This message is specifically for modules to store per-channel configuration data. -public struct ModuleSettings: Sendable { +public struct ModuleSettings { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -134,7 +132,7 @@ public struct ModuleSettings: Sendable { /// /// A pair of a channel number, mode and the (sharable) settings for that channel -public struct Channel: Sendable { +public struct Channel { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -172,7 +170,7 @@ public struct Channel: Sendable { /// cross band routing as needed. /// If a device has only a single radio (the common case) only one channel can be PRIMARY at a time /// (but any number of SECONDARY channels can't be sent received on that common frequency) - public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Role: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -211,13 +209,6 @@ public struct Channel: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Channel.Role] = [ - .disabled, - .primary, - .secondary, - ] - } public init() {} @@ -225,6 +216,26 @@ public struct Channel: Sendable { fileprivate var _settings: ChannelSettings? = nil } +#if swift(>=4.2) + +extension Channel.Role: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Channel.Role] = [ + .disabled, + .primary, + .secondary, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension ChannelSettings: @unchecked Sendable {} +extension ModuleSettings: @unchecked Sendable {} +extension Channel: @unchecked Sendable {} +extension Channel.Role: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift index 89370cc5..c3d93bf7 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift @@ -23,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This abstraction is used to contain any configuration for provisioning a node on any client. /// It is useful for importing and exporting configurations. -public struct DeviceProfile: Sendable { +public struct DeviceProfile { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -94,6 +94,10 @@ public struct DeviceProfile: Sendable { fileprivate var _moduleConfig: LocalModuleConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension DeviceProfile: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index aeaf9054..f396367c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct Config: Sendable { +public struct Config { // 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. @@ -89,7 +89,7 @@ public struct Config: Sendable { /// /// Payload Variant - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { case device(Config.DeviceConfig) case position(Config.PositionConfig) case power(Config.PowerConfig) @@ -98,11 +98,49 @@ public struct Config: Sendable { case lora(Config.LoRaConfig) case bluetooth(Config.BluetoothConfig) + #if !swift(>=4.1) + public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.device, .device): return { + guard case .device(let l) = lhs, case .device(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.position, .position): return { + guard case .position(let l) = lhs, case .position(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.power, .power): return { + guard case .power(let l) = lhs, case .power(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.network, .network): return { + guard case .network(let l) = lhs, case .network(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.display, .display): return { + guard case .display(let l) = lhs, case .display(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.lora, .lora): return { + guard case .lora(let l) = lhs, case .lora(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.bluetooth, .bluetooth): return { + guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// Configuration - public struct DeviceConfig: Sendable { + public struct DeviceConfig { // 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. @@ -164,7 +202,7 @@ public struct Config: Sendable { /// /// Defines the device's role on the Mesh network - public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Role: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -182,8 +220,6 @@ public struct Config: Sendable { /// The wifi radio and the oled screen will be put to sleep. /// This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. case router // = 2 - - /// NOTE: This enum value was marked as deprecated in the .proto file case routerClient // = 3 /// @@ -274,26 +310,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.Role] = [ - .client, - .clientMute, - .router, - .routerClient, - .repeater, - .tracker, - .sensor, - .tak, - .clientHidden, - .lostAndFound, - .takTracker, - ] - } /// /// Defines the device's behavior for how messages are rebroadcast - public enum RebroadcastMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RebroadcastMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -341,14 +362,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ - .all, - .allSkipDecoding, - .localOnly, - .knownOnly, - ] - } public init() {} @@ -356,7 +369,7 @@ public struct Config: Sendable { /// /// Position Config - public struct PositionConfig: Sendable { + public struct PositionConfig { // 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. @@ -378,8 +391,6 @@ public struct Config: Sendable { /// /// Is GPS enabled for this node? - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var gpsEnabled: Bool = false /// @@ -390,8 +401,6 @@ public struct Config: Sendable { /// /// Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var gpsAttemptTime: UInt32 = 0 /// @@ -432,7 +441,7 @@ public struct Config: Sendable { /// are always included (also time if GPS-synced) /// NOTE: the more fields are included, the larger the message will be - /// leading to longer airtime and a higher risk of packet loss - public enum PositionFlags: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum PositionFlags: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -522,24 +531,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.PositionFlags] = [ - .unset, - .altitude, - .altitudeMsl, - .geoidalSeparation, - .dop, - .hvdop, - .satinview, - .seqNo, - .timestamp, - .heading, - .speed, - ] - } - public enum GpsMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum GpsMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -577,13 +571,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.GpsMode] = [ - .disabled, - .enabled, - .notPresent, - ] - } public init() {} @@ -592,7 +579,7 @@ public struct Config: Sendable { /// /// Power Config\ /// See [Power Config](/docs/settings/config/power) for additional power config details. - public struct PowerConfig: Sendable { + public struct PowerConfig { // 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. @@ -652,7 +639,7 @@ public struct Config: Sendable { /// /// Network Config - public struct NetworkConfig: Sendable { + public struct NetworkConfig { // 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. @@ -699,7 +686,7 @@ public struct Config: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum AddressMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum AddressMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -731,15 +718,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.NetworkConfig.AddressMode] = [ - .dhcp, - .static, - ] - } - public struct IpV4Config: Sendable { + public struct IpV4Config { // 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. @@ -772,7 +753,7 @@ public struct Config: Sendable { /// /// Display Config - public struct DisplayConfig: Sendable { + public struct DisplayConfig { // 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. @@ -828,7 +809,7 @@ public struct Config: Sendable { /// /// How the GPS coordinates are displayed on the OLED screen. - public enum GpsCoordinateFormat: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum GpsCoordinateFormat: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -891,21 +872,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ - .dec, - .dms, - .utm, - .mgrs, - .olc, - .osgr, - ] - } /// /// Unit display preference - public enum DisplayUnits: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum DisplayUnits: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -937,17 +908,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ - .metric, - .imperial, - ] - } /// /// Override OLED outo detect with this if it fails. - public enum OledType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum OledType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -991,17 +956,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.OledType] = [ - .oledAuto, - .oledSsd1306, - .oledSh1106, - .oledSh1107, - ] - } - public enum DisplayMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum DisplayMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1045,17 +1002,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayMode] = [ - .default, - .twocolor, - .inverted, - .color, - ] - } - public enum CompassOrientation: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum CompassOrientation: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1123,18 +1072,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ - .degrees0, - .degrees90, - .degrees180, - .degrees270, - .degrees0Inverted, - .degrees90Inverted, - .degrees180Inverted, - .degrees270Inverted, - ] - } public init() {} @@ -1142,7 +1079,7 @@ public struct Config: Sendable { /// /// Lora Config - public struct LoRaConfig: @unchecked Sendable { + public struct LoRaConfig { // 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. @@ -1299,7 +1236,7 @@ public struct Config: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum RegionCode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RegionCode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1433,35 +1370,12 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - .lora24, - .ua433, - .ua868, - .my433, - .my919, - .sg923, - ] - } /// /// Standard predefined channel settings /// Note: these mappings must match ModemPreset Choice in the device code. - public enum ModemPreset: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ModemPreset: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1529,18 +1443,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.ModemPreset] = [ - .longFast, - .longSlow, - .veryLongSlow, - .mediumSlow, - .mediumFast, - .shortSlow, - .shortFast, - .longModerate, - ] - } public init() {} @@ -1548,7 +1450,7 @@ public struct Config: Sendable { fileprivate var _storage = _StorageClass.defaultInstance } - public struct BluetoothConfig: Sendable { + public struct BluetoothConfig { // 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. @@ -1571,7 +1473,7 @@ public struct Config: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum PairingMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum PairingMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1609,13 +1511,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.BluetoothConfig.PairingMode] = [ - .randomPin, - .fixedPin, - .noPin, - ] - } public init() {} @@ -1624,6 +1519,199 @@ public struct Config: Sendable { public init() {} } +#if swift(>=4.2) + +extension Config.DeviceConfig.Role: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.Role] = [ + .client, + .clientMute, + .router, + .routerClient, + .repeater, + .tracker, + .sensor, + .tak, + .clientHidden, + .lostAndFound, + .takTracker, + ] +} + +extension Config.DeviceConfig.RebroadcastMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ + .all, + .allSkipDecoding, + .localOnly, + .knownOnly, + ] +} + +extension Config.PositionConfig.PositionFlags: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.PositionFlags] = [ + .unset, + .altitude, + .altitudeMsl, + .geoidalSeparation, + .dop, + .hvdop, + .satinview, + .seqNo, + .timestamp, + .heading, + .speed, + ] +} + +extension Config.PositionConfig.GpsMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.GpsMode] = [ + .disabled, + .enabled, + .notPresent, + ] +} + +extension Config.NetworkConfig.AddressMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.NetworkConfig.AddressMode] = [ + .dhcp, + .static, + ] +} + +extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ + .dec, + .dms, + .utm, + .mgrs, + .olc, + .osgr, + ] +} + +extension Config.DisplayConfig.DisplayUnits: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ + .metric, + .imperial, + ] +} + +extension Config.DisplayConfig.OledType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.OledType] = [ + .oledAuto, + .oledSsd1306, + .oledSh1106, + .oledSh1107, + ] +} + +extension Config.DisplayConfig.DisplayMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayMode] = [ + .default, + .twocolor, + .inverted, + .color, + ] +} + +extension Config.DisplayConfig.CompassOrientation: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ + .degrees0, + .degrees90, + .degrees180, + .degrees270, + .degrees0Inverted, + .degrees90Inverted, + .degrees180Inverted, + .degrees270Inverted, + ] +} + +extension Config.LoRaConfig.RegionCode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.RegionCode] = [ + .unset, + .us, + .eu433, + .eu868, + .cn, + .jp, + .anz, + .kr, + .tw, + .ru, + .in, + .nz865, + .th, + .lora24, + .ua433, + .ua868, + .my433, + .my919, + .sg923, + ] +} + +extension Config.LoRaConfig.ModemPreset: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.ModemPreset] = [ + .longFast, + .longSlow, + .veryLongSlow, + .mediumSlow, + .mediumFast, + .shortSlow, + .shortFast, + .longModerate, + ] +} + +extension Config.BluetoothConfig.PairingMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.BluetoothConfig.PairingMode] = [ + .randomPin, + .fixedPin, + .noPin, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension Config: @unchecked Sendable {} +extension Config.OneOf_PayloadVariant: @unchecked Sendable {} +extension Config.DeviceConfig: @unchecked Sendable {} +extension Config.DeviceConfig.Role: @unchecked Sendable {} +extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {} +extension Config.PositionConfig: @unchecked Sendable {} +extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} +extension Config.PositionConfig.GpsMode: @unchecked Sendable {} +extension Config.PowerConfig: @unchecked Sendable {} +extension Config.NetworkConfig: @unchecked Sendable {} +extension Config.NetworkConfig.AddressMode: @unchecked Sendable {} +extension Config.NetworkConfig.IpV4Config: @unchecked Sendable {} +extension Config.DisplayConfig: @unchecked Sendable {} +extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} +extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} +extension Config.DisplayConfig.OledType: @unchecked Sendable {} +extension Config.DisplayConfig.DisplayMode: @unchecked Sendable {} +extension Config.DisplayConfig.CompassOrientation: @unchecked Sendable {} +extension Config.LoRaConfig: @unchecked Sendable {} +extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} +extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} +extension Config.BluetoothConfig: @unchecked Sendable {} +extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -2080,7 +2168,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 2) } - if self.adcMultiplierOverride.bitPattern != 0 { + if self.adcMultiplierOverride != 0 { try visitor.visitSingularFloatField(value: self.adcMultiplierOverride, fieldNumber: 3) } if self.waitBluetoothSecs != 0 { @@ -2524,7 +2612,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._codingRate != 0 { try visitor.visitSingularUInt32Field(value: _storage._codingRate, fieldNumber: 5) } - if _storage._frequencyOffset.bitPattern != 0 { + if _storage._frequencyOffset != 0 { try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 6) } if _storage._region != .unset { @@ -2548,7 +2636,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._sx126XRxBoostedGain != false { try visitor.visitSingularBoolField(value: _storage._sx126XRxBoostedGain, fieldNumber: 13) } - if _storage._overrideFrequency.bitPattern != 0 { + if _storage._overrideFrequency != 0 { try visitor.visitSingularFloatField(value: _storage._overrideFrequency, fieldNumber: 14) } if _storage._paFanDisabled != false { diff --git a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift index a4569714..a2ec180e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct DeviceConnectionStatus: Sendable { +public struct DeviceConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -81,7 +81,7 @@ public struct DeviceConnectionStatus: Sendable { /// /// WiFi connection status -public struct WifiConnectionStatus: Sendable { +public struct WifiConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -114,7 +114,7 @@ public struct WifiConnectionStatus: Sendable { /// /// Ethernet connection status -public struct EthernetConnectionStatus: Sendable { +public struct EthernetConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -139,7 +139,7 @@ public struct EthernetConnectionStatus: Sendable { /// /// Ethernet or WiFi connection status -public struct NetworkConnectionStatus: Sendable { +public struct NetworkConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -167,7 +167,7 @@ public struct NetworkConnectionStatus: Sendable { /// /// Bluetooth connection status -public struct BluetoothConnectionStatus: Sendable { +public struct BluetoothConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -191,7 +191,7 @@ public struct BluetoothConnectionStatus: Sendable { /// /// Serial connection status -public struct SerialConnectionStatus: Sendable { +public struct SerialConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -209,6 +209,15 @@ public struct SerialConnectionStatus: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension DeviceConnectionStatus: @unchecked Sendable {} +extension WifiConnectionStatus: @unchecked Sendable {} +extension EthernetConnectionStatus: @unchecked Sendable {} +extension NetworkConnectionStatus: @unchecked Sendable {} +extension BluetoothConnectionStatus: @unchecked Sendable {} +extension SerialConnectionStatus: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift index 834f9636..10b9af2b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Font sizes for the device screen -public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum ScreenFonts: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -60,18 +60,24 @@ public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension ScreenFonts: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [ScreenFonts] = [ .fontSmall, .fontMedium, .fontLarge, ] - } +#endif // swift(>=4.2) + /// /// Position with static location information only for NodeDBLite -public struct PositionLite: Sendable { +public struct PositionLite { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -106,7 +112,7 @@ public struct PositionLite: Sendable { public init() {} } -public struct NodeInfoLite: @unchecked Sendable { +public struct NodeInfoLite { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -209,7 +215,7 @@ public struct NodeInfoLite: @unchecked Sendable { /// FIXME, since we write this each time we enter deep sleep (and have infinite /// flash) it would be better to use some sort of append only data structure for /// the receive queue and use the preferences store for the other stuff -public struct DeviceState: @unchecked Sendable { +public struct DeviceState { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -269,8 +275,6 @@ public struct DeviceState: @unchecked Sendable { /// Used only during development. /// Indicates developer is testing and changes should never be saved to flash. /// Deprecated in 2.3.1 - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var noSave: Bool { get {return _storage._noSave} set {_uniqueStorage()._noSave = newValue} @@ -319,7 +323,7 @@ public struct DeviceState: @unchecked Sendable { /// /// The on-disk saved channels -public struct ChannelFile: Sendable { +public struct ChannelFile { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -342,7 +346,7 @@ public struct ChannelFile: Sendable { /// /// This can be used for customizing the firmware distribution. If populated, /// show a secondary bootup screen with custom logo and text for 2.5 seconds. -public struct OEMStore: @unchecked Sendable { +public struct OEMStore { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -401,6 +405,15 @@ public struct OEMStore: @unchecked Sendable { fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension ScreenFonts: @unchecked Sendable {} +extension PositionLite: @unchecked Sendable {} +extension NodeInfoLite: @unchecked Sendable {} +extension DeviceState: @unchecked Sendable {} +extension ChannelFile: @unchecked Sendable {} +extension OEMStore: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -568,7 +581,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr.bitPattern != 0 { + if _storage._snr != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index 17dd5baa..5e30d1cd 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct LocalConfig: @unchecked Sendable { +public struct LocalConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -118,7 +118,7 @@ public struct LocalConfig: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } -public struct LocalModuleConfig: @unchecked Sendable { +public struct LocalModuleConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -282,6 +282,11 @@ public struct LocalModuleConfig: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=5.5) && canImport(_Concurrency) +extension LocalConfig: @unchecked Sendable {} +extension LocalModuleConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index 996e8268..b12cc13f 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -25,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// bin/build-all.sh script. /// Because they will be used to find firmware filenames in the android app for OTA updates. /// To match the old style filenames, _ is converted to -, p is converted to . -public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum HardwareModel: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -496,6 +496,11 @@ public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension HardwareModel: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [HardwareModel] = [ .unset, @@ -571,12 +576,13 @@ public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { .trackerT1000E, .privateHw, ] - } +#endif // swift(>=4.2) + /// /// Shared constants between device and phone -public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum Constants: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -611,20 +617,26 @@ public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension Constants: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Constants] = [ .zero, .dataPayloadLen, ] - } +#endif // swift(>=4.2) + /// /// Error codes for critical errors /// The device might report these fault codes on the screen. /// If you encounter a fault code, please post on the meshtastic.discourse.group /// and we'll try to help. -public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum CriticalErrorCode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -676,6 +688,17 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { /// A (likely software but possibly hardware) failure was detected while trying to send packets. /// If this occurs on your board, please post in the forum so that we can ask you to collect some information to allow fixing this bug case radioSpiBug // = 11 + + /// + /// Corruption was detected on the flash filesystem but we were able to repair things. + /// If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. + case flashCorruptionRecoverable // = 12 + + /// + /// Corruption was detected on the flash filesystem but we were unable to repair things. + /// NOTE: Your node will probably need to be reconfigured the next time it reboots (it will lose the region code etc...) + /// If you see this failure in the field please post in the forum because we are interested in seeing if this is occurring in the field. + case flashCorruptionUnrecoverable // = 13 case UNRECOGNIZED(Int) public init() { @@ -696,6 +719,8 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { case 9: self = .brownout case 10: self = .sx1262Failure case 11: self = .radioSpiBug + case 12: self = .flashCorruptionRecoverable + case 13: self = .flashCorruptionUnrecoverable default: self = .UNRECOGNIZED(rawValue) } } @@ -714,10 +739,17 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { case .brownout: return 9 case .sx1262Failure: return 10 case .radioSpiBug: return 11 + case .flashCorruptionRecoverable: return 12 + case .flashCorruptionUnrecoverable: return 13 case .UNRECOGNIZED(let i): return i } } +} + +#if swift(>=4.2) + +extension CriticalErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [CriticalErrorCode] = [ .none, @@ -732,13 +764,16 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { .brownout, .sx1262Failure, .radioSpiBug, + .flashCorruptionRecoverable, + .flashCorruptionUnrecoverable, ] - } +#endif // swift(>=4.2) + /// /// a gps position -public struct Position: @unchecked Sendable { +public struct Position { // 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. @@ -927,7 +962,7 @@ public struct Position: @unchecked Sendable { /// /// How the location was acquired: manual, onboard GPS, external (EUD) GPS - public enum LocSource: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum LocSource: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -971,20 +1006,12 @@ public struct Position: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.LocSource] = [ - .locUnset, - .locManual, - .locInternal, - .locExternal, - ] - } /// /// How the altitude was acquired: manual, GPS int/ext, etc /// Default: same as location_source if present - public enum AltSource: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum AltSource: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1034,15 +1061,6 @@ public struct Position: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.AltSource] = [ - .altUnset, - .altManual, - .altInternal, - .altExternal, - .altBarometric, - ] - } public init() {} @@ -1050,6 +1068,31 @@ public struct Position: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=4.2) + +extension Position.LocSource: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.LocSource] = [ + .locUnset, + .locManual, + .locInternal, + .locExternal, + ] +} + +extension Position.AltSource: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.AltSource] = [ + .altUnset, + .altManual, + .altInternal, + .altExternal, + .altBarometric, + ] +} + +#endif // swift(>=4.2) + /// /// Broadcast when a newly powered mesh node wants to find a node num it can use /// Sent from the phone over bluetooth to set the user id for the owner of this node. @@ -1071,7 +1114,7 @@ public struct Position: @unchecked Sendable { /// A few nodenums are reserved and will never be requested: /// 0xff - broadcast /// 0 through 3 - for future use -public struct User: @unchecked Sendable { +public struct User { // 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. @@ -1096,8 +1139,6 @@ public struct User: @unchecked Sendable { /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -1124,7 +1165,7 @@ public struct User: @unchecked Sendable { /// /// A message used in our Dynamic Source Routing protocol (RFC 4728 based) -public struct RouteDiscovery: Sendable { +public struct RouteDiscovery { // 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. @@ -1140,7 +1181,7 @@ public struct RouteDiscovery: Sendable { /// /// A Routing control Data packet handled by the routing module -public struct Routing: Sendable { +public struct Routing { // 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. @@ -1180,7 +1221,7 @@ public struct Routing: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable, Sendable { + public enum OneOf_Variant: Equatable { /// /// A route request going from the requester case routeRequest(RouteDiscovery) @@ -1192,12 +1233,34 @@ public struct Routing: Sendable { /// in addition to ack.fail_id to provide details on the type of failure). case errorReason(Routing.Error) + #if !swift(>=4.1) + public static func ==(lhs: Routing.OneOf_Variant, rhs: Routing.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.routeRequest, .routeRequest): return { + guard case .routeRequest(let l) = lhs, case .routeRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.routeReply, .routeReply): return { + guard case .routeReply(let l) = lhs, case .routeReply(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.errorReason, .errorReason): return { + guard case .errorReason(let l) = lhs, case .errorReason(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide /// details on the type of failure). - public enum Error: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Error: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1291,32 +1354,38 @@ public struct Routing: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Routing.Error] = [ - .none, - .noRoute, - .gotNak, - .timeout, - .noInterface, - .maxRetransmit, - .noChannel, - .tooLarge, - .noResponse, - .dutyCycleLimit, - .badRequest, - .notAuthorized, - ] - } public init() {} } +#if swift(>=4.2) + +extension Routing.Error: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Routing.Error] = [ + .none, + .noRoute, + .gotNak, + .timeout, + .noInterface, + .maxRetransmit, + .noChannel, + .tooLarge, + .noResponse, + .dutyCycleLimit, + .badRequest, + .notAuthorized, + ] +} + +#endif // swift(>=4.2) + /// /// (Formerly called SubPacket) /// The payload portion fo a packet, this is the actual bytes that are sent /// inside a radio packet (because from/to are broken out by the comms library) -public struct DataMessage: @unchecked Sendable { +public struct DataMessage { // 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. @@ -1370,7 +1439,7 @@ public struct DataMessage: @unchecked Sendable { /// /// Waypoint message, used to share arbitrary locations across the mesh -public struct Waypoint: Sendable { +public struct Waypoint { // 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. @@ -1415,7 +1484,7 @@ public struct Waypoint: Sendable { /// /// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server -public struct MqttClientProxyMessage: @unchecked Sendable { +public struct MqttClientProxyMessage { // 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. @@ -1456,7 +1525,7 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// /// The actual service envelope payload or text for mqtt pub / sub - public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Bytes case data(Data) @@ -1464,6 +1533,24 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// Text case text(String) + #if !swift(>=4.1) + public static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.data, .data): return { + guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.text, .text): return { + guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -1473,7 +1560,7 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// A packet envelope sent/received over the mesh /// only payload_variant is sent in the payload portion of the LORA packet. /// The other fields are either not sent at all, or sent in the special 16 byte LORA header. -public struct MeshPacket: @unchecked Sendable { +public struct MeshPacket { // 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. @@ -1607,8 +1694,6 @@ public struct MeshPacket: @unchecked Sendable { /// /// Describe if this message is delayed - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var delayed: MeshPacket.Delayed { get {return _storage._delayed} set {_uniqueStorage()._delayed = newValue} @@ -1631,7 +1716,7 @@ public struct MeshPacket: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TODO: REPLACE case decoded(DataMessage) @@ -1639,6 +1724,24 @@ public struct MeshPacket: @unchecked Sendable { /// TODO: REPLACE case encrypted(Data) + #if !swift(>=4.1) + public static func ==(lhs: MeshPacket.OneOf_PayloadVariant, rhs: MeshPacket.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.decoded, .decoded): return { + guard case .decoded(let l) = lhs, case .decoded(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.encrypted, .encrypted): return { + guard case .encrypted(let l) = lhs, case .encrypted(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// @@ -1660,7 +1763,7 @@ public struct MeshPacket: @unchecked Sendable { /// So I bit the bullet and implemented a new (internal - not sent over the air) /// field in MeshPacket called 'priority'. /// And the transmission queue in the router object is now a priority queue. - public enum Priority: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Priority: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1725,22 +1828,11 @@ public struct MeshPacket: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Priority] = [ - .unset, - .min, - .background, - .default, - .reliable, - .ack, - .max, - ] - } /// /// Identify if this is a delayed packet - public enum Delayed: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Delayed: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1778,13 +1870,6 @@ public struct MeshPacket: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Delayed] = [ - .noDelay, - .broadcast, - .direct, - ] - } public init() {} @@ -1792,6 +1877,32 @@ public struct MeshPacket: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=4.2) + +extension MeshPacket.Priority: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Priority] = [ + .unset, + .min, + .background, + .default, + .reliable, + .ack, + .max, + ] +} + +extension MeshPacket.Delayed: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Delayed] = [ + .noDelay, + .broadcast, + .direct, + ] +} + +#endif // swift(>=4.2) + /// /// The bluetooth to device link: /// Old BTLE protocol docs from TODO, merge in above and make real docs... @@ -1809,7 +1920,7 @@ public struct MeshPacket: @unchecked Sendable { /// level etc) SET_CONFIG (switches device to a new set of radio params and /// preshared key, drops all existing nodes, force our node to rejoin this new group) /// Full information about a node on the mesh -public struct NodeInfo: @unchecked Sendable { +public struct NodeInfo { // 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. @@ -1910,7 +2021,7 @@ public struct NodeInfo: @unchecked Sendable { /// Unique local debugging info for this node /// Note: we don't include position or the user info, because that will come in the /// Sent to the phone in response to WantNodes. -public struct MyNodeInfo: Sendable { +public struct MyNodeInfo { // 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. @@ -1941,7 +2052,7 @@ public struct MyNodeInfo: Sendable { /// on the message it is assumed to be a continuation of the previously sent message. /// This allows the device code to use fixed maxlen 64 byte strings for messages, /// and then extend as needed by emitting multiple records. -public struct LogRecord: Sendable { +public struct LogRecord { // 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. @@ -1966,7 +2077,7 @@ public struct LogRecord: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum Level: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Level: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -2028,23 +2139,29 @@ public struct LogRecord: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [LogRecord.Level] = [ - .unset, - .critical, - .error, - .warning, - .info, - .debug, - .trace, - ] - } public init() {} } -public struct QueueStatus: Sendable { +#if swift(>=4.2) + +extension LogRecord.Level: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [LogRecord.Level] = [ + .unset, + .critical, + .error, + .warning, + .info, + .debug, + .trace, + ] +} + +#endif // swift(>=4.2) + +public struct QueueStatus { // 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. @@ -2071,7 +2188,7 @@ public struct QueueStatus: Sendable { /// It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? /// It will sit in that descriptor until consumed by the phone, /// at which point the next item in the FIFO will be populated. -public struct FromRadio: Sendable { +public struct FromRadio { // 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. @@ -2237,7 +2354,7 @@ public struct FromRadio: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Log levels, chosen to match python logging conventions. case packet(MeshPacket) @@ -2289,6 +2406,72 @@ public struct FromRadio: Sendable { /// File system manifest messages case fileInfo(FileInfo) + #if !swift(>=4.1) + public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.packet, .packet): return { + guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.myInfo, .myInfo): return { + guard case .myInfo(let l) = lhs, case .myInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nodeInfo, .nodeInfo): return { + guard case .nodeInfo(let l) = lhs, case .nodeInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.config, .config): return { + guard case .config(let l) = lhs, case .config(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.logRecord, .logRecord): return { + guard case .logRecord(let l) = lhs, case .logRecord(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.configCompleteID, .configCompleteID): return { + guard case .configCompleteID(let l) = lhs, case .configCompleteID(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebooted, .rebooted): return { + guard case .rebooted(let l) = lhs, case .rebooted(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.moduleConfig, .moduleConfig): return { + guard case .moduleConfig(let l) = lhs, case .moduleConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.channel, .channel): return { + guard case .channel(let l) = lhs, case .channel(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.queueStatus, .queueStatus): return { + guard case .queueStatus(let l) = lhs, case .queueStatus(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.xmodemPacket, .xmodemPacket): return { + guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.metadata, .metadata): return { + guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { + guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.fileInfo, .fileInfo): return { + guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -2296,7 +2479,7 @@ public struct FromRadio: Sendable { /// /// Individual File info for the device -public struct FileInfo: Sendable { +public struct FileInfo { // 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. @@ -2317,7 +2500,7 @@ public struct FileInfo: Sendable { /// /// Packets/commands to the radio will be written (reliably) to the toRadio characteristic. /// Once the write completes the phone can assume it is handled. -public struct ToRadio: Sendable { +public struct ToRadio { // 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. @@ -2397,7 +2580,7 @@ public struct ToRadio: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Send this packet on the mesh case packet(MeshPacket) @@ -2424,6 +2607,40 @@ public struct ToRadio: Sendable { /// Heartbeat message (used to keep the device connection awake on serial) case heartbeat(Heartbeat) + #if !swift(>=4.1) + public static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.packet, .packet): return { + guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.wantConfigID, .wantConfigID): return { + guard case .wantConfigID(let l) = lhs, case .wantConfigID(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.disconnect, .disconnect): return { + guard case .disconnect(let l) = lhs, case .disconnect(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.xmodemPacket, .xmodemPacket): return { + guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { + guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.heartbeat, .heartbeat): return { + guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -2431,7 +2648,7 @@ public struct ToRadio: Sendable { /// /// Compressed message payload -public struct Compressed: @unchecked Sendable { +public struct Compressed { // 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. @@ -2451,7 +2668,7 @@ public struct Compressed: @unchecked Sendable { /// /// Full info on edges for a single node -public struct NeighborInfo: Sendable { +public struct NeighborInfo { // 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. @@ -2479,7 +2696,7 @@ public struct NeighborInfo: Sendable { /// /// A single edge in the mesh -public struct Neighbor: Sendable { +public struct Neighbor { // 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. @@ -2509,7 +2726,7 @@ public struct Neighbor: Sendable { /// /// Device metadata response -public struct DeviceMetadata: Sendable { +public struct DeviceMetadata { // 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. @@ -2562,7 +2779,7 @@ public struct DeviceMetadata: Sendable { /// /// A heartbeat message is sent to the node from the client to keep the connection alive. /// This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. -public struct Heartbeat: Sendable { +public struct Heartbeat { // 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. @@ -2574,7 +2791,7 @@ public struct Heartbeat: Sendable { /// /// RemoteHardwarePins associated with a node -public struct NodeRemoteHardwarePin: Sendable { +public struct NodeRemoteHardwarePin { // 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. @@ -2601,7 +2818,7 @@ public struct NodeRemoteHardwarePin: Sendable { fileprivate var _pin: RemoteHardwarePin? = nil } -public struct ChunkedPayload: @unchecked Sendable { +public struct ChunkedPayload { // 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. @@ -2629,7 +2846,7 @@ public struct ChunkedPayload: @unchecked Sendable { /// /// Wrapper message for broken repeated oneof support -public struct resend_chunks: Sendable { +public struct resend_chunks { // 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. @@ -2643,7 +2860,7 @@ public struct resend_chunks: Sendable { /// /// Responses to a ChunkedPayload request -public struct ChunkedPayloadResponse: Sendable { +public struct ChunkedPayloadResponse { // 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. @@ -2686,7 +2903,7 @@ public struct ChunkedPayloadResponse: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Request to transfer chunked payload case requestTransfer(Bool) @@ -2697,11 +2914,75 @@ public struct ChunkedPayloadResponse: Sendable { /// Request missing indexes in the chunked payload case resendChunks(resend_chunks) + #if !swift(>=4.1) + public static func ==(lhs: ChunkedPayloadResponse.OneOf_PayloadVariant, rhs: ChunkedPayloadResponse.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.requestTransfer, .requestTransfer): return { + guard case .requestTransfer(let l) = lhs, case .requestTransfer(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.acceptTransfer, .acceptTransfer): return { + guard case .acceptTransfer(let l) = lhs, case .acceptTransfer(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.resendChunks, .resendChunks): return { + guard case .resendChunks(let l) = lhs, case .resendChunks(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension HardwareModel: @unchecked Sendable {} +extension Constants: @unchecked Sendable {} +extension CriticalErrorCode: @unchecked Sendable {} +extension Position: @unchecked Sendable {} +extension Position.LocSource: @unchecked Sendable {} +extension Position.AltSource: @unchecked Sendable {} +extension User: @unchecked Sendable {} +extension RouteDiscovery: @unchecked Sendable {} +extension Routing: @unchecked Sendable {} +extension Routing.OneOf_Variant: @unchecked Sendable {} +extension Routing.Error: @unchecked Sendable {} +extension DataMessage: @unchecked Sendable {} +extension Waypoint: @unchecked Sendable {} +extension MqttClientProxyMessage: @unchecked Sendable {} +extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {} +extension MeshPacket: @unchecked Sendable {} +extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} +extension MeshPacket.Priority: @unchecked Sendable {} +extension MeshPacket.Delayed: @unchecked Sendable {} +extension NodeInfo: @unchecked Sendable {} +extension MyNodeInfo: @unchecked Sendable {} +extension LogRecord: @unchecked Sendable {} +extension LogRecord.Level: @unchecked Sendable {} +extension QueueStatus: @unchecked Sendable {} +extension FromRadio: @unchecked Sendable {} +extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} +extension FileInfo: @unchecked Sendable {} +extension ToRadio: @unchecked Sendable {} +extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} +extension Compressed: @unchecked Sendable {} +extension NeighborInfo: @unchecked Sendable {} +extension Neighbor: @unchecked Sendable {} +extension DeviceMetadata: @unchecked Sendable {} +extension Heartbeat: @unchecked Sendable {} +extension NodeRemoteHardwarePin: @unchecked Sendable {} +extension ChunkedPayload: @unchecked Sendable {} +extension resend_chunks: @unchecked Sendable {} +extension ChunkedPayloadResponse: @unchecked Sendable {} +extension ChunkedPayloadResponse.OneOf_PayloadVariant: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -2804,6 +3085,8 @@ extension CriticalErrorCode: SwiftProtobuf._ProtoNameProviding { 9: .same(proto: "BROWNOUT"), 10: .same(proto: "SX1262_FAILURE"), 11: .same(proto: "RADIO_SPI_BUG"), + 12: .same(proto: "FLASH_CORRUPTION_RECOVERABLE"), + 13: .same(proto: "FLASH_CORRUPTION_UNRECOVERABLE"), ] } @@ -3647,7 +3930,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._rxTime != 0 { try visitor.visitSingularFixed32Field(value: _storage._rxTime, fieldNumber: 7) } - if _storage._rxSnr.bitPattern != 0 { + if _storage._rxSnr != 0 { try visitor.visitSingularFloatField(value: _storage._rxSnr, fieldNumber: 8) } if _storage._hopLimit != 0 { @@ -3822,7 +4105,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr.bitPattern != 0 { + if _storage._snr != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -4595,7 +4878,7 @@ extension Neighbor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if self.nodeID != 0 { try visitor.visitSingularUInt32Field(value: self.nodeID, fieldNumber: 1) } - if self.snr.bitPattern != 0 { + if self.snr != 0 { try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 2) } if self.lastRxTime != 0 { @@ -4708,8 +4991,8 @@ extension Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let _ = try decoder.nextFieldNumber() { + } } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index 6f3b2d76..c68ffd83 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum RemoteHardwarePinType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -58,18 +58,24 @@ public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension RemoteHardwarePinType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [RemoteHardwarePinType] = [ .unknown, .digitalRead, .digitalWrite, ] - } +#endif // swift(>=4.2) + /// /// Module Config -public struct ModuleConfig: Sendable { +public struct ModuleConfig { // 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. @@ -212,7 +218,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TODO: REPLACE case mqtt(ModuleConfig.MQTTConfig) @@ -253,11 +259,73 @@ public struct ModuleConfig: Sendable { /// TODO: REPLACE case paxcounter(ModuleConfig.PaxcounterConfig) + #if !swift(>=4.1) + public static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.mqtt, .mqtt): return { + guard case .mqtt(let l) = lhs, case .mqtt(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.serial, .serial): return { + guard case .serial(let l) = lhs, case .serial(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.externalNotification, .externalNotification): return { + guard case .externalNotification(let l) = lhs, case .externalNotification(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.storeForward, .storeForward): return { + guard case .storeForward(let l) = lhs, case .storeForward(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rangeTest, .rangeTest): return { + guard case .rangeTest(let l) = lhs, case .rangeTest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.telemetry, .telemetry): return { + guard case .telemetry(let l) = lhs, case .telemetry(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.cannedMessage, .cannedMessage): return { + guard case .cannedMessage(let l) = lhs, case .cannedMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.audio, .audio): return { + guard case .audio(let l) = lhs, case .audio(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.remoteHardware, .remoteHardware): return { + guard case .remoteHardware(let l) = lhs, case .remoteHardware(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.neighborInfo, .neighborInfo): return { + guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.ambientLighting, .ambientLighting): return { + guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.detectionSensor, .detectionSensor): return { + guard case .detectionSensor(let l) = lhs, case .detectionSensor(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.paxcounter, .paxcounter): return { + guard case .paxcounter(let l) = lhs, case .paxcounter(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// MQTT Client Config - public struct MQTTConfig: Sendable { + public struct MQTTConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -332,7 +400,7 @@ public struct ModuleConfig: Sendable { /// /// Settings for reporting unencrypted information about our node to a map via MQTT - public struct MapReportSettings: Sendable { + public struct MapReportSettings { // 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. @@ -352,7 +420,7 @@ public struct ModuleConfig: Sendable { /// /// RemoteHardwareModule Config - public struct RemoteHardwareConfig: Sendable { + public struct RemoteHardwareConfig { // 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. @@ -376,7 +444,7 @@ public struct ModuleConfig: Sendable { /// /// NeighborInfoModule Config - public struct NeighborInfoConfig: Sendable { + public struct NeighborInfoConfig { // 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. @@ -397,7 +465,7 @@ public struct ModuleConfig: Sendable { /// /// Detection Sensor Module Config - public struct DetectionSensorConfig: Sendable { + public struct DetectionSensorConfig { // 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. @@ -448,7 +516,7 @@ public struct ModuleConfig: Sendable { /// /// Audio Config for codec2 voice - public struct AudioConfig: Sendable { + public struct AudioConfig { // 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. @@ -485,7 +553,7 @@ public struct ModuleConfig: Sendable { /// /// Baudrate for codec2 voice - public enum Audio_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Audio_Baud: SwiftProtobuf.Enum { public typealias RawValue = Int case codec2Default // = 0 case codec23200 // = 1 @@ -532,19 +600,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ - .codec2Default, - .codec23200, - .codec22400, - .codec21600, - .codec21400, - .codec21300, - .codec21200, - .codec2700, - .codec2700B, - ] - } public init() {} @@ -552,7 +607,7 @@ public struct ModuleConfig: Sendable { /// /// Config for the Paxcounter Module - public struct PaxcounterConfig: Sendable { + public struct PaxcounterConfig { // 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. @@ -578,7 +633,7 @@ public struct ModuleConfig: Sendable { /// /// Serial Config - public struct SerialConfig: Sendable { + public struct SerialConfig { // 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. @@ -621,7 +676,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum Serial_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Serial_Baud: SwiftProtobuf.Enum { public typealias RawValue = Int case baudDefault // = 0 case baud110 // = 1 @@ -689,31 +744,11 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ - .baudDefault, - .baud110, - .baud300, - .baud600, - .baud1200, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - ] - } /// /// TODO: REPLACE - public enum Serial_Mode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Serial_Mode: SwiftProtobuf.Enum { public typealias RawValue = Int case `default` // = 0 case simple // = 1 @@ -758,17 +793,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ - .default, - .simple, - .proto, - .textmsg, - .nmea, - .caltopo, - .ws85, - ] - } public init() {} @@ -776,7 +800,7 @@ public struct ModuleConfig: Sendable { /// /// External Notifications Config - public struct ExternalNotificationConfig: Sendable { + public struct ExternalNotificationConfig { // 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. @@ -859,7 +883,7 @@ public struct ModuleConfig: Sendable { /// /// Store and Forward Module Config - public struct StoreForwardConfig: Sendable { + public struct StoreForwardConfig { // 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. @@ -895,7 +919,7 @@ public struct ModuleConfig: Sendable { /// /// Preferences for the RangeTestModule - public struct RangeTestConfig: Sendable { + public struct RangeTestConfig { // 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. @@ -920,7 +944,7 @@ public struct ModuleConfig: Sendable { /// /// Configuration for both device and environment metrics - public struct TelemetryConfig: Sendable { + public struct TelemetryConfig { // 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. @@ -977,7 +1001,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public struct CannedMessageConfig: Sendable { + public struct CannedMessageConfig { // 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. @@ -1032,7 +1056,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum InputEventChar: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum InputEventChar: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1100,18 +1124,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ - .none, - .up, - .down, - .left, - .right, - .select, - .back, - .cancel, - ] - } public init() {} @@ -1120,7 +1132,7 @@ public struct ModuleConfig: Sendable { /// ///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. ///Initially created for the RAK14001 RGB LED module. - public struct AmbientLightingConfig: Sendable { + public struct AmbientLightingConfig { // 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. @@ -1153,9 +1165,77 @@ public struct ModuleConfig: Sendable { public init() {} } +#if swift(>=4.2) + +extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ + .codec2Default, + .codec23200, + .codec22400, + .codec21600, + .codec21400, + .codec21300, + .codec21200, + .codec2700, + .codec2700B, + ] +} + +extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ + .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, + .baud2400, + .baud4800, + .baud9600, + .baud19200, + .baud38400, + .baud57600, + .baud115200, + .baud230400, + .baud460800, + .baud576000, + .baud921600, + ] +} + +extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ + .default, + .simple, + .proto, + .textmsg, + .nmea, + .caltopo, + .ws85, + ] +} + +extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ + .none, + .up, + .down, + .left, + .right, + .select, + .back, + .cancel, + ] +} + +#endif // swift(>=4.2) + /// /// A GPIO pin definition for remote hardware module -public struct RemoteHardwarePin: Sendable { +public struct RemoteHardwarePin { // 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. @@ -1177,6 +1257,31 @@ public struct RemoteHardwarePin: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension RemoteHardwarePinType: @unchecked Sendable {} +extension ModuleConfig: @unchecked Sendable {} +extension ModuleConfig.OneOf_PayloadVariant: @unchecked Sendable {} +extension ModuleConfig.MQTTConfig: @unchecked Sendable {} +extension ModuleConfig.MapReportSettings: @unchecked Sendable {} +extension ModuleConfig.RemoteHardwareConfig: @unchecked Sendable {} +extension ModuleConfig.NeighborInfoConfig: @unchecked Sendable {} +extension ModuleConfig.DetectionSensorConfig: @unchecked Sendable {} +extension ModuleConfig.AudioConfig: @unchecked Sendable {} +extension ModuleConfig.AudioConfig.Audio_Baud: @unchecked Sendable {} +extension ModuleConfig.PaxcounterConfig: @unchecked Sendable {} +extension ModuleConfig.SerialConfig: @unchecked Sendable {} +extension ModuleConfig.SerialConfig.Serial_Baud: @unchecked Sendable {} +extension ModuleConfig.SerialConfig.Serial_Mode: @unchecked Sendable {} +extension ModuleConfig.ExternalNotificationConfig: @unchecked Sendable {} +extension ModuleConfig.StoreForwardConfig: @unchecked Sendable {} +extension ModuleConfig.RangeTestConfig: @unchecked Sendable {} +extension ModuleConfig.TelemetryConfig: @unchecked Sendable {} +extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {} +extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {} +extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {} +extension RemoteHardwarePin: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift index fc5e37a1..efe6cdd5 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This message wraps a MeshPacket with extra metadata about the sender and how it arrived. -public struct ServiceEnvelope: Sendable { +public struct ServiceEnvelope { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -57,7 +57,7 @@ public struct ServiceEnvelope: Sendable { /// /// Information about a node intended to be reported unencrypted to a map using MQTT. -public struct MapReport: Sendable { +public struct MapReport { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -121,6 +121,11 @@ public struct MapReport: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension ServiceEnvelope: @unchecked Sendable {} +extension MapReport: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift index f82b3c51..cf8aa463 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct Paxcount: Sendable { +public struct Paxcount { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -44,6 +44,10 @@ public struct Paxcount: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension Paxcount: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index c5348a8a..c728c961 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -33,7 +33,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: This was formerly a Type enum named 'typ' with the same id # /// We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. /// This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically. -public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum PortNum: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -277,6 +277,11 @@ public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension PortNum: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [PortNum] = [ .unknownApp, @@ -308,9 +313,14 @@ public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { .atakForwarder, .max, ] - } +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension PortNum: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. extension PortNum: SwiftProtobuf._ProtoNameProviding { diff --git a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift index 9c61e6d0..5f51e948 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). ///But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) -public struct PowerMon: Sendable { +public struct PowerMon { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -31,7 +31,7 @@ public struct PowerMon: Sendable { /// Any significant power changing event in meshtastic should be tagged with a powermon state transition. ///If you are making new meshtastic features feel free to add new entries at the end of this definition. - public enum State: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum State: SwiftProtobuf.Enum { public typealias RawValue = Int case none // = 0 case cpuDeepSleep // = 1 @@ -104,31 +104,37 @@ public struct PowerMon: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerMon.State] = [ - .none, - .cpuDeepSleep, - .cpuLightSleep, - .vext1On, - .loraRxon, - .loraTxon, - .loraRxactive, - .btOn, - .ledOn, - .screenOn, - .screenDrawing, - .wifiOn, - .gpsActive, - ] - } public init() {} } +#if swift(>=4.2) + +extension PowerMon.State: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerMon.State] = [ + .none, + .cpuDeepSleep, + .cpuLightSleep, + .vext1On, + .loraRxon, + .loraTxon, + .loraRxactive, + .btOn, + .ledOn, + .screenOn, + .screenDrawing, + .wifiOn, + .gpsActive, + ] +} + +#endif // swift(>=4.2) + /// /// PowerStress testing support via the C++ PowerStress module -public struct PowerStressMessage: Sendable { +public struct PowerStressMessage { // 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. @@ -145,7 +151,7 @@ public struct PowerStressMessage: Sendable { /// What operation would we like the UUT to perform. ///note: senders should probably set want_response in their request packets, so that they can know when the state ///machine has started processing their request - public enum Opcode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Opcode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -266,35 +272,48 @@ public struct PowerStressMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerStressMessage.Opcode] = [ - .unset, - .printInfo, - .forceQuiet, - .endQuiet, - .screenOn, - .screenOff, - .cpuIdle, - .cpuDeepsleep, - .cpuFullon, - .ledOn, - .ledOff, - .loraOff, - .loraTx, - .loraRx, - .btOff, - .btOn, - .wifiOff, - .wifiOn, - .gpsOff, - .gpsOn, - ] - } public init() {} } +#if swift(>=4.2) + +extension PowerStressMessage.Opcode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerStressMessage.Opcode] = [ + .unset, + .printInfo, + .forceQuiet, + .endQuiet, + .screenOn, + .screenOff, + .cpuIdle, + .cpuDeepsleep, + .cpuFullon, + .ledOn, + .ledOff, + .loraOff, + .loraTx, + .loraRx, + .btOff, + .btOn, + .wifiOff, + .wifiOn, + .gpsOff, + .gpsOn, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension PowerMon: @unchecked Sendable {} +extension PowerMon.State: @unchecked Sendable {} +extension PowerStressMessage: @unchecked Sendable {} +extension PowerStressMessage.Opcode: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -304,8 +323,8 @@ extension PowerMon: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let _ = try decoder.nextFieldNumber() { + } } public func traverse(visitor: inout V) throws { @@ -360,7 +379,7 @@ extension PowerStressMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.cmd != .unset { try visitor.visitSingularEnumField(value: self.cmd, fieldNumber: 1) } - if self.numSeconds.bitPattern != 0 { + if self.numSeconds != 0 { try visitor.visitSingularFloatField(value: self.numSeconds, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift index 60f64504..ac6eeb26 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift @@ -30,7 +30,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// because no security yet (beyond the channel mechanism). /// It should be off by default and then protected based on some TBD mechanism /// (a special channel once multichannel support is included?) -public struct HardwareMessage: Sendable { +public struct HardwareMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -52,7 +52,7 @@ public struct HardwareMessage: Sendable { /// /// TODO: REPLACE - public enum TypeEnum: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum TypeEnum: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -110,21 +110,32 @@ public struct HardwareMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [HardwareMessage.TypeEnum] = [ - .unset, - .writeGpios, - .watchGpios, - .gpiosChanged, - .readGpios, - .readGpiosReply, - ] - } public init() {} } +#if swift(>=4.2) + +extension HardwareMessage.TypeEnum: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [HardwareMessage.TypeEnum] = [ + .unset, + .writeGpios, + .watchGpios, + .gpiosChanged, + .readGpios, + .readGpiosReply, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension HardwareMessage: @unchecked Sendable {} +extension HardwareMessage.TypeEnum: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift index c1f3f678..6fdf3208 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct RTTTLConfig: Sendable { +public struct RTTTLConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,6 +36,10 @@ public struct RTTTLConfig: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension RTTTLConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift index 0b67eaf6..54efa77b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct StoreAndForward: @unchecked Sendable { +public struct StoreAndForward { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -79,7 +79,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public enum OneOf_Variant: Equatable, @unchecked Sendable { + public enum OneOf_Variant: Equatable { /// /// TODO: REPLACE case stats(StoreAndForward.Statistics) @@ -93,12 +93,38 @@ public struct StoreAndForward: @unchecked Sendable { /// Text from history message. case text(Data) + #if !swift(>=4.1) + public static func ==(lhs: StoreAndForward.OneOf_Variant, rhs: StoreAndForward.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.stats, .stats): return { + guard case .stats(let l) = lhs, case .stats(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.history, .history): return { + guard case .history(let l) = lhs, case .history(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.heartbeat, .heartbeat): return { + guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.text, .text): return { + guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// 001 - 063 = From Router /// 064 - 127 = From Client - public enum RequestResponse: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RequestResponse: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -216,31 +242,11 @@ public struct StoreAndForward: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [StoreAndForward.RequestResponse] = [ - .unset, - .routerError, - .routerHeartbeat, - .routerPing, - .routerPong, - .routerBusy, - .routerHistory, - .routerStats, - .routerTextDirect, - .routerTextBroadcast, - .clientError, - .clientHistory, - .clientStats, - .clientPing, - .clientPong, - .clientAbort, - ] - } /// /// TODO: REPLACE - public struct Statistics: Sendable { + public struct Statistics { // 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. @@ -288,7 +294,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public struct History: Sendable { + public struct History { // 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. @@ -313,7 +319,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public struct Heartbeat: Sendable { + public struct Heartbeat { // 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. @@ -334,6 +340,41 @@ public struct StoreAndForward: @unchecked Sendable { public init() {} } +#if swift(>=4.2) + +extension StoreAndForward.RequestResponse: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [StoreAndForward.RequestResponse] = [ + .unset, + .routerError, + .routerHeartbeat, + .routerPing, + .routerPong, + .routerBusy, + .routerHistory, + .routerStats, + .routerTextDirect, + .routerTextBroadcast, + .clientError, + .clientHistory, + .clientStats, + .clientPing, + .clientPong, + .clientAbort, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension StoreAndForward: @unchecked Sendable {} +extension StoreAndForward.OneOf_Variant: @unchecked Sendable {} +extension StoreAndForward.RequestResponse: @unchecked Sendable {} +extension StoreAndForward.Statistics: @unchecked Sendable {} +extension StoreAndForward.History: @unchecked Sendable {} +extension StoreAndForward.Heartbeat: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index 7a9b81de..ec627e3d 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Supported I2C Sensors for telemetry in Meshtastic -public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum TelemetrySensorType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -198,6 +198,11 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension TelemetrySensorType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [TelemetrySensorType] = [ .sensorUnset, @@ -227,12 +232,13 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { .dfrobotLark, .nau7802, ] - } +#endif // swift(>=4.2) + /// /// Key native device metrics such as battery level -public struct DeviceMetrics: Sendable { +public struct DeviceMetrics { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -264,7 +270,7 @@ public struct DeviceMetrics: Sendable { /// /// Weather station or other environmental metrics -public struct EnvironmentMetrics: @unchecked Sendable { +public struct EnvironmentMetrics { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -399,7 +405,7 @@ public struct EnvironmentMetrics: @unchecked Sendable { /// /// Power Metrics (voltage / current / etc) -public struct PowerMetrics: Sendable { +public struct PowerMetrics { // 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. @@ -435,7 +441,7 @@ public struct PowerMetrics: Sendable { /// /// Air quality metrics -public struct AirQualityMetrics: Sendable { +public struct AirQualityMetrics { // 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. @@ -495,7 +501,7 @@ public struct AirQualityMetrics: Sendable { /// /// Types of Measurements the telemetry module is equipped to handle -public struct Telemetry: Sendable { +public struct Telemetry { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -548,7 +554,7 @@ public struct Telemetry: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable, Sendable { + public enum OneOf_Variant: Equatable { /// /// Key native device metrics such as battery level case deviceMetrics(DeviceMetrics) @@ -562,6 +568,32 @@ public struct Telemetry: Sendable { /// Power Metrics case powerMetrics(PowerMetrics) + #if !swift(>=4.1) + public static func ==(lhs: Telemetry.OneOf_Variant, rhs: Telemetry.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.deviceMetrics, .deviceMetrics): return { + guard case .deviceMetrics(let l) = lhs, case .deviceMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.environmentMetrics, .environmentMetrics): return { + guard case .environmentMetrics(let l) = lhs, case .environmentMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.airQualityMetrics, .airQualityMetrics): return { + guard case .airQualityMetrics(let l) = lhs, case .airQualityMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.powerMetrics, .powerMetrics): return { + guard case .powerMetrics(let l) = lhs, case .powerMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -569,7 +601,7 @@ public struct Telemetry: Sendable { /// /// NAU7802 Telemetry configuration, for saving to flash -public struct Nau7802Config: Sendable { +public struct Nau7802Config { // 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. @@ -587,6 +619,17 @@ public struct Nau7802Config: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension TelemetrySensorType: @unchecked Sendable {} +extension DeviceMetrics: @unchecked Sendable {} +extension EnvironmentMetrics: @unchecked Sendable {} +extension PowerMetrics: @unchecked Sendable {} +extension AirQualityMetrics: @unchecked Sendable {} +extension Telemetry: @unchecked Sendable {} +extension Telemetry.OneOf_Variant: @unchecked Sendable {} +extension Nau7802Config: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -652,13 +695,13 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.batteryLevel != 0 { try visitor.visitSingularUInt32Field(value: self.batteryLevel, fieldNumber: 1) } - if self.voltage.bitPattern != 0 { + if self.voltage != 0 { try visitor.visitSingularFloatField(value: self.voltage, fieldNumber: 2) } - if self.channelUtilization.bitPattern != 0 { + if self.channelUtilization != 0 { try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 3) } - if self.airUtilTx.bitPattern != 0 { + if self.airUtilTx != 0 { try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 4) } if self.uptimeSeconds != 0 { @@ -792,55 +835,55 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple public func traverse(visitor: inout V) throws { try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - if _storage._temperature.bitPattern != 0 { + if _storage._temperature != 0 { try visitor.visitSingularFloatField(value: _storage._temperature, fieldNumber: 1) } - if _storage._relativeHumidity.bitPattern != 0 { + if _storage._relativeHumidity != 0 { try visitor.visitSingularFloatField(value: _storage._relativeHumidity, fieldNumber: 2) } - if _storage._barometricPressure.bitPattern != 0 { + if _storage._barometricPressure != 0 { try visitor.visitSingularFloatField(value: _storage._barometricPressure, fieldNumber: 3) } - if _storage._gasResistance.bitPattern != 0 { + if _storage._gasResistance != 0 { try visitor.visitSingularFloatField(value: _storage._gasResistance, fieldNumber: 4) } - if _storage._voltage.bitPattern != 0 { + if _storage._voltage != 0 { try visitor.visitSingularFloatField(value: _storage._voltage, fieldNumber: 5) } - if _storage._current.bitPattern != 0 { + if _storage._current != 0 { try visitor.visitSingularFloatField(value: _storage._current, fieldNumber: 6) } if _storage._iaq != 0 { try visitor.visitSingularUInt32Field(value: _storage._iaq, fieldNumber: 7) } - if _storage._distance.bitPattern != 0 { + if _storage._distance != 0 { try visitor.visitSingularFloatField(value: _storage._distance, fieldNumber: 8) } - if _storage._lux.bitPattern != 0 { + if _storage._lux != 0 { try visitor.visitSingularFloatField(value: _storage._lux, fieldNumber: 9) } - if _storage._whiteLux.bitPattern != 0 { + if _storage._whiteLux != 0 { try visitor.visitSingularFloatField(value: _storage._whiteLux, fieldNumber: 10) } - if _storage._irLux.bitPattern != 0 { + if _storage._irLux != 0 { try visitor.visitSingularFloatField(value: _storage._irLux, fieldNumber: 11) } - if _storage._uvLux.bitPattern != 0 { + if _storage._uvLux != 0 { try visitor.visitSingularFloatField(value: _storage._uvLux, fieldNumber: 12) } if _storage._windDirection != 0 { try visitor.visitSingularUInt32Field(value: _storage._windDirection, fieldNumber: 13) } - if _storage._windSpeed.bitPattern != 0 { + if _storage._windSpeed != 0 { try visitor.visitSingularFloatField(value: _storage._windSpeed, fieldNumber: 14) } - if _storage._weight.bitPattern != 0 { + if _storage._weight != 0 { try visitor.visitSingularFloatField(value: _storage._weight, fieldNumber: 15) } - if _storage._windGust.bitPattern != 0 { + if _storage._windGust != 0 { try visitor.visitSingularFloatField(value: _storage._windGust, fieldNumber: 16) } - if _storage._windLull.bitPattern != 0 { + if _storage._windLull != 0 { try visitor.visitSingularFloatField(value: _storage._windLull, fieldNumber: 17) } } @@ -907,22 +950,22 @@ extension PowerMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat } public func traverse(visitor: inout V) throws { - if self.ch1Voltage.bitPattern != 0 { + if self.ch1Voltage != 0 { try visitor.visitSingularFloatField(value: self.ch1Voltage, fieldNumber: 1) } - if self.ch1Current.bitPattern != 0 { + if self.ch1Current != 0 { try visitor.visitSingularFloatField(value: self.ch1Current, fieldNumber: 2) } - if self.ch2Voltage.bitPattern != 0 { + if self.ch2Voltage != 0 { try visitor.visitSingularFloatField(value: self.ch2Voltage, fieldNumber: 3) } - if self.ch2Current.bitPattern != 0 { + if self.ch2Current != 0 { try visitor.visitSingularFloatField(value: self.ch2Current, fieldNumber: 4) } - if self.ch3Voltage.bitPattern != 0 { + if self.ch3Voltage != 0 { try visitor.visitSingularFloatField(value: self.ch3Voltage, fieldNumber: 5) } - if self.ch3Current.bitPattern != 0 { + if self.ch3Current != 0 { try visitor.visitSingularFloatField(value: self.ch3Current, fieldNumber: 6) } try unknownFields.traverse(visitor: &visitor) @@ -1174,7 +1217,7 @@ extension Nau7802Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.zeroOffset != 0 { try visitor.visitSingularInt32Field(value: self.zeroOffset, fieldNumber: 1) } - if self.calibrationFactor.bitPattern != 0 { + if self.calibrationFactor != 0 { try visitor.visitSingularFloatField(value: self.calibrationFactor, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift index 89d0097c..1f41fe0b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct XModem: @unchecked Sendable { +public struct XModem { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -35,7 +35,7 @@ public struct XModem: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum Control: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Control: SwiftProtobuf.Enum { public typealias RawValue = Int case nul // = 0 case soh // = 1 @@ -79,23 +79,34 @@ public struct XModem: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [XModem.Control] = [ - .nul, - .soh, - .stx, - .eot, - .ack, - .nak, - .can, - .ctrlz, - ] - } public init() {} } +#if swift(>=4.2) + +extension XModem.Control: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [XModem.Control] = [ + .nul, + .soh, + .stx, + .eot, + .ack, + .nak, + .can, + .ctrlz, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension XModem: @unchecked Sendable {} +extension XModem.Control: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/protobufs b/protobufs index 97674883..d0fe91ab 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 976748839fafcf0049bb364fe2c7226a194d18a9 +Subproject commit d0fe91ab99734cacdc188403f73fe30f766917cf From 3f139244e1df83c21b8f9ea1b944d0a3f3cf3551 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 7 Aug 2024 09:43:48 -0700 Subject: [PATCH 02/75] Initial security config setup --- Meshtastic.xcodeproj/project.pbxproj | 4 ++ .../contents | 12 +++++ .../Settings/Config/SecurityConfig.swift | 47 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 Meshtastic/Views/Settings/Config/SecurityConfig.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index cca267e7..f3c62dc1 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ DD1B8F402B35E2F10022AABC /* GPSStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1B8F3F2B35E2F10022AABC /* GPSStatus.swift */; }; DD1BD0EB2C601795008C0C70 /* CLLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BD0EA2C601795008C0C70 /* CLLocation.swift */; }; DD1BD0EE2C603C91008C0C70 /* CustomFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BD0ED2C603C91008C0C70 /* CustomFormatters.swift */; }; + DD1BD0F32C63C65E008C0C70 /* SecurityConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BD0F22C63C65E008C0C70 /* SecurityConfig.swift */; }; DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */; }; DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2160AE28C5552500C17253 /* MQTTConfig.swift */; }; DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */; }; @@ -292,6 +293,7 @@ DD1BD0EA2C601795008C0C70 /* CLLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLLocation.swift; sourceTree = ""; }; DD1BD0ED2C603C91008C0C70 /* CustomFormatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomFormatters.swift; sourceTree = ""; }; DD1BD0F12C61D3AD008C0C70 /* MeshtasticDataModelV 42.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 42.xcdatamodel"; sourceTree = ""; }; + DD1BD0F22C63C65E008C0C70 /* SecurityConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityConfig.swift; sourceTree = ""; }; DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserMessageList.swift; sourceTree = ""; }; DD2160AE28C5552500C17253 /* MQTTConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTConfig.swift; sourceTree = ""; }; DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = ""; }; @@ -680,6 +682,7 @@ DD2553582855B52700E55709 /* PositionConfig.swift */, DD8ED9C42898D51F00B3B0AB /* NetworkConfig.swift */, D93068DA2B81C85E0066FBC8 /* PowerConfig.swift */, + DD1BD0F22C63C65E008C0C70 /* SecurityConfig.swift */, DD61937B2863877A00E59241 /* Module */, ); path = Config; @@ -1276,6 +1279,7 @@ DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */, DDDB26482AACD6D1003AFCB7 /* NodeMapMapkit.swift in Sources */, DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */, + DD1BD0F32C63C65E008C0C70 /* SecurityConfig.swift in Sources */, DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */, DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */, 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */, diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents index 6b2eaa00..741b1252 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents @@ -245,6 +245,7 @@ + @@ -334,6 +335,17 @@ + + + + + + + + + + + diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift new file mode 100644 index 00000000..57153785 --- /dev/null +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -0,0 +1,47 @@ +// +// Security.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/7/24. +// + +import Foundation +import SwiftUI +import CoreData +import MeshtasticProtobufs +import OSLog + +struct SecurityConfig: View { + + @Environment(\.managedObjectContext) var context + @EnvironmentObject var bleManager: BLEManager + @Environment(\.dismiss) private var goBack + + var node: NodeInfoEntity? + + @State var hasChanges = false + @State var isManaged = false + @State var serialEnabled = true + @State var debugLogEnabled = false + @State var bluetoothLoggingEabled = false + @State var adminChannelEnabled = false + @State var publicKey = "" + @State var privateKey = "" + @State var adminKey = "" + + var body: some View { + VStack { + Form { + ConfigHeader(title: "Security", config: \.securityConfig, node: node, onAppear: setSecurityValues) + } + } + } + func setSecurityValues() { + self.isManaged = node?.securityConfig?.isManaged ?? false + self.serialEnabled = node?.securityConfig?.serialEnabled ?? false + self.debugLogEnabled = node?.securityConfig?.debugLogEnabled ?? false + self.bluetoothLoggingEabled = node?.securityConfig?.bluetoothLoggingEabled ?? false + self.adminChannelEnabled = node?.securityConfig?.adminChannelEnabled ?? false + self.hasChanges = false + } +} From 9f999805343b46108337a1fd3221050b7ed601d5 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 8 Aug 2024 07:33:31 -0700 Subject: [PATCH 03/75] initial security config proto mockup --- Localizable.xcstrings | 62 ++++++- Meshtastic/Helpers/BLEManager.swift | 31 ++++ .../contents | 6 +- Meshtastic/Persistence/Persistence.swift | 4 +- Meshtastic/Persistence/UpdateCoreData.swift | 49 ++++++ Meshtastic/Router/NavigationState.swift | 1 + Meshtastic/Views/ContentView.swift | 7 +- .../Messages/MessageContextMenuItems.swift | 6 +- Meshtastic/Views/Messages/UserList.swift | 6 + Meshtastic/Views/Nodes/NodeList.swift | 1 - .../Settings/Config/SecurityConfig.swift | 126 +++++++++++++- Meshtastic/Views/Settings/Settings.swift | 10 ++ .../Sources/meshtastic/config.pb.swift | 157 ++++++++++++++++++ .../Sources/meshtastic/localonly.pb.swift | 19 +++ .../Sources/meshtastic/mesh.pb.swift | 41 +++++ protobufs | 2 +- 16 files changed, 510 insertions(+), 18 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index d80208dd..b704efe3 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -481,6 +481,12 @@ } } } + }, + "Admin & Direct Message Keys" : { + + }, + "Admin Key" : { + }, "admin.log" : { "extractionState" : "manual", @@ -705,6 +711,9 @@ }, "All device and app data will be deleted. You will also need to forget your devices under Settings > Bluetooth." : { + }, + "Allow incoming device control over the insecure legacy admin channel." : { + }, "Allow Position Requests" : { @@ -1843,6 +1852,9 @@ } } } + }, + "Bluetooth Logs" : { + }, "bluetooth.config" : { "localizations" : { @@ -5337,6 +5349,9 @@ } } } + }, + "Developer" : { + }, "Developers" : { @@ -5401,6 +5416,9 @@ }, "Device GPS" : { + }, + "Device is managed by a mesh administrator." : { + }, "Device Logging Enabled" : { @@ -6954,6 +6972,9 @@ } } } + }, + "Encrypted" : { + }, "Encryption Enabled" : { @@ -8252,7 +8273,7 @@ "Hops Away" : { }, - "Hops Away %d) dB" : { + "Hops Away %d" : { }, "Hops Away:" : { @@ -10843,6 +10864,9 @@ }, "LED State" : { + }, + "Legacy Administration" : { + }, "Licensed Operator" : { @@ -15976,6 +16000,9 @@ }, "Other data sources" : { + }, + "Output live debug logging over serial." : { + }, "Output pin buzzer GPIO " : { @@ -16626,9 +16653,15 @@ }, "Primary GPIO" : { + }, + "Private Key" : { + }, "Project information" : { + }, + "Public Key" : { + }, "PWD" : { @@ -18801,6 +18834,12 @@ }, "Secondary" : { + }, + "Security" : { + + }, + "Security Config" : { + }, "Select a channel" : { @@ -19016,6 +19055,9 @@ }, "Sensor Options" : { + }, + "Sent out to other nodes on the mesh to allow them to compute a shared secret key." : { + }, "Sequence number" : { @@ -19083,6 +19125,12 @@ }, "Serial Console" : { + }, + "Serial Console over the Stream API." : { + + }, + "Serial Debug Logs" : { + }, "serial.config" : { "localizations" : { @@ -20916,6 +20964,9 @@ }, "The minimum distance change in meters to be considered for a smart position broadcast." : { + }, + "The public key authorized to send admin messages to this node." : { + }, "The region where you will be using your radios." : { @@ -22127,6 +22178,9 @@ }, "Use PWM Buzzer" : { + }, + "Used to create a shared key with a remote device." : { + }, "user" : { "localizations" : { @@ -22294,6 +22348,12 @@ }, "Via Mqtt" : { + }, + "View and export position-redacted device logs over Bluetooth" : { + + }, + "View Logs" : { + }, "voltage" : { "localizations" : { diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 475235de..13941ec9 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1970,6 +1970,37 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate return 0 } + public func saveSecurityConfig(config: Config.SecurityConfig, fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Int64 { + + var adminPacket = AdminMessage() + adminPacket.setConfig.security = config + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.channel = UInt32(adminIndex) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Int64 { var adminPacket = AdminMessage() diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents index 741b1252..a04f71ea 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents @@ -155,7 +155,9 @@ + + @@ -338,7 +340,7 @@ - + @@ -435,6 +437,8 @@ + + diff --git a/Meshtastic/Persistence/Persistence.swift b/Meshtastic/Persistence/Persistence.swift index 93ba7f16..70e9f898 100644 --- a/Meshtastic/Persistence/Persistence.swift +++ b/Meshtastic/Persistence/Persistence.swift @@ -104,8 +104,8 @@ extension NSPersistentContainer { } /// Restore backup persistent stores located in the directory referenced by `backupURL`. - /// - /// **Be very careful with this**. To restore a persistent store, the current persistent store must be removed from the container. When that happens, **all currently loaded Core Data objects** will become invalid. Using them after restoring will cause your app to crash. When calling this method you **must** ensure that you do not continue to use any previously fetched managed objects or existing fetched results controllers. **If this method does not throw, that does not mean your app is safe.** You need to take extra steps to prevent crashes. The details vary depending on the nature of your app. + /// **Be very careful with this**. To restore a persistent store, the current persistent store must be removed from the container. When that happens, **all currently loaded Core Data objects** will become invalid. Using them after restoring will cause your app to crash. + /// When calling this method you **must** ensure that you do not continue to use any previously fetched managed objects or existing fetched results controllers. **If this method does not throw, that does not mean your app is safe.** You need to take extra steps to prevent crashes. The details vary depending on the nature of your app. /// - Parameter backupURL: A file URL containing backup copies of all currently loaded persistent stores. /// - Throws: `CopyPersistentStoreError` in various situations. /// - Returns: Nothing. If no errors are thrown, the restore is complete. diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index c407f414..843554b2 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -766,6 +766,55 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context } } +func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, context: NSManagedObjectContext) { + + let logString = String.localizedStringWithFormat("mesh.log.security.config %@".localized, String(nodeNum)) + MeshLogger.log("🌐 \(logString)") + + let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) + + do { + let fetchedNode = try context.fetch(fetchNodeInfoRequest) + // Found a node, save Security Config + if !fetchedNode.isEmpty { + if fetchedNode[0].securityConfig == nil { + let newSecurityConfig = SecurityConfigEntity(context: context) + newSecurityConfig.publicKey = config.publicKey + newSecurityConfig.privateKey = config.privateKey + newSecurityConfig.adminKey = config.adminKey + newSecurityConfig.isManaged = config.isManaged + newSecurityConfig.serialEnabled = config.serialEnabled + newSecurityConfig.debugLogEnabled = config.debugLogEnabled + newSecurityConfig.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled + } else { + fetchedNode[0].securityConfig?.publicKey = config.publicKey + fetchedNode[0].securityConfig?.privateKey = config.privateKey + fetchedNode[0].securityConfig?.adminKey = config.adminKey + fetchedNode[0].securityConfig?.isManaged = config.isManaged + fetchedNode[0].securityConfig?.serialEnabled = config.serialEnabled + fetchedNode[0].securityConfig?.debugLogEnabled = config.debugLogEnabled + fetchedNode[0].securityConfig?.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled + } + + do { + try context.save() + Logger.data.info("💾 [NetworkConfigEntity] Updated Network Config for node: \(nodeNum.toHex(), privacy: .public)") + + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("💥 [NetworkConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)") + } + } else { + Logger.data.error("💥 [NetworkConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Network Config") + } + } catch { + let nsError = error as NSError + Logger.data.error("💥 [NetworkConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)") + } +} + func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightingConfig, nodeNum: Int64, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.ambientlighting.config %@".localized, String(nodeNum)) diff --git a/Meshtastic/Router/NavigationState.swift b/Meshtastic/Router/NavigationState.swift index b33fc48a..0ff61108 100644 --- a/Meshtastic/Router/NavigationState.swift +++ b/Meshtastic/Router/NavigationState.swift @@ -46,6 +46,7 @@ enum SettingsNavigationState: String { case paxCounter case ringtone case serial + case security case storeAndForward case telemetry case meshLog diff --git a/Meshtastic/Views/ContentView.swift b/Meshtastic/Views/ContentView.swift index b109a318..4ab6ac85 100644 --- a/Meshtastic/Views/ContentView.swift +++ b/Meshtastic/Views/ContentView.swift @@ -6,11 +6,8 @@ import SwiftUI @available(iOS 17.0, *) struct ContentView: View { - @ObservedObject - var appState: AppState - - @ObservedObject - var router: Router + @ObservedObject var appState: AppState + @ObservedObject var router: Router var body: some View { TabView(selection: Binding( diff --git a/Meshtastic/Views/Messages/MessageContextMenuItems.swift b/Meshtastic/Views/Messages/MessageContextMenuItems.swift index ab363f59..7835a723 100644 --- a/Meshtastic/Views/Messages/MessageContextMenuItems.swift +++ b/Meshtastic/Views/Messages/MessageContextMenuItems.swift @@ -13,6 +13,9 @@ struct MessageContextMenuItems: View { var body: some View { VStack { + if message.pkiEncrypted { + Label("Encrypted", systemImage: "lock") + } Text("channel") + Text(": \(message.channel)") } @@ -53,6 +56,7 @@ struct MessageContextMenuItems: View { let messageDate = Date(timeIntervalSince1970: TimeInterval(message.messageTimestamp)) Text("\(messageDate.formattedDate(format: MessageText.dateFormatString))").foregroundColor(.gray) } + if !isCurrentUser && !(message.fromUser?.userNode?.viaMqtt ?? false) && message.fromUser?.userNode?.hopsAway ?? -1 == 0 { VStack { Text("SNR \(String(format: "%.2f", message.snr)) dB") @@ -60,7 +64,7 @@ struct MessageContextMenuItems: View { } } else if !isCurrentUser && !(message.fromUser?.userNode?.viaMqtt ?? false) { VStack { - Text("Hops Away \(message.fromUser?.userNode?.hopsAway ?? 0)) dB") + Text("Hops Away \(message.fromUser?.userNode?.hopsAway ?? 0)") } } if isCurrentUser && message.receivedACK { diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 13eb837d..392ce4d0 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -32,6 +32,7 @@ struct UserList: View { @FetchRequest( sortDescriptors: [NSSortDescriptor(key: "lastMessage", ascending: false), NSSortDescriptor(key: "userNode.favorite", ascending: false), + NSSortDescriptor(key: "pkiEncrypted", ascending: false), NSSortDescriptor(key: "longName", ascending: true)], animation: .default ) @@ -69,6 +70,10 @@ struct UserList: View { VStack(alignment: .leading) { HStack { + if user.pkiEncrypted { + Image(systemName: "lock.fill") + .foregroundColor(.green) + } Text(user.longName ?? "unknown".localized) .font(.headline) Spacer() @@ -240,6 +245,7 @@ struct UserList: View { let searchPredicates = ["userId", "numString", "hwModel", "hwDisplayName", "longName", "shortName"].map { property in return NSPredicate(format: "%K CONTAINS[c] %@", property, searchText) } + /// Create a compound predicate using each text search preicate as an OR let textSearchPredicate = NSCompoundPredicate(type: .or, subpredicates: searchPredicates) /// Create an array of predicates to hold our AND predicates diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index c442b315..e05cb34b 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -37,7 +37,6 @@ struct NodeList: View { @State private var isPresentingDeleteNodeAlert = false @State private var deleteNodeId: Int64 = 0 - var boolFilters: [Bool] {[ isOnline, isFavorite, diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 57153785..47e56b18 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -20,27 +20,141 @@ struct SecurityConfig: View { var node: NodeInfoEntity? @State var hasChanges = false - @State var isManaged = false - @State var serialEnabled = true - @State var debugLogEnabled = false - @State var bluetoothLoggingEabled = false - @State var adminChannelEnabled = false @State var publicKey = "" @State var privateKey = "" @State var adminKey = "" + @State var isManaged = false + @State var serialEnabled = false + @State var debugLogEnabled = false + @State var bluetoothLoggingEnabled = false + @State var adminChannelEnabled = false var body: some View { VStack { Form { ConfigHeader(title: "Security", config: \.securityConfig, node: node, onAppear: setSecurityValues) + + Section(header: Text("Admin & Direct Message Keys")) { + VStack(alignment: .leading) { + Label("Public Key", systemImage: "key") + + Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") + .foregroundStyle(.secondary) + .font(.caption) + + TextField( + "Public Key", + text: $publicKey, + axis: .vertical + ) + .padding(5) + .keyboardType(.alphabet) + .foregroundColor(.secondary) + .disableAutocorrection(true) + .textSelection(.enabled) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) + ) + + } + VStack(alignment: .leading) { + Label("Private Key", systemImage: "key.fill") + + Text("Used to create a shared key with a remote device.") + .foregroundStyle(.secondary) + .font(.caption) + + TextField( + "Private Key", + text: $privateKey, + axis: .vertical + ) + .padding(5) + .disableAutocorrection(true) + .keyboardType(.alphabet) + .foregroundColor(.secondary) + .textSelection(.enabled) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) + ) + } + VStack(alignment: .leading) { + Label("Admin Key", systemImage: "key.viewfinder") + + Text("The public key authorized to send admin messages to this node.") + .foregroundStyle(.secondary) + .font(.caption) + + TextField( + "Admin Key", + text: $adminKey, + axis: .vertical + ) + .padding(5) + .disableAutocorrection(true) + .keyboardType(.alphabet) + .foregroundColor(.secondary) + .textSelection(.enabled) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) + ) + } + } + Section(header: Text("Logs")) { + Toggle(isOn: $bluetoothLoggingEnabled) { + Label("Bluetooth Logs", systemImage: "dot.radiowaves.right") + Text("View and export position-redacted device logs over Bluetooth") + Link("View Logs", destination: URL(string: "meshtastic:///settings/debugLogs")!) + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + } + Section(header: Text("Administration")) { + if adminKey.length > 0 || adminChannelEnabled { + Toggle(isOn: $isManaged) { + Label("Managed Device", systemImage: "gearshape.arrow.triangle.2.circlepath") + Text("Device is managed by a mesh administrator.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + } + Toggle(isOn: $adminChannelEnabled) { + Label("Legacy Administration", systemImage: "lock.slash") + Text("Allow incoming device control over the insecure legacy admin channel.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + } + Section(header: Text("Developer")) { + Toggle(isOn: $serialEnabled) { + Label("Serial Console", systemImage: "terminal") + Text("Serial Console over the Stream API.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + if serialEnabled { + Toggle(isOn: $debugLogEnabled) { + Label("Serial Debug Logs", systemImage: "ant.fill") + Text("Output live debug logging over serial.") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + } + } } } + .navigationTitle("Security Config") + .navigationBarItems(trailing: + ZStack { + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") + }) } func setSecurityValues() { + self.publicKey = node?.securityConfig?.publicKey?.base64EncodedString() ?? "" + self.privateKey = node?.securityConfig?.privateKey?.base64EncodedString() ?? "" + self.adminKey = node?.securityConfig?.adminKey?.base64EncodedString() ?? "" self.isManaged = node?.securityConfig?.isManaged ?? false self.serialEnabled = node?.securityConfig?.serialEnabled ?? false self.debugLogEnabled = node?.securityConfig?.debugLogEnabled ?? false - self.bluetoothLoggingEabled = node?.securityConfig?.bluetoothLoggingEabled ?? false + self.bluetoothLoggingEnabled = node?.securityConfig?.bluetoothLoggingEnabled ?? false self.adminChannelEnabled = node?.securityConfig?.adminChannelEnabled ?? false self.hasChanges = false } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 880dabf2..85aafd8f 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -73,6 +73,14 @@ struct Settings: View { } .disabled(selectedNode > 0 && selectedNode != preferredNodeNum) + NavigationLink(value: SettingsNavigationState.security) { + Label { + Text("Security") + } icon: { + Image(systemName: "lock.shield") + } + } + NavigationLink(value: SettingsNavigationState.shareQRCode) { Label { Text("share.channels") @@ -461,6 +469,8 @@ struct Settings: View { PaxCounterConfig(node: nodes.first(where: { $0.num == selectedNode })) case .ringtone: RtttlConfig(node: nodes.first(where: { $0.num == selectedNode })) + case .security: + SecurityConfig(node: nodes.first(where: { $0.num == selectedNode })) case .serial: SerialConfig(node: nodes.first(where: { $0.num == selectedNode })) case .storeAndForward: diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index f396367c..01e74689 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -85,6 +85,14 @@ public struct Config { set {payloadVariant = .bluetooth(newValue)} } + public var security: Config.SecurityConfig { + get { + if case .security(let v)? = payloadVariant {return v} + return Config.SecurityConfig() + } + set {payloadVariant = .security(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -97,6 +105,7 @@ public struct Config { case display(Config.DisplayConfig) case lora(Config.LoRaConfig) case bluetooth(Config.BluetoothConfig) + case security(Config.SecurityConfig) #if !swift(>=4.1) public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { @@ -132,6 +141,10 @@ public struct Config { guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } return l == r }() + case (.security, .security): return { + guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -151,11 +164,13 @@ public struct Config { /// /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI + /// Moved to SecurityConfig public var serialEnabled: Bool = false /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). /// Set this to true to leave the debug log outputting even when API is active. + /// Moved to SecurityConfig public var debugLogEnabled: Bool = false /// @@ -184,6 +199,7 @@ public struct Config { /// /// If true, device is considered to be "managed" by a mesh administrator /// Clients should then limit available configuration and administrative options inside the user interface + /// Moved to SecurityConfig public var isManaged: Bool = false /// @@ -1469,6 +1485,7 @@ public struct Config { /// /// Enables device (serial style logs) over Bluetooth + /// Moved to SecurityConfig public var deviceLoggingEnabled: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -1516,6 +1533,53 @@ public struct Config { public init() {} } + public struct SecurityConfig { + // 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 public key of the user's device. + /// This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + public var publicKey: Data = Data() + + /// + /// The private key of the device. + /// This is used to create a shared key with a remote device. + public var privateKey: Data = Data() + + /// + /// This is the public key authorized to send admin messages to this node + public var adminKey: Data = Data() + + /// + /// If true, device is considered to be "managed" by a mesh administrator + /// Clients should then limit available configuration and administrative options inside the user interface + public var isManaged: Bool = false + + /// + /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI + public var serialEnabled: Bool = false + + /// + /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). + /// Set this to true to leave the debug log outputting even when API is active. + public var debugLogEnabled: Bool = false + + /// + /// Enables device (serial style logs) over Bluetooth + /// Moved to SecurityConfig + public var bluetoothLoggingEnabled: Bool = false + + /// + /// Enables incoming admin control over the "admin" channel + public var adminChannelEnabled: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + } + public init() {} } @@ -1710,6 +1774,7 @@ extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} extension Config.BluetoothConfig: @unchecked Sendable {} extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} +extension Config.SecurityConfig: @unchecked Sendable {} #endif // swift(>=5.5) && canImport(_Concurrency) // MARK: - Code below here is support for the SwiftProtobuf runtime. @@ -1726,6 +1791,7 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas 5: .same(proto: "display"), 6: .same(proto: "lora"), 7: .same(proto: "bluetooth"), + 8: .same(proto: "security"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -1825,6 +1891,19 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas self.payloadVariant = .bluetooth(v) } }() + case 8: try { + var v: Config.SecurityConfig? + var hadOneofValue = false + if let current = self.payloadVariant { + hadOneofValue = true + if case .security(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.payloadVariant = .security(v) + } + }() default: break } } @@ -1864,6 +1943,10 @@ extension Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBas guard case .bluetooth(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 7) }() + case .security?: try { + guard case .security(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 8) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -2777,3 +2860,77 @@ extension Config.BluetoothConfig.PairingMode: SwiftProtobuf._ProtoNameProviding 2: .same(proto: "NO_PIN"), ] } + +extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Config.protoMessageName + ".SecurityConfig" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "public_key"), + 2: .standard(proto: "private_key"), + 3: .standard(proto: "admin_key"), + 4: .standard(proto: "is_managed"), + 5: .standard(proto: "serial_enabled"), + 6: .standard(proto: "debug_log_enabled"), + 7: .standard(proto: "bluetooth_logging_enabled"), + 8: .standard(proto: "admin_channel_enabled"), + ] + + public 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.decodeSingularBytesField(value: &self.publicKey) }() + case 2: try { try decoder.decodeSingularBytesField(value: &self.privateKey) }() + case 3: try { try decoder.decodeSingularBytesField(value: &self.adminKey) }() + case 4: try { try decoder.decodeSingularBoolField(value: &self.isManaged) }() + case 5: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() + case 6: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }() + case 7: try { try decoder.decodeSingularBoolField(value: &self.bluetoothLoggingEnabled) }() + case 8: try { try decoder.decodeSingularBoolField(value: &self.adminChannelEnabled) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.publicKey.isEmpty { + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 1) + } + if !self.privateKey.isEmpty { + try visitor.visitSingularBytesField(value: self.privateKey, fieldNumber: 2) + } + if !self.adminKey.isEmpty { + try visitor.visitSingularBytesField(value: self.adminKey, fieldNumber: 3) + } + if self.isManaged != false { + try visitor.visitSingularBoolField(value: self.isManaged, fieldNumber: 4) + } + if self.serialEnabled != false { + try visitor.visitSingularBoolField(value: self.serialEnabled, fieldNumber: 5) + } + if self.debugLogEnabled != false { + try visitor.visitSingularBoolField(value: self.debugLogEnabled, fieldNumber: 6) + } + if self.bluetoothLoggingEnabled != false { + try visitor.visitSingularBoolField(value: self.bluetoothLoggingEnabled, fieldNumber: 7) + } + if self.adminChannelEnabled != false { + try visitor.visitSingularBoolField(value: self.adminChannelEnabled, fieldNumber: 8) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Config.SecurityConfig, rhs: Config.SecurityConfig) -> Bool { + if lhs.publicKey != rhs.publicKey {return false} + if lhs.privateKey != rhs.privateKey {return false} + if lhs.adminKey != rhs.adminKey {return false} + if lhs.isManaged != rhs.isManaged {return false} + if lhs.serialEnabled != rhs.serialEnabled {return false} + if lhs.debugLogEnabled != rhs.debugLogEnabled {return false} + if lhs.bluetoothLoggingEnabled != rhs.bluetoothLoggingEnabled {return false} + if lhs.adminChannelEnabled != rhs.adminChannelEnabled {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index 5e30d1cd..0af27466 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -111,6 +111,17 @@ public struct LocalConfig { set {_uniqueStorage()._version = newValue} } + /// + /// The part of the config that is specific to Security settings + public var security: Config.SecurityConfig { + get {return _storage._security ?? Config.SecurityConfig()} + set {_uniqueStorage()._security = newValue} + } + /// Returns true if `security` has been explicitly set. + public var hasSecurity: Bool {return _storage._security != nil} + /// Clears the value of `security`. Subsequent reads from it will return its default value. + public mutating func clearSecurity() {_uniqueStorage()._security = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -302,6 +313,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati 6: .same(proto: "lora"), 7: .same(proto: "bluetooth"), 8: .same(proto: "version"), + 9: .same(proto: "security"), ] fileprivate class _StorageClass { @@ -313,6 +325,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati var _lora: Config.LoRaConfig? = nil var _bluetooth: Config.BluetoothConfig? = nil var _version: UInt32 = 0 + var _security: Config.SecurityConfig? = nil #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -335,6 +348,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati _lora = source._lora _bluetooth = source._bluetooth _version = source._version + _security = source._security } } @@ -361,6 +375,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati case 6: try { try decoder.decodeSingularMessageField(value: &_storage._lora) }() case 7: try { try decoder.decodeSingularMessageField(value: &_storage._bluetooth) }() case 8: try { try decoder.decodeSingularUInt32Field(value: &_storage._version) }() + case 9: try { try decoder.decodeSingularMessageField(value: &_storage._security) }() default: break } } @@ -397,6 +412,9 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if _storage._version != 0 { try visitor.visitSingularUInt32Field(value: _storage._version, fieldNumber: 8) } + try { if let v = _storage._security { + try visitor.visitSingularMessageField(value: v, fieldNumber: 9) + } }() } try unknownFields.traverse(visitor: &visitor) } @@ -414,6 +432,7 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati if _storage._lora != rhs_storage._lora {return false} if _storage._bluetooth != rhs_storage._bluetooth {return false} if _storage._version != rhs_storage._version {return false} + if _storage._security != rhs_storage._security {return false} return true } if !storagesAreEqual {return false} diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index b12cc13f..f0a7c55c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -1158,6 +1158,11 @@ public struct User { /// Indicates that the user's role in the mesh public var role: Config.DeviceConfig.Role = .client + /// + /// The public key of the user's device. + /// This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + public var publicKey: Data = Data() + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -1714,6 +1719,20 @@ public struct MeshPacket { set {_uniqueStorage()._hopStart = newValue} } + /// + /// Records the public key the packet was encrypted with, if applicable. + public var publicKey: Data { + get {return _storage._publicKey} + set {_uniqueStorage()._publicKey = newValue} + } + + /// + /// Indicates whether the packet was en/decrypted using PKI + public var pkiEncrypted: Bool { + get {return _storage._pkiEncrypted} + set {_uniqueStorage()._pkiEncrypted = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_PayloadVariant: Equatable { @@ -3367,6 +3386,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, 5: .standard(proto: "hw_model"), 6: .standard(proto: "is_licensed"), 7: .same(proto: "role"), + 8: .standard(proto: "public_key"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3382,6 +3402,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, case 5: try { try decoder.decodeSingularEnumField(value: &self.hwModel) }() case 6: try { try decoder.decodeSingularBoolField(value: &self.isLicensed) }() case 7: try { try decoder.decodeSingularEnumField(value: &self.role) }() + case 8: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }() default: break } } @@ -3409,6 +3430,9 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, if self.role != .client { try visitor.visitSingularEnumField(value: self.role, fieldNumber: 7) } + if !self.publicKey.isEmpty { + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 8) + } try unknownFields.traverse(visitor: &visitor) } @@ -3420,6 +3444,7 @@ extension User: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, if lhs.hwModel != rhs.hwModel {return false} if lhs.isLicensed != rhs.isLicensed {return false} if lhs.role != rhs.role {return false} + if lhs.publicKey != rhs.publicKey {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -3795,6 +3820,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio 13: .same(proto: "delayed"), 14: .standard(proto: "via_mqtt"), 15: .standard(proto: "hop_start"), + 16: .standard(proto: "public_key"), + 17: .standard(proto: "pki_encrypted"), ] fileprivate class _StorageClass { @@ -3812,6 +3839,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio var _delayed: MeshPacket.Delayed = .noDelay var _viaMqtt: Bool = false var _hopStart: UInt32 = 0 + var _publicKey: Data = Data() + var _pkiEncrypted: Bool = false #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -3840,6 +3869,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio _delayed = source._delayed _viaMqtt = source._viaMqtt _hopStart = source._hopStart + _publicKey = source._publicKey + _pkiEncrypted = source._pkiEncrypted } } @@ -3892,6 +3923,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio case 13: try { try decoder.decodeSingularEnumField(value: &_storage._delayed) }() case 14: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }() case 15: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopStart) }() + case 16: try { try decoder.decodeSingularBytesField(value: &_storage._publicKey) }() + case 17: try { try decoder.decodeSingularBoolField(value: &_storage._pkiEncrypted) }() default: break } } @@ -3954,6 +3987,12 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._hopStart != 0 { try visitor.visitSingularUInt32Field(value: _storage._hopStart, fieldNumber: 15) } + if !_storage._publicKey.isEmpty { + try visitor.visitSingularBytesField(value: _storage._publicKey, fieldNumber: 16) + } + if _storage._pkiEncrypted != false { + try visitor.visitSingularBoolField(value: _storage._pkiEncrypted, fieldNumber: 17) + } } try unknownFields.traverse(visitor: &visitor) } @@ -3977,6 +4016,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._delayed != rhs_storage._delayed {return false} if _storage._viaMqtt != rhs_storage._viaMqtt {return false} if _storage._hopStart != rhs_storage._hopStart {return false} + if _storage._publicKey != rhs_storage._publicKey {return false} + if _storage._pkiEncrypted != rhs_storage._pkiEncrypted {return false} return true } if !storagesAreEqual {return false} diff --git a/protobufs b/protobufs index d0fe91ab..81fd9d37 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit d0fe91ab99734cacdc188403f73fe30f766917cf +Subproject commit 81fd9d374f1b364c2812b7a0ca2784a7605b6835 From a274d6fcf8f03e6ef0ebb6d31dd24d0c3bfd4ed6 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 8 Aug 2024 10:39:45 -0700 Subject: [PATCH 04/75] Update protos --- Meshtastic/Helpers/BLEManager.swift | 2 +- .../contents | 2 +- Meshtastic/Persistence/UpdateCoreData.swift | 4 +- .../Settings/Config/SecurityConfig.swift | 6 +- .../Sources/meshtastic/admin.pb.swift | 54 +- .../Sources/meshtastic/config.pb.swift | 40 +- .../Sources/meshtastic/mesh.pb.swift | 277 +++++-- .../Sources/meshtastic/telemetry.pb.swift | 717 ++++++++++++------ protobufs | 2 +- 9 files changed, 799 insertions(+), 305 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 13941ec9..ec03b2f8 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1388,7 +1388,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendFactoryReset(fromUser: UserEntity, toUser: UserEntity) -> Bool { var adminPacket = AdminMessage() - adminPacket.factoryReset = 5 + adminPacket.factoryResetConfig = 5 var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents index a04f71ea..432be802 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents @@ -341,7 +341,7 @@ - + diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 843554b2..304c6a77 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -785,7 +785,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c newSecurityConfig.adminKey = config.adminKey newSecurityConfig.isManaged = config.isManaged newSecurityConfig.serialEnabled = config.serialEnabled - newSecurityConfig.debugLogEnabled = config.debugLogEnabled + newSecurityConfig.debugLogApiEnabled = config.debugLogApiEnabled newSecurityConfig.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled } else { fetchedNode[0].securityConfig?.publicKey = config.publicKey @@ -793,7 +793,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c fetchedNode[0].securityConfig?.adminKey = config.adminKey fetchedNode[0].securityConfig?.isManaged = config.isManaged fetchedNode[0].securityConfig?.serialEnabled = config.serialEnabled - fetchedNode[0].securityConfig?.debugLogEnabled = config.debugLogEnabled + fetchedNode[0].securityConfig?.debugLogApiEnabled = config.debugLogApiEnabled fetchedNode[0].securityConfig?.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled } diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 47e56b18..4c8bd85a 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -25,7 +25,7 @@ struct SecurityConfig: View { @State var adminKey = "" @State var isManaged = false @State var serialEnabled = false - @State var debugLogEnabled = false + @State var debugLogApiEnabled = false @State var bluetoothLoggingEnabled = false @State var adminChannelEnabled = false @@ -132,7 +132,7 @@ struct SecurityConfig: View { } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) if serialEnabled { - Toggle(isOn: $debugLogEnabled) { + Toggle(isOn: $debugLogApiEnabled) { Label("Serial Debug Logs", systemImage: "ant.fill") Text("Output live debug logging over serial.") } @@ -153,7 +153,7 @@ struct SecurityConfig: View { self.adminKey = node?.securityConfig?.adminKey?.base64EncodedString() ?? "" self.isManaged = node?.securityConfig?.isManaged ?? false self.serialEnabled = node?.securityConfig?.serialEnabled ?? false - self.debugLogEnabled = node?.securityConfig?.debugLogEnabled ?? false + self.debugLogApiEnabled = node?.securityConfig?.debugLogApiEnabled ?? false self.bluetoothLoggingEnabled = node?.securityConfig?.bluetoothLoggingEnabled ?? false self.adminChannelEnabled = node?.securityConfig?.adminChannelEnabled ?? false self.hasChanges = false diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index ba263709..f526f4ca 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -390,6 +390,16 @@ public struct AdminMessage { set {payloadVariant = .commitEditSettings(newValue)} } + /// + /// Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. + public var factoryResetDevice: Int32 { + get { + if case .factoryResetDevice(let v)? = payloadVariant {return v} + return 0 + } + set {payloadVariant = .factoryResetDevice(newValue)} + } + /// /// Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) /// Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. @@ -433,13 +443,13 @@ public struct AdminMessage { } /// - /// Tell the node to factory reset, all device settings will be returned to factory defaults. - public var factoryReset: Int32 { + /// Tell the node to factory reset config; all device state and configuration will be returned to factory defaults; BLE bonds will be preserved. + public var factoryResetConfig: Int32 { get { - if case .factoryReset(let v)? = payloadVariant {return v} + if case .factoryResetConfig(let v)? = payloadVariant {return v} return 0 } - set {payloadVariant = .factoryReset(newValue)} + set {payloadVariant = .factoryResetConfig(newValue)} } /// @@ -570,6 +580,9 @@ public struct AdminMessage { /// Commits an open transaction for any edits made to config, module config, owner, and channel settings case commitEditSettings(Bool) /// + /// Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. + case factoryResetDevice(Int32) + /// /// Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) /// Only Implemented for ESP32 Devices. This needs to be issued to send a new main firmware via bluetooth. case rebootOtaSeconds(Int32) @@ -584,8 +597,8 @@ public struct AdminMessage { /// Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) case shutdownSeconds(Int32) /// - /// Tell the node to factory reset, all device settings will be returned to factory defaults. - case factoryReset(Int32) + /// Tell the node to factory reset config; all device state and configuration will be returned to factory defaults; BLE bonds will be preserved. + case factoryResetConfig(Int32) /// /// Tell the node to reset the nodedb. case nodedbReset(Int32) @@ -736,6 +749,10 @@ public struct AdminMessage { guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } return l == r }() + case (.factoryResetDevice, .factoryResetDevice): return { + guard case .factoryResetDevice(let l) = lhs, case .factoryResetDevice(let r) = rhs else { preconditionFailure() } + return l == r + }() case (.rebootOtaSeconds, .rebootOtaSeconds): return { guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } return l == r @@ -752,8 +769,8 @@ public struct AdminMessage { guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } return l == r }() - case (.factoryReset, .factoryReset): return { - guard case .factoryReset(let l) = lhs, case .factoryReset(let r) = rhs else { preconditionFailure() } + case (.factoryResetConfig, .factoryResetConfig): return { + guard case .factoryResetConfig(let l) = lhs, case .factoryResetConfig(let r) = rhs else { preconditionFailure() } return l == r }() case (.nodedbReset, .nodedbReset): return { @@ -1070,11 +1087,12 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat 42: .standard(proto: "remove_fixed_position"), 64: .standard(proto: "begin_edit_settings"), 65: .standard(proto: "commit_edit_settings"), + 94: .standard(proto: "factory_reset_device"), 95: .standard(proto: "reboot_ota_seconds"), 96: .standard(proto: "exit_simulator"), 97: .standard(proto: "reboot_seconds"), 98: .standard(proto: "shutdown_seconds"), - 99: .standard(proto: "factory_reset"), + 99: .standard(proto: "factory_reset_config"), 100: .standard(proto: "nodedb_reset"), ] @@ -1429,6 +1447,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat self.payloadVariant = .commitEditSettings(v) } }() + case 94: try { + var v: Int32? + try decoder.decodeSingularInt32Field(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .factoryResetDevice(v) + } + }() case 95: try { var v: Int32? try decoder.decodeSingularInt32Field(value: &v) @@ -1466,7 +1492,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try decoder.decodeSingularInt32Field(value: &v) if let v = v { if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} - self.payloadVariant = .factoryReset(v) + self.payloadVariant = .factoryResetConfig(v) } }() case 100: try { @@ -1628,6 +1654,10 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat guard case .commitEditSettings(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 65) }() + case .factoryResetDevice?: try { + guard case .factoryResetDevice(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularInt32Field(value: v, fieldNumber: 94) + }() case .rebootOtaSeconds?: try { guard case .rebootOtaSeconds(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularInt32Field(value: v, fieldNumber: 95) @@ -1644,8 +1674,8 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat guard case .shutdownSeconds(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularInt32Field(value: v, fieldNumber: 98) }() - case .factoryReset?: try { - guard case .factoryReset(let v)? = self.payloadVariant else { preconditionFailure() } + case .factoryResetConfig?: try { + guard case .factoryResetConfig(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularInt32Field(value: v, fieldNumber: 99) }() case .nodedbReset?: try { diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index 01e74689..4b953470 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -1404,6 +1404,7 @@ public struct Config { /// /// Very Long Range - Slow + /// Deprecated in 2.5: Works only with txco and is unusably slow case veryLongSlow // = 2 /// @@ -1425,6 +1426,12 @@ public struct Config { /// /// Long Range - Moderately Fast case longModerate // = 7 + + /// + /// Short Range - Turbo + /// This is the fastest preset and the only one with 500kHz bandwidth. + /// It is not legal to use in all regions due to this wider bandwidth. + case shortTurbo // = 8 case UNRECOGNIZED(Int) public init() { @@ -1441,6 +1448,7 @@ public struct Config { case 5: self = .shortSlow case 6: self = .shortFast case 7: self = .longModerate + case 8: self = .shortTurbo default: self = .UNRECOGNIZED(rawValue) } } @@ -1455,6 +1463,7 @@ public struct Config { case .shortSlow: return 5 case .shortFast: return 6 case .longModerate: return 7 + case .shortTurbo: return 8 case .UNRECOGNIZED(let i): return i } } @@ -1540,39 +1549,38 @@ public struct Config { /// /// The public key of the user's device. - /// This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + /// Sent out to other nodes on the mesh to allow them to compute a shared secret key. public var publicKey: Data = Data() /// /// The private key of the device. - /// This is used to create a shared key with a remote device. + /// Used to create a shared key with a remote device. public var privateKey: Data = Data() /// - /// This is the public key authorized to send admin messages to this node + /// The public key authorized to send admin messages to this node. public var adminKey: Data = Data() /// - /// If true, device is considered to be "managed" by a mesh administrator - /// Clients should then limit available configuration and administrative options inside the user interface + /// If true, device is considered to be "managed" by a mesh administrator via admin messages + /// Device is managed by a mesh administrator. public var isManaged: Bool = false /// - /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI + /// Serial Console over the Stream API." public var serialEnabled: Bool = false /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). - /// Set this to true to leave the debug log outputting even when API is active. - public var debugLogEnabled: Bool = false + /// Output live debug logging over serial. + public var debugLogApiEnabled: Bool = false /// /// Enables device (serial style logs) over Bluetooth - /// Moved to SecurityConfig public var bluetoothLoggingEnabled: Bool = false /// - /// Enables incoming admin control over the "admin" channel + /// Allow incoming device control over the insecure legacy admin channel. public var adminChannelEnabled: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -1736,6 +1744,7 @@ extension Config.LoRaConfig.ModemPreset: CaseIterable { .shortSlow, .shortFast, .longModerate, + .shortTurbo, ] } @@ -2800,6 +2809,7 @@ extension Config.LoRaConfig.ModemPreset: SwiftProtobuf._ProtoNameProviding { 5: .same(proto: "SHORT_SLOW"), 6: .same(proto: "SHORT_FAST"), 7: .same(proto: "LONG_MODERATE"), + 8: .same(proto: "SHORT_TURBO"), ] } @@ -2869,7 +2879,7 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm 3: .standard(proto: "admin_key"), 4: .standard(proto: "is_managed"), 5: .standard(proto: "serial_enabled"), - 6: .standard(proto: "debug_log_enabled"), + 6: .standard(proto: "debug_log_api_enabled"), 7: .standard(proto: "bluetooth_logging_enabled"), 8: .standard(proto: "admin_channel_enabled"), ] @@ -2885,7 +2895,7 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm case 3: try { try decoder.decodeSingularBytesField(value: &self.adminKey) }() case 4: try { try decoder.decodeSingularBoolField(value: &self.isManaged) }() case 5: try { try decoder.decodeSingularBoolField(value: &self.serialEnabled) }() - case 6: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }() + case 6: try { try decoder.decodeSingularBoolField(value: &self.debugLogApiEnabled) }() case 7: try { try decoder.decodeSingularBoolField(value: &self.bluetoothLoggingEnabled) }() case 8: try { try decoder.decodeSingularBoolField(value: &self.adminChannelEnabled) }() default: break @@ -2909,8 +2919,8 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if self.serialEnabled != false { try visitor.visitSingularBoolField(value: self.serialEnabled, fieldNumber: 5) } - if self.debugLogEnabled != false { - try visitor.visitSingularBoolField(value: self.debugLogEnabled, fieldNumber: 6) + if self.debugLogApiEnabled != false { + try visitor.visitSingularBoolField(value: self.debugLogApiEnabled, fieldNumber: 6) } if self.bluetoothLoggingEnabled != false { try visitor.visitSingularBoolField(value: self.bluetoothLoggingEnabled, fieldNumber: 7) @@ -2927,7 +2937,7 @@ extension Config.SecurityConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm if lhs.adminKey != rhs.adminKey {return false} if lhs.isManaged != rhs.isManaged {return false} if lhs.serialEnabled != rhs.serialEnabled {return false} - if lhs.debugLogEnabled != rhs.debugLogEnabled {return false} + if lhs.debugLogApiEnabled != rhs.debugLogApiEnabled {return false} if lhs.bluetoothLoggingEnabled != rhs.bluetoothLoggingEnabled {return false} if lhs.adminChannelEnabled != rhs.adminChannelEnabled {return false} if lhs.unknownFields != rhs.unknownFields {return false} diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index f0a7c55c..489cd8e3 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -782,23 +782,35 @@ public struct Position { /// The new preferred location encoding, multiply by 1e-7 to get degrees /// in floating point public var latitudeI: Int32 { - get {return _storage._latitudeI} + get {return _storage._latitudeI ?? 0} set {_uniqueStorage()._latitudeI = newValue} } + /// Returns true if `latitudeI` has been explicitly set. + public var hasLatitudeI: Bool {return _storage._latitudeI != nil} + /// Clears the value of `latitudeI`. Subsequent reads from it will return its default value. + public mutating func clearLatitudeI() {_uniqueStorage()._latitudeI = nil} /// /// TODO: REPLACE public var longitudeI: Int32 { - get {return _storage._longitudeI} + get {return _storage._longitudeI ?? 0} set {_uniqueStorage()._longitudeI = newValue} } + /// Returns true if `longitudeI` has been explicitly set. + public var hasLongitudeI: Bool {return _storage._longitudeI != nil} + /// Clears the value of `longitudeI`. Subsequent reads from it will return its default value. + public mutating func clearLongitudeI() {_uniqueStorage()._longitudeI = nil} /// /// In meters above MSL (but see issue #359) public var altitude: Int32 { - get {return _storage._altitude} + get {return _storage._altitude ?? 0} set {_uniqueStorage()._altitude = newValue} } + /// Returns true if `altitude` has been explicitly set. + public var hasAltitude: Bool {return _storage._altitude != nil} + /// Clears the value of `altitude`. Subsequent reads from it will return its default value. + public mutating func clearAltitude() {_uniqueStorage()._altitude = nil} /// /// This is usually not sent over the mesh (to save space), but it is sent @@ -841,16 +853,24 @@ public struct Position { /// /// HAE altitude in meters - can be used instead of MSL altitude public var altitudeHae: Int32 { - get {return _storage._altitudeHae} + get {return _storage._altitudeHae ?? 0} set {_uniqueStorage()._altitudeHae = newValue} } + /// Returns true if `altitudeHae` has been explicitly set. + public var hasAltitudeHae: Bool {return _storage._altitudeHae != nil} + /// Clears the value of `altitudeHae`. Subsequent reads from it will return its default value. + public mutating func clearAltitudeHae() {_uniqueStorage()._altitudeHae = nil} /// /// Geoidal separation in meters public var altitudeGeoidalSeparation: Int32 { - get {return _storage._altitudeGeoidalSeparation} + get {return _storage._altitudeGeoidalSeparation ?? 0} set {_uniqueStorage()._altitudeGeoidalSeparation = newValue} } + /// Returns true if `altitudeGeoidalSeparation` has been explicitly set. + public var hasAltitudeGeoidalSeparation: Bool {return _storage._altitudeGeoidalSeparation != nil} + /// Clears the value of `altitudeGeoidalSeparation`. Subsequent reads from it will return its default value. + public mutating func clearAltitudeGeoidalSeparation() {_uniqueStorage()._altitudeGeoidalSeparation = nil} /// /// Horizontal, Vertical and Position Dilution of Precision, in 1/100 units @@ -894,16 +914,24 @@ public struct Position { /// - "yaw" indicates a relative rotation about the vertical axis /// TODO: REMOVE/INTEGRATE public var groundSpeed: UInt32 { - get {return _storage._groundSpeed} + get {return _storage._groundSpeed ?? 0} set {_uniqueStorage()._groundSpeed = newValue} } + /// Returns true if `groundSpeed` has been explicitly set. + public var hasGroundSpeed: Bool {return _storage._groundSpeed != nil} + /// Clears the value of `groundSpeed`. Subsequent reads from it will return its default value. + public mutating func clearGroundSpeed() {_uniqueStorage()._groundSpeed = nil} /// /// TODO: REPLACE public var groundTrack: UInt32 { - get {return _storage._groundTrack} + get {return _storage._groundTrack ?? 0} set {_uniqueStorage()._groundTrack = newValue} } + /// Returns true if `groundTrack` has been explicitly set. + public var hasGroundTrack: Bool {return _storage._groundTrack != nil} + /// Clears the value of `groundTrack`. Subsequent reads from it will return its default value. + public mutating func clearGroundTrack() {_uniqueStorage()._groundTrack = nil} /// /// GPS fix quality (from NMEA GxGGA statement or similar) @@ -1455,11 +1483,25 @@ public struct Waypoint { /// /// latitude_i - public var latitudeI: Int32 = 0 + public var latitudeI: Int32 { + get {return _latitudeI ?? 0} + set {_latitudeI = newValue} + } + /// Returns true if `latitudeI` has been explicitly set. + public var hasLatitudeI: Bool {return self._latitudeI != nil} + /// Clears the value of `latitudeI`. Subsequent reads from it will return its default value. + public mutating func clearLatitudeI() {self._latitudeI = nil} /// /// longitude_i - public var longitudeI: Int32 = 0 + public var longitudeI: Int32 { + get {return _longitudeI ?? 0} + set {_longitudeI = newValue} + } + /// Returns true if `longitudeI` has been explicitly set. + public var hasLongitudeI: Bool {return self._longitudeI != nil} + /// Clears the value of `longitudeI`. Subsequent reads from it will return its default value. + public mutating func clearLongitudeI() {self._longitudeI = nil} /// /// Time the waypoint is to expire (epoch) @@ -1485,6 +1527,9 @@ public struct Waypoint { public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _latitudeI: Int32? = nil + fileprivate var _longitudeI: Int32? = nil } /// @@ -2369,6 +2414,16 @@ public struct FromRadio { set {payloadVariant = .fileInfo(newValue)} } + /// + /// Notification message to the client + public var clientNotification: ClientNotification { + get { + if case .clientNotification(let v)? = payloadVariant {return v} + return ClientNotification() + } + set {payloadVariant = .clientNotification(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() /// @@ -2424,6 +2479,9 @@ public struct FromRadio { /// /// File system manifest messages case fileInfo(FileInfo) + /// + /// Notification message to the client + case clientNotification(ClientNotification) #if !swift(>=4.1) public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { @@ -2487,6 +2545,10 @@ public struct FromRadio { guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } return l == r }() + case (.clientNotification, .clientNotification): return { + guard case .clientNotification(let l) = lhs, case .clientNotification(let r) = rhs else { preconditionFailure() } + return l == r + }() default: return false } } @@ -2496,6 +2558,46 @@ public struct FromRadio { public init() {} } +/// +/// A notification message from the device to the client +/// To be used for important messages that should to be displayed to the user +/// in the form of push notifications or validation messages when saving +/// invalid configuration. +public struct ClientNotification { + // 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 id of the packet we're notifying in response to + public var replyID: UInt32 { + get {return _replyID ?? 0} + set {_replyID = newValue} + } + /// Returns true if `replyID` has been explicitly set. + public var hasReplyID: Bool {return self._replyID != nil} + /// Clears the value of `replyID`. Subsequent reads from it will return its default value. + public mutating func clearReplyID() {self._replyID = nil} + + /// + /// Seconds since 1970 - or 0 for unknown/unset + public var time: UInt32 = 0 + + /// + /// The level type of notification + public var level: LogRecord.Level = .unset + + /// + /// The message body of the notification + public var message: String = String() + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _replyID: UInt32? = nil +} + /// /// Individual File info for the device public struct FileInfo { @@ -2987,6 +3089,7 @@ extension LogRecord.Level: @unchecked Sendable {} extension QueueStatus: @unchecked Sendable {} extension FromRadio: @unchecked Sendable {} extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} +extension ClientNotification: @unchecked Sendable {} extension FileInfo: @unchecked Sendable {} extension ToRadio: @unchecked Sendable {} extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} @@ -3138,22 +3241,22 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB ] fileprivate class _StorageClass { - var _latitudeI: Int32 = 0 - var _longitudeI: Int32 = 0 - var _altitude: Int32 = 0 + var _latitudeI: Int32? = nil + var _longitudeI: Int32? = nil + var _altitude: Int32? = nil var _time: UInt32 = 0 var _locationSource: Position.LocSource = .locUnset var _altitudeSource: Position.AltSource = .altUnset var _timestamp: UInt32 = 0 var _timestampMillisAdjust: Int32 = 0 - var _altitudeHae: Int32 = 0 - var _altitudeGeoidalSeparation: Int32 = 0 + var _altitudeHae: Int32? = nil + var _altitudeGeoidalSeparation: Int32? = nil var _pdop: UInt32 = 0 var _hdop: UInt32 = 0 var _vdop: UInt32 = 0 var _gpsAccuracy: UInt32 = 0 - var _groundSpeed: UInt32 = 0 - var _groundTrack: UInt32 = 0 + var _groundSpeed: UInt32? = nil + var _groundTrack: UInt32? = nil var _fixQuality: UInt32 = 0 var _fixType: UInt32 = 0 var _satsInView: UInt32 = 0 @@ -3247,15 +3350,19 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public func traverse(visitor: inout V) throws { try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - if _storage._latitudeI != 0 { - try visitor.visitSingularSFixed32Field(value: _storage._latitudeI, fieldNumber: 1) - } - if _storage._longitudeI != 0 { - try visitor.visitSingularSFixed32Field(value: _storage._longitudeI, fieldNumber: 2) - } - if _storage._altitude != 0 { - try visitor.visitSingularInt32Field(value: _storage._altitude, fieldNumber: 3) - } + // 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._latitudeI { + try visitor.visitSingularSFixed32Field(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._longitudeI { + try visitor.visitSingularSFixed32Field(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._altitude { + try visitor.visitSingularInt32Field(value: v, fieldNumber: 3) + } }() if _storage._time != 0 { try visitor.visitSingularFixed32Field(value: _storage._time, fieldNumber: 4) } @@ -3271,12 +3378,12 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if _storage._timestampMillisAdjust != 0 { try visitor.visitSingularInt32Field(value: _storage._timestampMillisAdjust, fieldNumber: 8) } - if _storage._altitudeHae != 0 { - try visitor.visitSingularSInt32Field(value: _storage._altitudeHae, fieldNumber: 9) - } - if _storage._altitudeGeoidalSeparation != 0 { - try visitor.visitSingularSInt32Field(value: _storage._altitudeGeoidalSeparation, fieldNumber: 10) - } + try { if let v = _storage._altitudeHae { + try visitor.visitSingularSInt32Field(value: v, fieldNumber: 9) + } }() + try { if let v = _storage._altitudeGeoidalSeparation { + try visitor.visitSingularSInt32Field(value: v, fieldNumber: 10) + } }() if _storage._pdop != 0 { try visitor.visitSingularUInt32Field(value: _storage._pdop, fieldNumber: 11) } @@ -3289,12 +3396,12 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if _storage._gpsAccuracy != 0 { try visitor.visitSingularUInt32Field(value: _storage._gpsAccuracy, fieldNumber: 14) } - if _storage._groundSpeed != 0 { - try visitor.visitSingularUInt32Field(value: _storage._groundSpeed, fieldNumber: 15) - } - if _storage._groundTrack != 0 { - try visitor.visitSingularUInt32Field(value: _storage._groundTrack, fieldNumber: 16) - } + try { if let v = _storage._groundSpeed { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 15) + } }() + try { if let v = _storage._groundTrack { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 16) + } }() if _storage._fixQuality != 0 { try visitor.visitSingularUInt32Field(value: _storage._fixQuality, fieldNumber: 17) } @@ -3676,8 +3783,8 @@ extension Waypoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularUInt32Field(value: &self.id) }() - case 2: try { try decoder.decodeSingularSFixed32Field(value: &self.latitudeI) }() - case 3: try { try decoder.decodeSingularSFixed32Field(value: &self.longitudeI) }() + case 2: try { try decoder.decodeSingularSFixed32Field(value: &self._latitudeI) }() + case 3: try { try decoder.decodeSingularSFixed32Field(value: &self._longitudeI) }() case 4: try { try decoder.decodeSingularUInt32Field(value: &self.expire) }() case 5: try { try decoder.decodeSingularUInt32Field(value: &self.lockedTo) }() case 6: try { try decoder.decodeSingularStringField(value: &self.name) }() @@ -3689,15 +3796,19 @@ extension Waypoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB } public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 if self.id != 0 { try visitor.visitSingularUInt32Field(value: self.id, fieldNumber: 1) } - if self.latitudeI != 0 { - try visitor.visitSingularSFixed32Field(value: self.latitudeI, fieldNumber: 2) - } - if self.longitudeI != 0 { - try visitor.visitSingularSFixed32Field(value: self.longitudeI, fieldNumber: 3) - } + try { if let v = self._latitudeI { + try visitor.visitSingularSFixed32Field(value: v, fieldNumber: 2) + } }() + try { if let v = self._longitudeI { + try visitor.visitSingularSFixed32Field(value: v, fieldNumber: 3) + } }() if self.expire != 0 { try visitor.visitSingularUInt32Field(value: self.expire, fieldNumber: 4) } @@ -3718,8 +3829,8 @@ extension Waypoint: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static func ==(lhs: Waypoint, rhs: Waypoint) -> Bool { if lhs.id != rhs.id {return false} - if lhs.latitudeI != rhs.latitudeI {return false} - if lhs.longitudeI != rhs.longitudeI {return false} + if lhs._latitudeI != rhs._latitudeI {return false} + if lhs._longitudeI != rhs._longitudeI {return false} if lhs.expire != rhs.expire {return false} if lhs.lockedTo != rhs.lockedTo {return false} if lhs.name != rhs.name {return false} @@ -4369,6 +4480,7 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation 13: .same(proto: "metadata"), 14: .same(proto: "mqttClientProxyMessage"), 15: .same(proto: "fileInfo"), + 16: .same(proto: "clientNotification"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -4550,6 +4662,19 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation self.payloadVariant = .fileInfo(v) } }() + case 16: try { + var v: ClientNotification? + var hadOneofValue = false + if let current = self.payloadVariant { + hadOneofValue = true + if case .clientNotification(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.payloadVariant = .clientNotification(v) + } + }() default: break } } @@ -4620,6 +4745,10 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation guard case .fileInfo(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 15) }() + case .clientNotification?: try { + guard case .clientNotification(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 16) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -4633,6 +4762,60 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation } } +extension ClientNotification: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".ClientNotification" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "reply_id"), + 2: .same(proto: "time"), + 3: .same(proto: "level"), + 4: .same(proto: "message"), + ] + + public 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.decodeSingularUInt32Field(value: &self._replyID) }() + case 2: try { try decoder.decodeSingularFixed32Field(value: &self.time) }() + case 3: try { try decoder.decodeSingularEnumField(value: &self.level) }() + case 4: try { try decoder.decodeSingularStringField(value: &self.message) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._replyID { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 1) + } }() + if self.time != 0 { + try visitor.visitSingularFixed32Field(value: self.time, fieldNumber: 2) + } + if self.level != .unset { + try visitor.visitSingularEnumField(value: self.level, fieldNumber: 3) + } + if !self.message.isEmpty { + try visitor.visitSingularStringField(value: self.message, fieldNumber: 4) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: ClientNotification, rhs: ClientNotification) -> Bool { + if lhs._replyID != rhs._replyID {return false} + if lhs.time != rhs.time {return false} + if lhs.level != rhs.level {return false} + if lhs.message != rhs.message {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension FileInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".FileInfo" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index ec627e3d..de4e550c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -245,27 +245,68 @@ public struct DeviceMetrics { /// /// 0-100 (>100 means powered) - public var batteryLevel: UInt32 = 0 + public var batteryLevel: UInt32 { + get {return _batteryLevel ?? 0} + set {_batteryLevel = newValue} + } + /// Returns true if `batteryLevel` has been explicitly set. + public var hasBatteryLevel: Bool {return self._batteryLevel != nil} + /// Clears the value of `batteryLevel`. Subsequent reads from it will return its default value. + public mutating func clearBatteryLevel() {self._batteryLevel = nil} /// /// Voltage measured - public var voltage: Float = 0 + public var voltage: Float { + get {return _voltage ?? 0} + set {_voltage = newValue} + } + /// Returns true if `voltage` has been explicitly set. + public var hasVoltage: Bool {return self._voltage != nil} + /// Clears the value of `voltage`. Subsequent reads from it will return its default value. + public mutating func clearVoltage() {self._voltage = nil} /// /// Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). - public var channelUtilization: Float = 0 + public var channelUtilization: Float { + get {return _channelUtilization ?? 0} + set {_channelUtilization = newValue} + } + /// Returns true if `channelUtilization` has been explicitly set. + public var hasChannelUtilization: Bool {return self._channelUtilization != nil} + /// Clears the value of `channelUtilization`. Subsequent reads from it will return its default value. + public mutating func clearChannelUtilization() {self._channelUtilization = nil} /// /// Percent of airtime for transmission used within the last hour. - public var airUtilTx: Float = 0 + public var airUtilTx: Float { + get {return _airUtilTx ?? 0} + set {_airUtilTx = newValue} + } + /// Returns true if `airUtilTx` has been explicitly set. + public var hasAirUtilTx: Bool {return self._airUtilTx != nil} + /// Clears the value of `airUtilTx`. Subsequent reads from it will return its default value. + public mutating func clearAirUtilTx() {self._airUtilTx = nil} /// /// How long the device has been running since the last reboot (in seconds) - public var uptimeSeconds: UInt32 = 0 + public var uptimeSeconds: UInt32 { + get {return _uptimeSeconds ?? 0} + set {_uptimeSeconds = newValue} + } + /// Returns true if `uptimeSeconds` has been explicitly set. + public var hasUptimeSeconds: Bool {return self._uptimeSeconds != nil} + /// Clears the value of `uptimeSeconds`. Subsequent reads from it will return its default value. + public mutating func clearUptimeSeconds() {self._uptimeSeconds = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _batteryLevel: UInt32? = nil + fileprivate var _voltage: Float? = nil + fileprivate var _channelUtilization: Float? = nil + fileprivate var _airUtilTx: Float? = nil + fileprivate var _uptimeSeconds: UInt32? = nil } /// @@ -278,123 +319,191 @@ public struct EnvironmentMetrics { /// /// Temperature measured public var temperature: Float { - get {return _storage._temperature} + get {return _storage._temperature ?? 0} set {_uniqueStorage()._temperature = newValue} } + /// Returns true if `temperature` has been explicitly set. + public var hasTemperature: Bool {return _storage._temperature != nil} + /// Clears the value of `temperature`. Subsequent reads from it will return its default value. + public mutating func clearTemperature() {_uniqueStorage()._temperature = nil} /// /// Relative humidity percent measured public var relativeHumidity: Float { - get {return _storage._relativeHumidity} + get {return _storage._relativeHumidity ?? 0} set {_uniqueStorage()._relativeHumidity = newValue} } + /// Returns true if `relativeHumidity` has been explicitly set. + public var hasRelativeHumidity: Bool {return _storage._relativeHumidity != nil} + /// Clears the value of `relativeHumidity`. Subsequent reads from it will return its default value. + public mutating func clearRelativeHumidity() {_uniqueStorage()._relativeHumidity = nil} /// /// Barometric pressure in hPA measured public var barometricPressure: Float { - get {return _storage._barometricPressure} + get {return _storage._barometricPressure ?? 0} set {_uniqueStorage()._barometricPressure = newValue} } + /// Returns true if `barometricPressure` has been explicitly set. + public var hasBarometricPressure: Bool {return _storage._barometricPressure != nil} + /// Clears the value of `barometricPressure`. Subsequent reads from it will return its default value. + public mutating func clearBarometricPressure() {_uniqueStorage()._barometricPressure = nil} /// /// Gas resistance in MOhm measured public var gasResistance: Float { - get {return _storage._gasResistance} + get {return _storage._gasResistance ?? 0} set {_uniqueStorage()._gasResistance = newValue} } + /// Returns true if `gasResistance` has been explicitly set. + public var hasGasResistance: Bool {return _storage._gasResistance != nil} + /// Clears the value of `gasResistance`. Subsequent reads from it will return its default value. + public mutating func clearGasResistance() {_uniqueStorage()._gasResistance = nil} /// /// Voltage measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) public var voltage: Float { - get {return _storage._voltage} + get {return _storage._voltage ?? 0} set {_uniqueStorage()._voltage = newValue} } + /// Returns true if `voltage` has been explicitly set. + public var hasVoltage: Bool {return _storage._voltage != nil} + /// Clears the value of `voltage`. Subsequent reads from it will return its default value. + public mutating func clearVoltage() {_uniqueStorage()._voltage = nil} /// /// Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) public var current: Float { - get {return _storage._current} + get {return _storage._current ?? 0} set {_uniqueStorage()._current = newValue} } + /// Returns true if `current` has been explicitly set. + public var hasCurrent: Bool {return _storage._current != nil} + /// Clears the value of `current`. Subsequent reads from it will return its default value. + public mutating func clearCurrent() {_uniqueStorage()._current = nil} /// /// relative scale IAQ value as measured by Bosch BME680 . value 0-500. /// Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. public var iaq: UInt32 { - get {return _storage._iaq} + get {return _storage._iaq ?? 0} set {_uniqueStorage()._iaq = newValue} } + /// Returns true if `iaq` has been explicitly set. + public var hasIaq: Bool {return _storage._iaq != nil} + /// Clears the value of `iaq`. Subsequent reads from it will return its default value. + public mutating func clearIaq() {_uniqueStorage()._iaq = nil} /// /// RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. public var distance: Float { - get {return _storage._distance} + get {return _storage._distance ?? 0} set {_uniqueStorage()._distance = newValue} } + /// Returns true if `distance` has been explicitly set. + public var hasDistance: Bool {return _storage._distance != nil} + /// Clears the value of `distance`. Subsequent reads from it will return its default value. + public mutating func clearDistance() {_uniqueStorage()._distance = nil} /// /// VEML7700 high accuracy ambient light(Lux) digital 16-bit resolution sensor. public var lux: Float { - get {return _storage._lux} + get {return _storage._lux ?? 0} set {_uniqueStorage()._lux = newValue} } + /// Returns true if `lux` has been explicitly set. + public var hasLux: Bool {return _storage._lux != nil} + /// Clears the value of `lux`. Subsequent reads from it will return its default value. + public mutating func clearLux() {_uniqueStorage()._lux = nil} /// /// VEML7700 high accuracy white light(irradiance) not calibrated digital 16-bit resolution sensor. public var whiteLux: Float { - get {return _storage._whiteLux} + get {return _storage._whiteLux ?? 0} set {_uniqueStorage()._whiteLux = newValue} } + /// Returns true if `whiteLux` has been explicitly set. + public var hasWhiteLux: Bool {return _storage._whiteLux != nil} + /// Clears the value of `whiteLux`. Subsequent reads from it will return its default value. + public mutating func clearWhiteLux() {_uniqueStorage()._whiteLux = nil} /// /// Infrared lux public var irLux: Float { - get {return _storage._irLux} + get {return _storage._irLux ?? 0} set {_uniqueStorage()._irLux = newValue} } + /// Returns true if `irLux` has been explicitly set. + public var hasIrLux: Bool {return _storage._irLux != nil} + /// Clears the value of `irLux`. Subsequent reads from it will return its default value. + public mutating func clearIrLux() {_uniqueStorage()._irLux = nil} /// /// Ultraviolet lux public var uvLux: Float { - get {return _storage._uvLux} + get {return _storage._uvLux ?? 0} set {_uniqueStorage()._uvLux = newValue} } + /// Returns true if `uvLux` has been explicitly set. + public var hasUvLux: Bool {return _storage._uvLux != nil} + /// Clears the value of `uvLux`. Subsequent reads from it will return its default value. + public mutating func clearUvLux() {_uniqueStorage()._uvLux = nil} /// /// Wind direction in degrees /// 0 degrees = North, 90 = East, etc... public var windDirection: UInt32 { - get {return _storage._windDirection} + get {return _storage._windDirection ?? 0} set {_uniqueStorage()._windDirection = newValue} } + /// Returns true if `windDirection` has been explicitly set. + public var hasWindDirection: Bool {return _storage._windDirection != nil} + /// Clears the value of `windDirection`. Subsequent reads from it will return its default value. + public mutating func clearWindDirection() {_uniqueStorage()._windDirection = nil} /// /// Wind speed in m/s public var windSpeed: Float { - get {return _storage._windSpeed} + get {return _storage._windSpeed ?? 0} set {_uniqueStorage()._windSpeed = newValue} } + /// Returns true if `windSpeed` has been explicitly set. + public var hasWindSpeed: Bool {return _storage._windSpeed != nil} + /// Clears the value of `windSpeed`. Subsequent reads from it will return its default value. + public mutating func clearWindSpeed() {_uniqueStorage()._windSpeed = nil} /// /// Weight in KG public var weight: Float { - get {return _storage._weight} + get {return _storage._weight ?? 0} set {_uniqueStorage()._weight = newValue} } + /// Returns true if `weight` has been explicitly set. + public var hasWeight: Bool {return _storage._weight != nil} + /// Clears the value of `weight`. Subsequent reads from it will return its default value. + public mutating func clearWeight() {_uniqueStorage()._weight = nil} /// /// Wind gust in m/s public var windGust: Float { - get {return _storage._windGust} + get {return _storage._windGust ?? 0} set {_uniqueStorage()._windGust = newValue} } + /// Returns true if `windGust` has been explicitly set. + public var hasWindGust: Bool {return _storage._windGust != nil} + /// Clears the value of `windGust`. Subsequent reads from it will return its default value. + public mutating func clearWindGust() {_uniqueStorage()._windGust = nil} /// /// Wind lull in m/s public var windLull: Float { - get {return _storage._windLull} + get {return _storage._windLull ?? 0} set {_uniqueStorage()._windLull = newValue} } + /// Returns true if `windLull` has been explicitly set. + public var hasWindLull: Bool {return _storage._windLull != nil} + /// Clears the value of `windLull`. Subsequent reads from it will return its default value. + public mutating func clearWindLull() {_uniqueStorage()._windLull = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() @@ -412,31 +521,80 @@ public struct PowerMetrics { /// /// Voltage (Ch1) - public var ch1Voltage: Float = 0 + public var ch1Voltage: Float { + get {return _ch1Voltage ?? 0} + set {_ch1Voltage = newValue} + } + /// Returns true if `ch1Voltage` has been explicitly set. + public var hasCh1Voltage: Bool {return self._ch1Voltage != nil} + /// Clears the value of `ch1Voltage`. Subsequent reads from it will return its default value. + public mutating func clearCh1Voltage() {self._ch1Voltage = nil} /// /// Current (Ch1) - public var ch1Current: Float = 0 + public var ch1Current: Float { + get {return _ch1Current ?? 0} + set {_ch1Current = newValue} + } + /// Returns true if `ch1Current` has been explicitly set. + public var hasCh1Current: Bool {return self._ch1Current != nil} + /// Clears the value of `ch1Current`. Subsequent reads from it will return its default value. + public mutating func clearCh1Current() {self._ch1Current = nil} /// /// Voltage (Ch2) - public var ch2Voltage: Float = 0 + public var ch2Voltage: Float { + get {return _ch2Voltage ?? 0} + set {_ch2Voltage = newValue} + } + /// Returns true if `ch2Voltage` has been explicitly set. + public var hasCh2Voltage: Bool {return self._ch2Voltage != nil} + /// Clears the value of `ch2Voltage`. Subsequent reads from it will return its default value. + public mutating func clearCh2Voltage() {self._ch2Voltage = nil} /// /// Current (Ch2) - public var ch2Current: Float = 0 + public var ch2Current: Float { + get {return _ch2Current ?? 0} + set {_ch2Current = newValue} + } + /// Returns true if `ch2Current` has been explicitly set. + public var hasCh2Current: Bool {return self._ch2Current != nil} + /// Clears the value of `ch2Current`. Subsequent reads from it will return its default value. + public mutating func clearCh2Current() {self._ch2Current = nil} /// /// Voltage (Ch3) - public var ch3Voltage: Float = 0 + public var ch3Voltage: Float { + get {return _ch3Voltage ?? 0} + set {_ch3Voltage = newValue} + } + /// Returns true if `ch3Voltage` has been explicitly set. + public var hasCh3Voltage: Bool {return self._ch3Voltage != nil} + /// Clears the value of `ch3Voltage`. Subsequent reads from it will return its default value. + public mutating func clearCh3Voltage() {self._ch3Voltage = nil} /// /// Current (Ch3) - public var ch3Current: Float = 0 + public var ch3Current: Float { + get {return _ch3Current ?? 0} + set {_ch3Current = newValue} + } + /// Returns true if `ch3Current` has been explicitly set. + public var hasCh3Current: Bool {return self._ch3Current != nil} + /// Clears the value of `ch3Current`. Subsequent reads from it will return its default value. + public mutating func clearCh3Current() {self._ch3Current = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _ch1Voltage: Float? = nil + fileprivate var _ch1Current: Float? = nil + fileprivate var _ch2Voltage: Float? = nil + fileprivate var _ch2Current: Float? = nil + fileprivate var _ch3Voltage: Float? = nil + fileprivate var _ch3Current: Float? = nil } /// @@ -448,55 +606,152 @@ public struct AirQualityMetrics { /// /// Concentration Units Standard PM1.0 - public var pm10Standard: UInt32 = 0 + public var pm10Standard: UInt32 { + get {return _pm10Standard ?? 0} + set {_pm10Standard = newValue} + } + /// Returns true if `pm10Standard` has been explicitly set. + public var hasPm10Standard: Bool {return self._pm10Standard != nil} + /// Clears the value of `pm10Standard`. Subsequent reads from it will return its default value. + public mutating func clearPm10Standard() {self._pm10Standard = nil} /// /// Concentration Units Standard PM2.5 - public var pm25Standard: UInt32 = 0 + public var pm25Standard: UInt32 { + get {return _pm25Standard ?? 0} + set {_pm25Standard = newValue} + } + /// Returns true if `pm25Standard` has been explicitly set. + public var hasPm25Standard: Bool {return self._pm25Standard != nil} + /// Clears the value of `pm25Standard`. Subsequent reads from it will return its default value. + public mutating func clearPm25Standard() {self._pm25Standard = nil} /// /// Concentration Units Standard PM10.0 - public var pm100Standard: UInt32 = 0 + public var pm100Standard: UInt32 { + get {return _pm100Standard ?? 0} + set {_pm100Standard = newValue} + } + /// Returns true if `pm100Standard` has been explicitly set. + public var hasPm100Standard: Bool {return self._pm100Standard != nil} + /// Clears the value of `pm100Standard`. Subsequent reads from it will return its default value. + public mutating func clearPm100Standard() {self._pm100Standard = nil} /// /// Concentration Units Environmental PM1.0 - public var pm10Environmental: UInt32 = 0 + public var pm10Environmental: UInt32 { + get {return _pm10Environmental ?? 0} + set {_pm10Environmental = newValue} + } + /// Returns true if `pm10Environmental` has been explicitly set. + public var hasPm10Environmental: Bool {return self._pm10Environmental != nil} + /// Clears the value of `pm10Environmental`. Subsequent reads from it will return its default value. + public mutating func clearPm10Environmental() {self._pm10Environmental = nil} /// /// Concentration Units Environmental PM2.5 - public var pm25Environmental: UInt32 = 0 + public var pm25Environmental: UInt32 { + get {return _pm25Environmental ?? 0} + set {_pm25Environmental = newValue} + } + /// Returns true if `pm25Environmental` has been explicitly set. + public var hasPm25Environmental: Bool {return self._pm25Environmental != nil} + /// Clears the value of `pm25Environmental`. Subsequent reads from it will return its default value. + public mutating func clearPm25Environmental() {self._pm25Environmental = nil} /// /// Concentration Units Environmental PM10.0 - public var pm100Environmental: UInt32 = 0 + public var pm100Environmental: UInt32 { + get {return _pm100Environmental ?? 0} + set {_pm100Environmental = newValue} + } + /// Returns true if `pm100Environmental` has been explicitly set. + public var hasPm100Environmental: Bool {return self._pm100Environmental != nil} + /// Clears the value of `pm100Environmental`. Subsequent reads from it will return its default value. + public mutating func clearPm100Environmental() {self._pm100Environmental = nil} /// /// 0.3um Particle Count - public var particles03Um: UInt32 = 0 + public var particles03Um: UInt32 { + get {return _particles03Um ?? 0} + set {_particles03Um = newValue} + } + /// Returns true if `particles03Um` has been explicitly set. + public var hasParticles03Um: Bool {return self._particles03Um != nil} + /// Clears the value of `particles03Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles03Um() {self._particles03Um = nil} /// /// 0.5um Particle Count - public var particles05Um: UInt32 = 0 + public var particles05Um: UInt32 { + get {return _particles05Um ?? 0} + set {_particles05Um = newValue} + } + /// Returns true if `particles05Um` has been explicitly set. + public var hasParticles05Um: Bool {return self._particles05Um != nil} + /// Clears the value of `particles05Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles05Um() {self._particles05Um = nil} /// /// 1.0um Particle Count - public var particles10Um: UInt32 = 0 + public var particles10Um: UInt32 { + get {return _particles10Um ?? 0} + set {_particles10Um = newValue} + } + /// Returns true if `particles10Um` has been explicitly set. + public var hasParticles10Um: Bool {return self._particles10Um != nil} + /// Clears the value of `particles10Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles10Um() {self._particles10Um = nil} /// /// 2.5um Particle Count - public var particles25Um: UInt32 = 0 + public var particles25Um: UInt32 { + get {return _particles25Um ?? 0} + set {_particles25Um = newValue} + } + /// Returns true if `particles25Um` has been explicitly set. + public var hasParticles25Um: Bool {return self._particles25Um != nil} + /// Clears the value of `particles25Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles25Um() {self._particles25Um = nil} /// /// 5.0um Particle Count - public var particles50Um: UInt32 = 0 + public var particles50Um: UInt32 { + get {return _particles50Um ?? 0} + set {_particles50Um = newValue} + } + /// Returns true if `particles50Um` has been explicitly set. + public var hasParticles50Um: Bool {return self._particles50Um != nil} + /// Clears the value of `particles50Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles50Um() {self._particles50Um = nil} /// /// 10.0um Particle Count - public var particles100Um: UInt32 = 0 + public var particles100Um: UInt32 { + get {return _particles100Um ?? 0} + set {_particles100Um = newValue} + } + /// Returns true if `particles100Um` has been explicitly set. + public var hasParticles100Um: Bool {return self._particles100Um != nil} + /// Clears the value of `particles100Um`. Subsequent reads from it will return its default value. + public mutating func clearParticles100Um() {self._particles100Um = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} + + fileprivate var _pm10Standard: UInt32? = nil + fileprivate var _pm25Standard: UInt32? = nil + fileprivate var _pm100Standard: UInt32? = nil + fileprivate var _pm10Environmental: UInt32? = nil + fileprivate var _pm25Environmental: UInt32? = nil + fileprivate var _pm100Environmental: UInt32? = nil + fileprivate var _particles03Um: UInt32? = nil + fileprivate var _particles05Um: UInt32? = nil + fileprivate var _particles10Um: UInt32? = nil + fileprivate var _particles25Um: UInt32? = nil + fileprivate var _particles50Um: UInt32? = nil + fileprivate var _particles100Um: UInt32? = nil } /// @@ -681,41 +936,45 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularUInt32Field(value: &self.batteryLevel) }() - case 2: try { try decoder.decodeSingularFloatField(value: &self.voltage) }() - case 3: try { try decoder.decodeSingularFloatField(value: &self.channelUtilization) }() - case 4: try { try decoder.decodeSingularFloatField(value: &self.airUtilTx) }() - case 5: try { try decoder.decodeSingularUInt32Field(value: &self.uptimeSeconds) }() + case 1: try { try decoder.decodeSingularUInt32Field(value: &self._batteryLevel) }() + case 2: try { try decoder.decodeSingularFloatField(value: &self._voltage) }() + case 3: try { try decoder.decodeSingularFloatField(value: &self._channelUtilization) }() + case 4: try { try decoder.decodeSingularFloatField(value: &self._airUtilTx) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self._uptimeSeconds) }() default: break } } } public func traverse(visitor: inout V) throws { - if self.batteryLevel != 0 { - try visitor.visitSingularUInt32Field(value: self.batteryLevel, fieldNumber: 1) - } - if self.voltage != 0 { - try visitor.visitSingularFloatField(value: self.voltage, fieldNumber: 2) - } - if self.channelUtilization != 0 { - try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 3) - } - if self.airUtilTx != 0 { - try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 4) - } - if self.uptimeSeconds != 0 { - try visitor.visitSingularUInt32Field(value: self.uptimeSeconds, fieldNumber: 5) - } + // 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._batteryLevel { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 1) + } }() + try { if let v = self._voltage { + try visitor.visitSingularFloatField(value: v, fieldNumber: 2) + } }() + try { if let v = self._channelUtilization { + try visitor.visitSingularFloatField(value: v, fieldNumber: 3) + } }() + try { if let v = self._airUtilTx { + try visitor.visitSingularFloatField(value: v, fieldNumber: 4) + } }() + try { if let v = self._uptimeSeconds { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 5) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: DeviceMetrics, rhs: DeviceMetrics) -> Bool { - if lhs.batteryLevel != rhs.batteryLevel {return false} - if lhs.voltage != rhs.voltage {return false} - if lhs.channelUtilization != rhs.channelUtilization {return false} - if lhs.airUtilTx != rhs.airUtilTx {return false} - if lhs.uptimeSeconds != rhs.uptimeSeconds {return false} + if lhs._batteryLevel != rhs._batteryLevel {return false} + if lhs._voltage != rhs._voltage {return false} + if lhs._channelUtilization != rhs._channelUtilization {return false} + if lhs._airUtilTx != rhs._airUtilTx {return false} + if lhs._uptimeSeconds != rhs._uptimeSeconds {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -744,23 +1003,23 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple ] fileprivate class _StorageClass { - var _temperature: Float = 0 - var _relativeHumidity: Float = 0 - var _barometricPressure: Float = 0 - var _gasResistance: Float = 0 - var _voltage: Float = 0 - var _current: Float = 0 - var _iaq: UInt32 = 0 - var _distance: Float = 0 - var _lux: Float = 0 - var _whiteLux: Float = 0 - var _irLux: Float = 0 - var _uvLux: Float = 0 - var _windDirection: UInt32 = 0 - var _windSpeed: Float = 0 - var _weight: Float = 0 - var _windGust: Float = 0 - var _windLull: Float = 0 + var _temperature: Float? = nil + var _relativeHumidity: Float? = nil + var _barometricPressure: Float? = nil + var _gasResistance: Float? = nil + var _voltage: Float? = nil + var _current: Float? = nil + var _iaq: UInt32? = nil + var _distance: Float? = nil + var _lux: Float? = nil + var _whiteLux: Float? = nil + var _irLux: Float? = nil + var _uvLux: Float? = nil + var _windDirection: UInt32? = nil + var _windSpeed: Float? = nil + var _weight: Float? = nil + var _windGust: Float? = nil + var _windLull: Float? = nil #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -835,57 +1094,61 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple public func traverse(visitor: inout V) throws { try withExtendedLifetime(_storage) { (_storage: _StorageClass) in - if _storage._temperature != 0 { - try visitor.visitSingularFloatField(value: _storage._temperature, fieldNumber: 1) - } - if _storage._relativeHumidity != 0 { - try visitor.visitSingularFloatField(value: _storage._relativeHumidity, fieldNumber: 2) - } - if _storage._barometricPressure != 0 { - try visitor.visitSingularFloatField(value: _storage._barometricPressure, fieldNumber: 3) - } - if _storage._gasResistance != 0 { - try visitor.visitSingularFloatField(value: _storage._gasResistance, fieldNumber: 4) - } - if _storage._voltage != 0 { - try visitor.visitSingularFloatField(value: _storage._voltage, fieldNumber: 5) - } - if _storage._current != 0 { - try visitor.visitSingularFloatField(value: _storage._current, fieldNumber: 6) - } - if _storage._iaq != 0 { - try visitor.visitSingularUInt32Field(value: _storage._iaq, fieldNumber: 7) - } - if _storage._distance != 0 { - try visitor.visitSingularFloatField(value: _storage._distance, fieldNumber: 8) - } - if _storage._lux != 0 { - try visitor.visitSingularFloatField(value: _storage._lux, fieldNumber: 9) - } - if _storage._whiteLux != 0 { - try visitor.visitSingularFloatField(value: _storage._whiteLux, fieldNumber: 10) - } - if _storage._irLux != 0 { - try visitor.visitSingularFloatField(value: _storage._irLux, fieldNumber: 11) - } - if _storage._uvLux != 0 { - try visitor.visitSingularFloatField(value: _storage._uvLux, fieldNumber: 12) - } - if _storage._windDirection != 0 { - try visitor.visitSingularUInt32Field(value: _storage._windDirection, fieldNumber: 13) - } - if _storage._windSpeed != 0 { - try visitor.visitSingularFloatField(value: _storage._windSpeed, fieldNumber: 14) - } - if _storage._weight != 0 { - try visitor.visitSingularFloatField(value: _storage._weight, fieldNumber: 15) - } - if _storage._windGust != 0 { - try visitor.visitSingularFloatField(value: _storage._windGust, fieldNumber: 16) - } - if _storage._windLull != 0 { - try visitor.visitSingularFloatField(value: _storage._windLull, fieldNumber: 17) - } + // 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._temperature { + try visitor.visitSingularFloatField(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._relativeHumidity { + try visitor.visitSingularFloatField(value: v, fieldNumber: 2) + } }() + try { if let v = _storage._barometricPressure { + try visitor.visitSingularFloatField(value: v, fieldNumber: 3) + } }() + try { if let v = _storage._gasResistance { + try visitor.visitSingularFloatField(value: v, fieldNumber: 4) + } }() + try { if let v = _storage._voltage { + try visitor.visitSingularFloatField(value: v, fieldNumber: 5) + } }() + try { if let v = _storage._current { + try visitor.visitSingularFloatField(value: v, fieldNumber: 6) + } }() + try { if let v = _storage._iaq { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 7) + } }() + try { if let v = _storage._distance { + try visitor.visitSingularFloatField(value: v, fieldNumber: 8) + } }() + try { if let v = _storage._lux { + try visitor.visitSingularFloatField(value: v, fieldNumber: 9) + } }() + try { if let v = _storage._whiteLux { + try visitor.visitSingularFloatField(value: v, fieldNumber: 10) + } }() + try { if let v = _storage._irLux { + try visitor.visitSingularFloatField(value: v, fieldNumber: 11) + } }() + try { if let v = _storage._uvLux { + try visitor.visitSingularFloatField(value: v, fieldNumber: 12) + } }() + try { if let v = _storage._windDirection { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 13) + } }() + try { if let v = _storage._windSpeed { + try visitor.visitSingularFloatField(value: v, fieldNumber: 14) + } }() + try { if let v = _storage._weight { + try visitor.visitSingularFloatField(value: v, fieldNumber: 15) + } }() + try { if let v = _storage._windGust { + try visitor.visitSingularFloatField(value: v, fieldNumber: 16) + } }() + try { if let v = _storage._windLull { + try visitor.visitSingularFloatField(value: v, fieldNumber: 17) + } }() } try unknownFields.traverse(visitor: &visitor) } @@ -938,46 +1201,50 @@ extension PowerMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularFloatField(value: &self.ch1Voltage) }() - case 2: try { try decoder.decodeSingularFloatField(value: &self.ch1Current) }() - case 3: try { try decoder.decodeSingularFloatField(value: &self.ch2Voltage) }() - case 4: try { try decoder.decodeSingularFloatField(value: &self.ch2Current) }() - case 5: try { try decoder.decodeSingularFloatField(value: &self.ch3Voltage) }() - case 6: try { try decoder.decodeSingularFloatField(value: &self.ch3Current) }() + case 1: try { try decoder.decodeSingularFloatField(value: &self._ch1Voltage) }() + case 2: try { try decoder.decodeSingularFloatField(value: &self._ch1Current) }() + case 3: try { try decoder.decodeSingularFloatField(value: &self._ch2Voltage) }() + case 4: try { try decoder.decodeSingularFloatField(value: &self._ch2Current) }() + case 5: try { try decoder.decodeSingularFloatField(value: &self._ch3Voltage) }() + case 6: try { try decoder.decodeSingularFloatField(value: &self._ch3Current) }() default: break } } } public func traverse(visitor: inout V) throws { - if self.ch1Voltage != 0 { - try visitor.visitSingularFloatField(value: self.ch1Voltage, fieldNumber: 1) - } - if self.ch1Current != 0 { - try visitor.visitSingularFloatField(value: self.ch1Current, fieldNumber: 2) - } - if self.ch2Voltage != 0 { - try visitor.visitSingularFloatField(value: self.ch2Voltage, fieldNumber: 3) - } - if self.ch2Current != 0 { - try visitor.visitSingularFloatField(value: self.ch2Current, fieldNumber: 4) - } - if self.ch3Voltage != 0 { - try visitor.visitSingularFloatField(value: self.ch3Voltage, fieldNumber: 5) - } - if self.ch3Current != 0 { - try visitor.visitSingularFloatField(value: self.ch3Current, fieldNumber: 6) - } + // 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._ch1Voltage { + try visitor.visitSingularFloatField(value: v, fieldNumber: 1) + } }() + try { if let v = self._ch1Current { + try visitor.visitSingularFloatField(value: v, fieldNumber: 2) + } }() + try { if let v = self._ch2Voltage { + try visitor.visitSingularFloatField(value: v, fieldNumber: 3) + } }() + try { if let v = self._ch2Current { + try visitor.visitSingularFloatField(value: v, fieldNumber: 4) + } }() + try { if let v = self._ch3Voltage { + try visitor.visitSingularFloatField(value: v, fieldNumber: 5) + } }() + try { if let v = self._ch3Current { + try visitor.visitSingularFloatField(value: v, fieldNumber: 6) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: PowerMetrics, rhs: PowerMetrics) -> Bool { - if lhs.ch1Voltage != rhs.ch1Voltage {return false} - if lhs.ch1Current != rhs.ch1Current {return false} - if lhs.ch2Voltage != rhs.ch2Voltage {return false} - if lhs.ch2Current != rhs.ch2Current {return false} - if lhs.ch3Voltage != rhs.ch3Voltage {return false} - if lhs.ch3Current != rhs.ch3Current {return false} + if lhs._ch1Voltage != rhs._ch1Voltage {return false} + if lhs._ch1Current != rhs._ch1Current {return false} + if lhs._ch2Voltage != rhs._ch2Voltage {return false} + if lhs._ch2Current != rhs._ch2Current {return false} + if lhs._ch3Voltage != rhs._ch3Voltage {return false} + if lhs._ch3Current != rhs._ch3Current {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -1006,76 +1273,80 @@ extension AirQualityMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularUInt32Field(value: &self.pm10Standard) }() - case 2: try { try decoder.decodeSingularUInt32Field(value: &self.pm25Standard) }() - case 3: try { try decoder.decodeSingularUInt32Field(value: &self.pm100Standard) }() - case 4: try { try decoder.decodeSingularUInt32Field(value: &self.pm10Environmental) }() - case 5: try { try decoder.decodeSingularUInt32Field(value: &self.pm25Environmental) }() - case 6: try { try decoder.decodeSingularUInt32Field(value: &self.pm100Environmental) }() - case 7: try { try decoder.decodeSingularUInt32Field(value: &self.particles03Um) }() - case 8: try { try decoder.decodeSingularUInt32Field(value: &self.particles05Um) }() - case 9: try { try decoder.decodeSingularUInt32Field(value: &self.particles10Um) }() - case 10: try { try decoder.decodeSingularUInt32Field(value: &self.particles25Um) }() - case 11: try { try decoder.decodeSingularUInt32Field(value: &self.particles50Um) }() - case 12: try { try decoder.decodeSingularUInt32Field(value: &self.particles100Um) }() + case 1: try { try decoder.decodeSingularUInt32Field(value: &self._pm10Standard) }() + case 2: try { try decoder.decodeSingularUInt32Field(value: &self._pm25Standard) }() + case 3: try { try decoder.decodeSingularUInt32Field(value: &self._pm100Standard) }() + case 4: try { try decoder.decodeSingularUInt32Field(value: &self._pm10Environmental) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self._pm25Environmental) }() + case 6: try { try decoder.decodeSingularUInt32Field(value: &self._pm100Environmental) }() + case 7: try { try decoder.decodeSingularUInt32Field(value: &self._particles03Um) }() + case 8: try { try decoder.decodeSingularUInt32Field(value: &self._particles05Um) }() + case 9: try { try decoder.decodeSingularUInt32Field(value: &self._particles10Um) }() + case 10: try { try decoder.decodeSingularUInt32Field(value: &self._particles25Um) }() + case 11: try { try decoder.decodeSingularUInt32Field(value: &self._particles50Um) }() + case 12: try { try decoder.decodeSingularUInt32Field(value: &self._particles100Um) }() default: break } } } public func traverse(visitor: inout V) throws { - if self.pm10Standard != 0 { - try visitor.visitSingularUInt32Field(value: self.pm10Standard, fieldNumber: 1) - } - if self.pm25Standard != 0 { - try visitor.visitSingularUInt32Field(value: self.pm25Standard, fieldNumber: 2) - } - if self.pm100Standard != 0 { - try visitor.visitSingularUInt32Field(value: self.pm100Standard, fieldNumber: 3) - } - if self.pm10Environmental != 0 { - try visitor.visitSingularUInt32Field(value: self.pm10Environmental, fieldNumber: 4) - } - if self.pm25Environmental != 0 { - try visitor.visitSingularUInt32Field(value: self.pm25Environmental, fieldNumber: 5) - } - if self.pm100Environmental != 0 { - try visitor.visitSingularUInt32Field(value: self.pm100Environmental, fieldNumber: 6) - } - if self.particles03Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles03Um, fieldNumber: 7) - } - if self.particles05Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles05Um, fieldNumber: 8) - } - if self.particles10Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles10Um, fieldNumber: 9) - } - if self.particles25Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles25Um, fieldNumber: 10) - } - if self.particles50Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles50Um, fieldNumber: 11) - } - if self.particles100Um != 0 { - try visitor.visitSingularUInt32Field(value: self.particles100Um, fieldNumber: 12) - } + // 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._pm10Standard { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 1) + } }() + try { if let v = self._pm25Standard { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 2) + } }() + try { if let v = self._pm100Standard { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 3) + } }() + try { if let v = self._pm10Environmental { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 4) + } }() + try { if let v = self._pm25Environmental { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 5) + } }() + try { if let v = self._pm100Environmental { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 6) + } }() + try { if let v = self._particles03Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 7) + } }() + try { if let v = self._particles05Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 8) + } }() + try { if let v = self._particles10Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 9) + } }() + try { if let v = self._particles25Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 10) + } }() + try { if let v = self._particles50Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 11) + } }() + try { if let v = self._particles100Um { + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 12) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: AirQualityMetrics, rhs: AirQualityMetrics) -> Bool { - if lhs.pm10Standard != rhs.pm10Standard {return false} - if lhs.pm25Standard != rhs.pm25Standard {return false} - if lhs.pm100Standard != rhs.pm100Standard {return false} - if lhs.pm10Environmental != rhs.pm10Environmental {return false} - if lhs.pm25Environmental != rhs.pm25Environmental {return false} - if lhs.pm100Environmental != rhs.pm100Environmental {return false} - if lhs.particles03Um != rhs.particles03Um {return false} - if lhs.particles05Um != rhs.particles05Um {return false} - if lhs.particles10Um != rhs.particles10Um {return false} - if lhs.particles25Um != rhs.particles25Um {return false} - if lhs.particles50Um != rhs.particles50Um {return false} - if lhs.particles100Um != rhs.particles100Um {return false} + if lhs._pm10Standard != rhs._pm10Standard {return false} + if lhs._pm25Standard != rhs._pm25Standard {return false} + if lhs._pm100Standard != rhs._pm100Standard {return false} + if lhs._pm10Environmental != rhs._pm10Environmental {return false} + if lhs._pm25Environmental != rhs._pm25Environmental {return false} + if lhs._pm100Environmental != rhs._pm100Environmental {return false} + if lhs._particles03Um != rhs._particles03Um {return false} + if lhs._particles05Um != rhs._particles05Um {return false} + if lhs._particles10Um != rhs._particles10Um {return false} + if lhs._particles25Um != rhs._particles25Um {return false} + if lhs._particles50Um != rhs._particles50Um {return false} + if lhs._particles100Um != rhs._particles100Um {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/protobufs b/protobufs index 81fd9d37..c112ce6e 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 81fd9d374f1b364c2812b7a0ca2784a7605b6835 +Subproject commit c112ce6e1392e4bc812655fae5e8461c932b5267 From 9e4def79be049d46d694e9fce174b36b176de109 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 8 Aug 2024 21:52:43 -0700 Subject: [PATCH 05/75] Little tiny locks --- Meshtastic/Views/Messages/MessageContextMenuItems.swift | 2 +- Meshtastic/Views/Messages/UserMessageList.swift | 6 ++++++ protobufs | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Views/Messages/MessageContextMenuItems.swift b/Meshtastic/Views/Messages/MessageContextMenuItems.swift index 7835a723..c9c37cdc 100644 --- a/Meshtastic/Views/Messages/MessageContextMenuItems.swift +++ b/Meshtastic/Views/Messages/MessageContextMenuItems.swift @@ -56,7 +56,7 @@ struct MessageContextMenuItems: View { let messageDate = Date(timeIntervalSince1970: TimeInterval(message.messageTimestamp)) Text("\(messageDate.formattedDate(format: MessageText.dateFormatString))").foregroundColor(.gray) } - + if !isCurrentUser && !(message.fromUser?.userNode?.viaMqtt ?? false) && message.fromUser?.userNode?.hopsAway ?? -1 == 0 { VStack { Text("SNR \(String(format: "%.2f", message.snr)) dB") diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index ce0eb182..914fde3f 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -57,6 +57,12 @@ struct UserMessageList: View { self.replyMessageId = message.messageId self.messageFieldFocused = true } + if message.pkiEncrypted { + Image(systemName: "lock.circle.fill") + .foregroundStyle(.green) + .frame(height: 25) + .padding(.top, 5) + } if currentUser && message.canRetry || (message.receivedACK && !message.realACK) { RetryButton(message: message, destination: .user(user)) diff --git a/protobufs b/protobufs index c112ce6e..2fa7d6a4 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit c112ce6e1392e4bc812655fae5e8461c932b5267 +Subproject commit 2fa7d6a4b702fcd58b54b0d1d6e4b3b85164f649 From c430913015ce3b9ea571fc2e3b377b97d07b7d6f Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 9 Aug 2024 21:12:27 -0700 Subject: [PATCH 06/75] Security config updates --- Meshtastic/Helpers/MeshPackets.swift | 7 ++++++- Meshtastic/Persistence/UpdateCoreData.swift | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index d2987e46..c210082f 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -49,7 +49,7 @@ func generateMessageMarkdown (message: String) -> String { } func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) { - // We don't care about any of the Power settings, config is available for everything else + if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) { @@ -64,6 +64,8 @@ func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int6 upsertPositionConfigPacket(config: config.position, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.power(config.power) { upsertPowerConfigPacket(config: config.power, nodeNum: nodeNum, context: context) + } else if config.payloadVariant == Config.OneOf_PayloadVariant.security(config.security) { + upsertSecurityConfigPacket(config: config.security, nodeNum: nodeNum, context: context) } } @@ -276,6 +278,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje newTelemetries.append(telemetry) newNode.telemetries? = NSOrderedSet(array: newTelemetries) } + newNode.firstHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard))) newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard))) newNode.snr = nodeInfo.snr @@ -493,6 +496,8 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.power(config.power) { upsertPowerConfigPacket(config: config.power, nodeNum: Int64(packet.from), context: context) + } else if config.payloadVariant == Config.OneOf_PayloadVariant.security(config.security) { + upsertSecurityConfigPacket(config: config.security, nodeNum: Int64(packet.from), context: context) } } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) { let moduleConfig = adminMessage.getModuleConfigResponse diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 304c6a77..f33527e0 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -769,7 +769,7 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.security.config %@".localized, String(nodeNum)) - MeshLogger.log("🌐 \(logString)") + MeshLogger.log("🛡️ \(logString)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) @@ -799,19 +799,19 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c do { try context.save() - Logger.data.info("💾 [NetworkConfigEntity] Updated Network Config for node: \(nodeNum.toHex(), privacy: .public)") + Logger.data.info("💾 [SecurityConfigEntity] Updated Security Config for node: \(nodeNum.toHex(), privacy: .public)") } catch { context.rollback() let nsError = error as NSError - Logger.data.error("💥 [NetworkConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)") + Logger.data.error("💥 [SecurityConfigEntity] Error Updating Core Data: \(nsError, privacy: .public)") } } else { - Logger.data.error("💥 [NetworkConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Network Config") + Logger.data.error("💥 [SecurityConfigEntity] No Nodes found in local database matching node \(nodeNum.toHex(), privacy: .public) unable to save Security Config") } } catch { let nsError = error as NSError - Logger.data.error("💥 [NetworkConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)") + Logger.data.error("💥 [SecurityConfigEntity] Fetching node for core data failed: \(nsError, privacy: .public)") } } From aeb69e14cc0287e32ea87a44bfa26da342f77909 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 10 Aug 2024 07:05:09 -0700 Subject: [PATCH 07/75] simplify bool onchange --- .../Settings/Config/SecurityConfig.swift | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 4c8bd85a..3345c533 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -29,6 +29,14 @@ struct SecurityConfig: View { @State var bluetoothLoggingEnabled = false @State var adminChannelEnabled = false + var boolValues: [Bool] {[ + isManaged, + serialEnabled, + debugLogApiEnabled, + bluetoothLoggingEnabled, + adminChannelEnabled + ]} + var body: some View { VStack { Form { @@ -146,7 +154,41 @@ struct SecurityConfig: View { ZStack { ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") }) + .onChange(of: boolValues) { _ in + hasChanges = true + } + SaveConfigButton(node: node, hasChanges: $hasChanges) { + guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context), + let fromUser = connectedNode.user, + let toUser = node?.user else { + return + } + + var config = Config.SecurityConfig() + //config.publicKey = publicKey + //config.privateKey = privateKey + //config.adminKey = adminKey + config.isManaged = isManaged + config.serialEnabled = serialEnabled + config.debugLogApiEnabled = debugLogApiEnabled + config.bluetoothLoggingEnabled = bluetoothLoggingEnabled + config.adminChannelEnabled = adminChannelEnabled + + let adminMessageId = bleManager.saveSecurityConfig( + config: config, + fromUser: fromUser, + toUser: toUser, + adminIndex: connectedNode.myInfo?.adminIndex ?? 0 + ) + if adminMessageId > 0 { + // Should show a saved successfully alert once I know that to be true + // for now just disable the button after a successful save + hasChanges = false + goBack() + } + } } + func setSecurityValues() { self.publicKey = node?.securityConfig?.publicKey?.base64EncodedString() ?? "" self.privateKey = node?.securityConfig?.privateKey?.base64EncodedString() ?? "" From 1b61482c015f8afb2e82fad8d075ae1c349570ac Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 10 Aug 2024 21:20:12 -0700 Subject: [PATCH 08/75] Update protos --- MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift | 8 ++++++++ protobufs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index f526f4ca..3ea4ac4c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -815,6 +815,10 @@ public struct AdminMessage { /// /// TODO: REPLACE case bluetoothConfig // = 6 + + /// + /// TODO: REPLACE + case securityConfig // = 7 case UNRECOGNIZED(Int) public init() { @@ -830,6 +834,7 @@ public struct AdminMessage { case 4: self = .displayConfig case 5: self = .loraConfig case 6: self = .bluetoothConfig + case 7: self = .securityConfig default: self = .UNRECOGNIZED(rawValue) } } @@ -843,6 +848,7 @@ public struct AdminMessage { case .displayConfig: return 4 case .loraConfig: return 5 case .bluetoothConfig: return 6 + case .securityConfig: return 7 case .UNRECOGNIZED(let i): return i } } @@ -966,6 +972,7 @@ extension AdminMessage.ConfigType: CaseIterable { .displayConfig, .loraConfig, .bluetoothConfig, + .securityConfig, ] } @@ -1703,6 +1710,7 @@ extension AdminMessage.ConfigType: SwiftProtobuf._ProtoNameProviding { 4: .same(proto: "DISPLAY_CONFIG"), 5: .same(proto: "LORA_CONFIG"), 6: .same(proto: "BLUETOOTH_CONFIG"), + 7: .same(proto: "SECURITY_CONFIG"), ] } diff --git a/protobufs b/protobufs index 2fa7d6a4..66eb3184 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 2fa7d6a4b702fcd58b54b0d1d6e4b3b85164f649 +Subproject commit 66eb3184d5651705ae62f80bf4f65b94a62e7f06 From 7b4a3ec648de9dc37bfd5b0bfca2cdae0ee7b47a Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 00:08:43 -0700 Subject: [PATCH 09/75] Set security config --- Meshtastic/Persistence/UpdateCoreData.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index f33527e0..e8563315 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -787,6 +787,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c newSecurityConfig.serialEnabled = config.serialEnabled newSecurityConfig.debugLogApiEnabled = config.debugLogApiEnabled newSecurityConfig.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled + fetchedNode[0].securityConfig = newSecurityConfig } else { fetchedNode[0].securityConfig?.publicKey = config.publicKey fetchedNode[0].securityConfig?.privateKey = config.privateKey From 3acca7ddcb7776b0b5e0e7e835085dfa9cded193 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 08:09:00 -0700 Subject: [PATCH 10/75] Set saved values --- .../Views/Settings/Config/SecurityConfig.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 3345c533..9be5abd8 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -154,6 +154,18 @@ struct SecurityConfig: View { ZStack { ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") }) + .onAppear { + setSecurityValues() + + // Need to request a LoRaConfig from the remote node before allowing changes +// if bleManager.connectedPeripheral != nil && node?.securityConfig == nil { +// Logger.mesh.info("empty security config") +// let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? 0, context: context) +// if node != nil && connectedNode != nil { +// _ = bleManager.requestSecurityyConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) +// } +// } + } .onChange(of: boolValues) { _ in hasChanges = true } From c6298f785c2221b4261e0ffd4dfa6096ecb1578a Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 09:07:22 -0700 Subject: [PATCH 11/75] Standardize onAppear for settings that support admin messages --- .../Views/Settings/Config/BluetoothConfig.swift | 1 - .../Views/Settings/Config/ConfigHeader.swift | 3 ++- .../Views/Settings/Config/DeviceConfig.swift | 16 ++++++++++------ .../Views/Settings/Config/DisplayConfig.swift | 15 +++++++++------ .../Views/Settings/Config/LoRaConfig.swift | 14 +++++++++----- .../Config/Module/AmbientLightingConfig.swift | 14 +++++++++----- .../Config/Module/CannedMessagesConfig.swift | 14 +++++++++----- .../Config/Module/DetectionSensorConfig.swift | 14 +++++++++----- .../Module/ExternalNotificationConfig.swift | 14 +++++++++----- .../Settings/Config/Module/MQTTConfig.swift | 14 +++++++++----- .../Config/Module/PaxCounterConfig.swift | 1 - .../Settings/Config/Module/RangeTestConfig.swift | 14 +++++++++----- .../Settings/Config/Module/RtttlConfig.swift | 14 +++++++++----- .../Settings/Config/Module/SerialConfig.swift | 15 +++++++++------ .../Config/Module/StoreForwardConfig.swift | 14 +++++++++----- .../Settings/Config/Module/TelemetryConfig.swift | 14 +++++++++----- .../Views/Settings/Config/NetworkConfig.swift | 14 +++++++++----- .../Views/Settings/Config/PositionConfig.swift | 1 - .../Views/Settings/Config/PowerConfig.swift | 3 --- .../Views/Settings/Config/SecurityConfig.swift | 12 ------------ 20 files changed, 129 insertions(+), 92 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index b43813c2..aa36e193 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -107,7 +107,6 @@ struct BluetoothConfig: View { } ) .onAppear { - setBluetoothValues() // Need to request a BluetoothConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node, node.bluetoothConfig == nil { Logger.mesh.info("empty bluetooth config") diff --git a/Meshtastic/Views/Settings/Config/ConfigHeader.swift b/Meshtastic/Views/Settings/Config/ConfigHeader.swift index 3ff815f8..cef7f98c 100644 --- a/Meshtastic/Views/Settings/Config/ConfigHeader.swift +++ b/Meshtastic/Views/Settings/Config/ConfigHeader.swift @@ -23,11 +23,12 @@ struct ConfigHeader: View { .foregroundColor(.orange) } else { Text("Remote administration for: \(node?.user?.longName ?? "Unknown")") - .font(.title3) .onAppear(perform: onAppear) + .font(.title3) } } else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? -1 { Text("Configuration for: \(node?.user?.longName ?? "Unknown")") + .onAppear(perform: onAppear) } else { Text("Please connect to a radio to configure settings.") .font(.callout) diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 114898ca..0d3349e1 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -233,13 +233,17 @@ struct DeviceConfig: View { Spacer() } .navigationTitle("device.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setDeviceValues() - // Need to request a LoRaConfig from the remote node before allowing changes + // Need to request a DeviceConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.deviceConfig == nil { Logger.mesh.info("empty device config") let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context) diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index f800ebb6..0b497037 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -154,13 +154,16 @@ struct DisplayConfig: View { } .navigationTitle("display.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setDisplayValues() - // Need to request a LoRaConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.displayConfig == nil { Logger.mesh.info("empty display config") diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index c98e162c..d2062468 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -221,12 +221,16 @@ struct LoRaConfig: View { } } .navigationTitle("lora.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setLoRaValues() // Need to request a LoRaConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil { Logger.mesh.info("empty lora config") diff --git a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift index 3fe5560d..1949db37 100644 --- a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift @@ -80,12 +80,16 @@ struct AmbientLightingConfig: View { } } .navigationTitle("ambient.lighting.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setAmbientLightingConfigValue() // Need to request a Ambient Lighting Config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.ambientLightingConfig == nil { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index 670e24e1..d30872d5 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -224,12 +224,16 @@ struct CannedMessagesConfig: View { } } .navigationTitle("canned.messages.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setCannedMessagesValues() // Need to request a CannedMessagesModuleConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.cannedMessageConfig == nil { Logger.mesh.info("empty canned messages module config") diff --git a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift index 480c4e24..358576d4 100644 --- a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift @@ -180,12 +180,16 @@ struct DetectionSensorConfig: View { } } .navigationTitle("detection.sensor.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setDetectionSensorValues() // Need to request a Detection Sensor Module Config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.detectionSensorConfig == nil { Logger.mesh.info("empty detection sensor module config") diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index abdca8a2..fc6f33f2 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -190,12 +190,16 @@ struct ExternalNotificationConfig: View { } } .navigationTitle("external.notification.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setExternalNotificationValues() // Need to request a TelemetryModuleConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.externalNotificationConfig == nil { Logger.mesh.info("empty external notification module config") diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index f923e560..91bb80e1 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -271,10 +271,15 @@ struct MQTTConfig: View { } } .navigationTitle("mqtt.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?", mqttProxyConnected: bleManager.mqttProxyConnected) - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onChange(of: address) { newAddress in if node != nil && node?.mqttConfig != nil { if newAddress != node!.mqttConfig!.address { hasChanges = true } @@ -357,7 +362,6 @@ struct MQTTConfig: View { } } .onAppear { - setMqttValues() // Need to request a TelemetryModuleConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.mqttConfig == nil { Logger.mesh.info("empty mqtt module config") diff --git a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift index d7670a7c..ce9d34f8 100644 --- a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift @@ -58,7 +58,6 @@ struct PaxCounterConfig: View { ) }) .onAppear { - setPaxValues() // Need to request a PAX Counter module config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.paxCounterConfig == nil { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? 0, context: context) diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 0bf99d65..51c847e6 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -72,12 +72,16 @@ struct RangeTestConfig: View { } } .navigationTitle("range.test.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setRangeTestValues() // Need to request a RangeTestModule Config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.rangeTestConfig == nil { Logger.mesh.debug("empty range test module config") diff --git a/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift b/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift index 3128fffe..95f237a3 100644 --- a/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift @@ -62,12 +62,16 @@ struct RtttlConfig: View { } } .navigationTitle("config.ringtone.title") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setRtttLConfigValue() // Need to request a Rtttl Config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && (node?.rtttlConfig == nil || node?.rtttlConfig?.ringtone?.count ?? 0 == 0) { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) diff --git a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift index 813e1328..6d5b4421 100644 --- a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift @@ -127,13 +127,16 @@ struct SerialConfig: View { } } .navigationTitle("serial.config") - .navigationBarItems(trailing: - - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setSerialValues() // Need to request a SerialModuleConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.serialConfig == nil { Logger.mesh.debug("empty serial module config") diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index e73380f3..4829a5fa 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -137,10 +137,15 @@ struct StoreForwardConfig: View { } } .navigationTitle("storeforward.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { // Need to request a Detection Sensor Module Config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.storeForwardConfig == nil { @@ -150,7 +155,6 @@ struct StoreForwardConfig: View { _ = bleManager.requestStoreAndForwardModuleConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) } } - setStoreAndForwardValues() } .onChange(of: enabled) { newEnabled in if node != nil && node?.storeForwardConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift index a1f827b7..df811677 100644 --- a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift @@ -125,12 +125,16 @@ struct TelemetryConfig: View { } } .navigationTitle("telemetry.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setTelemetryValues() // Need to request a TelemetryModuleConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.telemetryConfig == nil { Logger.mesh.info("empty telemetry module config") diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index d969eab9..3bc28ef6 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -109,12 +109,16 @@ struct NetworkConfig: View { } } .navigationTitle("network.config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") - }) + .navigationBarItems( + trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: bleManager.connectedPeripheral?.shortName ?? "?" + ) + } + ) .onAppear { - setNetworkValues() // Need to request a NetworkConfig from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.networkConfig == nil { Logger.mesh.info("empty network config") diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index aa6960a0..2fd9bcf1 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -377,7 +377,6 @@ struct PositionConfig: View { } ) .onAppear { - setPositionValues() supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame // Need to request a PositionConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, node?.positionConfig == nil { diff --git a/Meshtastic/Views/Settings/Config/PowerConfig.swift b/Meshtastic/Views/Settings/Config/PowerConfig.swift index d8de7e44..8f67d6bd 100644 --- a/Meshtastic/Views/Settings/Config/PowerConfig.swift +++ b/Meshtastic/Views/Settings/Config/PowerConfig.swift @@ -119,7 +119,6 @@ struct PowerConfig: View { } .onAppear { Api().loadDeviceHardwareData { (hw) in - for device in hw { let currentHardware = node?.user?.hwModel ?? "UNSET" let deviceString = device.hwModelSlug.replacingOccurrences(of: "_", with: "") @@ -128,8 +127,6 @@ struct PowerConfig: View { } } } - setPowerValues() - // Need to request a Power config from the remote node before allowing changes if bleManager.connectedPeripheral != nil && node?.powerConfig == nil { let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? 0, context: context) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 9be5abd8..3345c533 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -154,18 +154,6 @@ struct SecurityConfig: View { ZStack { ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") }) - .onAppear { - setSecurityValues() - - // Need to request a LoRaConfig from the remote node before allowing changes -// if bleManager.connectedPeripheral != nil && node?.securityConfig == nil { -// Logger.mesh.info("empty security config") -// let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? 0, context: context) -// if node != nil && connectedNode != nil { -// _ = bleManager.requestSecurityyConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) -// } -// } - } .onChange(of: boolValues) { _ in hasChanges = true } From cbfde743afd9975f6ba8b1b95d89835e211d0881 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 09:59:52 -0700 Subject: [PATCH 12/75] Clean up save button display --- .../Settings/Config/SecurityConfig.swift | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 3345c533..1cc0fb7b 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -29,14 +29,6 @@ struct SecurityConfig: View { @State var bluetoothLoggingEnabled = false @State var adminChannelEnabled = false - var boolValues: [Bool] {[ - isManaged, - serialEnabled, - debugLogApiEnabled, - bluetoothLoggingEnabled, - adminChannelEnabled - ]} - var body: some View { VStack { Form { @@ -150,13 +142,39 @@ struct SecurityConfig: View { } } .navigationTitle("Security Config") - .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?") + .navigationBarItems(trailing: ZStack { + ConnectedDevice( + bluetoothOn: bleManager.isSwitchedOn, + deviceConnected: bleManager.connectedPeripheral != nil, + name: "\(bleManager.connectedPeripheral?.shortName ?? "?")" + ) }) - .onChange(of: boolValues) { _ in - hasChanges = true + .onChange(of: isManaged) { newIsManaged in + if node != nil && node!.securityConfig != nil { + if newIsManaged != node!.securityConfig!.isManaged { hasChanges = true } + } } + .onChange(of: serialEnabled) { newSerialEnabled in + if node != nil && node!.securityConfig != nil { + if newSerialEnabled != node!.securityConfig!.serialEnabled { hasChanges = true } + } + } + .onChange(of: debugLogApiEnabled) { newDebugLogApiEnabled in + if node != nil && node!.securityConfig != nil { + if newDebugLogApiEnabled != node!.securityConfig!.debugLogApiEnabled { hasChanges = true } + } + } + .onChange(of: bluetoothLoggingEnabled) { newBluetoothLoggingEnabled in + if node != nil && node!.securityConfig != nil { + if newBluetoothLoggingEnabled != node!.securityConfig!.bluetoothLoggingEnabled { hasChanges = true } + } + } + .onChange(of: adminChannelEnabled) { newAdminChannelEnabled in + if node != nil && node!.securityConfig != nil { + if newAdminChannelEnabled != node!.securityConfig!.adminChannelEnabled { hasChanges = true } + } + } + SaveConfigButton(node: node, hasChanges: $hasChanges) { guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context), let fromUser = connectedNode.user, From 3786bf5e1fa917cd3963042c553cb9cbc435d24e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 10:04:17 -0700 Subject: [PATCH 13/75] New plan --- .../Settings/Config/SecurityConfig.swift | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 1cc0fb7b..a3aa1f45 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -149,30 +149,30 @@ struct SecurityConfig: View { name: "\(bleManager.connectedPeripheral?.shortName ?? "?")" ) }) - .onChange(of: isManaged) { newIsManaged in - if node != nil && node!.securityConfig != nil { - if newIsManaged != node!.securityConfig!.isManaged { hasChanges = true } + .onChange(of: isManaged) { + if let val = node?.securityConfig?.isManaged { + hasChanges = $0 != val } } - .onChange(of: serialEnabled) { newSerialEnabled in - if node != nil && node!.securityConfig != nil { - if newSerialEnabled != node!.securityConfig!.serialEnabled { hasChanges = true } + .onChange(of: serialEnabled) { + if let val = node?.securityConfig?.serialEnabled { + hasChanges = $0 != val + } + } + .onChange(of: debugLogApiEnabled) { + if let val = node?.securityConfig?.debugLogApiEnabled { + hasChanges = $0 != val } } - .onChange(of: debugLogApiEnabled) { newDebugLogApiEnabled in - if node != nil && node!.securityConfig != nil { - if newDebugLogApiEnabled != node!.securityConfig!.debugLogApiEnabled { hasChanges = true } + .onChange(of: bluetoothLoggingEnabled) { + if let val = node?.securityConfig?.bluetoothLoggingEnabled { + hasChanges = $0 != val } } - .onChange(of: bluetoothLoggingEnabled) { newBluetoothLoggingEnabled in - if node != nil && node!.securityConfig != nil { - if newBluetoothLoggingEnabled != node!.securityConfig!.bluetoothLoggingEnabled { hasChanges = true } - } - } - .onChange(of: adminChannelEnabled) { newAdminChannelEnabled in - if node != nil && node!.securityConfig != nil { - if newAdminChannelEnabled != node!.securityConfig!.adminChannelEnabled { hasChanges = true } - } + .onChange(of: adminChannelEnabled) { + if let val = node?.securityConfig?.adminChannelEnabled { + hasChanges = $0 != val + } } SaveConfigButton(node: node, hasChanges: $hasChanges) { From 6f0fe8fd6fb0d0464cf3947a33d4bf2436b909ad Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 17:31:27 -0700 Subject: [PATCH 14/75] Clean up change events --- Meshtastic/Helpers/BLEManager.swift | 5 ++ .../Settings/Config/BluetoothConfig.swift | 20 +++---- .../Views/Settings/Config/DeviceConfig.swift | 34 ++++------- .../Views/Settings/Config/DisplayConfig.swift | 18 ++---- .../Views/Settings/Config/LoRaConfig.swift | 28 +++------ .../Config/Module/AmbientLightingConfig.swift | 20 ++++--- .../Config/Module/CannedMessagesConfig.swift | 24 ++++---- .../Config/Module/DetectionSensorConfig.swift | 18 +++--- .../Module/ExternalNotificationConfig.swift | 60 +++++++++---------- .../Settings/Config/Module/MQTTConfig.swift | 53 ++++++---------- .../Config/Module/PaxCounterConfig.swift | 8 +-- .../Config/Module/RangeTestConfig.swift | 18 ++---- .../Settings/Config/Module/SerialConfig.swift | 29 ++------- .../Views/Settings/Config/NetworkConfig.swift | 18 ++---- .../Settings/Config/PositionConfig.swift | 52 +++++++--------- .../Views/Settings/Config/PowerConfig.swift | 16 +++-- 16 files changed, 167 insertions(+), 254 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index ec03b2f8..fdbd2d52 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1140,6 +1140,11 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate guard let lastLocation = LocationsHandler.shared.locationsArray.last else { return nil } + + if lastLocation == CLLocation(latitude: 0, longitude: 0) { + return nil + } + positionPacket.latitudeI = Int32(lastLocation.coordinate.latitude * 1e7) positionPacket.longitudeI = Int32(lastLocation.coordinate.longitude * 1e7) let timestamp = lastLocation.timestamp diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index aa36e193..2e12dbdb 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -116,25 +116,19 @@ struct BluetoothConfig: View { } } } - .onChange(of: enabled) { newEnabled in - if node != nil && node!.bluetoothConfig != nil { - if newEnabled != node!.bluetoothConfig!.enabled { hasChanges = true } - } + .onChange(of: enabled) { + if $0 != node?.bluetoothConfig?.enabled { hasChanges = true } } - .onChange(of: mode) { newMode in - if node != nil && node!.bluetoothConfig != nil { - if newMode != node!.bluetoothConfig!.mode { hasChanges = true } - } + .onChange(of: mode) { + if $0 != node?.bluetoothConfig?.mode ?? -1 { hasChanges = true } } .onChange(of: fixedPin) { newFixedPin in - if node != nil && node!.bluetoothConfig != nil { + if node != nil && node?.bluetoothConfig != nil { if newFixedPin != String(node!.bluetoothConfig!.fixedPin) { hasChanges = true } } } - .onChange(of: deviceLoggingEnabled) { newDeviceLogging in - if node != nil && node!.bluetoothConfig != nil { - if newDeviceLogging != node!.bluetoothConfig!.deviceLoggingEnabled { hasChanges = true } - } + .onChange(of: deviceLoggingEnabled) { + if $0 != node?.bluetoothConfig?.deviceLoggingEnabled { hasChanges = true } } } func setBluetoothValues() { diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 0d3349e1..bde4d2ff 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -155,7 +155,7 @@ struct DeviceConfig: View { .disabled(node?.user == nil) .buttonStyle(.bordered) .buttonBorderShape(.capsule) - .controlSize(.large) + .controlSize(.regular) .padding(.leading) .confirmationDialog( "are.you.sure", @@ -180,7 +180,7 @@ struct DeviceConfig: View { .disabled(node?.user == nil) .buttonStyle(.bordered) .buttonBorderShape(.capsule) - .controlSize(.large) + .controlSize(.regular) .padding(.trailing) .confirmationDialog( "All device and app data will be deleted. You will also need to forget your devices under Settings > Bluetooth.", @@ -252,20 +252,14 @@ struct DeviceConfig: View { } } } - .onChange(of: deviceRole) { newRole in - if node != nil && node?.deviceConfig != nil { - if newRole != node!.deviceConfig!.role { hasChanges = true } - } + .onChange(of: deviceRole) { + if $0 != node?.deviceConfig?.role ?? -1 { hasChanges = true } } - .onChange(of: serialEnabled) { newSerial in - if node != nil && node?.deviceConfig != nil { - if newSerial != node!.deviceConfig!.serialEnabled { hasChanges = true } - } + .onChange(of: serialEnabled) { + if $0 != node?.deviceConfig?.serialEnabled { hasChanges = true } } - .onChange(of: debugLogEnabled) { newDebugLog in - if node != nil && node?.deviceConfig != nil { - if newDebugLog != node!.deviceConfig!.debugLogEnabled { hasChanges = true } - } + .onChange(of: debugLogEnabled) { + if $0 != node?.deviceConfig?.debugLogEnabled { hasChanges = true } } .onChange(of: buttonGPIO) { newButtonGPIO in if node != nil && node?.deviceConfig != nil { @@ -287,15 +281,11 @@ struct DeviceConfig: View { if newNodeInfoBroadcastSecs != node!.deviceConfig!.nodeInfoBroadcastSecs { hasChanges = true } } } - .onChange(of: doubleTapAsButtonPress) { newDoubleTapAsButtonPress in - if node != nil && node?.deviceConfig != nil { - if newDoubleTapAsButtonPress != node!.deviceConfig!.doubleTapAsButtonPress { hasChanges = true } - } + .onChange(of: doubleTapAsButtonPress) { + if $0 != node?.deviceConfig?.doubleTapAsButtonPress { hasChanges = true } } - .onChange(of: isManaged) { newIsManaged in - if node != nil && node?.deviceConfig != nil { - if newIsManaged != node!.deviceConfig!.isManaged { hasChanges = true } - } + .onChange(of: isManaged) { + if $0 != node?.deviceConfig?.isManaged { hasChanges = true } } .onChange(of: tzdef) { newTzdef in if node != nil && node?.deviceConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 0b497037..c26d741b 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -183,25 +183,19 @@ struct DisplayConfig: View { if newCarouselSecs != node!.displayConfig!.screenCarouselInterval { hasChanges = true } } } - .onChange(of: compassNorthTop) { newCompassNorthTop in - if node != nil && node!.displayConfig != nil { - if newCompassNorthTop != node!.displayConfig!.compassNorthTop { hasChanges = true } - } + .onChange(of: compassNorthTop) { + if $0 != node?.displayConfig?.compassNorthTop { hasChanges = true } } - .onChange(of: wakeOnTapOrMotion) { newWakeOnTapOrMotion in - if node != nil && node!.displayConfig != nil { - if newWakeOnTapOrMotion != node!.displayConfig!.wakeOnTapOrMotion { hasChanges = true } - } + .onChange(of: wakeOnTapOrMotion) { + if $0 != node?.displayConfig?.wakeOnTapOrMotion { hasChanges = true } } .onChange(of: gpsFormat) { newGpsFormat in if node != nil && node!.displayConfig != nil { if newGpsFormat != node!.displayConfig!.gpsFormat { hasChanges = true } } } - .onChange(of: flipScreen) { newFlipScreen in - if node != nil && node!.displayConfig != nil { - if newFlipScreen != node!.displayConfig!.flipScreen { hasChanges = true } - } + .onChange(of: flipScreen) { + if $0 != node?.displayConfig?.flipScreen { hasChanges = true } } .onChange(of: oledType) { newOledType in if node != nil && node!.displayConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index d2062468..24a79c31 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -245,10 +245,8 @@ struct LoRaConfig: View { if newRegion != node!.loRaConfig!.regionCode { hasChanges = true } } } - .onChange(of: usePreset) { newUsePreset in - if node != nil && node!.loRaConfig != nil { - if newUsePreset != node!.loRaConfig!.usePreset { hasChanges = true } - } + .onChange(of: usePreset) { + if $0 != node?.loRaConfig?.usePreset { hasChanges = true } } .onChange(of: modemPreset) { newModemPreset in if node != nil && node!.loRaConfig != nil { @@ -280,30 +278,22 @@ struct LoRaConfig: View { if newSpreadFactor != node!.loRaConfig!.spreadFactor { hasChanges = true } } } - .onChange(of: rxBoostedGain) { newRxBoostedGain in - if node != nil && node!.loRaConfig != nil { - if newRxBoostedGain != node!.loRaConfig!.sx126xRxBoostedGain { hasChanges = true } - } + .onChange(of: rxBoostedGain) { + if $0 != node?.loRaConfig?.sx126xRxBoostedGain { hasChanges = true } } .onChange(of: overrideFrequency) { newOverrideFrequency in - if node != nil && node!.loRaConfig != nil { - if newOverrideFrequency != node!.loRaConfig!.overrideFrequency { hasChanges = true } - } + if newOverrideFrequency != node?.loRaConfig?.overrideFrequency { hasChanges = true } } .onChange(of: txPower) { newTxPower in if node != nil && node!.loRaConfig != nil { if newTxPower != node!.loRaConfig!.txPower { hasChanges = true } } } - .onChange(of: txEnabled) { newTxEnabled in - if node != nil && node!.loRaConfig != nil { - if newTxEnabled != node!.loRaConfig!.txEnabled { hasChanges = true } - } + .onChange(of: txEnabled) { + if $0 != node?.loRaConfig?.txEnabled { hasChanges = true } } - .onChange(of: ignoreMqtt) { newIgnoreMqtt in - if node != nil && node!.loRaConfig != nil { - if newIgnoreMqtt != node!.loRaConfig!.ignoreMqtt { hasChanges = true } - } + .onChange(of: ignoreMqtt) { + if $0 != node?.loRaConfig?.ignoreMqtt { hasChanges = true } } } func setLoRaValues() { diff --git a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift index 1949db37..76c98752 100644 --- a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift @@ -50,10 +50,6 @@ struct AmbientLightingConfig: View { Stepper("Current: \(current)", value: $current, in: 0...31, step: 1) .padding(5) } - .onChange(of: color, initial: true) { - components = color.resolve(in: environment) - hasChanges = true - } } } .disabled(self.bleManager.connectedPeripheral == nil || node?.ambientLightingConfig == nil) @@ -98,9 +94,19 @@ struct AmbientLightingConfig: View { } } } - .onChange(of: ledState) { newLedState in - if node != nil && node!.ambientLightingConfig != nil { - if newLedState != node!.ambientLightingConfig!.ledState { hasChanges = true } + .onChange(of: ledState) { + if let val = node?.ambientLightingConfig?.ledState { + hasChanges = $0 != val + } + } + .onChange(of: current) { + if let val = node?.ambientLightingConfig?.current { + hasChanges = $0 != val + } + } + .onChange(of: color) { c in + if color != c { + hasChanges = true } } } diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index d30872d5..b4ec0b63 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -272,24 +272,24 @@ struct CannedMessagesConfig: View { hasChanges = true } - .onChange(of: enabled) { newEnabled in - if node != nil && node!.cannedMessageConfig != nil { - if newEnabled != node!.cannedMessageConfig!.enabled { hasChanges = true } + .onChange(of: enabled) { + if let val = node?.cannedMessageConfig?.enabled { + hasChanges = $0 != val } } - .onChange(of: sendBell) { newBell in - if node != nil && node!.cannedMessageConfig != nil { - if newBell != node!.cannedMessageConfig!.sendBell { hasChanges = true } + .onChange(of: sendBell) { + if let val = node?.cannedMessageConfig?.sendBell { + hasChanges = $0 != val } } - .onChange(of: rotary1Enabled) { newRot1 in - if node != nil && node!.cannedMessageConfig != nil { - if newRot1 != node!.cannedMessageConfig!.rotary1Enabled { hasChanges = true } + .onChange(of: rotary1Enabled) { + if let val = node?.cannedMessageConfig?.rotary1Enabled { + hasChanges = $0 != val } } - .onChange(of: updown1Enabled) { newUpDown in - if node != nil && node!.cannedMessageConfig != nil { - if newUpDown != node!.cannedMessageConfig!.updown1Enabled { hasChanges = true } + .onChange(of: updown1Enabled) { + if let val = node?.cannedMessageConfig?.updown1Enabled { + hasChanges = $0 != val } } .onChange(of: inputbrokerPinA) { newPinA in diff --git a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift index 358576d4..1ff1ed86 100644 --- a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift @@ -199,14 +199,14 @@ struct DetectionSensorConfig: View { } } } - .onChange(of: enabled) { newEnabled in - if node != nil && node?.detectionSensorConfig != nil { - if newEnabled != node!.detectionSensorConfig!.enabled { hasChanges = true } + .onChange(of: enabled) { + if let val = node?.detectionSensorConfig?.enabled { + hasChanges = $0 != val } } - .onChange(of: sendBell) { newSendBell in - if node != nil && node?.detectionSensorConfig != nil { - if newSendBell != node!.detectionSensorConfig!.sendBell { hasChanges = true } + .onChange(of: sendBell) { + if let val = node?.detectionSensorConfig?.sendBell { + hasChanges = $0 != val } } .onChange(of: detectionTriggeredHigh) { newDetectionTriggeredHigh in @@ -214,9 +214,9 @@ struct DetectionSensorConfig: View { if newDetectionTriggeredHigh != node!.detectionSensorConfig!.detectionTriggeredHigh { hasChanges = true } } } - .onChange(of: usePullup) { newUsePullup in - if node != nil && node?.detectionSensorConfig != nil { - if newUsePullup != node!.detectionSensorConfig!.usePullup { hasChanges = true } + .onChange(of: usePullup) { + if let val = node?.detectionSensorConfig?.usePullup { + hasChanges = $0 != val } } .onChange(of: name) { newName in diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index fc6f33f2..32cacbd3 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -209,44 +209,44 @@ struct ExternalNotificationConfig: View { } } } - .onChange(of: enabled) { newEnabled in - if node != nil && node!.externalNotificationConfig != nil { - if newEnabled != node!.externalNotificationConfig!.enabled { hasChanges = true } + .onChange(of: enabled) { + if let val = node?.externalNotificationConfig?.enabled { + hasChanges = $0 != val } } - .onChange(of: alertBell) { newAlertBell in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertBell != node!.externalNotificationConfig!.alertBell { hasChanges = true } + .onChange(of: alertBell) { + if let val = node?.externalNotificationConfig?.alertBell { + hasChanges = $0 != val } } - .onChange(of: alertBellBuzzer) { newAlertBellBuzzer in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertBellBuzzer != node!.externalNotificationConfig!.alertBellBuzzer { hasChanges = true } + .onChange(of: alertBellBuzzer) { + if let val = node?.externalNotificationConfig?.alertBellBuzzer { + hasChanges = $0 != val } } - .onChange(of: alertBellVibra) { newAlertBellVibra in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertBellVibra != node!.externalNotificationConfig!.alertBellVibra { hasChanges = true } + .onChange(of: alertBellVibra) { + if let val = node?.externalNotificationConfig?.alertBellVibra { + hasChanges = $0 != val } } - .onChange(of: alertMessage) { newAlertMessage in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertMessage != node!.externalNotificationConfig!.alertMessage { hasChanges = true } + .onChange(of: alertMessage) { + if let val = node?.externalNotificationConfig?.alertMessage { + hasChanges = $0 != val } } - .onChange(of: alertMessageBuzzer) { newAlertMessageBuzzer in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertMessageBuzzer != node!.externalNotificationConfig!.alertMessageBuzzer { hasChanges = true } + .onChange(of: alertMessageBuzzer) { + if let val = node?.externalNotificationConfig?.alertMessageBuzzer { + hasChanges = $0 != val } } - .onChange(of: alertMessageVibra) { newAlertMessageVibra in - if node != nil && node!.externalNotificationConfig != nil { - if newAlertMessageVibra != node!.externalNotificationConfig!.alertMessageVibra { hasChanges = true } + .onChange(of: alertMessageVibra) { + if let val = node?.externalNotificationConfig?.alertMessageVibra { + hasChanges = $0 != val } } - .onChange(of: active) { newActive in - if node != nil && node!.externalNotificationConfig != nil { - if newActive != node!.externalNotificationConfig!.active { hasChanges = true } + .onChange(of: active) { + if let val = node?.externalNotificationConfig?.active { + hasChanges = $0 != val } } .onChange(of: output) { newOutput in @@ -269,9 +269,9 @@ struct ExternalNotificationConfig: View { if newOutputMs != node!.externalNotificationConfig!.outputMilliseconds { hasChanges = true } } } - .onChange(of: usePWM) { newUsePWM in - if node != nil && node!.externalNotificationConfig != nil { - if newUsePWM != node!.externalNotificationConfig!.usePWM { hasChanges = true } + .onChange(of: usePWM) { + if let val = node?.externalNotificationConfig?.usePWM { + hasChanges = $0 != val } } .onChange(of: nagTimeout) { newNagTimeout in @@ -279,9 +279,9 @@ struct ExternalNotificationConfig: View { if newNagTimeout != node!.externalNotificationConfig!.nagTimeout { hasChanges = true } } } - .onChange(of: useI2SAsBuzzer) { newUseI2SAsBuzzer in - if node != nil && node!.externalNotificationConfig != nil { - if newUseI2SAsBuzzer != node!.externalNotificationConfig!.useI2SAsBuzzer { hasChanges = true } + .onChange(of: useI2SAsBuzzer) { + if let val = node?.externalNotificationConfig?.useI2SAsBuzzer { + hasChanges = $0 != val } } } diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 91bb80e1..d6176526 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -280,6 +280,18 @@ struct MQTTConfig: View { ) } ) + .onChange(of: enabled) { + if $0 != node?.mqttConfig?.enabled { hasChanges = true } + } + .onChange(of: proxyToClientEnabled) { newProxyToClientEnabled in + if newProxyToClientEnabled { + jsonEnabled = false + } + if newProxyToClientEnabled != node?.mqttConfig?.proxyToClientEnabled { hasChanges = true } + if newProxyToClientEnabled { + jsonEnabled = false + } + } .onChange(of: address) { newAddress in if node != nil && node?.mqttConfig != nil { if newAddress != node!.mqttConfig!.address { hasChanges = true } @@ -303,39 +315,17 @@ struct MQTTConfig: View { .onChange(of: selectedTopic) { newSelectedTopic in root = newSelectedTopic } - .onChange(of: enabled) { newEnabled in - if node != nil && node?.mqttConfig != nil { - if newEnabled != node!.mqttConfig!.enabled { hasChanges = true } - } - } - .onChange(of: proxyToClientEnabled) { newProxyToClientEnabled in - if newProxyToClientEnabled { - jsonEnabled = false - } - if node != nil && node?.mqttConfig != nil { - if newProxyToClientEnabled != node!.mqttConfig!.proxyToClientEnabled { hasChanges = true } - if newProxyToClientEnabled { - jsonEnabled = false - } - } - } - .onChange(of: encryptionEnabled) { newEncryptionEnabled in - if node != nil && node?.mqttConfig != nil { - if newEncryptionEnabled != node!.mqttConfig!.encryptionEnabled { hasChanges = true } - } + .onChange(of: encryptionEnabled) { + if $0 != node?.mqttConfig?.encryptionEnabled { hasChanges = true } } .onChange(of: jsonEnabled) { newJsonEnabled in if newJsonEnabled { proxyToClientEnabled = false } - if node != nil && node?.mqttConfig != nil { - if newJsonEnabled != node!.mqttConfig!.jsonEnabled { hasChanges = true } - } + if newJsonEnabled != node?.mqttConfig?.jsonEnabled { hasChanges = true } } - .onChange(of: tlsEnabled) { newTlsEnabled in - if node != nil && node?.mqttConfig != nil { - if newTlsEnabled != node!.mqttConfig!.tlsEnabled { hasChanges = true } - } + .onChange(of: tlsEnabled) { + if $0 != node?.mqttConfig?.tlsEnabled { hasChanges = true } } .onChange(of: mqttConnected) { newMqttConnected in if newMqttConnected == false { @@ -348,13 +338,8 @@ struct MQTTConfig: View { } } } - .onChange(of: mapReportingEnabled) { newMapReportingEnabled in - if node != nil && node?.mqttConfig != nil { - if newMapReportingEnabled != node!.mqttConfig!.mapReportingEnabled { hasChanges = true } - } - } - .onChange(of: preciseLocation) { _ in - hasChanges = true + .onChange(of: mapReportingEnabled) { + if $0 != node?.mqttConfig?.mapReportingEnabled { hasChanges = true } } .onChange(of: mapPublishIntervalSecs) { newMapPublishIntervalSecs in if node != nil && node?.mqttConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift index ce9d34f8..6e7bef08 100644 --- a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift @@ -67,14 +67,10 @@ struct PaxCounterConfig: View { } } .onChange(of: enabled) { - if let val = node?.paxCounterConfig?.enabled { - hasChanges = $0 != val - } + if $0 != node?.paxCounterConfig?.enabled { hasChanges = true } } .onChange(of: paxcounterUpdateInterval) { - if let val = node?.paxCounterConfig?.updateInterval { - hasChanges = $0 != val - } + if $0 != node?.paxCounterConfig?.updateInterval ?? -1 { hasChanges = true } } SaveConfigButton(node: node, hasChanges: $hasChanges) { diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 51c847e6..001ad2b1 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -91,20 +91,14 @@ struct RangeTestConfig: View { } } } - .onChange(of: enabled) { newEnabled in - if node != nil && node!.rangeTestConfig != nil { - if newEnabled != node!.rangeTestConfig!.enabled { hasChanges = true } - } + .onChange(of: enabled) { + if $0 != node?.rangeTestConfig?.enabled { hasChanges = true } } - .onChange(of: save) { newSave in - if node != nil && node!.rangeTestConfig != nil { - if newSave != node!.rangeTestConfig!.save { hasChanges = true } - } + .onChange(of: save) { + if $0 != node?.rangeTestConfig?.save { hasChanges = true } } - .onChange(of: sender) { newSender in - if node != nil && node!.rangeTestConfig != nil { - if newSender != node!.rangeTestConfig!.sender { hasChanges = true } - } + .onChange(of: sender) { + if $0 != node?.rangeTestConfig?.sender ?? -1 { hasChanges = true } } } } diff --git a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift index 6d5b4421..c7243a87 100644 --- a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift @@ -145,61 +145,40 @@ struct SerialConfig: View { _ = bleManager.requestSerialModuleConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) } } - } - .onChange(of: enabled) { newEnabled in - - if node != nil && node!.serialConfig != nil { - - if newEnabled != node!.serialConfig!.enabled { hasChanges = true } - } + .onChange(of: enabled) { + if $0 != node?.serialConfig?.enabled { hasChanges = true } } - .onChange(of: echo) { newEcho in - - if node != nil && node!.serialConfig != nil { - - if newEcho != node!.serialConfig!.echo { hasChanges = true } - } + .onChange(of: echo) { + if $0 != node?.serialConfig?.echo { hasChanges = true } } .onChange(of: rxd) { newRxd in - if node != nil && node!.serialConfig != nil { - if newRxd != node!.serialConfig!.rxd { hasChanges = true } } } .onChange(of: txd) { newTxd in - if node != nil && node!.serialConfig != nil { - if newTxd != node!.serialConfig!.txd { hasChanges = true } } } .onChange(of: baudRate) { newBaud in - if node != nil && node!.serialConfig != nil { - if newBaud != node!.serialConfig!.baudRate { hasChanges = true } } } .onChange(of: timeout) { newTimeout in - if node != nil && node!.serialConfig != nil { - if newTimeout != node!.serialConfig!.timeout { hasChanges = true } } } .onChange(of: overrideConsoleSerialPort) { newOverrideConsoleSerialPort in - if node != nil && node!.serialConfig != nil { - if newOverrideConsoleSerialPort != node!.serialConfig!.overrideConsoleSerialPort { hasChanges = true } } } .onChange(of: mode) { newMode in - if node != nil && node!.serialConfig != nil { - if newMode != node!.serialConfig!.mode { hasChanges = true } } } diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index 3bc28ef6..fb260a69 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -128,10 +128,8 @@ struct NetworkConfig: View { } } } - .onChange(of: wifiEnabled) { newEnabled in - if node != nil && node!.networkConfig != nil { - if newEnabled != node!.networkConfig!.wifiEnabled { hasChanges = true } - } + .onChange(of: wifiEnabled) { + if $0 != node?.networkConfig?.wifiEnabled { hasChanges = true } } .onChange(of: wifiSsid) { newSSID in if node != nil && node!.networkConfig != nil { @@ -143,15 +141,11 @@ struct NetworkConfig: View { if newPsk != node!.networkConfig!.wifiPsk { hasChanges = true } } } - .onChange(of: wifiMode) { newMode in - if node != nil && node!.networkConfig != nil { - if newMode != node!.networkConfig!.wifiMode { hasChanges = true } - } + .onChange(of: wifiMode) { + if $0 != node?.networkConfig?.wifiMode ?? -1 { hasChanges = true } } - .onChange(of: ethEnabled) { newEthEnabled in - if node != nil && node!.networkConfig != nil { - if newEthEnabled != node!.networkConfig!.ethEnabled { hasChanges = true } - } + .onChange(of: ethEnabled) { + if $0 != node?.networkConfig?.ethEnabled { hasChanges = true } } } func setNetworkValues() { diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index 2fd9bcf1..0f71b379 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -404,51 +404,39 @@ struct PositionConfig: View { } } } - .onChange(of: gpsMode) { _ in - handleChanges() + .onChange(of: gpsMode) { newGpsMode in + if newGpsMode != node?.positionConfig?.gpsMode ?? 0 { hasChanges = true } } - .onChange(of: rxGpio) { _ in - handleChanges() + .onChange(of: rxGpio) { newRxGpio in + if newRxGpio != node?.positionConfig?.rxGpio ?? 0 { hasChanges = true } } - .onChange(of: txGpio) { _ in - handleChanges() + .onChange(of: txGpio) { newTxGpio in + if newTxGpio != node?.positionConfig?.txGpio ?? 0 { hasChanges = true } } - .onChange(of: gpsEnGpio) { _ in - handleChanges() + .onChange(of: gpsEnGpio) { newGpsEnGpio in + if newGpsEnGpio != node?.positionConfig?.gpsEnGpio ?? 0 { hasChanges = true } } - .onChange(of: smartPositionEnabled) { _ in - handleChanges() + .onChange(of: smartPositionEnabled) { newSmartPositionEnabled in + if newSmartPositionEnabled != node?.positionConfig?.smartPositionEnabled { hasChanges = true } } - .onChange(of: positionBroadcastSeconds) { _ in - handleChanges() + .onChange(of: positionBroadcastSeconds) { newPositionBroadcastSeconds in + if newPositionBroadcastSeconds != node?.positionConfig?.positionBroadcastSeconds ?? 0 { hasChanges = true } } - .onChange(of: broadcastSmartMinimumIntervalSecs) { _ in - handleChanges() + .onChange(of: broadcastSmartMinimumIntervalSecs) { newBroadcastSmartMinimumIntervalSecs in + if newBroadcastSmartMinimumIntervalSecs != node?.positionConfig?.broadcastSmartMinimumIntervalSecs ?? 0 { hasChanges = true } } - .onChange(of: broadcastSmartMinimumDistance) { _ in - handleChanges() + .onChange(of: broadcastSmartMinimumDistance) { newBroadcastSmartMinimumDistance in + if newBroadcastSmartMinimumDistance != node?.positionConfig?.broadcastSmartMinimumDistance ?? 0 { hasChanges = true } } - .onChange(of: gpsUpdateInterval) { _ in - handleChanges() - } - .onChange(of: positionFlags) { _ in - handleChanges() + .onChange(of: gpsUpdateInterval) { newGpsUpdateInterval in + if newGpsUpdateInterval != node?.positionConfig?.gpsUpdateInterval ?? 0 { hasChanges = true } } } - func handleChanges() { + func handlePositionFlagtChanges() { guard let positionConfig = node?.positionConfig else { return } let pf = PositionFlags(rawValue: self.positionFlags) - hasChanges = positionConfig.deviceGpsEnabled != deviceGpsEnabled || - positionConfig.gpsMode != gpsMode || - positionConfig.rxGpio != rxGpio || - positionConfig.txGpio != txGpio || - positionConfig.gpsEnGpio != gpsEnGpio || - positionConfig.smartPositionEnabled != smartPositionEnabled || - positionConfig.positionBroadcastSeconds != positionBroadcastSeconds || - positionConfig.broadcastSmartMinimumIntervalSecs != broadcastSmartMinimumIntervalSecs || - positionConfig.broadcastSmartMinimumDistance != broadcastSmartMinimumDistance || - positionConfig.gpsUpdateInterval != gpsUpdateInterval || + hasChanges = pf.contains(.Altitude) || pf.contains(.AltitudeMsl) || pf.contains(.Satsinview) || diff --git a/Meshtastic/Views/Settings/Config/PowerConfig.swift b/Meshtastic/Views/Settings/Config/PowerConfig.swift index 8f67d6bd..4249aab1 100644 --- a/Meshtastic/Views/Settings/Config/PowerConfig.swift +++ b/Meshtastic/Views/Settings/Config/PowerConfig.swift @@ -136,12 +136,12 @@ struct PowerConfig: View { } } .onChange(of: isPowerSaving) { - if let val = node?.powerConfig?.isPowerSaving { - hasChanges = $0 != val - } + if $0 != node?.powerConfig?.isPowerSaving { hasChanges = true } } - .onChange(of: shutdownOnPowerLoss) { _ in - hasChanges = true + .onChange(of: shutdownOnPowerLoss) { newShutdownOnPowerLoss in + if newShutdownOnPowerLoss { + hasChanges = true + } } .onChange(of: shutdownAfterSecs) { if let val = node?.powerConfig?.onBatteryShutdownAfterSecs { @@ -151,10 +151,8 @@ struct PowerConfig: View { .onChange(of: adcOverride) { _ in hasChanges = true } - .onChange(of: adcMultiplier) { - if let val = node?.powerConfig?.adcMultiplierOverride { - hasChanges = $0 != val - } + .onChange(of: adcMultiplier) { newAdcMultiplier in + if newAdcMultiplier != node?.powerConfig?.adcMultiplierOverride ?? 0 { hasChanges = true } } .onChange(of: waitBluetoothSecs) { if let val = node?.powerConfig?.waitBluetoothSecs { From 61a6776b716b4b28139b14ed59d1978687894cfe Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 18:18:27 -0700 Subject: [PATCH 15/75] Fix merge conflict --- Meshtastic/Views/ContentView.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Views/ContentView.swift b/Meshtastic/Views/ContentView.swift index 4ab6ac85..e8384c35 100644 --- a/Meshtastic/Views/ContentView.swift +++ b/Meshtastic/Views/ContentView.swift @@ -6,8 +6,11 @@ import SwiftUI @available(iOS 17.0, *) struct ContentView: View { - @ObservedObject var appState: AppState - @ObservedObject var router: Router + @ObservedObject + var appState: AppState + + @ObservedObject + var router: Router var body: some View { TabView(selection: Binding( From c0fd6cbf942ce17e9a8dbc375a0bfb9a284b121c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 20:50:48 -0700 Subject: [PATCH 16/75] Security config details, scroll dismisses keyboard,font size updates for keys --- .../Settings/Config/SecurityConfig.swift | 41 +++++++++++-------- protobufs | 2 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index a3aa1f45..f3f79734 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -13,6 +13,7 @@ import OSLog struct SecurityConfig: View { + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @Environment(\.dismiss) private var goBack @@ -38,18 +39,16 @@ struct SecurityConfig: View { VStack(alignment: .leading) { Label("Public Key", systemImage: "key") - Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") - .foregroundStyle(.secondary) - .font(.caption) - TextField( "Public Key", text: $publicKey, axis: .vertical ) - .padding(5) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() .keyboardType(.alphabet) - .foregroundColor(.secondary) + .foregroundStyle(.tertiary) .disableAutocorrection(true) .textSelection(.enabled) .background( @@ -57,50 +56,55 @@ struct SecurityConfig: View { .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) ) + Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") + .foregroundStyle(.secondary) + .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Private Key", systemImage: "key.fill") - Text("Used to create a shared key with a remote device.") - .foregroundStyle(.secondary) - .font(.caption) - TextField( "Private Key", text: $privateKey, axis: .vertical ) - .padding(5) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() .disableAutocorrection(true) .keyboardType(.alphabet) - .foregroundColor(.secondary) + .foregroundStyle(.tertiary) .textSelection(.enabled) .background( RoundedRectangle(cornerRadius: 10.0) .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) ) + Text("Used to create a shared key with a remote device.") + .foregroundStyle(.secondary) + .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Admin Key", systemImage: "key.viewfinder") - Text("The public key authorized to send admin messages to this node.") - .foregroundStyle(.secondary) - .font(.caption) - TextField( "Admin Key", text: $adminKey, axis: .vertical ) - .padding(5) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() .disableAutocorrection(true) .keyboardType(.alphabet) - .foregroundColor(.secondary) + .foregroundStyle(.tertiary) .textSelection(.enabled) .background( RoundedRectangle(cornerRadius: 10.0) .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) ) + Text("The public key authorized to send admin messages to this node.") + .foregroundStyle(.secondary) + .font(idiom == .phone ? .caption : .callout) } } Section(header: Text("Logs")) { @@ -141,6 +145,7 @@ struct SecurityConfig: View { } } } + .scrollDismissesKeyboard(.immediately) .navigationTitle("Security Config") .navigationBarItems(trailing: ZStack { ConnectedDevice( diff --git a/protobufs b/protobufs index 66eb3184..0c052b5d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 66eb3184d5651705ae62f80bf4f65b94a62e7f06 +Subproject commit 0c052b5d25fe8ed74c675178702f20a3fbc29afa From 6c6b44fdaa43cb8345e2bee1775bc8fd530b49ba Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 11 Aug 2024 21:20:10 -0700 Subject: [PATCH 17/75] Simplify change events to not force unwrap values --- .../Settings/Config/BluetoothConfig.swift | 4 +-- .../Views/Settings/Config/DeviceConfig.swift | 20 +++--------- .../Views/Settings/Config/DisplayConfig.swift | 24 ++++---------- .../Views/Settings/Config/LoRaConfig.swift | 32 +++++-------------- .../Views/Settings/Config/NetworkConfig.swift | 9 ++---- .../Views/Settings/Config/PowerConfig.swift | 18 +++-------- .../Settings/Config/SecurityConfig.swift | 20 +++--------- 7 files changed, 33 insertions(+), 94 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index 2e12dbdb..75132df1 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -123,9 +123,7 @@ struct BluetoothConfig: View { if $0 != node?.bluetoothConfig?.mode ?? -1 { hasChanges = true } } .onChange(of: fixedPin) { newFixedPin in - if node != nil && node?.bluetoothConfig != nil { - if newFixedPin != String(node!.bluetoothConfig!.fixedPin) { hasChanges = true } - } + if newFixedPin != String(node?.bluetoothConfig?.fixedPin ?? -1) { hasChanges = true } } .onChange(of: deviceLoggingEnabled) { if $0 != node?.bluetoothConfig?.deviceLoggingEnabled { hasChanges = true } diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index bde4d2ff..ff23c6e5 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -262,24 +262,16 @@ struct DeviceConfig: View { if $0 != node?.deviceConfig?.debugLogEnabled { hasChanges = true } } .onChange(of: buttonGPIO) { newButtonGPIO in - if node != nil && node?.deviceConfig != nil { - if newButtonGPIO != node!.deviceConfig!.buttonGpio { hasChanges = true } - } + if newButtonGPIO != node?.deviceConfig?.buttonGpio ?? -1 { hasChanges = true } } .onChange(of: buzzerGPIO) { newBuzzerGPIO in - if node != nil && node?.deviceConfig != nil { - if newBuzzerGPIO != node!.deviceConfig!.buttonGpio { hasChanges = true } - } + if newBuzzerGPIO != node?.deviceConfig?.buttonGpio ?? -1 { hasChanges = true } } .onChange(of: rebroadcastMode) { newRebroadcastMode in - if node != nil && node?.deviceConfig != nil { - if newRebroadcastMode != node!.deviceConfig!.rebroadcastMode { hasChanges = true } - } + if newRebroadcastMode != node?.deviceConfig?.rebroadcastMode ?? -1 { hasChanges = true } } .onChange(of: nodeInfoBroadcastSecs) { newNodeInfoBroadcastSecs in - if node != nil && node?.deviceConfig != nil { - if newNodeInfoBroadcastSecs != node!.deviceConfig!.nodeInfoBroadcastSecs { hasChanges = true } - } + if newNodeInfoBroadcastSecs != node?.deviceConfig?.nodeInfoBroadcastSecs ?? -1 { hasChanges = true } } .onChange(of: doubleTapAsButtonPress) { if $0 != node?.deviceConfig?.doubleTapAsButtonPress { hasChanges = true } @@ -288,9 +280,7 @@ struct DeviceConfig: View { if $0 != node?.deviceConfig?.isManaged { hasChanges = true } } .onChange(of: tzdef) { newTzdef in - if node != nil && node?.deviceConfig != nil { - if newTzdef != node!.deviceConfig!.tzdef { hasChanges = true } - } + if newTzdef != node?.deviceConfig?.tzdef { hasChanges = true } } } func setDeviceValues() { diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index c26d741b..1f3f6de4 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -174,14 +174,10 @@ struct DisplayConfig: View { } } .onChange(of: screenOnSeconds) { newScreenSecs in - if node != nil && node!.displayConfig != nil { - if newScreenSecs != node!.displayConfig!.screenOnSeconds { hasChanges = true } - } + if newScreenSecs != node?.displayConfig?.screenOnSeconds ?? -1 { hasChanges = true } } .onChange(of: screenCarouselInterval) { newCarouselSecs in - if node != nil && node!.displayConfig != nil { - if newCarouselSecs != node!.displayConfig!.screenCarouselInterval { hasChanges = true } - } + if newCarouselSecs != node?.displayConfig?.screenCarouselInterval ?? -1 { hasChanges = true } } .onChange(of: compassNorthTop) { if $0 != node?.displayConfig?.compassNorthTop { hasChanges = true } @@ -190,27 +186,19 @@ struct DisplayConfig: View { if $0 != node?.displayConfig?.wakeOnTapOrMotion { hasChanges = true } } .onChange(of: gpsFormat) { newGpsFormat in - if node != nil && node!.displayConfig != nil { - if newGpsFormat != node!.displayConfig!.gpsFormat { hasChanges = true } - } + if newGpsFormat != node?.displayConfig?.gpsFormat ?? -1 { hasChanges = true } } .onChange(of: flipScreen) { if $0 != node?.displayConfig?.flipScreen { hasChanges = true } } .onChange(of: oledType) { newOledType in - if node != nil && node!.displayConfig != nil { - if newOledType != node!.displayConfig!.oledType { hasChanges = true } - } + if newOledType != node?.displayConfig?.oledType ?? -1 { hasChanges = true } } .onChange(of: displayMode) { newDisplayMode in - if node != nil && node!.displayConfig != nil { - if newDisplayMode != node!.displayConfig!.displayMode { hasChanges = true } - } + if newDisplayMode != node?.displayConfig?.displayMode ?? -1 { hasChanges = true } } .onChange(of: units) { newUnits in - if node != nil && node!.displayConfig != nil { - if newUnits != node!.displayConfig!.units { hasChanges = true } - } + if newUnits != node?.displayConfig?.units ?? -1 { hasChanges = true } } } func setDisplayValues() { diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 24a79c31..0a309815 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -241,42 +241,28 @@ struct LoRaConfig: View { } } .onChange(of: region) { newRegion in - if node != nil && node!.loRaConfig != nil { - if newRegion != node!.loRaConfig!.regionCode { hasChanges = true } - } + if newRegion != node?.loRaConfig?.regionCode ?? -1 { hasChanges = true } } .onChange(of: usePreset) { if $0 != node?.loRaConfig?.usePreset { hasChanges = true } } .onChange(of: modemPreset) { newModemPreset in - if node != nil && node!.loRaConfig != nil { - if newModemPreset != node!.loRaConfig!.modemPreset { hasChanges = true } - } + if newModemPreset != node?.loRaConfig?.modemPreset ?? -1 { hasChanges = true } } .onChange(of: hopLimit) { newHopLimit in - if node != nil && node!.loRaConfig != nil { - if newHopLimit != node!.loRaConfig!.hopLimit { hasChanges = true } - } + if newHopLimit != node?.loRaConfig?.hopLimit ?? -1 { hasChanges = true } } .onChange(of: channelNum) { newChannelNum in - if node != nil && node!.loRaConfig != nil { - if newChannelNum != node!.loRaConfig!.channelNum { hasChanges = true } - } + if newChannelNum != node?.loRaConfig?.channelNum ?? -1 { hasChanges = true } } .onChange(of: bandwidth) { newBandwidth in - if node != nil && node!.loRaConfig != nil { - if newBandwidth != node!.loRaConfig!.bandwidth { hasChanges = true } - } + if newBandwidth != node?.loRaConfig?.bandwidth ?? -1 { hasChanges = true } } .onChange(of: codingRate) { newCodingRate in - if node != nil && node!.loRaConfig != nil { - if newCodingRate != node!.loRaConfig!.codingRate { hasChanges = true } - } + if newCodingRate != node?.loRaConfig?.codingRate ?? -1 { hasChanges = true } } .onChange(of: spreadFactor) { newSpreadFactor in - if node != nil && node!.loRaConfig != nil { - if newSpreadFactor != node!.loRaConfig!.spreadFactor { hasChanges = true } - } + if newSpreadFactor != node?.loRaConfig?.spreadFactor ?? -1 { hasChanges = true } } .onChange(of: rxBoostedGain) { if $0 != node?.loRaConfig?.sx126xRxBoostedGain { hasChanges = true } @@ -285,9 +271,7 @@ struct LoRaConfig: View { if newOverrideFrequency != node?.loRaConfig?.overrideFrequency { hasChanges = true } } .onChange(of: txPower) { newTxPower in - if node != nil && node!.loRaConfig != nil { - if newTxPower != node!.loRaConfig!.txPower { hasChanges = true } - } + if newTxPower != node?.loRaConfig?.txPower ?? -1 { hasChanges = true } } .onChange(of: txEnabled) { if $0 != node?.loRaConfig?.txEnabled { hasChanges = true } diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index fb260a69..51981606 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -132,14 +132,11 @@ struct NetworkConfig: View { if $0 != node?.networkConfig?.wifiEnabled { hasChanges = true } } .onChange(of: wifiSsid) { newSSID in - if node != nil && node!.networkConfig != nil { - if newSSID != node!.networkConfig!.wifiSsid { hasChanges = true } - } + if newSSID != node?.networkConfig?.wifiSsid { hasChanges = true } + } .onChange(of: wifiPsk) { newPsk in - if node != nil && node!.networkConfig != nil { - if newPsk != node!.networkConfig!.wifiPsk { hasChanges = true } - } + if newPsk != node?.networkConfig?.wifiPsk { hasChanges = true } } .onChange(of: wifiMode) { if $0 != node?.networkConfig?.wifiMode ?? -1 { hasChanges = true } diff --git a/Meshtastic/Views/Settings/Config/PowerConfig.swift b/Meshtastic/Views/Settings/Config/PowerConfig.swift index 4249aab1..42b6a534 100644 --- a/Meshtastic/Views/Settings/Config/PowerConfig.swift +++ b/Meshtastic/Views/Settings/Config/PowerConfig.swift @@ -144,30 +144,22 @@ struct PowerConfig: View { } } .onChange(of: shutdownAfterSecs) { - if let val = node?.powerConfig?.onBatteryShutdownAfterSecs { - hasChanges = $0 != val - } + if $0 != node?.powerConfig?.minWakeSecs ?? -1 { hasChanges = true } } .onChange(of: adcOverride) { _ in hasChanges = true } .onChange(of: adcMultiplier) { newAdcMultiplier in - if newAdcMultiplier != node?.powerConfig?.adcMultiplierOverride ?? 0 { hasChanges = true } + if newAdcMultiplier != node?.powerConfig?.adcMultiplierOverride ?? -1 { hasChanges = true } } .onChange(of: waitBluetoothSecs) { - if let val = node?.powerConfig?.waitBluetoothSecs { - hasChanges = $0 != val - } + if $0 != node?.powerConfig?.waitBluetoothSecs ?? -1 { hasChanges = true } } .onChange(of: lsSecs) { - if let val = node?.powerConfig?.lsSecs { - hasChanges = $0 != val - } + if $0 != node?.powerConfig?.lsSecs ?? -1 { hasChanges = true } } .onChange(of: minWakeSecs) { - if let val = node?.powerConfig?.minWakeSecs { - hasChanges = $0 != val - } + if $0 != node?.powerConfig?.minWakeSecs ?? -1 { hasChanges = true } } SaveConfigButton(node: node, hasChanges: $hasChanges) { diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index f3f79734..9877bb3a 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -155,29 +155,19 @@ struct SecurityConfig: View { ) }) .onChange(of: isManaged) { - if let val = node?.securityConfig?.isManaged { - hasChanges = $0 != val - } + if $0 != node?.securityConfig?.isManaged { hasChanges = true } } .onChange(of: serialEnabled) { - if let val = node?.securityConfig?.serialEnabled { - hasChanges = $0 != val - } + if $0 != node?.securityConfig?.serialEnabled { hasChanges = true } } .onChange(of: debugLogApiEnabled) { - if let val = node?.securityConfig?.debugLogApiEnabled { - hasChanges = $0 != val - } + if $0 != node?.securityConfig?.debugLogApiEnabled { hasChanges = true } } .onChange(of: bluetoothLoggingEnabled) { - if let val = node?.securityConfig?.bluetoothLoggingEnabled { - hasChanges = $0 != val - } + if $0 != node?.securityConfig?.bluetoothLoggingEnabled { hasChanges = true } } .onChange(of: adminChannelEnabled) { - if let val = node?.securityConfig?.adminChannelEnabled { - hasChanges = $0 != val - } + if $0 != node?.securityConfig?.adminChannelEnabled { hasChanges = true } } SaveConfigButton(node: node, hasChanges: $hasChanges) { From d175f960cd2ed30f3a2a018ed89e1258783bdacb Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 05:20:19 -0700 Subject: [PATCH 18/75] Hook up new key values to messages --- Meshtastic/Helpers/MeshPackets.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index c210082f..126b0401 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -820,6 +820,8 @@ func textMessageAppPacket( newMessage.isEmoji = packet.decoded.emoji == 1 newMessage.channel = Int32(packet.channel) newMessage.portNum = Int32(packet.decoded.portnum.rawValue) + newMessage.publicKey = packet.publicKey + newMessage.pkiEncrypted = packet.pkiEncrypted if packet.decoded.portnum == PortNum.detectionSensorApp { if !UserDefaults.enableDetectionNotifications { newMessage.read = true From 1942f0e2dd6ceeb6cfa998bd9e79f0f3214059d7 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 05:55:48 -0700 Subject: [PATCH 19/75] Add pki info to message context menu --- Meshtastic/Views/Messages/MessageContextMenuItems.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Meshtastic/Views/Messages/MessageContextMenuItems.swift b/Meshtastic/Views/Messages/MessageContextMenuItems.swift index c9c37cdc..07792a9a 100644 --- a/Meshtastic/Views/Messages/MessageContextMenuItems.swift +++ b/Meshtastic/Views/Messages/MessageContextMenuItems.swift @@ -15,6 +15,10 @@ struct MessageContextMenuItems: View { VStack { if message.pkiEncrypted { Label("Encrypted", systemImage: "lock") + Text("Public Key") + Text(message.publicKey?.base64EncodedString() ?? "No Key") + .allowsTightening(true) + .monospaced() } Text("channel") + Text(": \(message.channel)") } From b1f1a996ca5f7de4768fc92dc6e2c89b4f283682 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 10:29:15 -0700 Subject: [PATCH 20/75] Set key values on use when a nodeinfo packet comes in over the mesh --- Meshtastic/Persistence/UpdateCoreData.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index e8563315..d52131b4 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -178,6 +178,8 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) newUser.role = Int32(newUserMessage.role.rawValue) newUser.hwModel = String(describing: newUserMessage.hwModel).uppercased() newUser.hwModelId = Int32(newUserMessage.hwModel.rawValue) + newUser.pkiEncrypted = packet.pkiEncrypted + newUser.publicKey = packet.publicKey Task { Api().loadDeviceHardwareData { (hw) in let dh = hw.first(where: { $0.hwModel == newUser.hwModelId }) From 9eb64bb3ed413eeddaac58b321fb4d76a34291e1 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 10:32:47 -0700 Subject: [PATCH 21/75] Set public key for nodedb packets --- Meshtastic/Helpers/MeshPackets.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 126b0401..963465b9 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -299,6 +299,10 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje } newUser.isLicensed = nodeInfo.user.isLicensed newUser.role = Int32(nodeInfo.user.role.rawValue) + if !nodeInfo.user.publicKey.isEmpty { + newUser.pkiEncrypted = true + newUser.publicKey = nodeInfo.user.publicKey + } newNode.user = newUser } else if nodeInfo.num > Constants.minimumNodeNum { let newUser = createUser(num: Int64(nodeInfo.num), context: context) From 6926d857ff2ed23d22a9892f6e4b9957f05e8798 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 14:42:47 -0700 Subject: [PATCH 22/75] Add secure input view to handle key inputs --- Meshtastic.xcodeproj/project.pbxproj | 4 ++ Meshtastic/Helpers/MeshPackets.swift | 2 + Meshtastic/Views/Helpers/SecureInput.swift | 57 +++++++++++++++++++ .../Settings/Config/SecurityConfig.swift | 55 +----------------- 4 files changed, 66 insertions(+), 52 deletions(-) create mode 100644 Meshtastic/Views/Helpers/SecureInput.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index f3c62dc1..f5108298 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */; }; DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; }; DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; }; + DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65712C6AB8EC0053C113 /* SecureInput.swift */; }; DD73FD1128750779000852D6 /* PositionLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FD1028750779000852D6 /* PositionLog.swift */; }; DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */; }; DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */; }; @@ -345,6 +346,7 @@ DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfig.swift; sourceTree = ""; }; DD6193782863875F00E59241 /* SerialConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfig.swift; sourceTree = ""; }; DD68BAE72C417A74004C01A0 /* MeshtasticDataModelV 40.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 40.xcdatamodel"; sourceTree = ""; }; + DD6F65712C6AB8EC0053C113 /* SecureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInput.swift; sourceTree = ""; }; DD73FD1028750779000852D6 /* PositionLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionLog.swift; sourceTree = ""; }; DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceMetricsLog.swift; sourceTree = ""; }; DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTips.swift; sourceTree = ""; }; @@ -912,6 +914,7 @@ DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */, DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */, DD5E523D298F5A7D00D21B61 /* Weather */, + DD6F65712C6AB8EC0053C113 /* SecureInput.swift */, ); path = Helpers; sourceTree = ""; @@ -1281,6 +1284,7 @@ DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */, DD1BD0F32C63C65E008C0C70 /* SecurityConfig.swift in Sources */, DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */, + DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */, DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */, 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */, DDDB444229F8A88700EE2349 /* Double.swift in Sources */, diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 963465b9..ceefb253 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -842,6 +842,8 @@ func textMessageAppPacket( } if fetchedUsers.first(where: { $0.num == packet.from }) != nil { newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) + newMessage.fromUser?.publicKey = packet.publicKey + newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) } diff --git a/Meshtastic/Views/Helpers/SecureInput.swift b/Meshtastic/Views/Helpers/SecureInput.swift new file mode 100644 index 00000000..b4fa54eb --- /dev/null +++ b/Meshtastic/Views/Helpers/SecureInput.swift @@ -0,0 +1,57 @@ +// +// SecureInput.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/12/24. +// + +import SwiftUI + +struct SecureInput: View { + + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + @Binding private var text: String + @State private var isSecure: Bool = true + private var title: String + + init(_ title: String, text: Binding) { + self.title = title + self._text = text + } + + var body: some View { + ZStack(alignment: .trailing) { + Group { + if isSecure { + SecureField(title, text: $text) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() + .keyboardType(.alphabet) + .foregroundStyle(.tertiary) + .disableAutocorrection(true) + .textSelection(.enabled) + } else { + TextField(title, text: $text, axis: .vertical) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() + .keyboardType(.alphabet) + .foregroundStyle(.tertiary) + .disableAutocorrection(true) + .textSelection(.enabled) + .lineLimit(...3) + } + }.padding(.trailing, 36) + + if !text.isEmpty { + Button(action: { + isSecure.toggle() + }) { + Image(systemName: self.isSecure ? "eye.slash" : "eye") + .accentColor(.secondary) + } + } + } + } +} diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 9877bb3a..d031306b 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -38,70 +38,21 @@ struct SecurityConfig: View { Section(header: Text("Admin & Direct Message Keys")) { VStack(alignment: .leading) { Label("Public Key", systemImage: "key") - - TextField( - "Public Key", - text: $publicKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .disableAutocorrection(true) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) - + SecureInput("Public Key", text: $publicKey) Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Private Key", systemImage: "key.fill") - - TextField( - "Private Key", - text: $privateKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .disableAutocorrection(true) - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) + SecureInput("Private Key", text: $privateKey) Text("Used to create a shared key with a remote device.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Admin Key", systemImage: "key.viewfinder") - - TextField( - "Admin Key", - text: $adminKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .disableAutocorrection(true) - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) + SecureInput("Private Key", text: $adminKey) Text("The public key authorized to send admin messages to this node.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) From 8dc4f3076dec3741b583c1c63fc364e47987a942 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 15:27:10 -0700 Subject: [PATCH 23/75] Set a key for an existing user if the key is empty --- Meshtastic/Helpers/MeshPackets.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index ceefb253..809bdbcc 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -360,6 +360,11 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje if fetchedNode[0].user == nil { fetchedNode[0].user = UserEntity(context: context) } + // Set the public key for a user if it is empty, don't update + if fetchedNode[0].user?.publicKey?.isEmpty == nil && !nodeInfo.user.publicKey.isEmpty { + fetchedNode[0].user?.pkiEncrypted = true + fetchedNode[0].user?.publicKey = nodeInfo.user.publicKey + } fetchedNode[0].user!.userId = nodeInfo.user.id fetchedNode[0].user!.num = Int64(nodeInfo.num) fetchedNode[0].user!.numString = String(nodeInfo.num) From e633009e9dd6f2e033c82f2e50f852fd2e1ff93c Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 16:46:25 -0700 Subject: [PATCH 24/75] Icons for each messge type --- Meshtastic/Views/Messages/UserList.swift | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 392ce4d0..361407de 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -28,6 +28,7 @@ struct UserList: View { @State private var roleFilter = false @State private var deviceRoles: Set = [] @State var isEditingFilters = false + @State private var showingTrustConfirm: Bool = false @FetchRequest( sortDescriptors: [NSSortDescriptor(key: "lastMessage", ascending: false), @@ -71,8 +72,17 @@ struct UserList: View { VStack(alignment: .leading) { HStack { if user.pkiEncrypted { - Image(systemName: "lock.fill") - .foregroundColor(.green) + if mostRecent == nil || user.publicKey == mostRecent?.publicKey { + Image(systemName: "lock.fill") + .foregroundColor(.green) + } else { + /// Public Key on the User and the Public Key on the Last Message don't match + Image(systemName: "lock.slash.fill") + .foregroundColor(.red) + } + } else { + Image(systemName: "lock.open.fill") + .foregroundColor(.yellow) } Text(user.longName ?? "unknown".localized) .font(.headline) @@ -245,7 +255,6 @@ struct UserList: View { let searchPredicates = ["userId", "numString", "hwModel", "hwDisplayName", "longName", "shortName"].map { property in return NSPredicate(format: "%K CONTAINS[c] %@", property, searchText) } - /// Create a compound predicate using each text search preicate as an OR let textSearchPredicate = NSCompoundPredicate(type: .or, subpredicates: searchPredicates) /// Create an array of predicates to hold our AND predicates From b3f32238c894a4bbae3f588779417ff2f3283f4d Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 16:56:33 -0700 Subject: [PATCH 25/75] add keyMatch value to user --- Meshtastic/Helpers/MeshPackets.swift | 12 ++++++++++-- .../MeshtasticDataModelV 42.xcdatamodel/contents | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 809bdbcc..96db5fd2 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -847,8 +847,16 @@ func textMessageAppPacket( } if fetchedUsers.first(where: { $0.num == packet.from }) != nil { newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) - newMessage.fromUser?.publicKey = packet.publicKey - newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted + if !(newMessage.fromUser?.publicKey?.isEmpty ?? true) { + /// We have a key, check if it matches + if newMessage.fromUser?.publicKey != newMessage.publicKey { + newMessage.fromUser?.keyMatch = false + } + } else { + /// We have no key, set it + newMessage.fromUser?.publicKey = packet.publicKey + newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted + } if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) } diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents index 432be802..b92f33f6 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents @@ -432,6 +432,7 @@ + From edde940a792614409811a5fb9ed98d936c90e06a Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 17:27:43 -0700 Subject: [PATCH 26/75] Use key match --- Meshtastic/Views/Messages/UserList.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 361407de..0bc00124 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -72,13 +72,13 @@ struct UserList: View { VStack(alignment: .leading) { HStack { if user.pkiEncrypted { - if mostRecent == nil || user.publicKey == mostRecent?.publicKey { - Image(systemName: "lock.fill") - .foregroundColor(.green) - } else { + if !user.keyMatch { /// Public Key on the User and the Public Key on the Last Message don't match Image(systemName: "lock.slash.fill") .foregroundColor(.red) + } else { + Image(systemName: "lock.fill") + .foregroundColor(.green) } } else { Image(systemName: "lock.open.fill") From 772a14d664325bd59f590a7517f4248e676a567e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 19:51:34 -0700 Subject: [PATCH 27/75] Add pki encryption toggle to user and node list filters --- Meshtastic/Views/Messages/UserList.swift | 11 ++++++++++- .../Views/Nodes/Helpers/NodeListFilter.swift | 16 +++++++++++++++- Meshtastic/Views/Nodes/NodeList.swift | 10 +++++++++- protobufs | 2 +- 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 0bc00124..c2ede597 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -20,6 +20,7 @@ struct UserList: View { @State private var viaLora = true @State private var viaMqtt = true @State private var isOnline = false + @State private var isPkiEncrypted = false @State private var isFavorite = false @State private var isEnvironment = false @State private var distanceFilter = false @@ -186,7 +187,7 @@ struct UserList: View { .listStyle(.plain) .navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count - 1))) .sheet(isPresented: $isEditingFilters) { - NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) + NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) } .onChange(of: searchText) { _ in searchUserList() @@ -212,6 +213,9 @@ struct UserList: View { .onChange(of: isOnline) { _ in searchUserList() } + .onChange(of: isPkiEncrypted) { _ in + searchUserList() + } .onChange(of: isFavorite) { _ in searchUserList() } @@ -292,6 +296,11 @@ struct UserList: View { let isOnlinePredicate = NSPredicate(format: "userNode.lastHeard >= %@", Calendar.current.date(byAdding: .minute, value: -15, to: Date())! as NSDate) predicates.append(isOnlinePredicate) } + /// Encrypted + if isPkiEncrypted { + let isPkiEncryptedPredicate = NSPredicate(format: "pkiEncrypted == YES") + predicates.append(isPkiEncryptedPredicate) + } /// Favorites if isFavorite { let isFavoritePredicate = NSPredicate(format: "userNode.favorite == YES") diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift index 6236f7b7..20435dd0 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift @@ -15,6 +15,7 @@ struct NodeListFilter: View { @Binding var viaLora: Bool @Binding var viaMqtt: Bool @Binding var isOnline: Bool + @Binding var isPkiEncrypted: Bool @Binding var isFavorite: Bool @Binding var isEnvironment: Bool @Binding var distanceFilter: Bool @@ -64,6 +65,19 @@ struct NodeListFilter: View { .toggleStyle(SwitchToggleStyle(tint: .accentColor)) .listRowSeparator(.visible) + Toggle(isOn: $isPkiEncrypted) { + + Label { + Text("Encrypted") + } icon: { + Image(systemName: "lock.fill") + .foregroundColor(.green) + .symbolRenderingMode(.hierarchical) + } + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .listRowSeparator(.visible) + Toggle(isOn: $isFavorite) { Label { @@ -173,7 +187,7 @@ struct NodeListFilter: View { .padding(.bottom) #endif } - .presentationDetents([.medium, .large]) + .presentationDetents([.fraction(0.7), .large]) .presentationContentInteraction(.scrolls) .presentationDragIndicator(.visible) .presentationBackgroundInteraction(.enabled(upThrough: .medium)) diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index e05cb34b..f85cad48 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -24,6 +24,7 @@ struct NodeList: View { @State private var viaLora = true @State private var viaMqtt = true @State private var isOnline = false + @State private var isPkiEncrypted = false @State private var isFavorite = false @State private var isEnvironment = false @State private var distanceFilter = false @@ -38,8 +39,9 @@ struct NodeList: View { @State private var deleteNodeId: Int64 = 0 var boolFilters: [Bool] {[ - isOnline, isFavorite, + isOnline, + isPkiEncrypted, isEnvironment, distanceFilter, roleFilter @@ -153,6 +155,7 @@ struct NodeList: View { viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, + isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, @@ -383,6 +386,11 @@ struct NodeList: View { let isOnlinePredicate = NSPredicate(format: "lastHeard >= %@", Calendar.current.date(byAdding: .minute, value: -15, to: Date())! as NSDate) predicates.append(isOnlinePredicate) } + /// Encrypted + if isPkiEncrypted { + let isPkiEncryptedPredicate = NSPredicate(format: "user.pkiEncrypted == YES") + predicates.append(isPkiEncryptedPredicate) + } /// Favorites if isFavorite { let isFavoritePredicate = NSPredicate(format: "favorite == YES") diff --git a/protobufs b/protobufs index 0c052b5d..3e753697 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 0c052b5d25fe8ed74c675178702f20a3fbc29afa +Subproject commit 3e753697aa1140d2c998cb63739729e733002874 From c1e625f7f9bed34585d1a4a023b28ec73efdceab Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 12 Aug 2024 20:02:11 -0700 Subject: [PATCH 28/75] filter touch up --- Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift index 20435dd0..eaaf7016 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift @@ -187,9 +187,9 @@ struct NodeListFilter: View { .padding(.bottom) #endif } - .presentationDetents([.fraction(0.7), .large]) + .presentationDetents([.fraction(0.65), .large]) .presentationContentInteraction(.scrolls) .presentationDragIndicator(.visible) - .presentationBackgroundInteraction(.enabled(upThrough: .medium)) + .presentationBackgroundInteraction(.enabled(upThrough: .large)) } } From 9368156eff825d7a203f5f31afea66ee6c6f4c30 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 13 Aug 2024 08:24:34 -0700 Subject: [PATCH 29/75] Use public key from user on outgoiong messages --- Meshtastic/Helpers/BLEManager.swift | 4 ++++ Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index fdbd2d52..92e1f94d 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1000,6 +1000,10 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if toUserNum > 0 { newMessage.toUser = fetchedUsers.first(where: { $0.num == toUserNum }) newMessage.toUser?.lastMessage = Date() + if newMessage.toUser?.pkiEncrypted ?? false { + newMessage.publicKey = newMessage.toUser?.publicKey + newMessage.pkiEncrypted = true + } } newMessage.fromUser = fetchedUsers.first(where: { $0.num == fromUserNum }) newMessage.isEmoji = isEmoji diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift index eaaf7016..66d88b28 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift @@ -187,7 +187,7 @@ struct NodeListFilter: View { .padding(.bottom) #endif } - .presentationDetents([.fraction(0.65), .large]) + .presentationDetents([.fraction(0.75), .large]) .presentationContentInteraction(.scrolls) .presentationDragIndicator(.visible) .presentationBackgroundInteraction(.enabled(upThrough: .large)) From 63b845fd62d5211fa37824c4692087de4dbd0efa Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 13 Aug 2024 14:02:57 -0700 Subject: [PATCH 30/75] send public key with new messages --- Meshtastic/Helpers/BLEManager.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 92e1f94d..4e7489dc 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1026,6 +1026,10 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate dataMessage.portnum = dataType var meshPacket = MeshPacket() + if newMessage.toUser?.pkiEncrypted ?? false { + meshPacket.pkiEncrypted = true + meshPacket.publicKey = newMessage.toUser?.publicKey ?? Data() + } meshPacket.id = UInt32(newMessage.messageId) if toUserNum > 0 { meshPacket.to = UInt32(toUserNum) From 5087430f02cf9d92e0649390e11e01337b399ef6 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 13 Aug 2024 16:44:29 -0700 Subject: [PATCH 31/75] Bump firmware version, remove outdated ble pairing information for factory reset --- Localizable.xcstrings | 2 +- Meshtastic/Views/Settings/Config/DeviceConfig.swift | 2 +- Meshtastic/Views/Settings/Firmware.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index b704efe3..6160d6ae 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -709,7 +709,7 @@ "All" : { }, - "All device and app data will be deleted. You will also need to forget your devices under Settings > Bluetooth." : { + "All device and app data will be deleted." : { }, "Allow incoming device control over the insecure legacy admin channel." : { diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index ff23c6e5..106614d2 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -183,7 +183,7 @@ struct DeviceConfig: View { .controlSize(.regular) .padding(.trailing) .confirmationDialog( - "All device and app data will be deleted. You will also need to forget your devices under Settings > Bluetooth.", + "All device and app data will be deleted.", isPresented: $isPresentingFactoryResetConfirm, titleVisibility: .visible ) { diff --git a/Meshtastic/Views/Settings/Firmware.swift b/Meshtastic/Views/Settings/Firmware.swift index e591761f..d76b1503 100644 --- a/Meshtastic/Views/Settings/Firmware.swift +++ b/Meshtastic/Views/Settings/Firmware.swift @@ -13,7 +13,7 @@ struct Firmware: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager var node: NodeInfoEntity? - @State var minimumVersion = "2.4.0" + @State var minimumVersion = "2.4.3" @State var version = "" @State private var currentDevice: DeviceHardware? @State private var latestStable: FirmwareRelease? From affdd3954229156a64fe2290b22d830ae20e2ecc Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 03:10:12 -0700 Subject: [PATCH 32/75] Add onFirstAppear extension --- Meshtastic.xcodeproj/project.pbxproj | 4 +++ Meshtastic/Extensions/View.swift | 30 +++++++++++++++++++ .../Views/Settings/Config/ConfigHeader.swift | 4 +-- 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Meshtastic/Extensions/View.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index f5108298..c891cca9 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -93,6 +93,7 @@ DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; }; DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; }; DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65712C6AB8EC0053C113 /* SecureInput.swift */; }; + DD6F65742C6CB80A0053C113 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65732C6CB80A0053C113 /* View.swift */; }; DD73FD1128750779000852D6 /* PositionLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FD1028750779000852D6 /* PositionLog.swift */; }; DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */; }; DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */; }; @@ -347,6 +348,7 @@ DD6193782863875F00E59241 /* SerialConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfig.swift; sourceTree = ""; }; DD68BAE72C417A74004C01A0 /* MeshtasticDataModelV 40.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 40.xcdatamodel"; sourceTree = ""; }; DD6F65712C6AB8EC0053C113 /* SecureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInput.swift; sourceTree = ""; }; + DD6F65732C6CB80A0053C113 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; DD73FD1028750779000852D6 /* PositionLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionLog.swift; sourceTree = ""; }; DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceMetricsLog.swift; sourceTree = ""; }; DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTips.swift; sourceTree = ""; }; @@ -1001,6 +1003,7 @@ DDD5BB172C2F9C36007E03CA /* OSLogEntryLog.swift */, DDF45C362BC46A5A005ED5F2 /* TimeZone.swift */, DDD5BB0C2C285F00007E03CA /* Logger.swift */, + DD6F65732C6CB80A0053C113 /* View.swift */, ); path = Extensions; sourceTree = ""; @@ -1374,6 +1377,7 @@ DDB6ABE228B13FB500384BA1 /* PositionConfigEnums.swift in Sources */, DD994B69295F88B60013760A /* IntervalEnums.swift in Sources */, DDDCD5702BB26F5C00BE6B60 /* NodeListFilter.swift in Sources */, + DD6F65742C6CB80A0053C113 /* View.swift in Sources */, DD1933762B0835D500771CD5 /* PositionAltitudeChart.swift in Sources */, DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */, DDB6CCFB2AAF805100945AF6 /* NodeMapSwiftUI.swift in Sources */, diff --git a/Meshtastic/Extensions/View.swift b/Meshtastic/Extensions/View.swift new file mode 100644 index 00000000..7349f36d --- /dev/null +++ b/Meshtastic/Extensions/View.swift @@ -0,0 +1,30 @@ +// +// View.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/14/24. +// + +import SwiftUI + +public extension View { + func onFirstAppear(_ action: @escaping () -> ()) -> some View { + modifier(FirstAppear(action: action)) + } +} + +private struct FirstAppear: ViewModifier { + let action: () -> () + + // Use this to only fire your block one time + @State private var hasAppeared = false + + func body(content: Content) -> some View { + // And then, track it here + content.onAppear { + guard !hasAppeared else { return } + hasAppeared = true + action() + } + } +} diff --git a/Meshtastic/Views/Settings/Config/ConfigHeader.swift b/Meshtastic/Views/Settings/Config/ConfigHeader.swift index cef7f98c..3f59a01a 100644 --- a/Meshtastic/Views/Settings/Config/ConfigHeader.swift +++ b/Meshtastic/Views/Settings/Config/ConfigHeader.swift @@ -23,12 +23,12 @@ struct ConfigHeader: View { .foregroundColor(.orange) } else { Text("Remote administration for: \(node?.user?.longName ?? "Unknown")") - .onAppear(perform: onAppear) + .onFirstAppear(onAppear) .font(.title3) } } else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? -1 { Text("Configuration for: \(node?.user?.longName ?? "Unknown")") - .onAppear(perform: onAppear) + .onFirstAppear(onAppear) } else { Text("Please connect to a radio to configure settings.") .font(.callout) From 1fdbd5cc3a23e7f7dd6723f32770696a0e5fb067 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 03:52:20 -0700 Subject: [PATCH 33/75] Switch to broken key icon for key match --- Meshtastic/Views/Messages/UserList.swift | 2 +- Meshtastic/Views/Nodes/Helpers/NodeListItem.swift | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index c2ede597..4d7b2fd9 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -75,7 +75,7 @@ struct UserList: View { if user.pkiEncrypted { if !user.keyMatch { /// Public Key on the User and the Public Key on the Last Message don't match - Image(systemName: "lock.slash.fill") + Image(systemName: "key.slash") .foregroundColor(.red) } else { Image(systemName: "lock.fill") diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index ba7dee6e..10829f31 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -145,7 +145,6 @@ struct NodeListItem: View { HStack { Image(systemName: "\(node.channel).circle.fill") .font(.title2) - .symbolRenderingMode(.multicolor) .frame(width: 30) Text("Channel") .foregroundColor(.secondary) @@ -216,7 +215,6 @@ struct NodeListItem: View { .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) Image(systemName: "\(node.hopsAway).square") .font(.title2) - .symbolRenderingMode(.multicolor) } } else { if node.snr != 0 && !node.viaMqtt { From 1c58539206e5f76bdd2ce4041de5c22d4880e7db Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 14 Aug 2024 12:43:26 -0500 Subject: [PATCH 34/75] Remove git shenanigans from gen_protos script --- scripts/gen_protos.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/gen_protos.sh b/scripts/gen_protos.sh index a587a8e3..d07bc798 100755 --- a/scripts/gen_protos.sh +++ b/scripts/gen_protos.sh @@ -1,12 +1,5 @@ #!/bin/bash -# simple sanity checking for repo -if [ ! -d "./protobufs" ]; then - git submodule update --init -else - git submodule update --remote --merge -fi - # simple sanity checking for executable if [ ! -x "$(which protoc)" ]; then brew install swift-protobuf From d987c09409bdf65602b4baca431aa0b9e001c006 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 14 Aug 2024 12:45:03 -0500 Subject: [PATCH 35/75] Update protos on 2.5 --- .../Sources/meshtastic/admin.pb.swift | 267 ++------- .../Sources/meshtastic/apponly.pb.swift | 6 +- .../Sources/meshtastic/atak.pb.swift | 64 +-- .../meshtastic/cannedmessages.pb.swift | 6 +- .../Sources/meshtastic/channel.pb.swift | 37 +- .../Sources/meshtastic/clientonly.pb.swift | 6 +- .../Sources/meshtastic/config.pb.swift | 445 ++++++--------- .../meshtastic/connection_status.pb.swift | 21 +- .../Sources/meshtastic/deviceonly.pb.swift | 154 ++++- .../Sources/meshtastic/localonly.pb.swift | 9 +- .../Sources/meshtastic/mesh.pb.swift | 530 +++++------------- .../Sources/meshtastic/module_config.pb.swift | 263 +++------ .../Sources/meshtastic/mqtt.pb.swift | 9 +- .../Sources/meshtastic/paxcount.pb.swift | 6 +- .../Sources/meshtastic/portnums.pb.swift | 14 +- .../Sources/meshtastic/powermon.pb.swift | 115 ++-- .../meshtastic/remote_hardware.pb.swift | 35 +- .../Sources/meshtastic/rtttl.pb.swift | 6 +- .../Sources/meshtastic/storeforward.pb.swift | 93 +-- .../Sources/meshtastic/telemetry.pb.swift | 87 ++- .../Sources/meshtastic/xmodem.pb.swift | 39 +- protobufs | 2 +- 22 files changed, 747 insertions(+), 1467 deletions(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 3ea4ac4c..4028fdcd 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -24,7 +24,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /// This message is used to do settings operations to both remote AND local nodes. /// (Prior to 1.2 these operations were done via special ToRadio operations) -public struct AdminMessage { +public struct AdminMessage: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -466,7 +466,7 @@ public struct AdminMessage { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send the specified channel in the response to this message /// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) @@ -603,189 +603,11 @@ public struct AdminMessage { /// Tell the node to reset the nodedb. case nodedbReset(Int32) - #if !swift(>=4.1) - public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.getChannelRequest, .getChannelRequest): return { - guard case .getChannelRequest(let l) = lhs, case .getChannelRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getChannelResponse, .getChannelResponse): return { - guard case .getChannelResponse(let l) = lhs, case .getChannelResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerRequest, .getOwnerRequest): return { - guard case .getOwnerRequest(let l) = lhs, case .getOwnerRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerResponse, .getOwnerResponse): return { - guard case .getOwnerResponse(let l) = lhs, case .getOwnerResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigRequest, .getConfigRequest): return { - guard case .getConfigRequest(let l) = lhs, case .getConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigResponse, .getConfigResponse): return { - guard case .getConfigResponse(let l) = lhs, case .getConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigRequest, .getModuleConfigRequest): return { - guard case .getModuleConfigRequest(let l) = lhs, case .getModuleConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigResponse, .getModuleConfigResponse): return { - guard case .getModuleConfigResponse(let l) = lhs, case .getModuleConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesRequest, .getCannedMessageModuleMessagesRequest): return { - guard case .getCannedMessageModuleMessagesRequest(let l) = lhs, case .getCannedMessageModuleMessagesRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesResponse, .getCannedMessageModuleMessagesResponse): return { - guard case .getCannedMessageModuleMessagesResponse(let l) = lhs, case .getCannedMessageModuleMessagesResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataRequest, .getDeviceMetadataRequest): return { - guard case .getDeviceMetadataRequest(let l) = lhs, case .getDeviceMetadataRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataResponse, .getDeviceMetadataResponse): return { - guard case .getDeviceMetadataResponse(let l) = lhs, case .getDeviceMetadataResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneRequest, .getRingtoneRequest): return { - guard case .getRingtoneRequest(let l) = lhs, case .getRingtoneRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneResponse, .getRingtoneResponse): return { - guard case .getRingtoneResponse(let l) = lhs, case .getRingtoneResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusRequest, .getDeviceConnectionStatusRequest): return { - guard case .getDeviceConnectionStatusRequest(let l) = lhs, case .getDeviceConnectionStatusRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusResponse, .getDeviceConnectionStatusResponse): return { - guard case .getDeviceConnectionStatusResponse(let l) = lhs, case .getDeviceConnectionStatusResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setHamMode, .setHamMode): return { - guard case .setHamMode(let l) = lhs, case .setHamMode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsRequest, .getNodeRemoteHardwarePinsRequest): return { - guard case .getNodeRemoteHardwarePinsRequest(let l) = lhs, case .getNodeRemoteHardwarePinsRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsResponse, .getNodeRemoteHardwarePinsResponse): return { - guard case .getNodeRemoteHardwarePinsResponse(let l) = lhs, case .getNodeRemoteHardwarePinsResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.enterDfuModeRequest, .enterDfuModeRequest): return { - guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.deleteFileRequest, .deleteFileRequest): return { - guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setScale, .setScale): return { - guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setOwner, .setOwner): return { - guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setChannel, .setChannel): return { - guard case .setChannel(let l) = lhs, case .setChannel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setConfig, .setConfig): return { - guard case .setConfig(let l) = lhs, case .setConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setModuleConfig, .setModuleConfig): return { - guard case .setModuleConfig(let l) = lhs, case .setModuleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setCannedMessageModuleMessages, .setCannedMessageModuleMessages): return { - guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setRingtoneMessage, .setRingtoneMessage): return { - guard case .setRingtoneMessage(let l) = lhs, case .setRingtoneMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeByNodenum, .removeByNodenum): return { - guard case .removeByNodenum(let l) = lhs, case .removeByNodenum(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFavoriteNode, .setFavoriteNode): return { - guard case .setFavoriteNode(let l) = lhs, case .setFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFavoriteNode, .removeFavoriteNode): return { - guard case .removeFavoriteNode(let l) = lhs, case .removeFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFixedPosition, .setFixedPosition): return { - guard case .setFixedPosition(let l) = lhs, case .setFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFixedPosition, .removeFixedPosition): return { - guard case .removeFixedPosition(let l) = lhs, case .removeFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.beginEditSettings, .beginEditSettings): return { - guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.commitEditSettings, .commitEditSettings): return { - guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetDevice, .factoryResetDevice): return { - guard case .factoryResetDevice(let l) = lhs, case .factoryResetDevice(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootOtaSeconds, .rebootOtaSeconds): return { - guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.exitSimulator, .exitSimulator): return { - guard case .exitSimulator(let l) = lhs, case .exitSimulator(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootSeconds, .rebootSeconds): return { - guard case .rebootSeconds(let l) = lhs, case .rebootSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.shutdownSeconds, .shutdownSeconds): return { - guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetConfig, .factoryResetConfig): return { - guard case .factoryResetConfig(let l) = lhs, case .factoryResetConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodedbReset, .nodedbReset): return { - guard case .nodedbReset(let l) = lhs, case .nodedbReset(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// TODO: REPLACE - public enum ConfigType: SwiftProtobuf.Enum { + public enum ConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -853,11 +675,23 @@ public struct AdminMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ConfigType] = [ + .deviceConfig, + .positionConfig, + .powerConfig, + .networkConfig, + .displayConfig, + .loraConfig, + .bluetoothConfig, + .securityConfig, + ] + } /// /// TODO: REPLACE - public enum ModuleConfigType: SwiftProtobuf.Enum { + public enum ModuleConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -955,51 +789,31 @@ public struct AdminMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ModuleConfigType] = [ + .mqttConfig, + .serialConfig, + .extnotifConfig, + .storeforwardConfig, + .rangetestConfig, + .telemetryConfig, + .cannedmsgConfig, + .audioConfig, + .remotehardwareConfig, + .neighborinfoConfig, + .ambientlightingConfig, + .detectionsensorConfig, + .paxcounterConfig, + ] + } public init() {} } -#if swift(>=4.2) - -extension AdminMessage.ConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ConfigType] = [ - .deviceConfig, - .positionConfig, - .powerConfig, - .networkConfig, - .displayConfig, - .loraConfig, - .bluetoothConfig, - .securityConfig, - ] -} - -extension AdminMessage.ModuleConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ModuleConfigType] = [ - .mqttConfig, - .serialConfig, - .extnotifConfig, - .storeforwardConfig, - .rangetestConfig, - .telemetryConfig, - .cannedmsgConfig, - .audioConfig, - .remotehardwareConfig, - .neighborinfoConfig, - .ambientlightingConfig, - .detectionsensorConfig, - .paxcounterConfig, - ] -} - -#endif // swift(>=4.2) - /// /// Parameters for setting up Meshtastic for ameteur radio usage -public struct HamParameters { +public struct HamParameters: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1029,7 +843,7 @@ public struct HamParameters { /// /// Response envelope for node_remote_hardware_pins -public struct NodeRemoteHardwarePinsResponse { +public struct NodeRemoteHardwarePinsResponse: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1043,15 +857,6 @@ public struct NodeRemoteHardwarePinsResponse { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension AdminMessage: @unchecked Sendable {} -extension AdminMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension AdminMessage.ConfigType: @unchecked Sendable {} -extension AdminMessage.ModuleConfigType: @unchecked Sendable {} -extension HamParameters: @unchecked Sendable {} -extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1763,7 +1568,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 2) } - if self.frequency != 0 { + if self.frequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.frequency, fieldNumber: 3) } if !self.shortName.isEmpty { diff --git a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift index 0457077c..18e66d8e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift @@ -26,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// any SECONDARY channels. /// No DISABLED channels are included. /// This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL -public struct ChannelSet { +public struct ChannelSet: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -53,10 +53,6 @@ public struct ChannelSet { fileprivate var _loraConfig: Config.LoRaConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension ChannelSet: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift index 4406deb3..1dd12469 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Team: SwiftProtobuf.Enum { +public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -130,11 +130,6 @@ public enum Team: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Team: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Team] = [ .unspecifedColor, @@ -153,13 +148,12 @@ extension Team: CaseIterable { .darkGreen, .brown, ] -} -#endif // swift(>=4.2) +} /// /// Role of the group member -public enum MemberRole: SwiftProtobuf.Enum { +public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -233,11 +227,6 @@ public enum MemberRole: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension MemberRole: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [MemberRole] = [ .unspecifed, @@ -250,13 +239,12 @@ extension MemberRole: CaseIterable { .rto, .k9, ] -} -#endif // swift(>=4.2) +} /// /// Packets for the official ATAK Plugin -public struct TAKPacket { +public struct TAKPacket: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -326,7 +314,7 @@ public struct TAKPacket { /// /// The payload of the packet - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// TAK position report case pli(PLI) @@ -334,24 +322,6 @@ public struct TAKPacket { /// ATAK GeoChat message case chat(GeoChat) - #if !swift(>=4.1) - public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.pli, .pli): return { - guard case .pli(let l) = lhs, case .pli(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.chat, .chat): return { - guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -363,7 +333,7 @@ public struct TAKPacket { /// /// ATAK GeoChat message -public struct GeoChat { +public struct GeoChat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -405,7 +375,7 @@ public struct GeoChat { /// /// ATAK Group /// <__group role='Team Member' name='Cyan'/> -public struct Group { +public struct Group: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -427,7 +397,7 @@ public struct Group { /// /// ATAK EUD Status /// -public struct Status { +public struct Status: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -444,7 +414,7 @@ public struct Status { /// /// ATAK Contact /// -public struct Contact { +public struct Contact: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -464,7 +434,7 @@ public struct Contact { /// /// Position Location Information from ATAK -public struct PLI { +public struct PLI: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -496,18 +466,6 @@ public struct PLI { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Team: @unchecked Sendable {} -extension MemberRole: @unchecked Sendable {} -extension TAKPacket: @unchecked Sendable {} -extension TAKPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension GeoChat: @unchecked Sendable {} -extension Group: @unchecked Sendable {} -extension Status: @unchecked Sendable {} -extension Contact: @unchecked Sendable {} -extension PLI: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift index 1b8c84de..a43393e1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct CannedMessageModuleConfig { +public struct CannedMessageModuleConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,10 +36,6 @@ public struct CannedMessageModuleConfig { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension CannedMessageModuleConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift index 5b9c7e49..a8c96595 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift @@ -36,13 +36,15 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// FIXME: Add description of multi-channel support and how primary vs secondary channels are used. /// FIXME: explain how apps use channels for security. /// explain how remote settings and remote gpio are managed as an example -public struct ChannelSettings { +public struct ChannelSettings: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// Deprecated in favor of LoraConfig.channel_num + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var channelNum: UInt32 = 0 /// @@ -111,7 +113,7 @@ public struct ChannelSettings { /// /// This message is specifically for modules to store per-channel configuration data. -public struct ModuleSettings { +public struct ModuleSettings: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -132,7 +134,7 @@ public struct ModuleSettings { /// /// A pair of a channel number, mode and the (sharable) settings for that channel -public struct Channel { +public struct Channel: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -170,7 +172,7 @@ public struct Channel { /// cross band routing as needed. /// If a device has only a single radio (the common case) only one channel can be PRIMARY at a time /// (but any number of SECONDARY channels can't be sent received on that common frequency) - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -209,6 +211,13 @@ public struct Channel { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Channel.Role] = [ + .disabled, + .primary, + .secondary, + ] + } public init() {} @@ -216,26 +225,6 @@ public struct Channel { fileprivate var _settings: ChannelSettings? = nil } -#if swift(>=4.2) - -extension Channel.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Channel.Role] = [ - .disabled, - .primary, - .secondary, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension ChannelSettings: @unchecked Sendable {} -extension ModuleSettings: @unchecked Sendable {} -extension Channel: @unchecked Sendable {} -extension Channel.Role: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift index c3d93bf7..89370cc5 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift @@ -23,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This abstraction is used to contain any configuration for provisioning a node on any client. /// It is useful for importing and exporting configurations. -public struct DeviceProfile { +public struct DeviceProfile: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -94,10 +94,6 @@ public struct DeviceProfile { fileprivate var _moduleConfig: LocalModuleConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceProfile: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index 4b953470..ecfeeefa 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct Config { +public struct Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -97,7 +97,7 @@ public struct Config { /// /// Payload Variant - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { case device(Config.DeviceConfig) case position(Config.PositionConfig) case power(Config.PowerConfig) @@ -107,53 +107,11 @@ public struct Config { case bluetooth(Config.BluetoothConfig) case security(Config.SecurityConfig) - #if !swift(>=4.1) - public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.device, .device): return { - guard case .device(let l) = lhs, case .device(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.position, .position): return { - guard case .position(let l) = lhs, case .position(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.power, .power): return { - guard case .power(let l) = lhs, case .power(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.network, .network): return { - guard case .network(let l) = lhs, case .network(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.display, .display): return { - guard case .display(let l) = lhs, case .display(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.lora, .lora): return { - guard case .lora(let l) = lhs, case .lora(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.bluetooth, .bluetooth): return { - guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.security, .security): return { - guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// Configuration - public struct DeviceConfig { + public struct DeviceConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -165,12 +123,16 @@ public struct Config { /// /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var serialEnabled: Bool = false /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). /// Set this to true to leave the debug log outputting even when API is active. /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var debugLogEnabled: Bool = false /// @@ -200,6 +162,8 @@ public struct Config { /// If true, device is considered to be "managed" by a mesh administrator /// Clients should then limit available configuration and administrative options inside the user interface /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var isManaged: Bool = false /// @@ -218,7 +182,7 @@ public struct Config { /// /// Defines the device's role on the Mesh network - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -236,6 +200,8 @@ public struct Config { /// The wifi radio and the oled screen will be put to sleep. /// This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. case router // = 2 + + /// NOTE: This enum value was marked as deprecated in the .proto file case routerClient // = 3 /// @@ -326,11 +292,26 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.Role] = [ + .client, + .clientMute, + .router, + .routerClient, + .repeater, + .tracker, + .sensor, + .tak, + .clientHidden, + .lostAndFound, + .takTracker, + ] + } /// /// Defines the device's behavior for how messages are rebroadcast - public enum RebroadcastMode: SwiftProtobuf.Enum { + public enum RebroadcastMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -378,6 +359,14 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ + .all, + .allSkipDecoding, + .localOnly, + .knownOnly, + ] + } public init() {} @@ -385,7 +374,7 @@ public struct Config { /// /// Position Config - public struct PositionConfig { + public struct PositionConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -407,6 +396,8 @@ public struct Config { /// /// Is GPS enabled for this node? + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsEnabled: Bool = false /// @@ -417,6 +408,8 @@ public struct Config { /// /// Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsAttemptTime: UInt32 = 0 /// @@ -457,7 +450,7 @@ public struct Config { /// are always included (also time if GPS-synced) /// NOTE: the more fields are included, the larger the message will be - /// leading to longer airtime and a higher risk of packet loss - public enum PositionFlags: SwiftProtobuf.Enum { + public enum PositionFlags: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -547,9 +540,24 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.PositionFlags] = [ + .unset, + .altitude, + .altitudeMsl, + .geoidalSeparation, + .dop, + .hvdop, + .satinview, + .seqNo, + .timestamp, + .heading, + .speed, + ] + } - public enum GpsMode: SwiftProtobuf.Enum { + public enum GpsMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -587,6 +595,13 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.GpsMode] = [ + .disabled, + .enabled, + .notPresent, + ] + } public init() {} @@ -595,7 +610,7 @@ public struct Config { /// /// Power Config\ /// See [Power Config](/docs/settings/config/power) for additional power config details. - public struct PowerConfig { + public struct PowerConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -655,7 +670,7 @@ public struct Config { /// /// Network Config - public struct NetworkConfig { + public struct NetworkConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -702,7 +717,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum AddressMode: SwiftProtobuf.Enum { + public enum AddressMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -734,9 +749,15 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.NetworkConfig.AddressMode] = [ + .dhcp, + .static, + ] + } - public struct IpV4Config { + public struct IpV4Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -769,7 +790,7 @@ public struct Config { /// /// Display Config - public struct DisplayConfig { + public struct DisplayConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -825,7 +846,7 @@ public struct Config { /// /// How the GPS coordinates are displayed on the OLED screen. - public enum GpsCoordinateFormat: SwiftProtobuf.Enum { + public enum GpsCoordinateFormat: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -888,11 +909,21 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ + .dec, + .dms, + .utm, + .mgrs, + .olc, + .osgr, + ] + } /// /// Unit display preference - public enum DisplayUnits: SwiftProtobuf.Enum { + public enum DisplayUnits: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -924,11 +955,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ + .metric, + .imperial, + ] + } /// /// Override OLED outo detect with this if it fails. - public enum OledType: SwiftProtobuf.Enum { + public enum OledType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -972,9 +1009,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.OledType] = [ + .oledAuto, + .oledSsd1306, + .oledSh1106, + .oledSh1107, + ] + } - public enum DisplayMode: SwiftProtobuf.Enum { + public enum DisplayMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1018,9 +1063,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayMode] = [ + .default, + .twocolor, + .inverted, + .color, + ] + } - public enum CompassOrientation: SwiftProtobuf.Enum { + public enum CompassOrientation: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1088,6 +1141,18 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ + .degrees0, + .degrees90, + .degrees180, + .degrees270, + .degrees0Inverted, + .degrees90Inverted, + .degrees180Inverted, + .degrees270Inverted, + ] + } public init() {} @@ -1095,7 +1160,7 @@ public struct Config { /// /// Lora Config - public struct LoRaConfig { + public struct LoRaConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1252,7 +1317,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum RegionCode: SwiftProtobuf.Enum { + public enum RegionCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1386,12 +1451,35 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.RegionCode] = [ + .unset, + .us, + .eu433, + .eu868, + .cn, + .jp, + .anz, + .kr, + .tw, + .ru, + .in, + .nz865, + .th, + .lora24, + .ua433, + .ua868, + .my433, + .my919, + .sg923, + ] + } /// /// Standard predefined channel settings /// Note: these mappings must match ModemPreset Choice in the device code. - public enum ModemPreset: SwiftProtobuf.Enum { + public enum ModemPreset: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1405,6 +1493,8 @@ public struct Config { /// /// Very Long Range - Slow /// Deprecated in 2.5: Works only with txco and is unusably slow + /// + /// NOTE: This enum value was marked as deprecated in the .proto file case veryLongSlow // = 2 /// @@ -1468,6 +1558,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.ModemPreset] = [ + .longFast, + .longSlow, + .veryLongSlow, + .mediumSlow, + .mediumFast, + .shortSlow, + .shortFast, + .longModerate, + .shortTurbo, + ] + } public init() {} @@ -1475,7 +1578,7 @@ public struct Config { fileprivate var _storage = _StorageClass.defaultInstance } - public struct BluetoothConfig { + public struct BluetoothConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1495,11 +1598,13 @@ public struct Config { /// /// Enables device (serial style logs) over Bluetooth /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var deviceLoggingEnabled: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum PairingMode: SwiftProtobuf.Enum { + public enum PairingMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1537,12 +1642,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.BluetoothConfig.PairingMode] = [ + .randomPin, + .fixedPin, + .noPin, + ] + } public init() {} } - public struct SecurityConfig { + public struct SecurityConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1591,201 +1703,6 @@ public struct Config { public init() {} } -#if swift(>=4.2) - -extension Config.DeviceConfig.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.Role] = [ - .client, - .clientMute, - .router, - .routerClient, - .repeater, - .tracker, - .sensor, - .tak, - .clientHidden, - .lostAndFound, - .takTracker, - ] -} - -extension Config.DeviceConfig.RebroadcastMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ - .all, - .allSkipDecoding, - .localOnly, - .knownOnly, - ] -} - -extension Config.PositionConfig.PositionFlags: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.PositionFlags] = [ - .unset, - .altitude, - .altitudeMsl, - .geoidalSeparation, - .dop, - .hvdop, - .satinview, - .seqNo, - .timestamp, - .heading, - .speed, - ] -} - -extension Config.PositionConfig.GpsMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.GpsMode] = [ - .disabled, - .enabled, - .notPresent, - ] -} - -extension Config.NetworkConfig.AddressMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.NetworkConfig.AddressMode] = [ - .dhcp, - .static, - ] -} - -extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ - .dec, - .dms, - .utm, - .mgrs, - .olc, - .osgr, - ] -} - -extension Config.DisplayConfig.DisplayUnits: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ - .metric, - .imperial, - ] -} - -extension Config.DisplayConfig.OledType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.OledType] = [ - .oledAuto, - .oledSsd1306, - .oledSh1106, - .oledSh1107, - ] -} - -extension Config.DisplayConfig.DisplayMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayMode] = [ - .default, - .twocolor, - .inverted, - .color, - ] -} - -extension Config.DisplayConfig.CompassOrientation: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ - .degrees0, - .degrees90, - .degrees180, - .degrees270, - .degrees0Inverted, - .degrees90Inverted, - .degrees180Inverted, - .degrees270Inverted, - ] -} - -extension Config.LoRaConfig.RegionCode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - .lora24, - .ua433, - .ua868, - .my433, - .my919, - .sg923, - ] -} - -extension Config.LoRaConfig.ModemPreset: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.ModemPreset] = [ - .longFast, - .longSlow, - .veryLongSlow, - .mediumSlow, - .mediumFast, - .shortSlow, - .shortFast, - .longModerate, - .shortTurbo, - ] -} - -extension Config.BluetoothConfig.PairingMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.BluetoothConfig.PairingMode] = [ - .randomPin, - .fixedPin, - .noPin, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension Config: @unchecked Sendable {} -extension Config.OneOf_PayloadVariant: @unchecked Sendable {} -extension Config.DeviceConfig: @unchecked Sendable {} -extension Config.DeviceConfig.Role: @unchecked Sendable {} -extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {} -extension Config.PositionConfig: @unchecked Sendable {} -extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} -extension Config.PositionConfig.GpsMode: @unchecked Sendable {} -extension Config.PowerConfig: @unchecked Sendable {} -extension Config.NetworkConfig: @unchecked Sendable {} -extension Config.NetworkConfig.AddressMode: @unchecked Sendable {} -extension Config.NetworkConfig.IpV4Config: @unchecked Sendable {} -extension Config.DisplayConfig: @unchecked Sendable {} -extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} -extension Config.DisplayConfig.OledType: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayMode: @unchecked Sendable {} -extension Config.DisplayConfig.CompassOrientation: @unchecked Sendable {} -extension Config.LoRaConfig: @unchecked Sendable {} -extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} -extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} -extension Config.BluetoothConfig: @unchecked Sendable {} -extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} -extension Config.SecurityConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -2260,7 +2177,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 2) } - if self.adcMultiplierOverride != 0 { + if self.adcMultiplierOverride.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.adcMultiplierOverride, fieldNumber: 3) } if self.waitBluetoothSecs != 0 { @@ -2704,7 +2621,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._codingRate != 0 { try visitor.visitSingularUInt32Field(value: _storage._codingRate, fieldNumber: 5) } - if _storage._frequencyOffset != 0 { + if _storage._frequencyOffset.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 6) } if _storage._region != .unset { @@ -2728,7 +2645,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._sx126XRxBoostedGain != false { try visitor.visitSingularBoolField(value: _storage._sx126XRxBoostedGain, fieldNumber: 13) } - if _storage._overrideFrequency != 0 { + if _storage._overrideFrequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._overrideFrequency, fieldNumber: 14) } if _storage._paFanDisabled != false { diff --git a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift index a2ec180e..a4569714 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct DeviceConnectionStatus { +public struct DeviceConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -81,7 +81,7 @@ public struct DeviceConnectionStatus { /// /// WiFi connection status -public struct WifiConnectionStatus { +public struct WifiConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -114,7 +114,7 @@ public struct WifiConnectionStatus { /// /// Ethernet connection status -public struct EthernetConnectionStatus { +public struct EthernetConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -139,7 +139,7 @@ public struct EthernetConnectionStatus { /// /// Ethernet or WiFi connection status -public struct NetworkConnectionStatus { +public struct NetworkConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -167,7 +167,7 @@ public struct NetworkConnectionStatus { /// /// Bluetooth connection status -public struct BluetoothConnectionStatus { +public struct BluetoothConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -191,7 +191,7 @@ public struct BluetoothConnectionStatus { /// /// Serial connection status -public struct SerialConnectionStatus { +public struct SerialConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -209,15 +209,6 @@ public struct SerialConnectionStatus { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceConnectionStatus: @unchecked Sendable {} -extension WifiConnectionStatus: @unchecked Sendable {} -extension EthernetConnectionStatus: @unchecked Sendable {} -extension NetworkConnectionStatus: @unchecked Sendable {} -extension BluetoothConnectionStatus: @unchecked Sendable {} -extension SerialConnectionStatus: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift index 10b9af2b..076e639e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Font sizes for the device screen -public enum ScreenFonts: SwiftProtobuf.Enum { +public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -60,24 +60,18 @@ public enum ScreenFonts: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension ScreenFonts: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [ScreenFonts] = [ .fontSmall, .fontMedium, .fontLarge, ] -} -#endif // swift(>=4.2) +} /// /// Position with static location information only for NodeDBLite -public struct PositionLite { +public struct PositionLite: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -112,7 +106,54 @@ public struct PositionLite { public init() {} } -public struct NodeInfoLite { +public struct UserLite: @unchecked Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// + /// This is the addr of the radio. + /// + /// NOTE: This field was marked as deprecated in the .proto file. + public var macaddr: Data = Data() + + /// + /// A full name for this user, i.e. "Kevin Hester" + public var longName: String = String() + + /// + /// A VERY short name, ideally two characters. + /// Suitable for a tiny OLED screen + public var shortName: String = String() + + /// + /// TBEAM, HELTEC, etc... + /// Starting in 1.2.11 moved to hw_model enum in the NodeInfo object. + /// Apps will still need the string here for older builds + /// (so OTA update can find the right image), but if the enum is available it will be used instead. + public var hwModel: HardwareModel = .unset + + /// + /// In some regions Ham radio operators have different bandwidth limitations than others. + /// If this user is a licensed operator, set this flag. + /// Also, "long_name" should be their licence number. + public var isLicensed: Bool = false + + /// + /// Indicates that the user's role in the mesh + public var role: Config.DeviceConfig.Role = .client + + /// + /// The public key of the user's device. + /// This is sent out to other nodes on the mesh to allow them to compute a shared secret key. + public var publicKey: Data = Data() + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + +public struct NodeInfoLite: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -126,8 +167,8 @@ public struct NodeInfoLite { /// /// The user info for this node - public var user: User { - get {return _storage._user ?? User()} + public var user: UserLite { + get {return _storage._user ?? UserLite()} set {_uniqueStorage()._user = newValue} } /// Returns true if `user` has been explicitly set. @@ -215,7 +256,7 @@ public struct NodeInfoLite { /// FIXME, since we write this each time we enter deep sleep (and have infinite /// flash) it would be better to use some sort of append only data structure for /// the receive queue and use the preferences store for the other stuff -public struct DeviceState { +public struct DeviceState: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -275,6 +316,8 @@ public struct DeviceState { /// Used only during development. /// Indicates developer is testing and changes should never be saved to flash. /// Deprecated in 2.3.1 + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var noSave: Bool { get {return _storage._noSave} set {_uniqueStorage()._noSave = newValue} @@ -323,7 +366,7 @@ public struct DeviceState { /// /// The on-disk saved channels -public struct ChannelFile { +public struct ChannelFile: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -346,7 +389,7 @@ public struct ChannelFile { /// /// This can be used for customizing the firmware distribution. If populated, /// show a secondary bootup screen with custom logo and text for 2.5 seconds. -public struct OEMStore { +public struct OEMStore: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -405,15 +448,6 @@ public struct OEMStore { fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension ScreenFonts: @unchecked Sendable {} -extension PositionLite: @unchecked Sendable {} -extension NodeInfoLite: @unchecked Sendable {} -extension DeviceState: @unchecked Sendable {} -extension ChannelFile: @unchecked Sendable {} -extension OEMStore: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -482,6 +516,74 @@ extension PositionLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat } } +extension UserLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".UserLite" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .same(proto: "macaddr"), + 2: .standard(proto: "long_name"), + 3: .standard(proto: "short_name"), + 4: .standard(proto: "hw_model"), + 5: .standard(proto: "is_licensed"), + 6: .same(proto: "role"), + 7: .standard(proto: "public_key"), + ] + + public 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.decodeSingularBytesField(value: &self.macaddr) }() + case 2: try { try decoder.decodeSingularStringField(value: &self.longName) }() + case 3: try { try decoder.decodeSingularStringField(value: &self.shortName) }() + case 4: try { try decoder.decodeSingularEnumField(value: &self.hwModel) }() + case 5: try { try decoder.decodeSingularBoolField(value: &self.isLicensed) }() + case 6: try { try decoder.decodeSingularEnumField(value: &self.role) }() + case 7: try { try decoder.decodeSingularBytesField(value: &self.publicKey) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if !self.macaddr.isEmpty { + try visitor.visitSingularBytesField(value: self.macaddr, fieldNumber: 1) + } + if !self.longName.isEmpty { + try visitor.visitSingularStringField(value: self.longName, fieldNumber: 2) + } + if !self.shortName.isEmpty { + try visitor.visitSingularStringField(value: self.shortName, fieldNumber: 3) + } + if self.hwModel != .unset { + try visitor.visitSingularEnumField(value: self.hwModel, fieldNumber: 4) + } + if self.isLicensed != false { + try visitor.visitSingularBoolField(value: self.isLicensed, fieldNumber: 5) + } + if self.role != .client { + try visitor.visitSingularEnumField(value: self.role, fieldNumber: 6) + } + if !self.publicKey.isEmpty { + try visitor.visitSingularBytesField(value: self.publicKey, fieldNumber: 7) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: UserLite, rhs: UserLite) -> Bool { + if lhs.macaddr != rhs.macaddr {return false} + if lhs.longName != rhs.longName {return false} + if lhs.shortName != rhs.shortName {return false} + if lhs.hwModel != rhs.hwModel {return false} + if lhs.isLicensed != rhs.isLicensed {return false} + if lhs.role != rhs.role {return false} + if lhs.publicKey != rhs.publicKey {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".NodeInfoLite" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ @@ -499,7 +601,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat fileprivate class _StorageClass { var _num: UInt32 = 0 - var _user: User? = nil + var _user: UserLite? = nil var _position: PositionLite? = nil var _snr: Float = 0 var _lastHeard: UInt32 = 0 @@ -581,7 +683,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index 0af27466..f2ef681d 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct LocalConfig { +public struct LocalConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -129,7 +129,7 @@ public struct LocalConfig { fileprivate var _storage = _StorageClass.defaultInstance } -public struct LocalModuleConfig { +public struct LocalModuleConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -293,11 +293,6 @@ public struct LocalModuleConfig { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=5.5) && canImport(_Concurrency) -extension LocalConfig: @unchecked Sendable {} -extension LocalModuleConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index 489cd8e3..c9482fc1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -25,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// bin/build-all.sh script. /// Because they will be used to find firmware filenames in the android app for OTA updates. /// To match the old style filenames, _ is converted to -, p is converted to . -public enum HardwareModel: SwiftProtobuf.Enum { +public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -329,6 +329,19 @@ public enum HardwareModel: SwiftProtobuf.Enum { /// Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. case trackerT1000E // = 71 + /// + /// RAK3172 STM32WLE5 Module (https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172) + case rak3172 // = 72 + + /// + /// Seeed Studio Wio-E5 (either mini or Dev kit) using STM32WL chip. + case wioE5 // = 73 + + /// + /// RadioMaster 900 Bandit, https://www.radiomasterrc.com/products/bandit-expresslrs-rf-module + /// SSD1306 OLED and No GPS + case radiomaster900Bandit // = 74 + /// /// ------------------------------------------------------------------------------------------------------------------------------------------ /// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. @@ -413,6 +426,9 @@ public enum HardwareModel: SwiftProtobuf.Enum { case 69: self = .heltecMeshNodeT114 case 70: self = .sensecapIndicator case 71: self = .trackerT1000E + case 72: self = .rak3172 + case 73: self = .wioE5 + case 74: self = .radiomaster900Bandit case 255: self = .privateHw default: self = .UNRECOGNIZED(rawValue) } @@ -491,16 +507,14 @@ public enum HardwareModel: SwiftProtobuf.Enum { case .heltecMeshNodeT114: return 69 case .sensecapIndicator: return 70 case .trackerT1000E: return 71 + case .rak3172: return 72 + case .wioE5: return 73 + case .radiomaster900Bandit: return 74 case .privateHw: return 255 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension HardwareModel: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [HardwareModel] = [ .unset, @@ -574,15 +588,17 @@ extension HardwareModel: CaseIterable { .heltecMeshNodeT114, .sensecapIndicator, .trackerT1000E, + .rak3172, + .wioE5, + .radiomaster900Bandit, .privateHw, ] -} -#endif // swift(>=4.2) +} /// /// Shared constants between device and phone -public enum Constants: SwiftProtobuf.Enum { +public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -617,26 +633,20 @@ public enum Constants: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Constants: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Constants] = [ .zero, .dataPayloadLen, ] -} -#endif // swift(>=4.2) +} /// /// Error codes for critical errors /// The device might report these fault codes on the screen. /// If you encounter a fault code, please post on the meshtastic.discourse.group /// and we'll try to help. -public enum CriticalErrorCode: SwiftProtobuf.Enum { +public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -745,11 +755,6 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension CriticalErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [CriticalErrorCode] = [ .none, @@ -767,13 +772,12 @@ extension CriticalErrorCode: CaseIterable { .flashCorruptionRecoverable, .flashCorruptionUnrecoverable, ] -} -#endif // swift(>=4.2) +} /// /// a gps position -public struct Position { +public struct Position: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -990,7 +994,7 @@ public struct Position { /// /// How the location was acquired: manual, onboard GPS, external (EUD) GPS - public enum LocSource: SwiftProtobuf.Enum { + public enum LocSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1034,12 +1038,20 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.LocSource] = [ + .locUnset, + .locManual, + .locInternal, + .locExternal, + ] + } /// /// How the altitude was acquired: manual, GPS int/ext, etc /// Default: same as location_source if present - public enum AltSource: SwiftProtobuf.Enum { + public enum AltSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1089,6 +1101,15 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.AltSource] = [ + .altUnset, + .altManual, + .altInternal, + .altExternal, + .altBarometric, + ] + } public init() {} @@ -1096,31 +1117,6 @@ public struct Position { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension Position.LocSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.LocSource] = [ - .locUnset, - .locManual, - .locInternal, - .locExternal, - ] -} - -extension Position.AltSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.AltSource] = [ - .altUnset, - .altManual, - .altInternal, - .altExternal, - .altBarometric, - ] -} - -#endif // swift(>=4.2) - /// /// Broadcast when a newly powered mesh node wants to find a node num it can use /// Sent from the phone over bluetooth to set the user id for the owner of this node. @@ -1142,7 +1138,7 @@ extension Position.AltSource: CaseIterable { /// A few nodenums are reserved and will never be requested: /// 0xff - broadcast /// 0 through 3 - for future use -public struct User { +public struct User: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1167,6 +1163,8 @@ public struct User { /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -1198,7 +1196,7 @@ public struct User { /// /// A message used in our Dynamic Source Routing protocol (RFC 4728 based) -public struct RouteDiscovery { +public struct RouteDiscovery: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1214,7 +1212,7 @@ public struct RouteDiscovery { /// /// A Routing control Data packet handled by the routing module -public struct Routing { +public struct Routing: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1254,7 +1252,7 @@ public struct Routing { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// A route request going from the requester case routeRequest(RouteDiscovery) @@ -1266,34 +1264,12 @@ public struct Routing { /// in addition to ack.fail_id to provide details on the type of failure). case errorReason(Routing.Error) - #if !swift(>=4.1) - public static func ==(lhs: Routing.OneOf_Variant, rhs: Routing.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.routeRequest, .routeRequest): return { - guard case .routeRequest(let l) = lhs, case .routeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.routeReply, .routeReply): return { - guard case .routeReply(let l) = lhs, case .routeReply(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.errorReason, .errorReason): return { - guard case .errorReason(let l) = lhs, case .errorReason(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide /// details on the type of failure). - public enum Error: SwiftProtobuf.Enum { + public enum Error: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1345,6 +1321,10 @@ public struct Routing { /// 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) case notAuthorized // = 33 + + /// + /// The client specified a PKI transport, but the node was unable to send the packet using PKI (and did not send the message at all) + case pkiFailed // = 34 case UNRECOGNIZED(Int) public init() { @@ -1365,6 +1345,7 @@ public struct Routing { case 9: self = .dutyCycleLimit case 32: self = .badRequest case 33: self = .notAuthorized + case 34: self = .pkiFailed default: self = .UNRECOGNIZED(rawValue) } } @@ -1383,42 +1364,38 @@ public struct Routing { case .dutyCycleLimit: return 9 case .badRequest: return 32 case .notAuthorized: return 33 + case .pkiFailed: return 34 case .UNRECOGNIZED(let i): return i } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Routing.Error] = [ + .none, + .noRoute, + .gotNak, + .timeout, + .noInterface, + .maxRetransmit, + .noChannel, + .tooLarge, + .noResponse, + .dutyCycleLimit, + .badRequest, + .notAuthorized, + .pkiFailed, + ] + } public init() {} } -#if swift(>=4.2) - -extension Routing.Error: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Routing.Error] = [ - .none, - .noRoute, - .gotNak, - .timeout, - .noInterface, - .maxRetransmit, - .noChannel, - .tooLarge, - .noResponse, - .dutyCycleLimit, - .badRequest, - .notAuthorized, - ] -} - -#endif // swift(>=4.2) - /// /// (Formerly called SubPacket) /// The payload portion fo a packet, this is the actual bytes that are sent /// inside a radio packet (because from/to are broken out by the comms library) -public struct DataMessage { +public struct DataMessage: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1472,7 +1449,7 @@ public struct DataMessage { /// /// Waypoint message, used to share arbitrary locations across the mesh -public struct Waypoint { +public struct Waypoint: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1534,7 +1511,7 @@ public struct Waypoint { /// /// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server -public struct MqttClientProxyMessage { +public struct MqttClientProxyMessage: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1575,7 +1552,7 @@ public struct MqttClientProxyMessage { /// /// The actual service envelope payload or text for mqtt pub / sub - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// Bytes case data(Data) @@ -1583,24 +1560,6 @@ public struct MqttClientProxyMessage { /// Text case text(String) - #if !swift(>=4.1) - public static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.data, .data): return { - guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -1610,7 +1569,7 @@ public struct MqttClientProxyMessage { /// A packet envelope sent/received over the mesh /// only payload_variant is sent in the payload portion of the LORA packet. /// The other fields are either not sent at all, or sent in the special 16 byte LORA header. -public struct MeshPacket { +public struct MeshPacket: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1744,6 +1703,8 @@ public struct MeshPacket { /// /// Describe if this message is delayed + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var delayed: MeshPacket.Delayed { get {return _storage._delayed} set {_uniqueStorage()._delayed = newValue} @@ -1780,7 +1741,7 @@ public struct MeshPacket { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case decoded(DataMessage) @@ -1788,24 +1749,6 @@ public struct MeshPacket { /// TODO: REPLACE case encrypted(Data) - #if !swift(>=4.1) - public static func ==(lhs: MeshPacket.OneOf_PayloadVariant, rhs: MeshPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.decoded, .decoded): return { - guard case .decoded(let l) = lhs, case .decoded(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.encrypted, .encrypted): return { - guard case .encrypted(let l) = lhs, case .encrypted(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// @@ -1827,7 +1770,7 @@ public struct MeshPacket { /// So I bit the bullet and implemented a new (internal - not sent over the air) /// field in MeshPacket called 'priority'. /// And the transmission queue in the router object is now a priority queue. - public enum Priority: SwiftProtobuf.Enum { + public enum Priority: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1892,11 +1835,22 @@ public struct MeshPacket { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Priority] = [ + .unset, + .min, + .background, + .default, + .reliable, + .ack, + .max, + ] + } /// /// Identify if this is a delayed packet - public enum Delayed: SwiftProtobuf.Enum { + public enum Delayed: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1934,6 +1888,13 @@ public struct MeshPacket { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Delayed] = [ + .noDelay, + .broadcast, + .direct, + ] + } public init() {} @@ -1941,32 +1902,6 @@ public struct MeshPacket { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension MeshPacket.Priority: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Priority] = [ - .unset, - .min, - .background, - .default, - .reliable, - .ack, - .max, - ] -} - -extension MeshPacket.Delayed: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Delayed] = [ - .noDelay, - .broadcast, - .direct, - ] -} - -#endif // swift(>=4.2) - /// /// The bluetooth to device link: /// Old BTLE protocol docs from TODO, merge in above and make real docs... @@ -1984,7 +1919,7 @@ extension MeshPacket.Delayed: CaseIterable { /// level etc) SET_CONFIG (switches device to a new set of radio params and /// preshared key, drops all existing nodes, force our node to rejoin this new group) /// Full information about a node on the mesh -public struct NodeInfo { +public struct NodeInfo: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2085,7 +2020,7 @@ public struct NodeInfo { /// Unique local debugging info for this node /// Note: we don't include position or the user info, because that will come in the /// Sent to the phone in response to WantNodes. -public struct MyNodeInfo { +public struct MyNodeInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2116,7 +2051,7 @@ public struct MyNodeInfo { /// on the message it is assumed to be a continuation of the previously sent message. /// This allows the device code to use fixed maxlen 64 byte strings for messages, /// and then extend as needed by emitting multiple records. -public struct LogRecord { +public struct LogRecord: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2141,7 +2076,7 @@ public struct LogRecord { /// /// Log levels, chosen to match python logging conventions. - public enum Level: SwiftProtobuf.Enum { + public enum Level: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -2203,29 +2138,23 @@ public struct LogRecord { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [LogRecord.Level] = [ + .unset, + .critical, + .error, + .warning, + .info, + .debug, + .trace, + ] + } public init() {} } -#if swift(>=4.2) - -extension LogRecord.Level: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [LogRecord.Level] = [ - .unset, - .critical, - .error, - .warning, - .info, - .debug, - .trace, - ] -} - -#endif // swift(>=4.2) - -public struct QueueStatus { +public struct QueueStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2252,7 +2181,7 @@ public struct QueueStatus { /// It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? /// It will sit in that descriptor until consumed by the phone, /// at which point the next item in the FIFO will be populated. -public struct FromRadio { +public struct FromRadio: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2428,7 +2357,7 @@ public struct FromRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Log levels, chosen to match python logging conventions. case packet(MeshPacket) @@ -2483,76 +2412,6 @@ public struct FromRadio { /// Notification message to the client case clientNotification(ClientNotification) - #if !swift(>=4.1) - public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.myInfo, .myInfo): return { - guard case .myInfo(let l) = lhs, case .myInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodeInfo, .nodeInfo): return { - guard case .nodeInfo(let l) = lhs, case .nodeInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.config, .config): return { - guard case .config(let l) = lhs, case .config(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.logRecord, .logRecord): return { - guard case .logRecord(let l) = lhs, case .logRecord(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.configCompleteID, .configCompleteID): return { - guard case .configCompleteID(let l) = lhs, case .configCompleteID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebooted, .rebooted): return { - guard case .rebooted(let l) = lhs, case .rebooted(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.moduleConfig, .moduleConfig): return { - guard case .moduleConfig(let l) = lhs, case .moduleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.channel, .channel): return { - guard case .channel(let l) = lhs, case .channel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.queueStatus, .queueStatus): return { - guard case .queueStatus(let l) = lhs, case .queueStatus(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.metadata, .metadata): return { - guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.fileInfo, .fileInfo): return { - guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.clientNotification, .clientNotification): return { - guard case .clientNotification(let l) = lhs, case .clientNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -2563,7 +2422,7 @@ public struct FromRadio { /// To be used for important messages that should to be displayed to the user /// in the form of push notifications or validation messages when saving /// invalid configuration. -public struct ClientNotification { +public struct ClientNotification: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2600,7 +2459,7 @@ public struct ClientNotification { /// /// Individual File info for the device -public struct FileInfo { +public struct FileInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2621,7 +2480,7 @@ public struct FileInfo { /// /// Packets/commands to the radio will be written (reliably) to the toRadio characteristic. /// Once the write completes the phone can assume it is handled. -public struct ToRadio { +public struct ToRadio: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2701,7 +2560,7 @@ public struct ToRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send this packet on the mesh case packet(MeshPacket) @@ -2728,40 +2587,6 @@ public struct ToRadio { /// Heartbeat message (used to keep the device connection awake on serial) case heartbeat(Heartbeat) - #if !swift(>=4.1) - public static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.wantConfigID, .wantConfigID): return { - guard case .wantConfigID(let l) = lhs, case .wantConfigID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.disconnect, .disconnect): return { - guard case .disconnect(let l) = lhs, case .disconnect(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -2769,7 +2594,7 @@ public struct ToRadio { /// /// Compressed message payload -public struct Compressed { +public struct Compressed: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2789,7 +2614,7 @@ public struct Compressed { /// /// Full info on edges for a single node -public struct NeighborInfo { +public struct NeighborInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2817,7 +2642,7 @@ public struct NeighborInfo { /// /// A single edge in the mesh -public struct Neighbor { +public struct Neighbor: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2847,7 +2672,7 @@ public struct Neighbor { /// /// Device metadata response -public struct DeviceMetadata { +public struct DeviceMetadata: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2900,7 +2725,7 @@ public struct DeviceMetadata { /// /// A heartbeat message is sent to the node from the client to keep the connection alive. /// This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. -public struct Heartbeat { +public struct Heartbeat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2912,7 +2737,7 @@ public struct Heartbeat { /// /// RemoteHardwarePins associated with a node -public struct NodeRemoteHardwarePin { +public struct NodeRemoteHardwarePin: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2939,7 +2764,7 @@ public struct NodeRemoteHardwarePin { fileprivate var _pin: RemoteHardwarePin? = nil } -public struct ChunkedPayload { +public struct ChunkedPayload: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2967,7 +2792,7 @@ public struct ChunkedPayload { /// /// Wrapper message for broken repeated oneof support -public struct resend_chunks { +public struct resend_chunks: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2981,7 +2806,7 @@ public struct resend_chunks { /// /// Responses to a ChunkedPayload request -public struct ChunkedPayloadResponse { +public struct ChunkedPayloadResponse: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3024,7 +2849,7 @@ public struct ChunkedPayloadResponse { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Request to transfer chunked payload case requestTransfer(Bool) @@ -3035,76 +2860,11 @@ public struct ChunkedPayloadResponse { /// Request missing indexes in the chunked payload case resendChunks(resend_chunks) - #if !swift(>=4.1) - public static func ==(lhs: ChunkedPayloadResponse.OneOf_PayloadVariant, rhs: ChunkedPayloadResponse.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.requestTransfer, .requestTransfer): return { - guard case .requestTransfer(let l) = lhs, case .requestTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.acceptTransfer, .acceptTransfer): return { - guard case .acceptTransfer(let l) = lhs, case .acceptTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.resendChunks, .resendChunks): return { - guard case .resendChunks(let l) = lhs, case .resendChunks(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension HardwareModel: @unchecked Sendable {} -extension Constants: @unchecked Sendable {} -extension CriticalErrorCode: @unchecked Sendable {} -extension Position: @unchecked Sendable {} -extension Position.LocSource: @unchecked Sendable {} -extension Position.AltSource: @unchecked Sendable {} -extension User: @unchecked Sendable {} -extension RouteDiscovery: @unchecked Sendable {} -extension Routing: @unchecked Sendable {} -extension Routing.OneOf_Variant: @unchecked Sendable {} -extension Routing.Error: @unchecked Sendable {} -extension DataMessage: @unchecked Sendable {} -extension Waypoint: @unchecked Sendable {} -extension MqttClientProxyMessage: @unchecked Sendable {} -extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket: @unchecked Sendable {} -extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket.Priority: @unchecked Sendable {} -extension MeshPacket.Delayed: @unchecked Sendable {} -extension NodeInfo: @unchecked Sendable {} -extension MyNodeInfo: @unchecked Sendable {} -extension LogRecord: @unchecked Sendable {} -extension LogRecord.Level: @unchecked Sendable {} -extension QueueStatus: @unchecked Sendable {} -extension FromRadio: @unchecked Sendable {} -extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension ClientNotification: @unchecked Sendable {} -extension FileInfo: @unchecked Sendable {} -extension ToRadio: @unchecked Sendable {} -extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension Compressed: @unchecked Sendable {} -extension NeighborInfo: @unchecked Sendable {} -extension Neighbor: @unchecked Sendable {} -extension DeviceMetadata: @unchecked Sendable {} -extension Heartbeat: @unchecked Sendable {} -extension NodeRemoteHardwarePin: @unchecked Sendable {} -extension ChunkedPayload: @unchecked Sendable {} -extension resend_chunks: @unchecked Sendable {} -extension ChunkedPayloadResponse: @unchecked Sendable {} -extension ChunkedPayloadResponse.OneOf_PayloadVariant: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -3182,6 +2942,9 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 69: .same(proto: "HELTEC_MESH_NODE_T114"), 70: .same(proto: "SENSECAP_INDICATOR"), 71: .same(proto: "TRACKER_T1000_E"), + 72: .same(proto: "RAK3172"), + 73: .same(proto: "WIO_E5"), + 74: .same(proto: "RADIOMASTER_900_BANDIT"), 255: .same(proto: "PRIVATE_HW"), ] } @@ -3686,6 +3449,7 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding { 9: .same(proto: "DUTY_CYCLE_LIMIT"), 32: .same(proto: "BAD_REQUEST"), 33: .same(proto: "NOT_AUTHORIZED"), + 34: .same(proto: "PKI_FAILED"), ] } @@ -4074,7 +3838,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._rxTime != 0 { try visitor.visitSingularFixed32Field(value: _storage._rxTime, fieldNumber: 7) } - if _storage._rxSnr != 0 { + if _storage._rxSnr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._rxSnr, fieldNumber: 8) } if _storage._hopLimit != 0 { @@ -4257,7 +4021,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -5102,7 +4866,7 @@ extension Neighbor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if self.nodeID != 0 { try visitor.visitSingularUInt32Field(value: self.nodeID, fieldNumber: 1) } - if self.snr != 0 { + if self.snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 2) } if self.lastRxTime != 0 { @@ -5215,8 +4979,8 @@ extension Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index c68ffd83..6f3b2d76 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum RemoteHardwarePinType: SwiftProtobuf.Enum { +public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -58,24 +58,18 @@ public enum RemoteHardwarePinType: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension RemoteHardwarePinType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [RemoteHardwarePinType] = [ .unknown, .digitalRead, .digitalWrite, ] -} -#endif // swift(>=4.2) +} /// /// Module Config -public struct ModuleConfig { +public struct ModuleConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -218,7 +212,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// TODO: REPLACE case mqtt(ModuleConfig.MQTTConfig) @@ -259,73 +253,11 @@ public struct ModuleConfig { /// TODO: REPLACE case paxcounter(ModuleConfig.PaxcounterConfig) - #if !swift(>=4.1) - public static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.mqtt, .mqtt): return { - guard case .mqtt(let l) = lhs, case .mqtt(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.serial, .serial): return { - guard case .serial(let l) = lhs, case .serial(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.externalNotification, .externalNotification): return { - guard case .externalNotification(let l) = lhs, case .externalNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.storeForward, .storeForward): return { - guard case .storeForward(let l) = lhs, case .storeForward(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rangeTest, .rangeTest): return { - guard case .rangeTest(let l) = lhs, case .rangeTest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.telemetry, .telemetry): return { - guard case .telemetry(let l) = lhs, case .telemetry(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.cannedMessage, .cannedMessage): return { - guard case .cannedMessage(let l) = lhs, case .cannedMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.audio, .audio): return { - guard case .audio(let l) = lhs, case .audio(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.remoteHardware, .remoteHardware): return { - guard case .remoteHardware(let l) = lhs, case .remoteHardware(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.neighborInfo, .neighborInfo): return { - guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.ambientLighting, .ambientLighting): return { - guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.detectionSensor, .detectionSensor): return { - guard case .detectionSensor(let l) = lhs, case .detectionSensor(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.paxcounter, .paxcounter): return { - guard case .paxcounter(let l) = lhs, case .paxcounter(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// MQTT Client Config - public struct MQTTConfig { + public struct MQTTConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -400,7 +332,7 @@ public struct ModuleConfig { /// /// Settings for reporting unencrypted information about our node to a map via MQTT - public struct MapReportSettings { + public struct MapReportSettings: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -420,7 +352,7 @@ public struct ModuleConfig { /// /// RemoteHardwareModule Config - public struct RemoteHardwareConfig { + public struct RemoteHardwareConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -444,7 +376,7 @@ public struct ModuleConfig { /// /// NeighborInfoModule Config - public struct NeighborInfoConfig { + public struct NeighborInfoConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -465,7 +397,7 @@ public struct ModuleConfig { /// /// Detection Sensor Module Config - public struct DetectionSensorConfig { + public struct DetectionSensorConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -516,7 +448,7 @@ public struct ModuleConfig { /// /// Audio Config for codec2 voice - public struct AudioConfig { + public struct AudioConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -553,7 +485,7 @@ public struct ModuleConfig { /// /// Baudrate for codec2 voice - public enum Audio_Baud: SwiftProtobuf.Enum { + public enum Audio_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case codec2Default // = 0 case codec23200 // = 1 @@ -600,6 +532,19 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ + .codec2Default, + .codec23200, + .codec22400, + .codec21600, + .codec21400, + .codec21300, + .codec21200, + .codec2700, + .codec2700B, + ] + } public init() {} @@ -607,7 +552,7 @@ public struct ModuleConfig { /// /// Config for the Paxcounter Module - public struct PaxcounterConfig { + public struct PaxcounterConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -633,7 +578,7 @@ public struct ModuleConfig { /// /// Serial Config - public struct SerialConfig { + public struct SerialConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -676,7 +621,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum Serial_Baud: SwiftProtobuf.Enum { + public enum Serial_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case baudDefault // = 0 case baud110 // = 1 @@ -744,11 +689,31 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ + .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, + .baud2400, + .baud4800, + .baud9600, + .baud19200, + .baud38400, + .baud57600, + .baud115200, + .baud230400, + .baud460800, + .baud576000, + .baud921600, + ] + } /// /// TODO: REPLACE - public enum Serial_Mode: SwiftProtobuf.Enum { + public enum Serial_Mode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case `default` // = 0 case simple // = 1 @@ -793,6 +758,17 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ + .default, + .simple, + .proto, + .textmsg, + .nmea, + .caltopo, + .ws85, + ] + } public init() {} @@ -800,7 +776,7 @@ public struct ModuleConfig { /// /// External Notifications Config - public struct ExternalNotificationConfig { + public struct ExternalNotificationConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -883,7 +859,7 @@ public struct ModuleConfig { /// /// Store and Forward Module Config - public struct StoreForwardConfig { + public struct StoreForwardConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -919,7 +895,7 @@ public struct ModuleConfig { /// /// Preferences for the RangeTestModule - public struct RangeTestConfig { + public struct RangeTestConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -944,7 +920,7 @@ public struct ModuleConfig { /// /// Configuration for both device and environment metrics - public struct TelemetryConfig { + public struct TelemetryConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1001,7 +977,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public struct CannedMessageConfig { + public struct CannedMessageConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1056,7 +1032,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum InputEventChar: SwiftProtobuf.Enum { + public enum InputEventChar: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1124,6 +1100,18 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ + .none, + .up, + .down, + .left, + .right, + .select, + .back, + .cancel, + ] + } public init() {} @@ -1132,7 +1120,7 @@ public struct ModuleConfig { /// ///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. ///Initially created for the RAK14001 RGB LED module. - public struct AmbientLightingConfig { + public struct AmbientLightingConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1165,77 +1153,9 @@ public struct ModuleConfig { public init() {} } -#if swift(>=4.2) - -extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ - .codec2Default, - .codec23200, - .codec22400, - .codec21600, - .codec21400, - .codec21300, - .codec21200, - .codec2700, - .codec2700B, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ - .baudDefault, - .baud110, - .baud300, - .baud600, - .baud1200, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ - .default, - .simple, - .proto, - .textmsg, - .nmea, - .caltopo, - .ws85, - ] -} - -extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ - .none, - .up, - .down, - .left, - .right, - .select, - .back, - .cancel, - ] -} - -#endif // swift(>=4.2) - /// /// A GPIO pin definition for remote hardware module -public struct RemoteHardwarePin { +public struct RemoteHardwarePin: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1257,31 +1177,6 @@ public struct RemoteHardwarePin { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RemoteHardwarePinType: @unchecked Sendable {} -extension ModuleConfig: @unchecked Sendable {} -extension ModuleConfig.OneOf_PayloadVariant: @unchecked Sendable {} -extension ModuleConfig.MQTTConfig: @unchecked Sendable {} -extension ModuleConfig.MapReportSettings: @unchecked Sendable {} -extension ModuleConfig.RemoteHardwareConfig: @unchecked Sendable {} -extension ModuleConfig.NeighborInfoConfig: @unchecked Sendable {} -extension ModuleConfig.DetectionSensorConfig: @unchecked Sendable {} -extension ModuleConfig.AudioConfig: @unchecked Sendable {} -extension ModuleConfig.AudioConfig.Audio_Baud: @unchecked Sendable {} -extension ModuleConfig.PaxcounterConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Baud: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Mode: @unchecked Sendable {} -extension ModuleConfig.ExternalNotificationConfig: @unchecked Sendable {} -extension ModuleConfig.StoreForwardConfig: @unchecked Sendable {} -extension ModuleConfig.RangeTestConfig: @unchecked Sendable {} -extension ModuleConfig.TelemetryConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {} -extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {} -extension RemoteHardwarePin: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift index efe6cdd5..fc5e37a1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This message wraps a MeshPacket with extra metadata about the sender and how it arrived. -public struct ServiceEnvelope { +public struct ServiceEnvelope: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -57,7 +57,7 @@ public struct ServiceEnvelope { /// /// Information about a node intended to be reported unencrypted to a map using MQTT. -public struct MapReport { +public struct MapReport: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -121,11 +121,6 @@ public struct MapReport { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension ServiceEnvelope: @unchecked Sendable {} -extension MapReport: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift index cf8aa463..f82b3c51 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct Paxcount { +public struct Paxcount: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -44,10 +44,6 @@ public struct Paxcount { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Paxcount: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index c728c961..c5348a8a 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -33,7 +33,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: This was formerly a Type enum named 'typ' with the same id # /// We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. /// This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically. -public enum PortNum: SwiftProtobuf.Enum { +public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -277,11 +277,6 @@ public enum PortNum: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension PortNum: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [PortNum] = [ .unknownApp, @@ -313,14 +308,9 @@ extension PortNum: CaseIterable { .atakForwarder, .max, ] + } -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension PortNum: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. extension PortNum: SwiftProtobuf._ProtoNameProviding { diff --git a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift index 5f51e948..9c61e6d0 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). ///But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) -public struct PowerMon { +public struct PowerMon: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -31,7 +31,7 @@ public struct PowerMon { /// Any significant power changing event in meshtastic should be tagged with a powermon state transition. ///If you are making new meshtastic features feel free to add new entries at the end of this definition. - public enum State: SwiftProtobuf.Enum { + public enum State: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case none // = 0 case cpuDeepSleep // = 1 @@ -104,37 +104,31 @@ public struct PowerMon { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerMon.State] = [ + .none, + .cpuDeepSleep, + .cpuLightSleep, + .vext1On, + .loraRxon, + .loraTxon, + .loraRxactive, + .btOn, + .ledOn, + .screenOn, + .screenDrawing, + .wifiOn, + .gpsActive, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerMon.State: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerMon.State] = [ - .none, - .cpuDeepSleep, - .cpuLightSleep, - .vext1On, - .loraRxon, - .loraTxon, - .loraRxactive, - .btOn, - .ledOn, - .screenOn, - .screenDrawing, - .wifiOn, - .gpsActive, - ] -} - -#endif // swift(>=4.2) - /// /// PowerStress testing support via the C++ PowerStress module -public struct PowerStressMessage { +public struct PowerStressMessage: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -151,7 +145,7 @@ public struct PowerStressMessage { /// What operation would we like the UUT to perform. ///note: senders should probably set want_response in their request packets, so that they can know when the state ///machine has started processing their request - public enum Opcode: SwiftProtobuf.Enum { + public enum Opcode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -272,48 +266,35 @@ public struct PowerStressMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerStressMessage.Opcode] = [ + .unset, + .printInfo, + .forceQuiet, + .endQuiet, + .screenOn, + .screenOff, + .cpuIdle, + .cpuDeepsleep, + .cpuFullon, + .ledOn, + .ledOff, + .loraOff, + .loraTx, + .loraRx, + .btOff, + .btOn, + .wifiOff, + .wifiOn, + .gpsOff, + .gpsOn, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerStressMessage.Opcode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerStressMessage.Opcode] = [ - .unset, - .printInfo, - .forceQuiet, - .endQuiet, - .screenOn, - .screenOff, - .cpuIdle, - .cpuDeepsleep, - .cpuFullon, - .ledOn, - .ledOff, - .loraOff, - .loraTx, - .loraRx, - .btOff, - .btOn, - .wifiOff, - .wifiOn, - .gpsOff, - .gpsOn, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension PowerMon: @unchecked Sendable {} -extension PowerMon.State: @unchecked Sendable {} -extension PowerStressMessage: @unchecked Sendable {} -extension PowerStressMessage.Opcode: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -323,8 +304,8 @@ extension PowerMon: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { @@ -379,7 +360,7 @@ extension PowerStressMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.cmd != .unset { try visitor.visitSingularEnumField(value: self.cmd, fieldNumber: 1) } - if self.numSeconds != 0 { + if self.numSeconds.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.numSeconds, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift index ac6eeb26..60f64504 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift @@ -30,7 +30,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// because no security yet (beyond the channel mechanism). /// It should be off by default and then protected based on some TBD mechanism /// (a special channel once multichannel support is included?) -public struct HardwareMessage { +public struct HardwareMessage: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -52,7 +52,7 @@ public struct HardwareMessage { /// /// TODO: REPLACE - public enum TypeEnum: SwiftProtobuf.Enum { + public enum TypeEnum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -110,32 +110,21 @@ public struct HardwareMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [HardwareMessage.TypeEnum] = [ + .unset, + .writeGpios, + .watchGpios, + .gpiosChanged, + .readGpios, + .readGpiosReply, + ] + } public init() {} } -#if swift(>=4.2) - -extension HardwareMessage.TypeEnum: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [HardwareMessage.TypeEnum] = [ - .unset, - .writeGpios, - .watchGpios, - .gpiosChanged, - .readGpios, - .readGpiosReply, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension HardwareMessage: @unchecked Sendable {} -extension HardwareMessage.TypeEnum: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift index 6fdf3208..c1f3f678 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct RTTTLConfig { +public struct RTTTLConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,10 +36,6 @@ public struct RTTTLConfig { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RTTTLConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift index 54efa77b..0b67eaf6 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct StoreAndForward { +public struct StoreAndForward: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -79,7 +79,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case stats(StoreAndForward.Statistics) @@ -93,38 +93,12 @@ public struct StoreAndForward { /// Text from history message. case text(Data) - #if !swift(>=4.1) - public static func ==(lhs: StoreAndForward.OneOf_Variant, rhs: StoreAndForward.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.stats, .stats): return { - guard case .stats(let l) = lhs, case .stats(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.history, .history): return { - guard case .history(let l) = lhs, case .history(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// 001 - 063 = From Router /// 064 - 127 = From Client - public enum RequestResponse: SwiftProtobuf.Enum { + public enum RequestResponse: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -242,11 +216,31 @@ public struct StoreAndForward { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [StoreAndForward.RequestResponse] = [ + .unset, + .routerError, + .routerHeartbeat, + .routerPing, + .routerPong, + .routerBusy, + .routerHistory, + .routerStats, + .routerTextDirect, + .routerTextBroadcast, + .clientError, + .clientHistory, + .clientStats, + .clientPing, + .clientPong, + .clientAbort, + ] + } /// /// TODO: REPLACE - public struct Statistics { + public struct Statistics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -294,7 +288,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct History { + public struct History: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -319,7 +313,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct Heartbeat { + public struct Heartbeat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -340,41 +334,6 @@ public struct StoreAndForward { public init() {} } -#if swift(>=4.2) - -extension StoreAndForward.RequestResponse: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [StoreAndForward.RequestResponse] = [ - .unset, - .routerError, - .routerHeartbeat, - .routerPing, - .routerPong, - .routerBusy, - .routerHistory, - .routerStats, - .routerTextDirect, - .routerTextBroadcast, - .clientError, - .clientHistory, - .clientStats, - .clientPing, - .clientPong, - .clientAbort, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension StoreAndForward: @unchecked Sendable {} -extension StoreAndForward.OneOf_Variant: @unchecked Sendable {} -extension StoreAndForward.RequestResponse: @unchecked Sendable {} -extension StoreAndForward.Statistics: @unchecked Sendable {} -extension StoreAndForward.History: @unchecked Sendable {} -extension StoreAndForward.Heartbeat: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index de4e550c..7289b713 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Supported I2C Sensors for telemetry in Meshtastic -public enum TelemetrySensorType: SwiftProtobuf.Enum { +public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -128,6 +128,18 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { /// /// NAU7802 Scale Chip or compatible case nau7802 // = 25 + + /// + /// BMP3XX High accuracy temperature and pressure + case bmp3Xx // = 26 + + /// + /// ICM-20948 9-Axis digital motion processor + case icm20948 // = 27 + + /// + /// MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) + case max17048 // = 28 case UNRECOGNIZED(Int) public init() { @@ -162,6 +174,9 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case 23: self = .aht10 case 24: self = .dfrobotLark case 25: self = .nau7802 + case 26: self = .bmp3Xx + case 27: self = .icm20948 + case 28: self = .max17048 default: self = .UNRECOGNIZED(rawValue) } } @@ -194,15 +209,13 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case .aht10: return 23 case .dfrobotLark: return 24 case .nau7802: return 25 + case .bmp3Xx: return 26 + case .icm20948: return 27 + case .max17048: return 28 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension TelemetrySensorType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [TelemetrySensorType] = [ .sensorUnset, @@ -231,14 +244,16 @@ extension TelemetrySensorType: CaseIterable { .aht10, .dfrobotLark, .nau7802, + .bmp3Xx, + .icm20948, + .max17048, ] -} -#endif // swift(>=4.2) +} /// /// Key native device metrics such as battery level -public struct DeviceMetrics { +public struct DeviceMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -311,7 +326,7 @@ public struct DeviceMetrics { /// /// Weather station or other environmental metrics -public struct EnvironmentMetrics { +public struct EnvironmentMetrics: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -514,7 +529,7 @@ public struct EnvironmentMetrics { /// /// Power Metrics (voltage / current / etc) -public struct PowerMetrics { +public struct PowerMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -599,7 +614,7 @@ public struct PowerMetrics { /// /// Air quality metrics -public struct AirQualityMetrics { +public struct AirQualityMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -756,7 +771,7 @@ public struct AirQualityMetrics { /// /// Types of Measurements the telemetry module is equipped to handle -public struct Telemetry { +public struct Telemetry: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -809,7 +824,7 @@ public struct Telemetry { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// Key native device metrics such as battery level case deviceMetrics(DeviceMetrics) @@ -823,32 +838,6 @@ public struct Telemetry { /// Power Metrics case powerMetrics(PowerMetrics) - #if !swift(>=4.1) - public static func ==(lhs: Telemetry.OneOf_Variant, rhs: Telemetry.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.deviceMetrics, .deviceMetrics): return { - guard case .deviceMetrics(let l) = lhs, case .deviceMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.environmentMetrics, .environmentMetrics): return { - guard case .environmentMetrics(let l) = lhs, case .environmentMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.airQualityMetrics, .airQualityMetrics): return { - guard case .airQualityMetrics(let l) = lhs, case .airQualityMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.powerMetrics, .powerMetrics): return { - guard case .powerMetrics(let l) = lhs, case .powerMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -856,7 +845,7 @@ public struct Telemetry { /// /// NAU7802 Telemetry configuration, for saving to flash -public struct Nau7802Config { +public struct Nau7802Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -874,17 +863,6 @@ public struct Nau7802Config { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension TelemetrySensorType: @unchecked Sendable {} -extension DeviceMetrics: @unchecked Sendable {} -extension EnvironmentMetrics: @unchecked Sendable {} -extension PowerMetrics: @unchecked Sendable {} -extension AirQualityMetrics: @unchecked Sendable {} -extension Telemetry: @unchecked Sendable {} -extension Telemetry.OneOf_Variant: @unchecked Sendable {} -extension Nau7802Config: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -917,6 +895,9 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding { 23: .same(proto: "AHT10"), 24: .same(proto: "DFROBOT_LARK"), 25: .same(proto: "NAU7802"), + 26: .same(proto: "BMP3XX"), + 27: .same(proto: "ICM20948"), + 28: .same(proto: "MAX17048"), ] } @@ -1488,7 +1469,7 @@ extension Nau7802Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.zeroOffset != 0 { try visitor.visitSingularInt32Field(value: self.zeroOffset, fieldNumber: 1) } - if self.calibrationFactor != 0 { + if self.calibrationFactor.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.calibrationFactor, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift index 1f41fe0b..89d0097c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct XModem { +public struct XModem: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -35,7 +35,7 @@ public struct XModem { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum Control: SwiftProtobuf.Enum { + public enum Control: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case nul // = 0 case soh // = 1 @@ -79,34 +79,23 @@ public struct XModem { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [XModem.Control] = [ + .nul, + .soh, + .stx, + .eot, + .ack, + .nak, + .can, + .ctrlz, + ] + } public init() {} } -#if swift(>=4.2) - -extension XModem.Control: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [XModem.Control] = [ - .nul, - .soh, - .stx, - .eot, - .ack, - .nak, - .can, - .ctrlz, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension XModem: @unchecked Sendable {} -extension XModem.Control: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/protobufs b/protobufs index 3e753697..97fa3451 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 3e753697aa1140d2c998cb63739729e733002874 +Subproject commit 97fa34517f80332a11046a73f26d55100fbee9e2 From 7b3553bbf168acc556a8c6c3ca25a2f06d96c953 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 10:52:59 -0700 Subject: [PATCH 36/75] Add new error --- Meshtastic/Enums/RoutingError.swift | 6 +++++- protobufs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 0773265b..50de17a5 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -21,6 +21,7 @@ enum RoutingError: Int, CaseIterable, Identifiable { case dutyCycleLimit = 9 case badRequest = 32 case notAuthorized = 33 + case pkiFailed = 34 var id: Int { self.rawValue } var display: String { @@ -50,6 +51,8 @@ enum RoutingError: Int, CaseIterable, Identifiable { return "routing.badRequest".localized case .notAuthorized: return "routing.notauthorized".localized + case .pkiFailed: + return "routing.pkiFailed".localized } } func protoEnumValue() -> Routing.Error { @@ -80,7 +83,8 @@ enum RoutingError: Int, CaseIterable, Identifiable { return Routing.Error.badRequest case .notAuthorized: return Routing.Error.notAuthorized - + case .pkiFailed: + return Routing.Error.pkiFailed } } } diff --git a/protobufs b/protobufs index 97fa3451..3e753697 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 97fa34517f80332a11046a73f26d55100fbee9e2 +Subproject commit 3e753697aa1140d2c998cb63739729e733002874 From 7a4ae7957da013611643730e26dfb1394aff6952 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 11:08:22 -0700 Subject: [PATCH 37/75] translation value for ack error --- Localizable.xcstrings | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 6160d6ae..8f9fe742 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -18440,6 +18440,17 @@ } } }, + "routing.pkifailed" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "PKI Failed" + } + } + } + }, "routing.timeout" : { "extractionState" : "migrated", "localizations" : { From 59a104d9e97b8f780fa20dc55c237d0075ec5b15 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 14:11:08 -0700 Subject: [PATCH 38/75] ack! --- Localizable.xcstrings | 22 +++++++---- Meshtastic/Enums/RoutingError.swift | 39 +++++++++++++++++++ Meshtastic/Resources/DeviceHardware.json | 2 +- Meshtastic/Tips/MessagesTips.swift | 2 +- .../Views/Messages/ChannelMessageList.swift | 8 ++-- Meshtastic/Views/Messages/UserList.swift | 2 +- .../Views/Messages/UserMessageList.swift | 6 ++- 7 files changed, 64 insertions(+), 17 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 8f9fe742..1656a3f4 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -334,9 +334,6 @@ }, "Ack Time: %@" : { - }, - "Acknowledged" : { - }, "Acknowledged by another node" : { @@ -6700,9 +6697,6 @@ }, "Drag & Drop is the recommended way to update firmware for NRF devices. If your iPhone or iPad is USB-C it will work with your regular USB-C charging cable, for lightning devices you need the Apple Lightning to USB camera adaptor." : { - }, - "Each node is an available contact. Contacts with recent messages or marked as favorites show up at the top of the list. Select a contact to send or view messages. Long press to favorite or mute the contact or delete the conversation." : { - }, "echo" : { "localizations" : { @@ -7209,6 +7203,9 @@ }, "Favorites" : { + }, + "Favorites and nodes with recent messages show up at the top of the list. Contacts using the shared key display an open lock, nodes with a private key show a green lock and a red key with a slash will show up if a key has changed for a contact. Long press to favorite or mute the contact or delete a conversation." : { + }, "Fifteen Minutes" : { @@ -18446,7 +18443,18 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "PKI Failed" + "value" : "Encrypted Send Failed" + } + } + } + }, + "routing.pkiunknownpubkey" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unknown Public Key" } } } diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 50de17a5..6dc83692 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -5,6 +5,7 @@ // Copyright(c) Garth Vander Houwen 8/4/22. // import Foundation +import SwiftUI import MeshtasticProtobufs enum RoutingError: Int, CaseIterable, Identifiable { @@ -22,6 +23,7 @@ enum RoutingError: Int, CaseIterable, Identifiable { case badRequest = 32 case notAuthorized = 33 case pkiFailed = 34 + case pkiUnknownPubkey = 35 var id: Int { self.rawValue } var display: String { @@ -53,6 +55,41 @@ enum RoutingError: Int, CaseIterable, Identifiable { return "routing.notauthorized".localized case .pkiFailed: return "routing.pkiFailed".localized + case .pkiUnknownPubkey: + return "routing.pkiunknownpubkey".localized + } + } + var color: Color { + switch self { + + case .none: + return Color.secondary + case .noRoute: + return Color.red + case .gotNak: + return Color.red + case .timeout: + return Color.orange + case .noInterface: + return Color.red + case .maxRetransmit: + return Color.red + case .noChannel: + return Color.orange + case .tooLarge: + return Color.red + case .noResponse: + return Color.orange + case .dutyCycleLimit: + return Color.orange + case .badRequest: + return Color.red + case .notAuthorized: + return Color.red + case .pkiFailed: + return Color.red + case .pkiUnknownPubkey: + return Color.red } } func protoEnumValue() -> Routing.Error { @@ -85,6 +122,8 @@ enum RoutingError: Int, CaseIterable, Identifiable { return Routing.Error.notAuthorized case .pkiFailed: return Routing.Error.pkiFailed + case .pkiUnknownPubkey: + return Routing.Error.pkiFailed } } } diff --git a/Meshtastic/Resources/DeviceHardware.json b/Meshtastic/Resources/DeviceHardware.json index 09eb2e6c..cbad8df9 100644 --- a/Meshtastic/Resources/DeviceHardware.json +++ b/Meshtastic/Resources/DeviceHardware.json @@ -370,7 +370,7 @@ { "hwModel": 66, "hwModelSlug": "HELTEC_VISION_MASTER_T190", - "platformioTarget": "heltec-vision-master-T190", + "platformioTarget": "heltec-vision-master-t190", "architecture": "esp32-s3", "activelySupported": true, "displayName": "Heltec Vision Master T190" diff --git a/Meshtastic/Tips/MessagesTips.swift b/Meshtastic/Tips/MessagesTips.swift index d78daa0e..5bd50d54 100644 --- a/Meshtastic/Tips/MessagesTips.swift +++ b/Meshtastic/Tips/MessagesTips.swift @@ -38,7 +38,7 @@ struct ContactsTip: Tip { } var message: Text? { // Text("tip.messages.contacts.message") - Text("Each node is an available contact. Contacts with recent messages or marked as favorites show up at the top of the list. Select a contact to send or view messages. Long press to favorite or mute the contact or delete the conversation.") + Text("Favorites and nodes with recent messages show up at the top of the list. Contacts using the shared key display an open lock, nodes with a private key show a green lock and a red key with a slash will show up if a key has changed for a contact. Long press to favorite or mute the contact or delete a conversation.") } var image: Image? { Image(systemName: "person.circle") diff --git a/Meshtastic/Views/Messages/ChannelMessageList.swift b/Meshtastic/Views/Messages/ChannelMessageList.swift index b996e790..95b727f0 100644 --- a/Meshtastic/Views/Messages/ChannelMessageList.swift +++ b/Meshtastic/Views/Messages/ChannelMessageList.swift @@ -84,16 +84,14 @@ struct ChannelMessageList: View { } HStack { - if currentUser && message.receivedACK { - // Ack Received - Text("Acknowledged").font(.caption2).foregroundColor(.gray) - } else if currentUser && message.ackError == 0 { + if currentUser && message.ackError == 0 { // Empty Error Text("Waiting to be acknowledged. . .").font(.caption2).foregroundColor(.orange) } else if currentUser && message.ackError > 0 { let ackErrorVal = RoutingError(rawValue: Int(message.ackError)) Text("\(ackErrorVal?.display ?? "Empty Ack Error")").fixedSize(horizontal: false, vertical: true) - .font(.caption2).foregroundColor(.red) + .foregroundStyle(ackErrorVal?.color ?? .red) + .font(.caption2) } else if isDetectionSensorMessage { let messageDate = message.timestamp Text(" \(messageDate.formattedDate(format: MessageText.dateFormatString))").font(.caption2).foregroundColor(.gray) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 4d7b2fd9..96dd398e 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -185,7 +185,7 @@ struct UserList: View { } } .listStyle(.plain) - .navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count - 1))) + .navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count))) .sheet(isPresented: $isEditingFilters) { NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) } diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 914fde3f..977c1686 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -78,7 +78,9 @@ struct UserMessageList: View { if currentUser && message.receivedACK { // Ack Received if message.realACK { - Text("\(ackErrorVal?.display ?? "Empty Ack Error")").font(.caption2).foregroundColor(.gray) + Text("\(ackErrorVal?.display ?? "Empty Ack Error")") + .font(.caption2) + .foregroundStyle(ackErrorVal?.color ?? Color.secondary) } else { Text("Acknowledged by another node").font(.caption2).foregroundColor(.orange) } @@ -87,7 +89,7 @@ struct UserMessageList: View { Text("Waiting to be acknowledged. . .").font(.caption2).foregroundColor(.yellow) } else if currentUser && message.ackError > 0 { Text("\(ackErrorVal?.display ?? "Empty Ack Error")").fixedSize(horizontal: false, vertical: true) - .font(.caption2).foregroundColor(.red) + .foregroundStyle(ackErrorVal?.color ?? Color.red) } } } From 761f73da7700d75dfb36f26ef4865927859fb282 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 14 Aug 2024 16:22:40 -0500 Subject: [PATCH 39/75] 2.5 update protos --- MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift | 8 ++++++++ protobufs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index c9482fc1..2aa80dc1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -1325,6 +1325,10 @@ public struct Routing: Sendable { /// /// The client specified a PKI transport, but the node was unable to send the packet using PKI (and did not send the message at all) case pkiFailed // = 34 + + /// + /// The receiving node does not have a Public Key to decode with + case pkiUnknownPubkey // = 35 case UNRECOGNIZED(Int) public init() { @@ -1346,6 +1350,7 @@ public struct Routing: Sendable { case 32: self = .badRequest case 33: self = .notAuthorized case 34: self = .pkiFailed + case 35: self = .pkiUnknownPubkey default: self = .UNRECOGNIZED(rawValue) } } @@ -1365,6 +1370,7 @@ public struct Routing: Sendable { case .badRequest: return 32 case .notAuthorized: return 33 case .pkiFailed: return 34 + case .pkiUnknownPubkey: return 35 case .UNRECOGNIZED(let i): return i } } @@ -1384,6 +1390,7 @@ public struct Routing: Sendable { .badRequest, .notAuthorized, .pkiFailed, + .pkiUnknownPubkey, ] } @@ -3450,6 +3457,7 @@ extension Routing.Error: SwiftProtobuf._ProtoNameProviding { 32: .same(proto: "BAD_REQUEST"), 33: .same(proto: "NOT_AUTHORIZED"), 34: .same(proto: "PKI_FAILED"), + 35: .same(proto: "PKI_UNKNOWN_PUBKEY"), ] } diff --git a/protobufs b/protobufs index 3e753697..8b5b2faf 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 3e753697aa1140d2c998cb63739729e733002874 +Subproject commit 8b5b2faf662b364754809f923271022f4f1492ed From b3301bac7a2f896bb0eb8b19f60f4fc67f1dc259 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 14:57:34 -0700 Subject: [PATCH 40/75] turn on key match warning on receipt of a pki failed error --- Meshtastic/Helpers/MeshPackets.swift | 3 +++ protobufs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 96db5fd2..44538947 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -628,6 +628,9 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana } } fetchedMessage[0].ackError = Int32(routingMessage.errorReason.rawValue) + if routingError == RoutingError.pkiFailed { + fetchedMessage[0].toUser?.keyMatch = false + } if routingMessage.errorReason == Routing.Error.none { diff --git a/protobufs b/protobufs index 8b5b2faf..3e753697 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8b5b2faf662b364754809f923271022f4f1492ed +Subproject commit 3e753697aa1140d2c998cb63739729e733002874 From c48f96b2b43bd101df45badcdfc75afbbd469873 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 15:00:20 -0700 Subject: [PATCH 41/75] Add unknown pubkey --- Meshtastic/Enums/RoutingError.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 6dc83692..4bdb8388 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -123,7 +123,7 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .pkiFailed: return Routing.Error.pkiFailed case .pkiUnknownPubkey: - return Routing.Error.pkiFailed + return Routing.Error.pkiUnknownPubkey } } } From c77da6b119bfb1e1f94e5806f14879700f8d5479 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 14 Aug 2024 19:02:43 -0500 Subject: [PATCH 42/75] Short turbo preset --- Meshtastic/Enums/LoraConfigEnums.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Meshtastic/Enums/LoraConfigEnums.swift b/Meshtastic/Enums/LoraConfigEnums.swift index 7da6268e..b0dd9966 100644 --- a/Meshtastic/Enums/LoraConfigEnums.swift +++ b/Meshtastic/Enums/LoraConfigEnums.swift @@ -210,6 +210,7 @@ enum ModemPresets: Int, CaseIterable, Identifiable { case medFast = 4 case shortSlow = 5 case shortFast = 6 + case shortTurbo = 8 var id: Int { self.rawValue } var description: String { @@ -230,6 +231,8 @@ enum ModemPresets: Int, CaseIterable, Identifiable { return "Short Range - Slow" case .shortFast: return "Short Range - Fast" + case .shortTurbo: + return "Short Range - Turbo" } } var name: String { @@ -250,6 +253,8 @@ enum ModemPresets: Int, CaseIterable, Identifiable { return "ShortSlow" case .shortFast: return "ShortFast" + case .shortTurbo: + return "ShortTurbo" } } func snrLimit() -> Float { @@ -270,6 +275,8 @@ enum ModemPresets: Int, CaseIterable, Identifiable { return -10 case .shortFast: return -7.5 + case .shortTurbo: + return -7.5 } } func protoEnumValue() -> Config.LoRaConfig.ModemPreset { @@ -290,6 +297,8 @@ enum ModemPresets: Int, CaseIterable, Identifiable { return Config.LoRaConfig.ModemPreset.shortSlow case .shortFast: return Config.LoRaConfig.ModemPreset.shortFast + case .shortTurbo: + return Config.LoRaConfig.ModemPreset.shortTurbo } } } From 8c3b4ada3781f7ad183ca94756801948d6989cda Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 17:04:48 -0700 Subject: [PATCH 43/75] Move the lock to the message corner --- Meshtastic/Views/Messages/MessageText.swift | 16 +++++++++++++++- Meshtastic/Views/Messages/UserMessageList.swift | 6 ------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Meshtastic/Views/Messages/MessageText.swift b/Meshtastic/Views/Messages/MessageText.swift index 0cdd4be8..57adc99c 100644 --- a/Meshtastic/Views/Messages/MessageText.swift +++ b/Meshtastic/Views/Messages/MessageText.swift @@ -24,11 +24,25 @@ struct MessageText: View { let markdownText = LocalizedStringKey(message.messagePayloadMarkdown ?? (message.messagePayload ?? "EMPTY MESSAGE")) return Text(markdownText) .tint(Self.linkBlue) - .padding(10) + .padding(.vertical, 10) + .padding(.horizontal, 8) .foregroundColor(.white) .background(isCurrentUser ? .accentColor : Color(.gray)) .cornerRadius(15) .overlay { + if message.pkiEncrypted { + VStack (alignment: .trailing) { + Spacer() + HStack { + Spacer() + Image(systemName: "lock.circle.fill") + .symbolRenderingMode(.palette) + .foregroundStyle(.white, .green) + .font(.system(size: 20)) + .offset(x: 8, y: 8) + } + } + } let isDetectionSensorMessage = message.portNum == Int32(PortNum.detectionSensorApp.rawValue) if tapBackDestination.overlaySensorMessage { VStack { diff --git a/Meshtastic/Views/Messages/UserMessageList.swift b/Meshtastic/Views/Messages/UserMessageList.swift index 977c1686..b0ec3a10 100644 --- a/Meshtastic/Views/Messages/UserMessageList.swift +++ b/Meshtastic/Views/Messages/UserMessageList.swift @@ -57,12 +57,6 @@ struct UserMessageList: View { self.replyMessageId = message.messageId self.messageFieldFocused = true } - if message.pkiEncrypted { - Image(systemName: "lock.circle.fill") - .foregroundStyle(.green) - .frame(height: 25) - .padding(.top, 5) - } if currentUser && message.canRetry || (message.receivedACK && !message.realACK) { RetryButton(message: message, destination: .user(user)) From 3b0d40668f8438ba3f72e743ca542cf3dd867c9a Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 17:09:05 -0700 Subject: [PATCH 44/75] Remove public key from context menu --- Meshtastic/Views/Messages/MessageContextMenuItems.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Meshtastic/Views/Messages/MessageContextMenuItems.swift b/Meshtastic/Views/Messages/MessageContextMenuItems.swift index 07792a9a..c9c37cdc 100644 --- a/Meshtastic/Views/Messages/MessageContextMenuItems.swift +++ b/Meshtastic/Views/Messages/MessageContextMenuItems.swift @@ -15,10 +15,6 @@ struct MessageContextMenuItems: View { VStack { if message.pkiEncrypted { Label("Encrypted", systemImage: "lock") - Text("Public Key") - Text(message.publicKey?.base64EncodedString() ?? "No Key") - .allowsTightening(true) - .monospaced() } Text("channel") + Text(": \(message.channel)") } From 0b5e72cd43fb930343dd173dbff46fcf7cd4fb76 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 20:52:47 -0700 Subject: [PATCH 45/75] Public key mismatch warning --- Localizable.xcstrings | 6 ++++++ Meshtastic/Helpers/MeshPackets.swift | 2 ++ .../contents | 1 + .../Views/Nodes/Helpers/NodeDetail.swift | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 1656a3f4..11662cbc 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -10784,6 +10784,9 @@ }, "Key" : { + }, + "Key does not match the public key that was used previously, delete the node and let it negotatiate keys again." : { + }, "Key Mapping" : { @@ -16659,6 +16662,9 @@ }, "Public Key" : { + }, + "Public Key Mismatch" : { + }, "PWD" : { diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 44538947..952899dd 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -630,6 +630,7 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana fetchedMessage[0].ackError = Int32(routingMessage.errorReason.rawValue) if routingError == RoutingError.pkiFailed { fetchedMessage[0].toUser?.keyMatch = false + fetchedMessage[0].toUser?.newPublicKey = fetchedMessage[0].publicKey } if routingMessage.errorReason == Routing.Error.none { @@ -854,6 +855,7 @@ func textMessageAppPacket( /// We have a key, check if it matches if newMessage.fromUser?.publicKey != newMessage.publicKey { newMessage.fromUser?.keyMatch = false + newMessage.fromUser?.newPublicKey = newMessage.publicKey } } else { /// We have no key, set it diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents index b92f33f6..ac5d631b 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 42.xcdatamodel/contents @@ -436,6 +436,7 @@ + diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index 68769280..0d9897c7 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -44,6 +44,24 @@ struct NodeDetail: View { NodeInfoItem(node: node) } Section("Node") { + if let user = node.user { + if user.keyMatch { + Label { + VStack(alignment: .leading) { + Text("Public Key Mismatch") + .font(.title3) + .foregroundStyle(.red) + Text("Key does not match the public key that was used previously, delete the node and let it negotatiate keys again.") + .font(.caption) + .foregroundStyle(.red) + } + } icon: { + Image(systemName: "key.slash.fill") + .symbolRenderingMode(.multicolor) + .foregroundStyle(.red) + } + } + } HStack { Label { Text("Node Number") From 197b567db0c7ece2a29eaa9233a28619645fd7fc Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 21:32:17 -0700 Subject: [PATCH 46/75] Clean up the filters --- Meshtastic/Views/Messages/UserList.swift | 20 ++++++++++---------- Meshtastic/Views/Nodes/NodeList.swift | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 96dd398e..d4bfdbf1 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -30,6 +30,15 @@ struct UserList: View { @State private var deviceRoles: Set = [] @State var isEditingFilters = false @State private var showingTrustConfirm: Bool = false + + var boolFilters: [Bool] {[ + isFavorite, + isOnline, + isPkiEncrypted, + isEnvironment, + distanceFilter, + roleFilter + ]} @FetchRequest( sortDescriptors: [NSSortDescriptor(key: "lastMessage", ascending: false), @@ -210,21 +219,12 @@ struct UserList: View { .onChange(of: hopsAway) { _ in searchUserList() } - .onChange(of: isOnline) { _ in - searchUserList() - } - .onChange(of: isPkiEncrypted) { _ in - searchUserList() - } - .onChange(of: isFavorite) { _ in + .onChange(of: [boolFilters]) { _ in searchUserList() } .onChange(of: maxDistance) { _ in searchUserList() } - .onChange(of: distanceFilter) { _ in - searchUserList() - } .onAppear { searchUserList() } diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index f85cad48..310abc9b 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -302,7 +302,7 @@ struct NodeList: View { await searchNodeList() } } - .onChange(of: boolFilters) { _ in + .onChange(of: [boolFilters]) { _ in Task { await searchNodeList() } From 5c8eea9ea8d72006e5d452d0f7ad45e101a9506b Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 14 Aug 2024 21:36:31 -0700 Subject: [PATCH 47/75] Key match warning search on first appear --- Meshtastic/Views/Messages/UserList.swift | 2 +- Meshtastic/Views/Nodes/Helpers/NodeDetail.swift | 2 +- Meshtastic/Views/Nodes/NodeList.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index d4bfdbf1..cdbf291a 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -225,7 +225,7 @@ struct UserList: View { .onChange(of: maxDistance) { _ in searchUserList() } - .onAppear { + .onFirstAppear { searchUserList() } .safeAreaInset(edge: .bottom, alignment: .trailing) { diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index 0d9897c7..e8eeeecd 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -45,7 +45,7 @@ struct NodeDetail: View { } Section("Node") { if let user = node.user { - if user.keyMatch { + if !user.keyMatch { Label { VStack(alignment: .leading) { Text("Public Key Mismatch") diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 310abc9b..5248b6bf 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -337,7 +337,7 @@ struct NodeList: View { self.selectedNode = nil } } - .onAppear { + .onFirstAppear { Task { await searchNodeList() } From fd38f96dc7494ff8643bb0d09c0d83fa4cf4d1fc Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 07:20:45 -0700 Subject: [PATCH 48/75] Bump version, set current timestamp for packets with a 0 timestamp --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- Meshtastic/Helpers/MeshPackets.swift | 6 +++++- Meshtastic/Views/Messages/MessageText.swift | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index c891cca9..2e083bd6 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1629,7 +1629,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1664,7 +1664,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1696,7 +1696,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1729,7 +1729,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 952899dd..42f3b2ca 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -826,7 +826,11 @@ func textMessageAppPacket( let fetchedUsers = try context.fetch(messageUsers) let newMessage = MessageEntity(context: context) newMessage.messageId = Int64(packet.id) - newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime) + if packet.rxTime == 0 { + newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970) + } else { + newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime) + } newMessage.receivedACK = false newMessage.snr = packet.rxSnr newMessage.rssi = packet.rxRssi diff --git a/Meshtastic/Views/Messages/MessageText.swift b/Meshtastic/Views/Messages/MessageText.swift index 57adc99c..93f8cf25 100644 --- a/Meshtastic/Views/Messages/MessageText.swift +++ b/Meshtastic/Views/Messages/MessageText.swift @@ -31,7 +31,7 @@ struct MessageText: View { .cornerRadius(15) .overlay { if message.pkiEncrypted { - VStack (alignment: .trailing) { + VStack(alignment: .trailing) { Spacer() HStack { Spacer() From 72b7cc3e3c332f336b1ad55a2fa1a313e4130924 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 08:15:11 -0700 Subject: [PATCH 49/75] Node list message user context menu item --- Localizable.xcstrings | 3 +++ Meshtastic/Views/Nodes/NodeList.swift | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 11662cbc..785091d8 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -14524,6 +14524,9 @@ } } } + }, + "Message" : { + }, "message.details" : { "localizations" : { diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 5248b6bf..e252aa95 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -88,8 +88,15 @@ struct NodeList: View { context: context, node: node ) - /// Don't show trace route, position exchange or delete context menu items for the connected node + /// Don't show message, trace route, position exchange or delete context menu items for the connected node if connectedNode.num != node.num { + Button(action: { + if let url = URL(string: "meshtastic:///messages?userNum=\(node.num)") { + UIApplication.shared.open(url) + } + }) { + Label("Message", systemImage: "message") + } Button { let traceRouteSent = bleManager.sendTraceRouteRequest( destNum: node.num, From 2415ef28af09dc543596cdcc6a19b1ac7df20476 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 13:43:31 -0700 Subject: [PATCH 50/75] Update some last heard dates if they aer 0 --- Meshtastic/Helpers/MeshPackets.swift | 18 +++++++++++++++--- Meshtastic/Persistence/UpdateCoreData.swift | 10 +++++++--- Meshtastic/Views/Messages/UserList.swift | 1 + .../Views/Nodes/Helpers/NodeListItem.swift | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 42f3b2ca..3a398ccf 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -638,7 +638,12 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana fetchedMessage[0].receivedACK = true } fetchedMessage[0].ackSNR = packet.rxSnr - fetchedMessage[0].ackTimestamp = Int32(truncatingIfNeeded: packet.rxTime) + + if packet.rxTime == 0 { + fetchedMessage[0].ackTimestamp = Int32(Date().timeIntervalSince1970) + } else { + fetchedMessage[0].ackTimestamp = Int32(truncatingIfNeeded: packet.rxTime) + } if fetchedMessage[0].toUser != nil { fetchedMessage[0].toUser!.objectWillChange.send() @@ -727,7 +732,12 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage return } mutableTelemetries.add(telemetry) - fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(truncatingIfNeeded: packet.rxTime))) + if packet.rxTime == 0 { + fetchedNode[0].lastHeard = Date() + } else { + fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(packet.rxTime)) + } + fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet } try context.save() @@ -866,7 +876,9 @@ func textMessageAppPacket( newMessage.fromUser?.publicKey = packet.publicKey newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted } - if packet.rxTime > 0 { + if packet.rxTime == 0 { + newMessage.fromUser?.userNode?.lastHeard = Date() + } else { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) } } diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index d52131b4..ba391495 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -148,6 +148,9 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) if packet.rxTime > 0 { newNode.firstHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + } else { + newNode.firstHeard = Date() + newNode.lastHeard = Date() } newNode.snr = packet.rxSnr newNode.rssi = packet.rxRssi @@ -233,9 +236,8 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) fetchedNode[0].num = Int64(packet.from) if packet.rxTime > 0 { fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) - if fetchedNode[0].firstHeard == nil { - fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) - } + } else { + fetchedNode[0].lastHeard = Date() } fetchedNode[0].snr = packet.rxSnr fetchedNode[0].rssi = packet.rxRssi @@ -363,6 +365,8 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(positionMessage.time))) } else if packet.rxTime > 0 { fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + } else { + fetchedNode[0].lastHeard = Date() } fetchedNode[0].snr = packet.rxSnr fetchedNode[0].rssi = packet.rxRssi diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index cdbf291a..5294c752 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -96,6 +96,7 @@ struct UserList: View { } Text(user.longName ?? "unknown".localized) .font(.headline) + .allowsTightening(true) Spacer() if user.userNode?.favorite ?? false { Image(systemName: "star.fill") diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index 10829f31..5d46806c 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -29,8 +29,8 @@ struct NodeListItem: View { VStack(alignment: .leading) { HStack { Text(node.user?.longName ?? "unknown".localized) - .fontWeight(.medium) .font(.headline) + .allowsTightening(true) if node.favorite { Spacer() Image(systemName: "star.fill") From 7e80accfad79cf6500d77b8cb7a8633b0cf7baa7 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 13:55:46 -0700 Subject: [PATCH 51/75] use > 0 for all empy rx times --- Meshtastic/Helpers/MeshPackets.swift | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 3a398ccf..87ada50b 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -638,11 +638,10 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana fetchedMessage[0].receivedACK = true } fetchedMessage[0].ackSNR = packet.rxSnr - - if packet.rxTime == 0 { - fetchedMessage[0].ackTimestamp = Int32(Date().timeIntervalSince1970) - } else { + if packet.rxTime > 0 { fetchedMessage[0].ackTimestamp = Int32(truncatingIfNeeded: packet.rxTime) + } else { + fetchedMessage[0].ackTimestamp = Int32(Date().timeIntervalSince1970) } if fetchedMessage[0].toUser != nil { @@ -732,12 +731,11 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage return } mutableTelemetries.add(telemetry) - if packet.rxTime == 0 { - fetchedNode[0].lastHeard = Date() - } else { + if packet.rxTime > 0 { fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(packet.rxTime)) + } else { + fetchedNode[0].lastHeard = Date() } - fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet } try context.save() @@ -836,10 +834,10 @@ func textMessageAppPacket( let fetchedUsers = try context.fetch(messageUsers) let newMessage = MessageEntity(context: context) newMessage.messageId = Int64(packet.id) - if packet.rxTime == 0 { - newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970) - } else { + if packet.rxTime > 0 { newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime) + } else { + newMessage.messageTimestamp = Int32(Date().timeIntervalSince1970) } newMessage.receivedACK = false newMessage.snr = packet.rxSnr @@ -876,10 +874,10 @@ func textMessageAppPacket( newMessage.fromUser?.publicKey = packet.publicKey newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted } - if packet.rxTime == 0 { - newMessage.fromUser?.userNode?.lastHeard = Date() - } else { + if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + } else { + newMessage.fromUser?.userNode?.lastHeard = Date() } } newMessage.messagePayload = messageText From ce3aacba6374e4ac83495f7c87fb50e8ac20909e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 16:31:58 -0700 Subject: [PATCH 52/75] Help! --- Localizable.xcstrings | 35 ++++++++- Meshtastic.xcodeproj/project.pbxproj | 20 +++++ Meshtastic/Enums/RoutingError.swift | 4 +- Meshtastic/Tips/MessagesTips.swift | 19 ----- Meshtastic/Views/Helpers/Help/AckErrors.swift | 44 +++++++++++ .../Helpers/Help/DirectMessagesHelp.swift | 75 +++++++++++++++++++ .../Views/Helpers/Help/LockLegend.swift | 61 +++++++++++++++ Meshtastic/Views/Messages/UserList.swift | 35 ++++++--- 8 files changed, 258 insertions(+), 35 deletions(-) create mode 100644 Meshtastic/Views/Helpers/Help/AckErrors.swift create mode 100644 Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift create mode 100644 Meshtastic/Views/Helpers/Help/LockLegend.swift diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 785091d8..798611fc 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -4810,9 +4810,6 @@ } } } - }, - "Contacts" : { - }, "contacts %@" : { "extractionState" : "migrated", @@ -6315,6 +6312,15 @@ }, "Direct" : { + }, + "Direct Message Help" : { + + }, + "Direct messages are using the new public key infrastructure to encrypt the message." : { + + }, + "Direct messages are using the shared key for the channel when communicating with this node." : { + }, "direct.messages" : { "localizations" : { @@ -7204,7 +7210,7 @@ "Favorites" : { }, - "Favorites and nodes with recent messages show up at the top of the list. Contacts using the shared key display an open lock, nodes with a private key show a green lock and a red key with a slash will show up if a key has changed for a contact. Long press to favorite or mute the contact or delete a conversation." : { + "Favorites and nodes with recent messages show up at the top of the contact list." : { }, "Fifteen Minutes" : { @@ -11272,6 +11278,9 @@ }, "Long Name: %@" : { + }, + "Long press to favorite or mute the contact or delete a conversation." : { + }, "Longitude" : { @@ -14527,6 +14536,9 @@ }, "Message" : { + }, + "Message Status Options" : { + }, "message.details" : { "localizations" : { @@ -15406,6 +15418,9 @@ } } } + }, + "Node Encryption Status" : { + }, "Node History" : { @@ -16665,6 +16680,9 @@ }, "Public Key" : { + }, + "Public Key Encryption" : { + }, "Public Key Mismatch" : { @@ -19763,6 +19781,9 @@ } } } + }, + "Shared Key" : { + }, "Short Name" : { @@ -20995,6 +21016,9 @@ }, "The public key authorized to send admin messages to this node." : { + }, + "The public key does not match the key that was used previously, delete the node and let it negotatiate keys again. Usually the other user did a factory reset, but it could indicate a security issue." : { + }, "The region where you will be using your radios." : { @@ -22519,6 +22543,9 @@ }, "Website" : { + }, + "What does the lock mean?" : { + }, "What is Meshtastic?" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 2e083bd6..2c59e43b 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -94,6 +94,9 @@ DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; }; DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65712C6AB8EC0053C113 /* SecureInput.swift */; }; DD6F65742C6CB80A0053C113 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65732C6CB80A0053C113 /* View.swift */; }; + DD6F65762C6EA5490053C113 /* AckErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65752C6EA5490053C113 /* AckErrors.swift */; }; + DD6F65792C6EADE60053C113 /* DirectMessagesHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65782C6EADE60053C113 /* DirectMessagesHelp.swift */; }; + DD6F657B2C6EC2900053C113 /* LockLegend.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F657A2C6EC2900053C113 /* LockLegend.swift */; }; DD73FD1128750779000852D6 /* PositionLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FD1028750779000852D6 /* PositionLog.swift */; }; DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */; }; DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */; }; @@ -349,6 +352,9 @@ DD68BAE72C417A74004C01A0 /* MeshtasticDataModelV 40.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 40.xcdatamodel"; sourceTree = ""; }; DD6F65712C6AB8EC0053C113 /* SecureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInput.swift; sourceTree = ""; }; DD6F65732C6CB80A0053C113 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; + DD6F65752C6EA5490053C113 /* AckErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AckErrors.swift; sourceTree = ""; }; + DD6F65782C6EADE60053C113 /* DirectMessagesHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectMessagesHelp.swift; sourceTree = ""; }; + DD6F657A2C6EC2900053C113 /* LockLegend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockLegend.swift; sourceTree = ""; }; DD73FD1028750779000852D6 /* PositionLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionLog.swift; sourceTree = ""; }; DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceMetricsLog.swift; sourceTree = ""; }; DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTips.swift; sourceTree = ""; }; @@ -710,6 +716,16 @@ path = Module; sourceTree = ""; }; + DD6F65772C6EAB860053C113 /* Help */ = { + isa = PBXGroup; + children = ( + DD6F65752C6EA5490053C113 /* AckErrors.swift */, + DD6F65782C6EADE60053C113 /* DirectMessagesHelp.swift */, + DD6F657A2C6EC2900053C113 /* LockLegend.swift */, + ); + path = Help; + sourceTree = ""; + }; DD7709392AA1ABA1007A8BF0 /* Tips */ = { isa = PBXGroup; children = ( @@ -902,6 +918,7 @@ DDC2E18D26CE25CB0042C5E4 /* Helpers */ = { isa = PBXGroup; children = ( + DD6F65772C6EAB860053C113 /* Help */, DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */, DD3CC24B2C498D6C001BD3A2 /* BatteryCompact.swift */, DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */, @@ -1300,6 +1317,7 @@ DD3CC6BE28E4CD9800FA9159 /* BatteryGauge.swift in Sources */, DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */, DD3619152B1EF9F900C41C8C /* LocationsHandler.swift in Sources */, + DD6F65792C6EADE60053C113 /* DirectMessagesHelp.swift in Sources */, 25F5D5C02C3F6DA6008036E3 /* Router.swift in Sources */, DDDB444A29F8AA3A00EE2349 /* CLLocationCoordinate2D.swift in Sources */, 25C49D902C471AEA0024FBD1 /* Constants.swift in Sources */, @@ -1358,6 +1376,7 @@ 251926852C3BA97800249DF5 /* FavoriteNodeButton.swift in Sources */, D9C983A02B79D0E800BDBE6A /* AlertButton.swift in Sources */, DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */, + DD6F65762C6EA5490053C113 /* AckErrors.swift in Sources */, DDDB445029F8AC9C00EE2349 /* UIImage.swift in Sources */, DD86D40F2881BE4C00BAEB7A /* CsvDocument.swift in Sources */, DDB75A142A0593E2006ED576 /* OfflineTileManager.swift in Sources */, @@ -1385,6 +1404,7 @@ DD15E4F52B8BFC8E00654F61 /* PaxCounterLog.swift in Sources */, 25F5D5C22C3F6E4B008036E3 /* AppState.swift in Sources */, DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */, + DD6F657B2C6EC2900053C113 /* LockLegend.swift in Sources */, DD97E96628EFD9820056DDA4 /* MeshtasticLogo.swift in Sources */, DDAB580D2B0DAA9E00147258 /* Routes.swift in Sources */, D93068D52B812B700066FBC8 /* MessageDestination.swift in Sources */, diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 4bdb8388..b47a15f9 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -54,7 +54,7 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .notAuthorized: return "routing.notauthorized".localized case .pkiFailed: - return "routing.pkiFailed".localized + return "routing.pkifailed".localized case .pkiUnknownPubkey: return "routing.pkiunknownpubkey".localized } @@ -77,7 +77,7 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .noChannel: return Color.orange case .tooLarge: - return Color.red + return Color.orange case .noResponse: return Color.orange case .dutyCycleLimit: diff --git a/Meshtastic/Tips/MessagesTips.swift b/Meshtastic/Tips/MessagesTips.swift index 5bd50d54..4771e386 100644 --- a/Meshtastic/Tips/MessagesTips.swift +++ b/Meshtastic/Tips/MessagesTips.swift @@ -25,22 +25,3 @@ struct MessagesTip: Tip { Image(systemName: "bubble.left.and.bubble.right") } } - -@available(iOS 17.0, macOS 14.0, *) -struct ContactsTip: Tip { - - var id: String { - return "tip.messages.contacts" - } - var title: Text { - // Text("tip.messages.contacts.title") - Text("Contacts") - } - var message: Text? { - // Text("tip.messages.contacts.message") - Text("Favorites and nodes with recent messages show up at the top of the list. Contacts using the shared key display an open lock, nodes with a private key show a green lock and a red key with a slash will show up if a key has changed for a contact. Long press to favorite or mute the contact or delete a conversation.") - } - var image: Image? { - Image(systemName: "person.circle") - } -} diff --git a/Meshtastic/Views/Helpers/Help/AckErrors.swift b/Meshtastic/Views/Helpers/Help/AckErrors.swift new file mode 100644 index 00000000..c20a58f9 --- /dev/null +++ b/Meshtastic/Views/Helpers/Help/AckErrors.swift @@ -0,0 +1,44 @@ +// +// IAQScale.swift +// Meshtastic +// +// Copyright Garth Vander Houwen 4/24/24. +// + +import SwiftUI + +struct AckErrors: View { + + var body: some View { + VStack(alignment: .leading) { + Text("Message Status Options") + .font(.title2) + HStack { + RoundedRectangle(cornerRadius: 5) + .fill(.orange) + .frame(width: 20, height: 12) + Text("Acknowledged by another node") + .font(.caption) + .foregroundStyle(.orange) + } + ForEach(RoutingError.allCases) { re in + HStack { + RoundedRectangle(cornerRadius: 5) + .fill(re.color) + .frame(width: 20, height: 12) + Text(re.display) + .font(.caption) + .foregroundStyle(re.color) + } + } + } + } +} + +struct AckErrorsPreviews: PreviewProvider { + static var previews: some View { + VStack { + AckErrors() + } + } +} diff --git a/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift new file mode 100644 index 00000000..dd57f29f --- /dev/null +++ b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift @@ -0,0 +1,75 @@ +// +// DirectMessagesHelp.swift +// Meshtastic +// +// Copyright Garth Vander Houwen on 8/15/24. +// + +import SwiftUI + +struct DirectMessagesHelp: View { + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + @Environment(\.dismiss) private var dismiss + + var body: some View { + ScrollView { + Text("Direct Message Help") + .font(.title) + .padding(.vertical) + VStack(alignment: .leading) { + HStack { + Image(systemName: "star.fill") + .foregroundColor(.yellow) + .padding(.bottom) + Text("Favorites and nodes with recent messages show up at the top of the contact list.") + .fixedSize(horizontal: false, vertical: true) + .padding(.bottom) + } + HStack { + Image(systemName: "hand.tap") + .padding(.bottom) + Text("Long press to favorite or mute the contact or delete a conversation.") + .fixedSize(horizontal: false, vertical: true) + .padding(.bottom) + } + } + if idiom == .phone { + VStack(alignment: .leading) { + LockLegend() + AckErrors() + } + } else { + HStack(alignment: .top) { + LockLegend() + AckErrors() + } + } +#if targetEnvironment(macCatalyst) + Spacer() + Button { + dismiss() + } label: { + Label("close", systemImage: "xmark") + } + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding(.bottom) +#endif + } + .frame(minHeight: 0, maxHeight: .infinity, alignment: .leading) + .padding() + .presentationDetents([.large]) + .presentationContentInteraction(.scrolls) + .presentationDragIndicator(.visible) + .presentationBackgroundInteraction(.enabled(upThrough: .large)) + } +} + +struct DirectMessagesHelpPreviews: PreviewProvider { + static var previews: some View { + VStack { + AckErrors() + } + } +} diff --git a/Meshtastic/Views/Helpers/Help/LockLegend.swift b/Meshtastic/Views/Helpers/Help/LockLegend.swift new file mode 100644 index 00000000..b47aaf20 --- /dev/null +++ b/Meshtastic/Views/Helpers/Help/LockLegend.swift @@ -0,0 +1,61 @@ +// +// LockLegend.swift +// Meshtastic +// +// Copyright Garth Vander Houwen 8/15/24. +// + +import SwiftUI + +struct LockLegend: View { + + var body: some View { + VStack(alignment: .leading) { + Text("Node Encryption Status") + .font(.title2) + Text("What does the lock mean?") + .padding(.bottom) + VStack(alignment: .leading) { + HStack { + Image(systemName: "lock.open.fill") + .foregroundColor(.yellow) + Text("Shared Key") + .fontWeight(.semibold) + } + Text("Direct messages are using the shared key for the channel when communicating with this node.") + .fixedSize(horizontal: false, vertical: true) + } + .padding(.bottom) + VStack(alignment: .leading) { + HStack { + Image(systemName: "lock.fill") + .foregroundColor(.green) + Text("Public Key Encryption") + .fontWeight(.semibold) + } + Text("Direct messages are using the new public key infrastructure to encrypt the message.") + .fixedSize(horizontal: false, vertical: true) + } + .padding(.bottom) + VStack(alignment: .leading) { + HStack { + Image(systemName: "key.slash") + .foregroundColor(.red) + Text("Public Key Mismatch") + .fontWeight(.semibold) + } + Text("The public key does not match the key that was used previously, delete the node and let it negotatiate keys again. Usually the other user did a factory reset, but it could indicate a security issue.") + .fixedSize(horizontal: false, vertical: true) + } + .padding(.bottom) + } + } +} + +struct LockLegendPreviews: PreviewProvider { + static var previews: some View { + VStack { + LockLegend() + } + } +} diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 5294c752..e3d07d3a 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -28,9 +28,10 @@ struct UserList: View { @State private var hopsAway: Double = -1.0 @State private var roleFilter = false @State private var deviceRoles: Set = [] - @State var isEditingFilters = false + @State private var editingFilters = false + @State private var showingHelp = false @State private var showingTrustConfirm: Bool = false - + var boolFilters: [Bool] {[ isFavorite, isOnline, @@ -59,9 +60,6 @@ struct UserList: View { let dateFormatString = (localeDateFormat ?? "MM/dd/YY") VStack { List(selection: $userSelection) { - if #available(iOS 17.0, macOS 14.0, *) { - TipView(ContactsTip(), arrowEdge: .bottom) - } ForEach(users) { (user: UserEntity) in let mostRecent = user.messageList.last let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64((mostRecent?.messageTimestamp ?? 0 )))) @@ -196,9 +194,12 @@ struct UserList: View { } .listStyle(.plain) .navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count))) - .sheet(isPresented: $isEditingFilters) { + .sheet(isPresented: $editingFilters) { NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) } + .sheet(isPresented: $showingHelp) { + DirectMessagesHelp() + } .onChange(of: searchText) { _ in searchUserList() } @@ -229,25 +230,39 @@ struct UserList: View { .onFirstAppear { searchUserList() } - .safeAreaInset(edge: .bottom, alignment: .trailing) { + .safeAreaInset(edge: .bottom, alignment: .leading) { HStack { Button(action: { withAnimation { - isEditingFilters = !isEditingFilters + showingHelp = !showingHelp } }) { - Image(systemName: !isEditingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill") + Image(systemName: !editingFilters ? "questionmark.circle" : "questionmark.circle.fill") + .padding(.vertical, 5) + } + .tint(Color(UIColor.secondarySystemBackground)) + .foregroundColor(.accentColor) + .buttonStyle(.borderedProminent) + + Spacer() + + Button(action: { + withAnimation { + editingFilters = !editingFilters + } + }) { + Image(systemName: !editingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill") .padding(.vertical, 5) } .tint(Color(UIColor.secondarySystemBackground)) .foregroundColor(.accentColor) .buttonStyle(.borderedProminent) - } .controlSize(.regular) .padding(5) } .padding(.bottom, 5) + .padding(.bottom, 5) .searchable(text: $searchText, placement: users.count > 10 ? .navigationBarDrawer(displayMode: .always) : .automatic, prompt: "Find a contact") .disableAutocorrection(true) .scrollDismissesKeyboard(.immediately) From 9345f4f1391c0596d17070c4edf675531bd36ca6 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 16:39:04 -0700 Subject: [PATCH 53/75] Set version back --- Meshtastic.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 2c59e43b..58f16fe5 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1649,7 +1649,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.0; + MARKETING_VERSION = 2.4.2; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1684,7 +1684,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.0; + MARKETING_VERSION = 2.4.2; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1716,7 +1716,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.0; + MARKETING_VERSION = 2.4.2; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1749,7 +1749,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.0; + MARKETING_VERSION = 2.4.2; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; From bbc6d4d40a9f5bdbf5cc67a47cfc50c512a151e2 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 15 Aug 2024 20:20:59 -0700 Subject: [PATCH 54/75] Updated help text. --- Localizable.xcstrings | 7 ++----- .../Views/Helpers/Help/DirectMessagesHelp.swift | 1 + Meshtastic/Views/Helpers/Help/LockLegend.swift | 15 ++++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 798611fc..514c0443 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -6319,7 +6319,7 @@ "Direct messages are using the new public key infrastructure to encrypt the message." : { }, - "Direct messages are using the shared key for the channel when communicating with this node." : { + "Direct messages are using the shared key for the channel." : { }, "direct.messages" : { @@ -15418,9 +15418,6 @@ } } } - }, - "Node Encryption Status" : { - }, "Node History" : { @@ -21017,7 +21014,7 @@ "The public key authorized to send admin messages to this node." : { }, - "The public key does not match the key that was used previously, delete the node and let it negotatiate keys again. Usually the other user did a factory reset, but it could indicate a security issue." : { + "The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action." : { }, "The region where you will be using your radios." : { diff --git a/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift index dd57f29f..f4f8bda3 100644 --- a/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift +++ b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift @@ -42,6 +42,7 @@ struct DirectMessagesHelp: View { HStack(alignment: .top) { LockLegend() AckErrors() + .padding(.trailing) } } #if targetEnvironment(macCatalyst) diff --git a/Meshtastic/Views/Helpers/Help/LockLegend.swift b/Meshtastic/Views/Helpers/Help/LockLegend.swift index b47aaf20..adfa91b5 100644 --- a/Meshtastic/Views/Helpers/Help/LockLegend.swift +++ b/Meshtastic/Views/Helpers/Help/LockLegend.swift @@ -11,10 +11,9 @@ struct LockLegend: View { var body: some View { VStack(alignment: .leading) { - Text("Node Encryption Status") - .font(.title2) Text("What does the lock mean?") - .padding(.bottom) + .font(.title2) + .padding(.bottom, 5) VStack(alignment: .leading) { HStack { Image(systemName: "lock.open.fill") @@ -22,7 +21,9 @@ struct LockLegend: View { Text("Shared Key") .fontWeight(.semibold) } - Text("Direct messages are using the shared key for the channel when communicating with this node.") + Text("Direct messages are using the shared key for the channel.") + .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) + .font(.callout) .fixedSize(horizontal: false, vertical: true) } .padding(.bottom) @@ -34,6 +35,8 @@ struct LockLegend: View { .fontWeight(.semibold) } Text("Direct messages are using the new public key infrastructure to encrypt the message.") + .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) + .font(.callout) .fixedSize(horizontal: false, vertical: true) } .padding(.bottom) @@ -44,7 +47,9 @@ struct LockLegend: View { Text("Public Key Mismatch") .fontWeight(.semibold) } - Text("The public key does not match the key that was used previously, delete the node and let it negotatiate keys again. Usually the other user did a factory reset, but it could indicate a security issue.") + Text("The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action.") + .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) + .font(.callout) .fixedSize(horizontal: false, vertical: true) } .padding(.bottom) From 0ac32df941a15f67af8e8a48aaf87ac5a90d84a1 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 16 Aug 2024 07:55:23 -0700 Subject: [PATCH 55/75] Bump versions --- Localizable.xcstrings | 5 +-- Meshtastic.xcodeproj/project.pbxproj | 8 ++-- Meshtastic/Enums/RoutingError.swift | 37 ++++++++++++++++++- .../Helpers/Help/DirectMessagesHelp.swift | 2 +- .../Views/Helpers/Help/LockLegend.swift | 2 +- .../Views/Nodes/Helpers/NodeDetail.swift | 2 +- Meshtastic/Views/Settings/Firmware.swift | 2 +- 7 files changed, 44 insertions(+), 14 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 514c0443..671a3838 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -6316,7 +6316,7 @@ "Direct Message Help" : { }, - "Direct messages are using the new public key infrastructure to encrypt the message." : { + "Direct messages are using the new public key infrastructure for encryption." : { }, "Direct messages are using the shared key for the channel." : { @@ -10790,9 +10790,6 @@ }, "Key" : { - }, - "Key does not match the public key that was used previously, delete the node and let it negotatiate keys again." : { - }, "Key Mapping" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 58f16fe5..2c59e43b 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1649,7 +1649,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1684,7 +1684,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1716,7 +1716,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1749,7 +1749,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.4.2; + MARKETING_VERSION = 2.5.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index b47a15f9..c7588b0c 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -73,11 +73,11 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .noInterface: return Color.red case .maxRetransmit: - return Color.red + return Color.orange case .noChannel: return Color.orange case .tooLarge: - return Color.orange + return Color.red case .noResponse: return Color.orange case .dutyCycleLimit: @@ -92,6 +92,39 @@ enum RoutingError: Int, CaseIterable, Identifiable { return Color.red } } + var canRetry: Bool { + switch self { + + case .none: + return false + case .noRoute: + return false + case .gotNak: + return false + case .timeout: + return true + case .noInterface: + return false + case .maxRetransmit: + return true + case .noChannel: + return true + case .tooLarge: + return false + case .noResponse: + return true + case .dutyCycleLimit: + return true + case .badRequest: + return false + case .notAuthorized: + return false + case .pkiFailed: + return false + case .pkiUnknownPubkey: + return false + } + } func protoEnumValue() -> Routing.Error { switch self { diff --git a/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift index f4f8bda3..fd0f0414 100644 --- a/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift +++ b/Meshtastic/Views/Helpers/Help/DirectMessagesHelp.swift @@ -13,7 +13,7 @@ struct DirectMessagesHelp: View { var body: some View { ScrollView { - Text("Direct Message Help") + Label("Direct Message Help", systemImage: "questionmark.circle") .font(.title) .padding(.vertical) VStack(alignment: .leading) { diff --git a/Meshtastic/Views/Helpers/Help/LockLegend.swift b/Meshtastic/Views/Helpers/Help/LockLegend.swift index adfa91b5..9c5d216b 100644 --- a/Meshtastic/Views/Helpers/Help/LockLegend.swift +++ b/Meshtastic/Views/Helpers/Help/LockLegend.swift @@ -34,7 +34,7 @@ struct LockLegend: View { Text("Public Key Encryption") .fontWeight(.semibold) } - Text("Direct messages are using the new public key infrastructure to encrypt the message.") + Text("Direct messages are using the new public key infrastructure for encryption.") .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) .font(.callout) .fixedSize(horizontal: false, vertical: true) diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index e8eeeecd..8a78c08c 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -51,7 +51,7 @@ struct NodeDetail: View { Text("Public Key Mismatch") .font(.title3) .foregroundStyle(.red) - Text("Key does not match the public key that was used previously, delete the node and let it negotatiate keys again.") + Text("The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action.") .font(.caption) .foregroundStyle(.red) } diff --git a/Meshtastic/Views/Settings/Firmware.swift b/Meshtastic/Views/Settings/Firmware.swift index d76b1503..9a450775 100644 --- a/Meshtastic/Views/Settings/Firmware.swift +++ b/Meshtastic/Views/Settings/Firmware.swift @@ -13,7 +13,7 @@ struct Firmware: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager var node: NodeInfoEntity? - @State var minimumVersion = "2.4.3" + @State var minimumVersion = "2.4.2" @State var version = "" @State private var currentDevice: DeviceHardware? @State private var latestStable: FirmwareRelease? From e7f6402e5166164ada11431d88f064debf2397cb Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 16 Aug 2024 09:38:09 -0700 Subject: [PATCH 56/75] Hook ack errors up to the canRetry bool --- Meshtastic/Extensions/CoreData/MessageEntityExtension.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Meshtastic/Extensions/CoreData/MessageEntityExtension.swift b/Meshtastic/Extensions/CoreData/MessageEntityExtension.swift index 18d97f6c..70f36c3d 100644 --- a/Meshtastic/Extensions/CoreData/MessageEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/MessageEntityExtension.swift @@ -19,7 +19,8 @@ extension MessageEntity { } var canRetry: Bool { - return ackError == 9 || ackError == 5 || ackError == 3 + let re = RoutingError(rawValue: Int(ackError)) + return re?.canRetry ?? false } var tapbacks: [MessageEntity] { From 81084976db7d845192edca0660cb32bc5c3c8ae1 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 16 Aug 2024 10:44:56 -0700 Subject: [PATCH 57/75] Hops away for position popower --- Localizable.xcstrings | 3 ++ .../Nodes/Helpers/Map/PositionPopover.swift | 34 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 671a3838..16d61fea 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -8281,6 +8281,9 @@ }, "Hops Away:" : { + }, + "Hops Away: %d" : { + }, "Hour" : { diff --git a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift index b3b9c18e..0c708058 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift @@ -14,6 +14,7 @@ struct PositionPopover: View { @ObservedObject var locationsHandler = LocationsHandler.shared @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @Environment(\.dismiss) private var dismiss var position: PositionEntity var popover: Bool = true @@ -52,9 +53,13 @@ struct PositionPopover: View { VStack(alignment: .leading) { /// Time Label { - Text("heard".localized + ":") + if idiom != .phone { + Text("heard".localized + ":") + } LastHeardText(lastHeard: position.time) .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) + .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) } icon: { Image(systemName: position.nodePosition?.isOnline ?? false ? "checkmark.circle.fill" : "moon.circle.fill") .symbolRenderingMode(.hierarchical) @@ -67,12 +72,28 @@ struct PositionPopover: View { Text("\(String(format: "%.6f", position.coordinate.latitude)), \(String(format: "%.6f", position.coordinate.longitude))") .textSelection(.enabled) .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) + .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) } icon: { Image(systemName: "mappin.and.ellipse") .symbolRenderingMode(.hierarchical) .frame(width: 35) } .padding(.bottom, 5) + /// Hops Away + if position.nodePosition?.hopsAway ?? 0 > 0 { + Label { + Text("Hops Away: \(position.nodePosition?.hopsAway ?? 0)") + .textSelection(.enabled) + .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) + } icon: { + Image(systemName: "hare") + .symbolRenderingMode(.hierarchical) + .frame(width: 35) + } + .padding(.bottom, 5) + } /// Altitude Label { let formatter = MeasurementFormatter() @@ -81,9 +102,11 @@ struct PositionPopover: View { if Locale.current.measurementSystem == .metric { Text(altitudeFormatter.string(from: distanceInMeters)) .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } else { Text(altitudeFormatter.string(from: distanceInFeet)) .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } } icon: { @@ -98,6 +121,7 @@ struct PositionPopover: View { Label { Text("Sats in view: \(String(position.satsInView))") .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } icon: { Image(systemName: "sparkles") .symbolRenderingMode(.hierarchical) @@ -110,6 +134,7 @@ struct PositionPopover: View { Label { Text("Sequence: \(String(position.seqNo))") .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } icon: { Image(systemName: "number") .symbolRenderingMode(.hierarchical) @@ -134,6 +159,7 @@ struct PositionPopover: View { Label { Text("Speed: \(speed.formatted(.measurement(width: .abbreviated, numberFormatStyle: .number.precision(.fractionLength(0)))))") .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } icon: { Image(systemName: "gauge.with.dots.needle.33percent") .symbolRenderingMode(.hierarchical) @@ -144,6 +170,7 @@ struct PositionPopover: View { Label { Text("MQTT") + .font(idiom == .phone ? .callout : .body) } icon: { Image(systemName: "network") .symbolRenderingMode(.hierarchical) @@ -159,6 +186,7 @@ struct PositionPopover: View { Label { Text("distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway)))") .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) } icon: { Image(systemName: "lines.measurement.horizontal") .symbolRenderingMode(.hierarchical) @@ -223,9 +251,9 @@ struct PositionPopover: View { #endif } } - .presentationDetents([.medium, .large]) + .presentationDetents([.fraction(0.65), .large]) .presentationContentInteraction(.scrolls) .presentationDragIndicator(.visible) - .presentationBackgroundInteraction(.enabled(upThrough: .medium)) + .presentationBackgroundInteraction(.enabled(upThrough: .large)) } } From 7d63a21418d6308200caeb798bf380bc6649a041 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 16 Aug 2024 16:26:54 -0700 Subject: [PATCH 58/75] Hook retry up to ack errors --- Meshtastic/Enums/RoutingError.swift | 45 +++++----------------- Meshtastic/Views/Messages/UserList.swift | 2 - Meshtastic/Views/Nodes/MeshMap.swift | 49 ++++++++++++++++++++++-- 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index c7588b0c..3af6e9b2 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -60,55 +60,30 @@ enum RoutingError: Int, CaseIterable, Identifiable { } } var color: Color { - switch self { - - case .none: + if self == .none { return Color.secondary - case .noRoute: - return Color.red - case .gotNak: - return Color.red - case .timeout: + } else if self.canRetry { return Color.orange - case .noInterface: - return Color.red - case .maxRetransmit: - return Color.orange - case .noChannel: - return Color.orange - case .tooLarge: - return Color.red - case .noResponse: - return Color.orange - case .dutyCycleLimit: - return Color.orange - case .badRequest: - return Color.red - case .notAuthorized: - return Color.red - case .pkiFailed: - return Color.red - case .pkiUnknownPubkey: + } else { return Color.red } } var canRetry: Bool { switch self { - case .none: return false case .noRoute: - return false + return true case .gotNak: - return false + return true case .timeout: return true case .noInterface: - return false + return true case .maxRetransmit: - return true + return false case .noChannel: - return true + return false case .tooLarge: return false case .noResponse: @@ -116,9 +91,9 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .dutyCycleLimit: return true case .badRequest: - return false + return true case .notAuthorized: - return false + return true case .pkiFailed: return false case .pkiUnknownPubkey: diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index e3d07d3a..cb3582ab 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -243,9 +243,7 @@ struct UserList: View { .tint(Color(UIColor.secondarySystemBackground)) .foregroundColor(.accentColor) .buttonStyle(.borderedProminent) - Spacer() - Button(action: { withAnimation { editingFilters = !editingFilters diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index 2dc8d105..31923562 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -33,13 +33,27 @@ struct MeshMap: View { @Namespace var mapScope @State var mapStyle: MapStyle = MapStyle.standard(elevation: .flat, emphasis: MapStyle.StandardEmphasis.muted, pointsOfInterest: .excludingAll, showsTraffic: false) @State var position = MapCameraPosition.automatic - @State var isEditingSettings = false + @State private var editingSettings = false + @State private var editingFilters = false @State var selectedPosition: PositionEntity? @State var editingWaypoint: WaypointEntity? @State var selectedWaypoint: WaypointEntity? @State var selectedWaypointId: String? @State var newWaypointCoord: CLLocationCoordinate2D? @State var isMeshMap = true + /// Filter + @State private var searchText = "" + @State private var viaLora = true + @State private var viaMqtt = true + @State private var isOnline = false + @State private var isPkiEncrypted = false + @State private var isFavorite = false + @State private var isEnvironment = false + @State private var distanceFilter = false + @State private var maxDistance: Double = 800000 + @State private var hopsAway: Double = -1.0 + @State private var roleFilter = false + @State private var deviceRoles: Set = [] var body: some View { @@ -106,7 +120,7 @@ struct MeshMap: View { WaypointForm(waypoint: selection, editMode: true) .padding() } - .sheet(isPresented: $isEditingSettings) { + .sheet(isPresented: $editingSettings) { MapSettingsForm(traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap) } .onChange(of: router.navigationState) { @@ -128,14 +142,41 @@ struct MeshMap: View { return } } + .sheet(isPresented: $editingFilters) { + NodeListFilter( + viaLora: $viaLora, + viaMqtt: $viaMqtt, + isOnline: $isOnline, + isPkiEncrypted: $isPkiEncrypted, + isFavorite: $isFavorite, + isEnvironment: $isEnvironment, + distanceFilter: $distanceFilter, + maximumDistance: $maxDistance, + hopsAway: $hopsAway, + roleFilter: $roleFilter, + deviceRoles: $deviceRoles + ) + } .safeAreaInset(edge: .bottom, alignment: .trailing) { HStack { Button(action: { withAnimation { - isEditingSettings = !isEditingSettings + editingSettings = !editingSettings } }) { - Image(systemName: isEditingSettings ? "info.circle.fill" : "info.circle") + Image(systemName: editingSettings ? "info.circle.fill" : "info.circle") + .padding(.vertical, 5) + } + .tint(Color(UIColor.secondarySystemBackground)) + .foregroundColor(.accentColor) + .buttonStyle(.borderedProminent) + Spacer() + Button(action: { + withAnimation { + editingFilters = !editingFilters + } + }) { + Image(systemName: !editingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill") .padding(.vertical, 5) } .tint(Color(UIColor.secondarySystemBackground)) From 385663478249d32ec6bef2bdaef6cb803abf41e2 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 16 Aug 2024 21:20:22 -0700 Subject: [PATCH 59/75] update protobufs --- .../Sources/meshtastic/admin.pb.swift | 311 +++++++++-- .../Sources/meshtastic/apponly.pb.swift | 6 +- .../Sources/meshtastic/atak.pb.swift | 64 ++- .../meshtastic/cannedmessages.pb.swift | 6 +- .../Sources/meshtastic/channel.pb.swift | 37 +- .../Sources/meshtastic/clientonly.pb.swift | 6 +- .../Sources/meshtastic/config.pb.swift | 445 +++++++++------- .../meshtastic/connection_status.pb.swift | 21 +- .../Sources/meshtastic/deviceonly.pb.swift | 38 +- .../Sources/meshtastic/localonly.pb.swift | 9 +- .../Sources/meshtastic/mesh.pb.swift | 501 ++++++++++++++---- .../Sources/meshtastic/module_config.pb.swift | 263 ++++++--- .../Sources/meshtastic/mqtt.pb.swift | 9 +- .../Sources/meshtastic/paxcount.pb.swift | 6 +- .../Sources/meshtastic/portnums.pb.swift | 14 +- .../Sources/meshtastic/powermon.pb.swift | 115 ++-- .../meshtastic/remote_hardware.pb.swift | 35 +- .../Sources/meshtastic/rtttl.pb.swift | 6 +- .../Sources/meshtastic/storeforward.pb.swift | 93 +++- .../Sources/meshtastic/telemetry.pb.swift | 217 +++++++- .../Sources/meshtastic/xmodem.pb.swift | 39 +- protobufs | 2 +- 22 files changed, 1666 insertions(+), 577 deletions(-) diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 4028fdcd..0f1c3586 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -24,11 +24,17 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /// This message is used to do settings operations to both remote AND local nodes. /// (Prior to 1.2 these operations were done via special ToRadio operations) -public struct AdminMessage: Sendable { +public struct AdminMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + /// + /// The node generates this key and sends it with any get_x_response packets. + /// The client MUST include the same key with any set_x commands. Key expires after 300 seconds. + /// Prevents replay attacks for admin messages. + public var sessionPasskey: Data = Data() + /// /// TODO: REPLACE public var payloadVariant: AdminMessage.OneOf_PayloadVariant? = nil @@ -369,6 +375,17 @@ public struct AdminMessage: Sendable { set {payloadVariant = .removeFixedPosition(newValue)} } + /// + /// Set time only on the node + /// Convenience method to set the time on the node (as Net quality) without any other position data + public var setTimeOnly: UInt32 { + get { + if case .setTimeOnly(let v)? = payloadVariant {return v} + return 0 + } + set {payloadVariant = .setTimeOnly(newValue)} + } + /// /// Begins an edit transaction for config, module config, owner, and channel settings changes /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) @@ -466,7 +483,7 @@ public struct AdminMessage: Sendable { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Send the specified channel in the response to this message /// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) @@ -573,6 +590,10 @@ public struct AdminMessage: Sendable { /// Clear fixed position coordinates and then set position.fixed_position = false case removeFixedPosition(Bool) /// + /// Set time only on the node + /// Convenience method to set the time on the node (as Net quality) without any other position data + case setTimeOnly(UInt32) + /// /// Begins an edit transaction for config, module config, owner, and channel settings changes /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) case beginEditSettings(Bool) @@ -603,11 +624,193 @@ public struct AdminMessage: Sendable { /// Tell the node to reset the nodedb. case nodedbReset(Int32) + #if !swift(>=4.1) + public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.getChannelRequest, .getChannelRequest): return { + guard case .getChannelRequest(let l) = lhs, case .getChannelRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getChannelResponse, .getChannelResponse): return { + guard case .getChannelResponse(let l) = lhs, case .getChannelResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getOwnerRequest, .getOwnerRequest): return { + guard case .getOwnerRequest(let l) = lhs, case .getOwnerRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getOwnerResponse, .getOwnerResponse): return { + guard case .getOwnerResponse(let l) = lhs, case .getOwnerResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getConfigRequest, .getConfigRequest): return { + guard case .getConfigRequest(let l) = lhs, case .getConfigRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getConfigResponse, .getConfigResponse): return { + guard case .getConfigResponse(let l) = lhs, case .getConfigResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getModuleConfigRequest, .getModuleConfigRequest): return { + guard case .getModuleConfigRequest(let l) = lhs, case .getModuleConfigRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getModuleConfigResponse, .getModuleConfigResponse): return { + guard case .getModuleConfigResponse(let l) = lhs, case .getModuleConfigResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getCannedMessageModuleMessagesRequest, .getCannedMessageModuleMessagesRequest): return { + guard case .getCannedMessageModuleMessagesRequest(let l) = lhs, case .getCannedMessageModuleMessagesRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getCannedMessageModuleMessagesResponse, .getCannedMessageModuleMessagesResponse): return { + guard case .getCannedMessageModuleMessagesResponse(let l) = lhs, case .getCannedMessageModuleMessagesResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceMetadataRequest, .getDeviceMetadataRequest): return { + guard case .getDeviceMetadataRequest(let l) = lhs, case .getDeviceMetadataRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceMetadataResponse, .getDeviceMetadataResponse): return { + guard case .getDeviceMetadataResponse(let l) = lhs, case .getDeviceMetadataResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getRingtoneRequest, .getRingtoneRequest): return { + guard case .getRingtoneRequest(let l) = lhs, case .getRingtoneRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getRingtoneResponse, .getRingtoneResponse): return { + guard case .getRingtoneResponse(let l) = lhs, case .getRingtoneResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceConnectionStatusRequest, .getDeviceConnectionStatusRequest): return { + guard case .getDeviceConnectionStatusRequest(let l) = lhs, case .getDeviceConnectionStatusRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getDeviceConnectionStatusResponse, .getDeviceConnectionStatusResponse): return { + guard case .getDeviceConnectionStatusResponse(let l) = lhs, case .getDeviceConnectionStatusResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setHamMode, .setHamMode): return { + guard case .setHamMode(let l) = lhs, case .setHamMode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getNodeRemoteHardwarePinsRequest, .getNodeRemoteHardwarePinsRequest): return { + guard case .getNodeRemoteHardwarePinsRequest(let l) = lhs, case .getNodeRemoteHardwarePinsRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.getNodeRemoteHardwarePinsResponse, .getNodeRemoteHardwarePinsResponse): return { + guard case .getNodeRemoteHardwarePinsResponse(let l) = lhs, case .getNodeRemoteHardwarePinsResponse(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.enterDfuModeRequest, .enterDfuModeRequest): return { + guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.deleteFileRequest, .deleteFileRequest): return { + guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setScale, .setScale): return { + guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setOwner, .setOwner): return { + guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setChannel, .setChannel): return { + guard case .setChannel(let l) = lhs, case .setChannel(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setConfig, .setConfig): return { + guard case .setConfig(let l) = lhs, case .setConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setModuleConfig, .setModuleConfig): return { + guard case .setModuleConfig(let l) = lhs, case .setModuleConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setCannedMessageModuleMessages, .setCannedMessageModuleMessages): return { + guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setRingtoneMessage, .setRingtoneMessage): return { + guard case .setRingtoneMessage(let l) = lhs, case .setRingtoneMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeByNodenum, .removeByNodenum): return { + guard case .removeByNodenum(let l) = lhs, case .removeByNodenum(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setFavoriteNode, .setFavoriteNode): return { + guard case .setFavoriteNode(let l) = lhs, case .setFavoriteNode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeFavoriteNode, .removeFavoriteNode): return { + guard case .removeFavoriteNode(let l) = lhs, case .removeFavoriteNode(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setFixedPosition, .setFixedPosition): return { + guard case .setFixedPosition(let l) = lhs, case .setFixedPosition(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.removeFixedPosition, .removeFixedPosition): return { + guard case .removeFixedPosition(let l) = lhs, case .removeFixedPosition(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.setTimeOnly, .setTimeOnly): return { + guard case .setTimeOnly(let l) = lhs, case .setTimeOnly(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.beginEditSettings, .beginEditSettings): return { + guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.commitEditSettings, .commitEditSettings): return { + guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.factoryResetDevice, .factoryResetDevice): return { + guard case .factoryResetDevice(let l) = lhs, case .factoryResetDevice(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebootOtaSeconds, .rebootOtaSeconds): return { + guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.exitSimulator, .exitSimulator): return { + guard case .exitSimulator(let l) = lhs, case .exitSimulator(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebootSeconds, .rebootSeconds): return { + guard case .rebootSeconds(let l) = lhs, case .rebootSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.shutdownSeconds, .shutdownSeconds): return { + guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.factoryResetConfig, .factoryResetConfig): return { + guard case .factoryResetConfig(let l) = lhs, case .factoryResetConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nodedbReset, .nodedbReset): return { + guard case .nodedbReset(let l) = lhs, case .nodedbReset(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// TODO: REPLACE - public enum ConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ConfigType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -675,23 +878,11 @@ public struct AdminMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ConfigType] = [ - .deviceConfig, - .positionConfig, - .powerConfig, - .networkConfig, - .displayConfig, - .loraConfig, - .bluetoothConfig, - .securityConfig, - ] - } /// /// TODO: REPLACE - public enum ModuleConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ModuleConfigType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -789,31 +980,51 @@ public struct AdminMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ModuleConfigType] = [ - .mqttConfig, - .serialConfig, - .extnotifConfig, - .storeforwardConfig, - .rangetestConfig, - .telemetryConfig, - .cannedmsgConfig, - .audioConfig, - .remotehardwareConfig, - .neighborinfoConfig, - .ambientlightingConfig, - .detectionsensorConfig, - .paxcounterConfig, - ] - } public init() {} } +#if swift(>=4.2) + +extension AdminMessage.ConfigType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ConfigType] = [ + .deviceConfig, + .positionConfig, + .powerConfig, + .networkConfig, + .displayConfig, + .loraConfig, + .bluetoothConfig, + .securityConfig, + ] +} + +extension AdminMessage.ModuleConfigType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ModuleConfigType] = [ + .mqttConfig, + .serialConfig, + .extnotifConfig, + .storeforwardConfig, + .rangetestConfig, + .telemetryConfig, + .cannedmsgConfig, + .audioConfig, + .remotehardwareConfig, + .neighborinfoConfig, + .ambientlightingConfig, + .detectionsensorConfig, + .paxcounterConfig, + ] +} + +#endif // swift(>=4.2) + /// /// Parameters for setting up Meshtastic for ameteur radio usage -public struct HamParameters: Sendable { +public struct HamParameters { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -843,7 +1054,7 @@ public struct HamParameters: Sendable { /// /// Response envelope for node_remote_hardware_pins -public struct NodeRemoteHardwarePinsResponse: Sendable { +public struct NodeRemoteHardwarePinsResponse { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -857,6 +1068,15 @@ public struct NodeRemoteHardwarePinsResponse: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension AdminMessage: @unchecked Sendable {} +extension AdminMessage.OneOf_PayloadVariant: @unchecked Sendable {} +extension AdminMessage.ConfigType: @unchecked Sendable {} +extension AdminMessage.ModuleConfigType: @unchecked Sendable {} +extension HamParameters: @unchecked Sendable {} +extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -864,6 +1084,7 @@ fileprivate let _protobuf_package = "meshtastic" extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".AdminMessage" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 101: .standard(proto: "session_passkey"), 1: .standard(proto: "get_channel_request"), 2: .standard(proto: "get_channel_response"), 3: .standard(proto: "get_owner_request"), @@ -897,6 +1118,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat 40: .standard(proto: "remove_favorite_node"), 41: .standard(proto: "set_fixed_position"), 42: .standard(proto: "remove_fixed_position"), + 43: .standard(proto: "set_time_only"), 64: .standard(proto: "begin_edit_settings"), 65: .standard(proto: "commit_edit_settings"), 94: .standard(proto: "factory_reset_device"), @@ -1243,6 +1465,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat self.payloadVariant = .removeFixedPosition(v) } }() + case 43: try { + var v: UInt32? + try decoder.decodeSingularFixed32Field(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .setTimeOnly(v) + } + }() case 64: try { var v: Bool? try decoder.decodeSingularBoolField(value: &v) @@ -1315,6 +1545,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat self.payloadVariant = .nodedbReset(v) } }() + case 101: try { try decoder.decodeSingularBytesField(value: &self.sessionPasskey) }() default: break } } @@ -1458,6 +1689,10 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat guard case .removeFixedPosition(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 42) }() + case .setTimeOnly?: try { + guard case .setTimeOnly(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularFixed32Field(value: v, fieldNumber: 43) + }() case .beginEditSettings?: try { guard case .beginEditSettings(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 64) @@ -1496,10 +1731,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat }() case nil: break } + if !self.sessionPasskey.isEmpty { + try visitor.visitSingularBytesField(value: self.sessionPasskey, fieldNumber: 101) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: AdminMessage, rhs: AdminMessage) -> Bool { + if lhs.sessionPasskey != rhs.sessionPasskey {return false} if lhs.payloadVariant != rhs.payloadVariant {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -1568,7 +1807,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 2) } - if self.frequency.bitPattern != 0 { + if self.frequency != 0 { try visitor.visitSingularFloatField(value: self.frequency, fieldNumber: 3) } if !self.shortName.isEmpty { diff --git a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift index 18e66d8e..0457077c 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift @@ -26,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// any SECONDARY channels. /// No DISABLED channels are included. /// This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL -public struct ChannelSet: Sendable { +public struct ChannelSet { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -53,6 +53,10 @@ public struct ChannelSet: Sendable { fileprivate var _loraConfig: Config.LoRaConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension ChannelSet: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift index 1dd12469..4406deb3 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum Team: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -130,6 +130,11 @@ public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension Team: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Team] = [ .unspecifedColor, @@ -148,12 +153,13 @@ public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { .darkGreen, .brown, ] - } +#endif // swift(>=4.2) + /// /// Role of the group member -public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum MemberRole: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -227,6 +233,11 @@ public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension MemberRole: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [MemberRole] = [ .unspecifed, @@ -239,12 +250,13 @@ public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { .rto, .k9, ] - } +#endif // swift(>=4.2) + /// /// Packets for the official ATAK Plugin -public struct TAKPacket: Sendable { +public struct TAKPacket { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -314,7 +326,7 @@ public struct TAKPacket: Sendable { /// /// The payload of the packet - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TAK position report case pli(PLI) @@ -322,6 +334,24 @@ public struct TAKPacket: Sendable { /// ATAK GeoChat message case chat(GeoChat) + #if !swift(>=4.1) + public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.pli, .pli): return { + guard case .pli(let l) = lhs, case .pli(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.chat, .chat): return { + guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -333,7 +363,7 @@ public struct TAKPacket: Sendable { /// /// ATAK GeoChat message -public struct GeoChat: Sendable { +public struct GeoChat { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -375,7 +405,7 @@ public struct GeoChat: Sendable { /// /// ATAK Group /// <__group role='Team Member' name='Cyan'/> -public struct Group: Sendable { +public struct Group { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -397,7 +427,7 @@ public struct Group: Sendable { /// /// ATAK EUD Status /// -public struct Status: Sendable { +public struct Status { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -414,7 +444,7 @@ public struct Status: Sendable { /// /// ATAK Contact /// -public struct Contact: Sendable { +public struct Contact { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -434,7 +464,7 @@ public struct Contact: Sendable { /// /// Position Location Information from ATAK -public struct PLI: Sendable { +public struct PLI { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -466,6 +496,18 @@ public struct PLI: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension Team: @unchecked Sendable {} +extension MemberRole: @unchecked Sendable {} +extension TAKPacket: @unchecked Sendable {} +extension TAKPacket.OneOf_PayloadVariant: @unchecked Sendable {} +extension GeoChat: @unchecked Sendable {} +extension Group: @unchecked Sendable {} +extension Status: @unchecked Sendable {} +extension Contact: @unchecked Sendable {} +extension PLI: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift index a43393e1..1b8c84de 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct CannedMessageModuleConfig: Sendable { +public struct CannedMessageModuleConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,6 +36,10 @@ public struct CannedMessageModuleConfig: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension CannedMessageModuleConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift index a8c96595..5b9c7e49 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift @@ -36,15 +36,13 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// FIXME: Add description of multi-channel support and how primary vs secondary channels are used. /// FIXME: explain how apps use channels for security. /// explain how remote settings and remote gpio are managed as an example -public struct ChannelSettings: @unchecked Sendable { +public struct ChannelSettings { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// Deprecated in favor of LoraConfig.channel_num - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var channelNum: UInt32 = 0 /// @@ -113,7 +111,7 @@ public struct ChannelSettings: @unchecked Sendable { /// /// This message is specifically for modules to store per-channel configuration data. -public struct ModuleSettings: Sendable { +public struct ModuleSettings { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -134,7 +132,7 @@ public struct ModuleSettings: Sendable { /// /// A pair of a channel number, mode and the (sharable) settings for that channel -public struct Channel: Sendable { +public struct Channel { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -172,7 +170,7 @@ public struct Channel: Sendable { /// cross band routing as needed. /// If a device has only a single radio (the common case) only one channel can be PRIMARY at a time /// (but any number of SECONDARY channels can't be sent received on that common frequency) - public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Role: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -211,13 +209,6 @@ public struct Channel: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Channel.Role] = [ - .disabled, - .primary, - .secondary, - ] - } public init() {} @@ -225,6 +216,26 @@ public struct Channel: Sendable { fileprivate var _settings: ChannelSettings? = nil } +#if swift(>=4.2) + +extension Channel.Role: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Channel.Role] = [ + .disabled, + .primary, + .secondary, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension ChannelSettings: @unchecked Sendable {} +extension ModuleSettings: @unchecked Sendable {} +extension Channel: @unchecked Sendable {} +extension Channel.Role: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift index 89370cc5..c3d93bf7 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift @@ -23,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This abstraction is used to contain any configuration for provisioning a node on any client. /// It is useful for importing and exporting configurations. -public struct DeviceProfile: Sendable { +public struct DeviceProfile { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -94,6 +94,10 @@ public struct DeviceProfile: Sendable { fileprivate var _moduleConfig: LocalModuleConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension DeviceProfile: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index ecfeeefa..4b953470 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct Config: Sendable { +public struct Config { // 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. @@ -97,7 +97,7 @@ public struct Config: Sendable { /// /// Payload Variant - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { case device(Config.DeviceConfig) case position(Config.PositionConfig) case power(Config.PowerConfig) @@ -107,11 +107,53 @@ public struct Config: Sendable { case bluetooth(Config.BluetoothConfig) case security(Config.SecurityConfig) + #if !swift(>=4.1) + public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.device, .device): return { + guard case .device(let l) = lhs, case .device(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.position, .position): return { + guard case .position(let l) = lhs, case .position(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.power, .power): return { + guard case .power(let l) = lhs, case .power(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.network, .network): return { + guard case .network(let l) = lhs, case .network(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.display, .display): return { + guard case .display(let l) = lhs, case .display(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.lora, .lora): return { + guard case .lora(let l) = lhs, case .lora(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.bluetooth, .bluetooth): return { + guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.security, .security): return { + guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// Configuration - public struct DeviceConfig: Sendable { + public struct DeviceConfig { // 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. @@ -123,16 +165,12 @@ public struct Config: Sendable { /// /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI /// Moved to SecurityConfig - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var serialEnabled: Bool = false /// /// By default we turn off logging as soon as an API client connects (to keep shared serial link quiet). /// Set this to true to leave the debug log outputting even when API is active. /// Moved to SecurityConfig - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var debugLogEnabled: Bool = false /// @@ -162,8 +200,6 @@ public struct Config: Sendable { /// If true, device is considered to be "managed" by a mesh administrator /// Clients should then limit available configuration and administrative options inside the user interface /// Moved to SecurityConfig - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var isManaged: Bool = false /// @@ -182,7 +218,7 @@ public struct Config: Sendable { /// /// Defines the device's role on the Mesh network - public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Role: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -200,8 +236,6 @@ public struct Config: Sendable { /// The wifi radio and the oled screen will be put to sleep. /// This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. case router // = 2 - - /// NOTE: This enum value was marked as deprecated in the .proto file case routerClient // = 3 /// @@ -292,26 +326,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.Role] = [ - .client, - .clientMute, - .router, - .routerClient, - .repeater, - .tracker, - .sensor, - .tak, - .clientHidden, - .lostAndFound, - .takTracker, - ] - } /// /// Defines the device's behavior for how messages are rebroadcast - public enum RebroadcastMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RebroadcastMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -359,14 +378,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ - .all, - .allSkipDecoding, - .localOnly, - .knownOnly, - ] - } public init() {} @@ -374,7 +385,7 @@ public struct Config: Sendable { /// /// Position Config - public struct PositionConfig: Sendable { + public struct PositionConfig { // 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. @@ -396,8 +407,6 @@ public struct Config: Sendable { /// /// Is GPS enabled for this node? - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var gpsEnabled: Bool = false /// @@ -408,8 +417,6 @@ public struct Config: Sendable { /// /// Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var gpsAttemptTime: UInt32 = 0 /// @@ -450,7 +457,7 @@ public struct Config: Sendable { /// are always included (also time if GPS-synced) /// NOTE: the more fields are included, the larger the message will be - /// leading to longer airtime and a higher risk of packet loss - public enum PositionFlags: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum PositionFlags: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -540,24 +547,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.PositionFlags] = [ - .unset, - .altitude, - .altitudeMsl, - .geoidalSeparation, - .dop, - .hvdop, - .satinview, - .seqNo, - .timestamp, - .heading, - .speed, - ] - } - public enum GpsMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum GpsMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -595,13 +587,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.GpsMode] = [ - .disabled, - .enabled, - .notPresent, - ] - } public init() {} @@ -610,7 +595,7 @@ public struct Config: Sendable { /// /// Power Config\ /// See [Power Config](/docs/settings/config/power) for additional power config details. - public struct PowerConfig: Sendable { + public struct PowerConfig { // 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. @@ -670,7 +655,7 @@ public struct Config: Sendable { /// /// Network Config - public struct NetworkConfig: Sendable { + public struct NetworkConfig { // 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. @@ -717,7 +702,7 @@ public struct Config: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum AddressMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum AddressMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -749,15 +734,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.NetworkConfig.AddressMode] = [ - .dhcp, - .static, - ] - } - public struct IpV4Config: Sendable { + public struct IpV4Config { // 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. @@ -790,7 +769,7 @@ public struct Config: Sendable { /// /// Display Config - public struct DisplayConfig: Sendable { + public struct DisplayConfig { // 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. @@ -846,7 +825,7 @@ public struct Config: Sendable { /// /// How the GPS coordinates are displayed on the OLED screen. - public enum GpsCoordinateFormat: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum GpsCoordinateFormat: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -909,21 +888,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ - .dec, - .dms, - .utm, - .mgrs, - .olc, - .osgr, - ] - } /// /// Unit display preference - public enum DisplayUnits: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum DisplayUnits: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -955,17 +924,11 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ - .metric, - .imperial, - ] - } /// /// Override OLED outo detect with this if it fails. - public enum OledType: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum OledType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1009,17 +972,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.OledType] = [ - .oledAuto, - .oledSsd1306, - .oledSh1106, - .oledSh1107, - ] - } - public enum DisplayMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum DisplayMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1063,17 +1018,9 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayMode] = [ - .default, - .twocolor, - .inverted, - .color, - ] - } - public enum CompassOrientation: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum CompassOrientation: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1141,18 +1088,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ - .degrees0, - .degrees90, - .degrees180, - .degrees270, - .degrees0Inverted, - .degrees90Inverted, - .degrees180Inverted, - .degrees270Inverted, - ] - } public init() {} @@ -1160,7 +1095,7 @@ public struct Config: Sendable { /// /// Lora Config - public struct LoRaConfig: @unchecked Sendable { + public struct LoRaConfig { // 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. @@ -1317,7 +1252,7 @@ public struct Config: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum RegionCode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RegionCode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1451,35 +1386,12 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - .lora24, - .ua433, - .ua868, - .my433, - .my919, - .sg923, - ] - } /// /// Standard predefined channel settings /// Note: these mappings must match ModemPreset Choice in the device code. - public enum ModemPreset: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum ModemPreset: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1493,8 +1405,6 @@ public struct Config: Sendable { /// /// Very Long Range - Slow /// Deprecated in 2.5: Works only with txco and is unusably slow - /// - /// NOTE: This enum value was marked as deprecated in the .proto file case veryLongSlow // = 2 /// @@ -1558,19 +1468,6 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.ModemPreset] = [ - .longFast, - .longSlow, - .veryLongSlow, - .mediumSlow, - .mediumFast, - .shortSlow, - .shortFast, - .longModerate, - .shortTurbo, - ] - } public init() {} @@ -1578,7 +1475,7 @@ public struct Config: Sendable { fileprivate var _storage = _StorageClass.defaultInstance } - public struct BluetoothConfig: Sendable { + public struct BluetoothConfig { // 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. @@ -1598,13 +1495,11 @@ public struct Config: Sendable { /// /// Enables device (serial style logs) over Bluetooth /// Moved to SecurityConfig - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var deviceLoggingEnabled: Bool = false public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum PairingMode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum PairingMode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1642,19 +1537,12 @@ public struct Config: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.BluetoothConfig.PairingMode] = [ - .randomPin, - .fixedPin, - .noPin, - ] - } public init() {} } - public struct SecurityConfig: @unchecked Sendable { + public struct SecurityConfig { // 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. @@ -1703,6 +1591,201 @@ public struct Config: Sendable { public init() {} } +#if swift(>=4.2) + +extension Config.DeviceConfig.Role: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.Role] = [ + .client, + .clientMute, + .router, + .routerClient, + .repeater, + .tracker, + .sensor, + .tak, + .clientHidden, + .lostAndFound, + .takTracker, + ] +} + +extension Config.DeviceConfig.RebroadcastMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ + .all, + .allSkipDecoding, + .localOnly, + .knownOnly, + ] +} + +extension Config.PositionConfig.PositionFlags: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.PositionFlags] = [ + .unset, + .altitude, + .altitudeMsl, + .geoidalSeparation, + .dop, + .hvdop, + .satinview, + .seqNo, + .timestamp, + .heading, + .speed, + ] +} + +extension Config.PositionConfig.GpsMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.GpsMode] = [ + .disabled, + .enabled, + .notPresent, + ] +} + +extension Config.NetworkConfig.AddressMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.NetworkConfig.AddressMode] = [ + .dhcp, + .static, + ] +} + +extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ + .dec, + .dms, + .utm, + .mgrs, + .olc, + .osgr, + ] +} + +extension Config.DisplayConfig.DisplayUnits: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ + .metric, + .imperial, + ] +} + +extension Config.DisplayConfig.OledType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.OledType] = [ + .oledAuto, + .oledSsd1306, + .oledSh1106, + .oledSh1107, + ] +} + +extension Config.DisplayConfig.DisplayMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayMode] = [ + .default, + .twocolor, + .inverted, + .color, + ] +} + +extension Config.DisplayConfig.CompassOrientation: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ + .degrees0, + .degrees90, + .degrees180, + .degrees270, + .degrees0Inverted, + .degrees90Inverted, + .degrees180Inverted, + .degrees270Inverted, + ] +} + +extension Config.LoRaConfig.RegionCode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.RegionCode] = [ + .unset, + .us, + .eu433, + .eu868, + .cn, + .jp, + .anz, + .kr, + .tw, + .ru, + .in, + .nz865, + .th, + .lora24, + .ua433, + .ua868, + .my433, + .my919, + .sg923, + ] +} + +extension Config.LoRaConfig.ModemPreset: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.ModemPreset] = [ + .longFast, + .longSlow, + .veryLongSlow, + .mediumSlow, + .mediumFast, + .shortSlow, + .shortFast, + .longModerate, + .shortTurbo, + ] +} + +extension Config.BluetoothConfig.PairingMode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.BluetoothConfig.PairingMode] = [ + .randomPin, + .fixedPin, + .noPin, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension Config: @unchecked Sendable {} +extension Config.OneOf_PayloadVariant: @unchecked Sendable {} +extension Config.DeviceConfig: @unchecked Sendable {} +extension Config.DeviceConfig.Role: @unchecked Sendable {} +extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {} +extension Config.PositionConfig: @unchecked Sendable {} +extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} +extension Config.PositionConfig.GpsMode: @unchecked Sendable {} +extension Config.PowerConfig: @unchecked Sendable {} +extension Config.NetworkConfig: @unchecked Sendable {} +extension Config.NetworkConfig.AddressMode: @unchecked Sendable {} +extension Config.NetworkConfig.IpV4Config: @unchecked Sendable {} +extension Config.DisplayConfig: @unchecked Sendable {} +extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} +extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} +extension Config.DisplayConfig.OledType: @unchecked Sendable {} +extension Config.DisplayConfig.DisplayMode: @unchecked Sendable {} +extension Config.DisplayConfig.CompassOrientation: @unchecked Sendable {} +extension Config.LoRaConfig: @unchecked Sendable {} +extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} +extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} +extension Config.BluetoothConfig: @unchecked Sendable {} +extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} +extension Config.SecurityConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -2177,7 +2260,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 2) } - if self.adcMultiplierOverride.bitPattern != 0 { + if self.adcMultiplierOverride != 0 { try visitor.visitSingularFloatField(value: self.adcMultiplierOverride, fieldNumber: 3) } if self.waitBluetoothSecs != 0 { @@ -2621,7 +2704,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._codingRate != 0 { try visitor.visitSingularUInt32Field(value: _storage._codingRate, fieldNumber: 5) } - if _storage._frequencyOffset.bitPattern != 0 { + if _storage._frequencyOffset != 0 { try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 6) } if _storage._region != .unset { @@ -2645,7 +2728,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._sx126XRxBoostedGain != false { try visitor.visitSingularBoolField(value: _storage._sx126XRxBoostedGain, fieldNumber: 13) } - if _storage._overrideFrequency.bitPattern != 0 { + if _storage._overrideFrequency != 0 { try visitor.visitSingularFloatField(value: _storage._overrideFrequency, fieldNumber: 14) } if _storage._paFanDisabled != false { diff --git a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift index a4569714..a2ec180e 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct DeviceConnectionStatus: Sendable { +public struct DeviceConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -81,7 +81,7 @@ public struct DeviceConnectionStatus: Sendable { /// /// WiFi connection status -public struct WifiConnectionStatus: Sendable { +public struct WifiConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -114,7 +114,7 @@ public struct WifiConnectionStatus: Sendable { /// /// Ethernet connection status -public struct EthernetConnectionStatus: Sendable { +public struct EthernetConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -139,7 +139,7 @@ public struct EthernetConnectionStatus: Sendable { /// /// Ethernet or WiFi connection status -public struct NetworkConnectionStatus: Sendable { +public struct NetworkConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -167,7 +167,7 @@ public struct NetworkConnectionStatus: Sendable { /// /// Bluetooth connection status -public struct BluetoothConnectionStatus: Sendable { +public struct BluetoothConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -191,7 +191,7 @@ public struct BluetoothConnectionStatus: Sendable { /// /// Serial connection status -public struct SerialConnectionStatus: Sendable { +public struct SerialConnectionStatus { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -209,6 +209,15 @@ public struct SerialConnectionStatus: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension DeviceConnectionStatus: @unchecked Sendable {} +extension WifiConnectionStatus: @unchecked Sendable {} +extension EthernetConnectionStatus: @unchecked Sendable {} +extension NetworkConnectionStatus: @unchecked Sendable {} +extension BluetoothConnectionStatus: @unchecked Sendable {} +extension SerialConnectionStatus: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift index 076e639e..43506399 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Font sizes for the device screen -public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum ScreenFonts: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -60,18 +60,24 @@ public enum ScreenFonts: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension ScreenFonts: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [ScreenFonts] = [ .fontSmall, .fontMedium, .fontLarge, ] - } +#endif // swift(>=4.2) + /// /// Position with static location information only for NodeDBLite -public struct PositionLite: Sendable { +public struct PositionLite { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -106,15 +112,13 @@ public struct PositionLite: Sendable { public init() {} } -public struct UserLite: @unchecked Sendable { +public struct UserLite { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// This is the addr of the radio. - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -153,7 +157,7 @@ public struct UserLite: @unchecked Sendable { public init() {} } -public struct NodeInfoLite: @unchecked Sendable { +public struct NodeInfoLite { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -256,7 +260,7 @@ public struct NodeInfoLite: @unchecked Sendable { /// FIXME, since we write this each time we enter deep sleep (and have infinite /// flash) it would be better to use some sort of append only data structure for /// the receive queue and use the preferences store for the other stuff -public struct DeviceState: @unchecked Sendable { +public struct DeviceState { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -316,8 +320,6 @@ public struct DeviceState: @unchecked Sendable { /// Used only during development. /// Indicates developer is testing and changes should never be saved to flash. /// Deprecated in 2.3.1 - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var noSave: Bool { get {return _storage._noSave} set {_uniqueStorage()._noSave = newValue} @@ -366,7 +368,7 @@ public struct DeviceState: @unchecked Sendable { /// /// The on-disk saved channels -public struct ChannelFile: Sendable { +public struct ChannelFile { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -389,7 +391,7 @@ public struct ChannelFile: Sendable { /// /// This can be used for customizing the firmware distribution. If populated, /// show a secondary bootup screen with custom logo and text for 2.5 seconds. -public struct OEMStore: @unchecked Sendable { +public struct OEMStore { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -448,6 +450,16 @@ public struct OEMStore: @unchecked Sendable { fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil } +#if swift(>=5.5) && canImport(_Concurrency) +extension ScreenFonts: @unchecked Sendable {} +extension PositionLite: @unchecked Sendable {} +extension UserLite: @unchecked Sendable {} +extension NodeInfoLite: @unchecked Sendable {} +extension DeviceState: @unchecked Sendable {} +extension ChannelFile: @unchecked Sendable {} +extension OEMStore: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -683,7 +695,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr.bitPattern != 0 { + if _storage._snr != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index f2ef681d..0af27466 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct LocalConfig: @unchecked Sendable { +public struct LocalConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -129,7 +129,7 @@ public struct LocalConfig: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } -public struct LocalModuleConfig: @unchecked Sendable { +public struct LocalModuleConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -293,6 +293,11 @@ public struct LocalModuleConfig: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=5.5) && canImport(_Concurrency) +extension LocalConfig: @unchecked Sendable {} +extension LocalModuleConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index 2aa80dc1..1f4c60a5 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -25,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// bin/build-all.sh script. /// Because they will be used to find firmware filenames in the android app for OTA updates. /// To match the old style filenames, _ is converted to -, p is converted to . -public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum HardwareModel: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -515,6 +515,11 @@ public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension HardwareModel: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [HardwareModel] = [ .unset, @@ -593,12 +598,13 @@ public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { .radiomaster900Bandit, .privateHw, ] - } +#endif // swift(>=4.2) + /// /// Shared constants between device and phone -public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum Constants: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -633,20 +639,26 @@ public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension Constants: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Constants] = [ .zero, .dataPayloadLen, ] - } +#endif // swift(>=4.2) + /// /// Error codes for critical errors /// The device might report these fault codes on the screen. /// If you encounter a fault code, please post on the meshtastic.discourse.group /// and we'll try to help. -public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum CriticalErrorCode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -755,6 +767,11 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension CriticalErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [CriticalErrorCode] = [ .none, @@ -772,12 +789,13 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { .flashCorruptionRecoverable, .flashCorruptionUnrecoverable, ] - } +#endif // swift(>=4.2) + /// /// a gps position -public struct Position: @unchecked Sendable { +public struct Position { // 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. @@ -994,7 +1012,7 @@ public struct Position: @unchecked Sendable { /// /// How the location was acquired: manual, onboard GPS, external (EUD) GPS - public enum LocSource: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum LocSource: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1038,20 +1056,12 @@ public struct Position: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.LocSource] = [ - .locUnset, - .locManual, - .locInternal, - .locExternal, - ] - } /// /// How the altitude was acquired: manual, GPS int/ext, etc /// Default: same as location_source if present - public enum AltSource: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum AltSource: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1101,15 +1111,6 @@ public struct Position: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.AltSource] = [ - .altUnset, - .altManual, - .altInternal, - .altExternal, - .altBarometric, - ] - } public init() {} @@ -1117,6 +1118,31 @@ public struct Position: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=4.2) + +extension Position.LocSource: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.LocSource] = [ + .locUnset, + .locManual, + .locInternal, + .locExternal, + ] +} + +extension Position.AltSource: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.AltSource] = [ + .altUnset, + .altManual, + .altInternal, + .altExternal, + .altBarometric, + ] +} + +#endif // swift(>=4.2) + /// /// Broadcast when a newly powered mesh node wants to find a node num it can use /// Sent from the phone over bluetooth to set the user id for the owner of this node. @@ -1138,7 +1164,7 @@ public struct Position: @unchecked Sendable { /// A few nodenums are reserved and will never be requested: /// 0xff - broadcast /// 0 through 3 - for future use -public struct User: @unchecked Sendable { +public struct User { // 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. @@ -1163,8 +1189,6 @@ public struct User: @unchecked Sendable { /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -1196,7 +1220,7 @@ public struct User: @unchecked Sendable { /// /// A message used in our Dynamic Source Routing protocol (RFC 4728 based) -public struct RouteDiscovery: Sendable { +public struct RouteDiscovery { // 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. @@ -1212,7 +1236,7 @@ public struct RouteDiscovery: Sendable { /// /// A Routing control Data packet handled by the routing module -public struct Routing: Sendable { +public struct Routing { // 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. @@ -1252,7 +1276,7 @@ public struct Routing: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable, Sendable { + public enum OneOf_Variant: Equatable { /// /// A route request going from the requester case routeRequest(RouteDiscovery) @@ -1264,12 +1288,34 @@ public struct Routing: Sendable { /// in addition to ack.fail_id to provide details on the type of failure). case errorReason(Routing.Error) + #if !swift(>=4.1) + public static func ==(lhs: Routing.OneOf_Variant, rhs: Routing.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.routeRequest, .routeRequest): return { + guard case .routeRequest(let l) = lhs, case .routeRequest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.routeReply, .routeReply): return { + guard case .routeReply(let l) = lhs, case .routeReply(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.errorReason, .errorReason): return { + guard case .errorReason(let l) = lhs, case .errorReason(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide /// details on the type of failure). - public enum Error: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Error: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1375,34 +1421,40 @@ public struct Routing: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Routing.Error] = [ - .none, - .noRoute, - .gotNak, - .timeout, - .noInterface, - .maxRetransmit, - .noChannel, - .tooLarge, - .noResponse, - .dutyCycleLimit, - .badRequest, - .notAuthorized, - .pkiFailed, - .pkiUnknownPubkey, - ] - } public init() {} } +#if swift(>=4.2) + +extension Routing.Error: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Routing.Error] = [ + .none, + .noRoute, + .gotNak, + .timeout, + .noInterface, + .maxRetransmit, + .noChannel, + .tooLarge, + .noResponse, + .dutyCycleLimit, + .badRequest, + .notAuthorized, + .pkiFailed, + .pkiUnknownPubkey, + ] +} + +#endif // swift(>=4.2) + /// /// (Formerly called SubPacket) /// The payload portion fo a packet, this is the actual bytes that are sent /// inside a radio packet (because from/to are broken out by the comms library) -public struct DataMessage: @unchecked Sendable { +public struct DataMessage { // 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. @@ -1456,7 +1508,7 @@ public struct DataMessage: @unchecked Sendable { /// /// Waypoint message, used to share arbitrary locations across the mesh -public struct Waypoint: Sendable { +public struct Waypoint { // 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. @@ -1518,7 +1570,7 @@ public struct Waypoint: Sendable { /// /// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server -public struct MqttClientProxyMessage: @unchecked Sendable { +public struct MqttClientProxyMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1559,7 +1611,7 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// /// The actual service envelope payload or text for mqtt pub / sub - public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Bytes case data(Data) @@ -1567,6 +1619,24 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// Text case text(String) + #if !swift(>=4.1) + public static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.data, .data): return { + guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.text, .text): return { + guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -1576,7 +1646,7 @@ public struct MqttClientProxyMessage: @unchecked Sendable { /// A packet envelope sent/received over the mesh /// only payload_variant is sent in the payload portion of the LORA packet. /// The other fields are either not sent at all, or sent in the special 16 byte LORA header. -public struct MeshPacket: @unchecked Sendable { +public struct MeshPacket { // 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. @@ -1710,8 +1780,6 @@ public struct MeshPacket: @unchecked Sendable { /// /// Describe if this message is delayed - /// - /// NOTE: This field was marked as deprecated in the .proto file. public var delayed: MeshPacket.Delayed { get {return _storage._delayed} set {_uniqueStorage()._delayed = newValue} @@ -1748,7 +1816,7 @@ public struct MeshPacket: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TODO: REPLACE case decoded(DataMessage) @@ -1756,6 +1824,24 @@ public struct MeshPacket: @unchecked Sendable { /// TODO: REPLACE case encrypted(Data) + #if !swift(>=4.1) + public static func ==(lhs: MeshPacket.OneOf_PayloadVariant, rhs: MeshPacket.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.decoded, .decoded): return { + guard case .decoded(let l) = lhs, case .decoded(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.encrypted, .encrypted): return { + guard case .encrypted(let l) = lhs, case .encrypted(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// @@ -1777,7 +1863,7 @@ public struct MeshPacket: @unchecked Sendable { /// So I bit the bullet and implemented a new (internal - not sent over the air) /// field in MeshPacket called 'priority'. /// And the transmission queue in the router object is now a priority queue. - public enum Priority: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Priority: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1842,22 +1928,11 @@ public struct MeshPacket: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Priority] = [ - .unset, - .min, - .background, - .default, - .reliable, - .ack, - .max, - ] - } /// /// Identify if this is a delayed packet - public enum Delayed: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Delayed: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1895,13 +1970,6 @@ public struct MeshPacket: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Delayed] = [ - .noDelay, - .broadcast, - .direct, - ] - } public init() {} @@ -1909,6 +1977,32 @@ public struct MeshPacket: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +#if swift(>=4.2) + +extension MeshPacket.Priority: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Priority] = [ + .unset, + .min, + .background, + .default, + .reliable, + .ack, + .max, + ] +} + +extension MeshPacket.Delayed: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Delayed] = [ + .noDelay, + .broadcast, + .direct, + ] +} + +#endif // swift(>=4.2) + /// /// The bluetooth to device link: /// Old BTLE protocol docs from TODO, merge in above and make real docs... @@ -1926,7 +2020,7 @@ public struct MeshPacket: @unchecked Sendable { /// level etc) SET_CONFIG (switches device to a new set of radio params and /// preshared key, drops all existing nodes, force our node to rejoin this new group) /// Full information about a node on the mesh -public struct NodeInfo: @unchecked Sendable { +public struct NodeInfo { // 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. @@ -2027,7 +2121,7 @@ public struct NodeInfo: @unchecked Sendable { /// Unique local debugging info for this node /// Note: we don't include position or the user info, because that will come in the /// Sent to the phone in response to WantNodes. -public struct MyNodeInfo: Sendable { +public struct MyNodeInfo { // 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. @@ -2058,7 +2152,7 @@ public struct MyNodeInfo: Sendable { /// on the message it is assumed to be a continuation of the previously sent message. /// This allows the device code to use fixed maxlen 64 byte strings for messages, /// and then extend as needed by emitting multiple records. -public struct LogRecord: Sendable { +public struct LogRecord { // 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. @@ -2083,7 +2177,7 @@ public struct LogRecord: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum Level: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Level: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -2145,23 +2239,29 @@ public struct LogRecord: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [LogRecord.Level] = [ - .unset, - .critical, - .error, - .warning, - .info, - .debug, - .trace, - ] - } public init() {} } -public struct QueueStatus: Sendable { +#if swift(>=4.2) + +extension LogRecord.Level: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [LogRecord.Level] = [ + .unset, + .critical, + .error, + .warning, + .info, + .debug, + .trace, + ] +} + +#endif // swift(>=4.2) + +public struct QueueStatus { // 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. @@ -2188,7 +2288,7 @@ public struct QueueStatus: Sendable { /// It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? /// It will sit in that descriptor until consumed by the phone, /// at which point the next item in the FIFO will be populated. -public struct FromRadio: Sendable { +public struct FromRadio { // 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. @@ -2364,7 +2464,7 @@ public struct FromRadio: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Log levels, chosen to match python logging conventions. case packet(MeshPacket) @@ -2419,6 +2519,76 @@ public struct FromRadio: Sendable { /// Notification message to the client case clientNotification(ClientNotification) + #if !swift(>=4.1) + public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.packet, .packet): return { + guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.myInfo, .myInfo): return { + guard case .myInfo(let l) = lhs, case .myInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.nodeInfo, .nodeInfo): return { + guard case .nodeInfo(let l) = lhs, case .nodeInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.config, .config): return { + guard case .config(let l) = lhs, case .config(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.logRecord, .logRecord): return { + guard case .logRecord(let l) = lhs, case .logRecord(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.configCompleteID, .configCompleteID): return { + guard case .configCompleteID(let l) = lhs, case .configCompleteID(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rebooted, .rebooted): return { + guard case .rebooted(let l) = lhs, case .rebooted(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.moduleConfig, .moduleConfig): return { + guard case .moduleConfig(let l) = lhs, case .moduleConfig(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.channel, .channel): return { + guard case .channel(let l) = lhs, case .channel(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.queueStatus, .queueStatus): return { + guard case .queueStatus(let l) = lhs, case .queueStatus(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.xmodemPacket, .xmodemPacket): return { + guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.metadata, .metadata): return { + guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { + guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.fileInfo, .fileInfo): return { + guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.clientNotification, .clientNotification): return { + guard case .clientNotification(let l) = lhs, case .clientNotification(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -2429,7 +2599,7 @@ public struct FromRadio: Sendable { /// To be used for important messages that should to be displayed to the user /// in the form of push notifications or validation messages when saving /// invalid configuration. -public struct ClientNotification: Sendable { +public struct ClientNotification { // 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. @@ -2466,7 +2636,7 @@ public struct ClientNotification: Sendable { /// /// Individual File info for the device -public struct FileInfo: Sendable { +public struct FileInfo { // 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. @@ -2487,7 +2657,7 @@ public struct FileInfo: Sendable { /// /// Packets/commands to the radio will be written (reliably) to the toRadio characteristic. /// Once the write completes the phone can assume it is handled. -public struct ToRadio: Sendable { +public struct ToRadio { // 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. @@ -2567,7 +2737,7 @@ public struct ToRadio: Sendable { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Send this packet on the mesh case packet(MeshPacket) @@ -2594,6 +2764,40 @@ public struct ToRadio: Sendable { /// Heartbeat message (used to keep the device connection awake on serial) case heartbeat(Heartbeat) + #if !swift(>=4.1) + public static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.packet, .packet): return { + guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.wantConfigID, .wantConfigID): return { + guard case .wantConfigID(let l) = lhs, case .wantConfigID(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.disconnect, .disconnect): return { + guard case .disconnect(let l) = lhs, case .disconnect(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.xmodemPacket, .xmodemPacket): return { + guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { + guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.heartbeat, .heartbeat): return { + guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -2601,7 +2805,7 @@ public struct ToRadio: Sendable { /// /// Compressed message payload -public struct Compressed: @unchecked Sendable { +public struct Compressed { // 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. @@ -2621,7 +2825,7 @@ public struct Compressed: @unchecked Sendable { /// /// Full info on edges for a single node -public struct NeighborInfo: Sendable { +public struct NeighborInfo { // 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. @@ -2649,7 +2853,7 @@ public struct NeighborInfo: Sendable { /// /// A single edge in the mesh -public struct Neighbor: Sendable { +public struct Neighbor { // 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. @@ -2679,7 +2883,7 @@ public struct Neighbor: Sendable { /// /// Device metadata response -public struct DeviceMetadata: Sendable { +public struct DeviceMetadata { // 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. @@ -2732,7 +2936,7 @@ public struct DeviceMetadata: Sendable { /// /// A heartbeat message is sent to the node from the client to keep the connection alive. /// This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. -public struct Heartbeat: Sendable { +public struct Heartbeat { // 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. @@ -2744,7 +2948,7 @@ public struct Heartbeat: Sendable { /// /// RemoteHardwarePins associated with a node -public struct NodeRemoteHardwarePin: Sendable { +public struct NodeRemoteHardwarePin { // 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. @@ -2771,7 +2975,7 @@ public struct NodeRemoteHardwarePin: Sendable { fileprivate var _pin: RemoteHardwarePin? = nil } -public struct ChunkedPayload: @unchecked Sendable { +public struct ChunkedPayload { // 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. @@ -2799,7 +3003,7 @@ public struct ChunkedPayload: @unchecked Sendable { /// /// Wrapper message for broken repeated oneof support -public struct resend_chunks: Sendable { +public struct resend_chunks { // 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. @@ -2813,7 +3017,7 @@ public struct resend_chunks: Sendable { /// /// Responses to a ChunkedPayload request -public struct ChunkedPayloadResponse: Sendable { +public struct ChunkedPayloadResponse { // 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. @@ -2856,7 +3060,7 @@ public struct ChunkedPayloadResponse: Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// Request to transfer chunked payload case requestTransfer(Bool) @@ -2867,11 +3071,76 @@ public struct ChunkedPayloadResponse: Sendable { /// Request missing indexes in the chunked payload case resendChunks(resend_chunks) + #if !swift(>=4.1) + public static func ==(lhs: ChunkedPayloadResponse.OneOf_PayloadVariant, rhs: ChunkedPayloadResponse.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.requestTransfer, .requestTransfer): return { + guard case .requestTransfer(let l) = lhs, case .requestTransfer(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.acceptTransfer, .acceptTransfer): return { + guard case .acceptTransfer(let l) = lhs, case .acceptTransfer(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.resendChunks, .resendChunks): return { + guard case .resendChunks(let l) = lhs, case .resendChunks(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension HardwareModel: @unchecked Sendable {} +extension Constants: @unchecked Sendable {} +extension CriticalErrorCode: @unchecked Sendable {} +extension Position: @unchecked Sendable {} +extension Position.LocSource: @unchecked Sendable {} +extension Position.AltSource: @unchecked Sendable {} +extension User: @unchecked Sendable {} +extension RouteDiscovery: @unchecked Sendable {} +extension Routing: @unchecked Sendable {} +extension Routing.OneOf_Variant: @unchecked Sendable {} +extension Routing.Error: @unchecked Sendable {} +extension DataMessage: @unchecked Sendable {} +extension Waypoint: @unchecked Sendable {} +extension MqttClientProxyMessage: @unchecked Sendable {} +extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {} +extension MeshPacket: @unchecked Sendable {} +extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} +extension MeshPacket.Priority: @unchecked Sendable {} +extension MeshPacket.Delayed: @unchecked Sendable {} +extension NodeInfo: @unchecked Sendable {} +extension MyNodeInfo: @unchecked Sendable {} +extension LogRecord: @unchecked Sendable {} +extension LogRecord.Level: @unchecked Sendable {} +extension QueueStatus: @unchecked Sendable {} +extension FromRadio: @unchecked Sendable {} +extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} +extension ClientNotification: @unchecked Sendable {} +extension FileInfo: @unchecked Sendable {} +extension ToRadio: @unchecked Sendable {} +extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} +extension Compressed: @unchecked Sendable {} +extension NeighborInfo: @unchecked Sendable {} +extension Neighbor: @unchecked Sendable {} +extension DeviceMetadata: @unchecked Sendable {} +extension Heartbeat: @unchecked Sendable {} +extension NodeRemoteHardwarePin: @unchecked Sendable {} +extension ChunkedPayload: @unchecked Sendable {} +extension resend_chunks: @unchecked Sendable {} +extension ChunkedPayloadResponse: @unchecked Sendable {} +extension ChunkedPayloadResponse.OneOf_PayloadVariant: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -3846,7 +4115,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._rxTime != 0 { try visitor.visitSingularFixed32Field(value: _storage._rxTime, fieldNumber: 7) } - if _storage._rxSnr.bitPattern != 0 { + if _storage._rxSnr != 0 { try visitor.visitSingularFloatField(value: _storage._rxSnr, fieldNumber: 8) } if _storage._hopLimit != 0 { @@ -4029,7 +4298,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr.bitPattern != 0 { + if _storage._snr != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -4874,7 +5143,7 @@ extension Neighbor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if self.nodeID != 0 { try visitor.visitSingularUInt32Field(value: self.nodeID, fieldNumber: 1) } - if self.snr.bitPattern != 0 { + if self.snr != 0 { try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 2) } if self.lastRxTime != 0 { @@ -4987,8 +5256,8 @@ extension Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let _ = try decoder.nextFieldNumber() { + } } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index 6f3b2d76..c68ffd83 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum RemoteHardwarePinType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -58,18 +58,24 @@ public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension RemoteHardwarePinType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [RemoteHardwarePinType] = [ .unknown, .digitalRead, .digitalWrite, ] - } +#endif // swift(>=4.2) + /// /// Module Config -public struct ModuleConfig: Sendable { +public struct ModuleConfig { // 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. @@ -212,7 +218,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable, Sendable { + public enum OneOf_PayloadVariant: Equatable { /// /// TODO: REPLACE case mqtt(ModuleConfig.MQTTConfig) @@ -253,11 +259,73 @@ public struct ModuleConfig: Sendable { /// TODO: REPLACE case paxcounter(ModuleConfig.PaxcounterConfig) + #if !swift(>=4.1) + public static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.mqtt, .mqtt): return { + guard case .mqtt(let l) = lhs, case .mqtt(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.serial, .serial): return { + guard case .serial(let l) = lhs, case .serial(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.externalNotification, .externalNotification): return { + guard case .externalNotification(let l) = lhs, case .externalNotification(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.storeForward, .storeForward): return { + guard case .storeForward(let l) = lhs, case .storeForward(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.rangeTest, .rangeTest): return { + guard case .rangeTest(let l) = lhs, case .rangeTest(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.telemetry, .telemetry): return { + guard case .telemetry(let l) = lhs, case .telemetry(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.cannedMessage, .cannedMessage): return { + guard case .cannedMessage(let l) = lhs, case .cannedMessage(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.audio, .audio): return { + guard case .audio(let l) = lhs, case .audio(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.remoteHardware, .remoteHardware): return { + guard case .remoteHardware(let l) = lhs, case .remoteHardware(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.neighborInfo, .neighborInfo): return { + guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.ambientLighting, .ambientLighting): return { + guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.detectionSensor, .detectionSensor): return { + guard case .detectionSensor(let l) = lhs, case .detectionSensor(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.paxcounter, .paxcounter): return { + guard case .paxcounter(let l) = lhs, case .paxcounter(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// MQTT Client Config - public struct MQTTConfig: Sendable { + public struct MQTTConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -332,7 +400,7 @@ public struct ModuleConfig: Sendable { /// /// Settings for reporting unencrypted information about our node to a map via MQTT - public struct MapReportSettings: Sendable { + public struct MapReportSettings { // 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. @@ -352,7 +420,7 @@ public struct ModuleConfig: Sendable { /// /// RemoteHardwareModule Config - public struct RemoteHardwareConfig: Sendable { + public struct RemoteHardwareConfig { // 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. @@ -376,7 +444,7 @@ public struct ModuleConfig: Sendable { /// /// NeighborInfoModule Config - public struct NeighborInfoConfig: Sendable { + public struct NeighborInfoConfig { // 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. @@ -397,7 +465,7 @@ public struct ModuleConfig: Sendable { /// /// Detection Sensor Module Config - public struct DetectionSensorConfig: Sendable { + public struct DetectionSensorConfig { // 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. @@ -448,7 +516,7 @@ public struct ModuleConfig: Sendable { /// /// Audio Config for codec2 voice - public struct AudioConfig: Sendable { + public struct AudioConfig { // 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. @@ -485,7 +553,7 @@ public struct ModuleConfig: Sendable { /// /// Baudrate for codec2 voice - public enum Audio_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Audio_Baud: SwiftProtobuf.Enum { public typealias RawValue = Int case codec2Default // = 0 case codec23200 // = 1 @@ -532,19 +600,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ - .codec2Default, - .codec23200, - .codec22400, - .codec21600, - .codec21400, - .codec21300, - .codec21200, - .codec2700, - .codec2700B, - ] - } public init() {} @@ -552,7 +607,7 @@ public struct ModuleConfig: Sendable { /// /// Config for the Paxcounter Module - public struct PaxcounterConfig: Sendable { + public struct PaxcounterConfig { // 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. @@ -578,7 +633,7 @@ public struct ModuleConfig: Sendable { /// /// Serial Config - public struct SerialConfig: Sendable { + public struct SerialConfig { // 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. @@ -621,7 +676,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum Serial_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Serial_Baud: SwiftProtobuf.Enum { public typealias RawValue = Int case baudDefault // = 0 case baud110 // = 1 @@ -689,31 +744,11 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ - .baudDefault, - .baud110, - .baud300, - .baud600, - .baud1200, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - ] - } /// /// TODO: REPLACE - public enum Serial_Mode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Serial_Mode: SwiftProtobuf.Enum { public typealias RawValue = Int case `default` // = 0 case simple // = 1 @@ -758,17 +793,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ - .default, - .simple, - .proto, - .textmsg, - .nmea, - .caltopo, - .ws85, - ] - } public init() {} @@ -776,7 +800,7 @@ public struct ModuleConfig: Sendable { /// /// External Notifications Config - public struct ExternalNotificationConfig: Sendable { + public struct ExternalNotificationConfig { // 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. @@ -859,7 +883,7 @@ public struct ModuleConfig: Sendable { /// /// Store and Forward Module Config - public struct StoreForwardConfig: Sendable { + public struct StoreForwardConfig { // 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. @@ -895,7 +919,7 @@ public struct ModuleConfig: Sendable { /// /// Preferences for the RangeTestModule - public struct RangeTestConfig: Sendable { + public struct RangeTestConfig { // 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. @@ -920,7 +944,7 @@ public struct ModuleConfig: Sendable { /// /// Configuration for both device and environment metrics - public struct TelemetryConfig: Sendable { + public struct TelemetryConfig { // 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. @@ -977,7 +1001,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public struct CannedMessageConfig: Sendable { + public struct CannedMessageConfig { // 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. @@ -1032,7 +1056,7 @@ public struct ModuleConfig: Sendable { /// /// TODO: REPLACE - public enum InputEventChar: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum InputEventChar: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -1100,18 +1124,6 @@ public struct ModuleConfig: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ - .none, - .up, - .down, - .left, - .right, - .select, - .back, - .cancel, - ] - } public init() {} @@ -1120,7 +1132,7 @@ public struct ModuleConfig: Sendable { /// ///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. ///Initially created for the RAK14001 RGB LED module. - public struct AmbientLightingConfig: Sendable { + public struct AmbientLightingConfig { // 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. @@ -1153,9 +1165,77 @@ public struct ModuleConfig: Sendable { public init() {} } +#if swift(>=4.2) + +extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ + .codec2Default, + .codec23200, + .codec22400, + .codec21600, + .codec21400, + .codec21300, + .codec21200, + .codec2700, + .codec2700B, + ] +} + +extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ + .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, + .baud2400, + .baud4800, + .baud9600, + .baud19200, + .baud38400, + .baud57600, + .baud115200, + .baud230400, + .baud460800, + .baud576000, + .baud921600, + ] +} + +extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ + .default, + .simple, + .proto, + .textmsg, + .nmea, + .caltopo, + .ws85, + ] +} + +extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ + .none, + .up, + .down, + .left, + .right, + .select, + .back, + .cancel, + ] +} + +#endif // swift(>=4.2) + /// /// A GPIO pin definition for remote hardware module -public struct RemoteHardwarePin: Sendable { +public struct RemoteHardwarePin { // 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. @@ -1177,6 +1257,31 @@ public struct RemoteHardwarePin: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension RemoteHardwarePinType: @unchecked Sendable {} +extension ModuleConfig: @unchecked Sendable {} +extension ModuleConfig.OneOf_PayloadVariant: @unchecked Sendable {} +extension ModuleConfig.MQTTConfig: @unchecked Sendable {} +extension ModuleConfig.MapReportSettings: @unchecked Sendable {} +extension ModuleConfig.RemoteHardwareConfig: @unchecked Sendable {} +extension ModuleConfig.NeighborInfoConfig: @unchecked Sendable {} +extension ModuleConfig.DetectionSensorConfig: @unchecked Sendable {} +extension ModuleConfig.AudioConfig: @unchecked Sendable {} +extension ModuleConfig.AudioConfig.Audio_Baud: @unchecked Sendable {} +extension ModuleConfig.PaxcounterConfig: @unchecked Sendable {} +extension ModuleConfig.SerialConfig: @unchecked Sendable {} +extension ModuleConfig.SerialConfig.Serial_Baud: @unchecked Sendable {} +extension ModuleConfig.SerialConfig.Serial_Mode: @unchecked Sendable {} +extension ModuleConfig.ExternalNotificationConfig: @unchecked Sendable {} +extension ModuleConfig.StoreForwardConfig: @unchecked Sendable {} +extension ModuleConfig.RangeTestConfig: @unchecked Sendable {} +extension ModuleConfig.TelemetryConfig: @unchecked Sendable {} +extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {} +extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {} +extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {} +extension RemoteHardwarePin: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift index fc5e37a1..efe6cdd5 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This message wraps a MeshPacket with extra metadata about the sender and how it arrived. -public struct ServiceEnvelope: Sendable { +public struct ServiceEnvelope { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -57,7 +57,7 @@ public struct ServiceEnvelope: Sendable { /// /// Information about a node intended to be reported unencrypted to a map using MQTT. -public struct MapReport: Sendable { +public struct MapReport { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -121,6 +121,11 @@ public struct MapReport: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension ServiceEnvelope: @unchecked Sendable {} +extension MapReport: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift index f82b3c51..cf8aa463 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct Paxcount: Sendable { +public struct Paxcount { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -44,6 +44,10 @@ public struct Paxcount: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension Paxcount: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index c5348a8a..c728c961 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -33,7 +33,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: This was formerly a Type enum named 'typ' with the same id # /// We have change to this 'portnum' based scheme for specifying app handlers for particular payloads. /// This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically. -public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum PortNum: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -277,6 +277,11 @@ public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension PortNum: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [PortNum] = [ .unknownApp, @@ -308,9 +313,14 @@ public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { .atakForwarder, .max, ] - } +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension PortNum: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. extension PortNum: SwiftProtobuf._ProtoNameProviding { diff --git a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift index 9c61e6d0..5f51e948 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). ///But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) -public struct PowerMon: Sendable { +public struct PowerMon { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -31,7 +31,7 @@ public struct PowerMon: Sendable { /// Any significant power changing event in meshtastic should be tagged with a powermon state transition. ///If you are making new meshtastic features feel free to add new entries at the end of this definition. - public enum State: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum State: SwiftProtobuf.Enum { public typealias RawValue = Int case none // = 0 case cpuDeepSleep // = 1 @@ -104,31 +104,37 @@ public struct PowerMon: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerMon.State] = [ - .none, - .cpuDeepSleep, - .cpuLightSleep, - .vext1On, - .loraRxon, - .loraTxon, - .loraRxactive, - .btOn, - .ledOn, - .screenOn, - .screenDrawing, - .wifiOn, - .gpsActive, - ] - } public init() {} } +#if swift(>=4.2) + +extension PowerMon.State: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerMon.State] = [ + .none, + .cpuDeepSleep, + .cpuLightSleep, + .vext1On, + .loraRxon, + .loraTxon, + .loraRxactive, + .btOn, + .ledOn, + .screenOn, + .screenDrawing, + .wifiOn, + .gpsActive, + ] +} + +#endif // swift(>=4.2) + /// /// PowerStress testing support via the C++ PowerStress module -public struct PowerStressMessage: Sendable { +public struct PowerStressMessage { // 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. @@ -145,7 +151,7 @@ public struct PowerStressMessage: Sendable { /// What operation would we like the UUT to perform. ///note: senders should probably set want_response in their request packets, so that they can know when the state ///machine has started processing their request - public enum Opcode: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Opcode: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -266,35 +272,48 @@ public struct PowerStressMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerStressMessage.Opcode] = [ - .unset, - .printInfo, - .forceQuiet, - .endQuiet, - .screenOn, - .screenOff, - .cpuIdle, - .cpuDeepsleep, - .cpuFullon, - .ledOn, - .ledOff, - .loraOff, - .loraTx, - .loraRx, - .btOff, - .btOn, - .wifiOff, - .wifiOn, - .gpsOff, - .gpsOn, - ] - } public init() {} } +#if swift(>=4.2) + +extension PowerStressMessage.Opcode: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerStressMessage.Opcode] = [ + .unset, + .printInfo, + .forceQuiet, + .endQuiet, + .screenOn, + .screenOff, + .cpuIdle, + .cpuDeepsleep, + .cpuFullon, + .ledOn, + .ledOff, + .loraOff, + .loraTx, + .loraRx, + .btOff, + .btOn, + .wifiOff, + .wifiOn, + .gpsOff, + .gpsOn, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension PowerMon: @unchecked Sendable {} +extension PowerMon.State: @unchecked Sendable {} +extension PowerStressMessage: @unchecked Sendable {} +extension PowerStressMessage.Opcode: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -304,8 +323,8 @@ extension PowerMon: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - // Load everything into unknown fields - while try decoder.nextFieldNumber() != nil {} + while let _ = try decoder.nextFieldNumber() { + } } public func traverse(visitor: inout V) throws { @@ -360,7 +379,7 @@ extension PowerStressMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.cmd != .unset { try visitor.visitSingularEnumField(value: self.cmd, fieldNumber: 1) } - if self.numSeconds.bitPattern != 0 { + if self.numSeconds != 0 { try visitor.visitSingularFloatField(value: self.numSeconds, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift index 60f64504..ac6eeb26 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift @@ -30,7 +30,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// because no security yet (beyond the channel mechanism). /// It should be off by default and then protected based on some TBD mechanism /// (a special channel once multichannel support is included?) -public struct HardwareMessage: Sendable { +public struct HardwareMessage { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -52,7 +52,7 @@ public struct HardwareMessage: Sendable { /// /// TODO: REPLACE - public enum TypeEnum: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum TypeEnum: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -110,21 +110,32 @@ public struct HardwareMessage: Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [HardwareMessage.TypeEnum] = [ - .unset, - .writeGpios, - .watchGpios, - .gpiosChanged, - .readGpios, - .readGpiosReply, - ] - } public init() {} } +#if swift(>=4.2) + +extension HardwareMessage.TypeEnum: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [HardwareMessage.TypeEnum] = [ + .unset, + .writeGpios, + .watchGpios, + .gpiosChanged, + .readGpios, + .readGpiosReply, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension HardwareMessage: @unchecked Sendable {} +extension HardwareMessage.TypeEnum: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift index c1f3f678..6fdf3208 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct RTTTLConfig: Sendable { +public struct RTTTLConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,6 +36,10 @@ public struct RTTTLConfig: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension RTTTLConfig: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift index 0b67eaf6..54efa77b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct StoreAndForward: @unchecked Sendable { +public struct StoreAndForward { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -79,7 +79,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public enum OneOf_Variant: Equatable, @unchecked Sendable { + public enum OneOf_Variant: Equatable { /// /// TODO: REPLACE case stats(StoreAndForward.Statistics) @@ -93,12 +93,38 @@ public struct StoreAndForward: @unchecked Sendable { /// Text from history message. case text(Data) + #if !swift(>=4.1) + public static func ==(lhs: StoreAndForward.OneOf_Variant, rhs: StoreAndForward.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.stats, .stats): return { + guard case .stats(let l) = lhs, case .stats(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.history, .history): return { + guard case .history(let l) = lhs, case .history(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.heartbeat, .heartbeat): return { + guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.text, .text): return { + guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } /// /// 001 - 063 = From Router /// 064 - 127 = From Client - public enum RequestResponse: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum RequestResponse: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -216,31 +242,11 @@ public struct StoreAndForward: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [StoreAndForward.RequestResponse] = [ - .unset, - .routerError, - .routerHeartbeat, - .routerPing, - .routerPong, - .routerBusy, - .routerHistory, - .routerStats, - .routerTextDirect, - .routerTextBroadcast, - .clientError, - .clientHistory, - .clientStats, - .clientPing, - .clientPong, - .clientAbort, - ] - } /// /// TODO: REPLACE - public struct Statistics: Sendable { + public struct Statistics { // 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. @@ -288,7 +294,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public struct History: Sendable { + public struct History { // 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. @@ -313,7 +319,7 @@ public struct StoreAndForward: @unchecked Sendable { /// /// TODO: REPLACE - public struct Heartbeat: Sendable { + public struct Heartbeat { // 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. @@ -334,6 +340,41 @@ public struct StoreAndForward: @unchecked Sendable { public init() {} } +#if swift(>=4.2) + +extension StoreAndForward.RequestResponse: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [StoreAndForward.RequestResponse] = [ + .unset, + .routerError, + .routerHeartbeat, + .routerPing, + .routerPong, + .routerBusy, + .routerHistory, + .routerStats, + .routerTextDirect, + .routerTextBroadcast, + .clientError, + .clientHistory, + .clientStats, + .clientPing, + .clientPong, + .clientAbort, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension StoreAndForward: @unchecked Sendable {} +extension StoreAndForward.OneOf_Variant: @unchecked Sendable {} +extension StoreAndForward.RequestResponse: @unchecked Sendable {} +extension StoreAndForward.Statistics: @unchecked Sendable {} +extension StoreAndForward.History: @unchecked Sendable {} +extension StoreAndForward.Heartbeat: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index 7289b713..e4b9ee08 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Supported I2C Sensors for telemetry in Meshtastic -public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { +public enum TelemetrySensorType: SwiftProtobuf.Enum { public typealias RawValue = Int /// @@ -216,6 +216,11 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { } } +} + +#if swift(>=4.2) + +extension TelemetrySensorType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [TelemetrySensorType] = [ .sensorUnset, @@ -248,12 +253,13 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { .icm20948, .max17048, ] - } +#endif // swift(>=4.2) + /// /// Key native device metrics such as battery level -public struct DeviceMetrics: Sendable { +public struct DeviceMetrics { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -326,7 +332,7 @@ public struct DeviceMetrics: Sendable { /// /// Weather station or other environmental metrics -public struct EnvironmentMetrics: @unchecked Sendable { +public struct EnvironmentMetrics { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -529,7 +535,7 @@ public struct EnvironmentMetrics: @unchecked Sendable { /// /// Power Metrics (voltage / current / etc) -public struct PowerMetrics: Sendable { +public struct PowerMetrics { // 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. @@ -614,7 +620,7 @@ public struct PowerMetrics: Sendable { /// /// Air quality metrics -public struct AirQualityMetrics: Sendable { +public struct AirQualityMetrics { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -769,9 +775,53 @@ public struct AirQualityMetrics: Sendable { fileprivate var _particles100Um: UInt32? = nil } +/// +/// Local device mesh statistics +public struct LocalStats { + // 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. + + /// + /// How long the device has been running since the last reboot (in seconds) + public var uptimeSeconds: UInt32 = 0 + + /// + /// Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). + public var channelUtilization: Float = 0 + + /// + /// Percent of airtime for transmission used within the last hour. + public var airUtilTx: Float = 0 + + /// + /// Number of packets sent + public var numPacketsTx: UInt32 = 0 + + /// + /// Number of packets received good + public var numPacketsRx: UInt32 = 0 + + /// + /// Number of packets received that are malformed or violate the protocol + public var numPacketsRxBad: UInt32 = 0 + + /// + /// Number of nodes online (in the past 2 hours) + public var numOnlineNodes: UInt32 = 0 + + /// + /// Number of nodes total + public var numTotalNodes: UInt32 = 0 + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} +} + /// /// Types of Measurements the telemetry module is equipped to handle -public struct Telemetry: Sendable { +public struct Telemetry { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -822,9 +872,19 @@ public struct Telemetry: Sendable { set {variant = .powerMetrics(newValue)} } + /// + /// Local device mesh statistics + public var localStats: LocalStats { + get { + if case .localStats(let v)? = variant {return v} + return LocalStats() + } + set {variant = .localStats(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable, Sendable { + public enum OneOf_Variant: Equatable { /// /// Key native device metrics such as battery level case deviceMetrics(DeviceMetrics) @@ -837,7 +897,40 @@ public struct Telemetry: Sendable { /// /// Power Metrics case powerMetrics(PowerMetrics) + /// + /// Local device mesh statistics + case localStats(LocalStats) + #if !swift(>=4.1) + public static func ==(lhs: Telemetry.OneOf_Variant, rhs: Telemetry.OneOf_Variant) -> Bool { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch (lhs, rhs) { + case (.deviceMetrics, .deviceMetrics): return { + guard case .deviceMetrics(let l) = lhs, case .deviceMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.environmentMetrics, .environmentMetrics): return { + guard case .environmentMetrics(let l) = lhs, case .environmentMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.airQualityMetrics, .airQualityMetrics): return { + guard case .airQualityMetrics(let l) = lhs, case .airQualityMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.powerMetrics, .powerMetrics): return { + guard case .powerMetrics(let l) = lhs, case .powerMetrics(let r) = rhs else { preconditionFailure() } + return l == r + }() + case (.localStats, .localStats): return { + guard case .localStats(let l) = lhs, case .localStats(let r) = rhs else { preconditionFailure() } + return l == r + }() + default: return false + } + } + #endif } public init() {} @@ -845,7 +938,7 @@ public struct Telemetry: Sendable { /// /// NAU7802 Telemetry configuration, for saving to flash -public struct Nau7802Config: Sendable { +public struct Nau7802Config { // 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. @@ -863,6 +956,18 @@ public struct Nau7802Config: Sendable { public init() {} } +#if swift(>=5.5) && canImport(_Concurrency) +extension TelemetrySensorType: @unchecked Sendable {} +extension DeviceMetrics: @unchecked Sendable {} +extension EnvironmentMetrics: @unchecked Sendable {} +extension PowerMetrics: @unchecked Sendable {} +extension AirQualityMetrics: @unchecked Sendable {} +extension LocalStats: @unchecked Sendable {} +extension Telemetry: @unchecked Sendable {} +extension Telemetry.OneOf_Variant: @unchecked Sendable {} +extension Nau7802Config: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1333,6 +1438,80 @@ extension AirQualityMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem } } +extension LocalStats: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".LocalStats" + public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ + 1: .standard(proto: "uptime_seconds"), + 2: .standard(proto: "channel_utilization"), + 3: .standard(proto: "air_util_tx"), + 4: .standard(proto: "num_packets_tx"), + 5: .standard(proto: "num_packets_rx"), + 6: .standard(proto: "num_packets_rx_bad"), + 7: .standard(proto: "num_online_nodes"), + 8: .standard(proto: "num_total_nodes"), + ] + + public 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.decodeSingularUInt32Field(value: &self.uptimeSeconds) }() + case 2: try { try decoder.decodeSingularFloatField(value: &self.channelUtilization) }() + case 3: try { try decoder.decodeSingularFloatField(value: &self.airUtilTx) }() + case 4: try { try decoder.decodeSingularUInt32Field(value: &self.numPacketsTx) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self.numPacketsRx) }() + case 6: try { try decoder.decodeSingularUInt32Field(value: &self.numPacketsRxBad) }() + case 7: try { try decoder.decodeSingularUInt32Field(value: &self.numOnlineNodes) }() + case 8: try { try decoder.decodeSingularUInt32Field(value: &self.numTotalNodes) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.uptimeSeconds != 0 { + try visitor.visitSingularUInt32Field(value: self.uptimeSeconds, fieldNumber: 1) + } + if self.channelUtilization != 0 { + try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 2) + } + if self.airUtilTx != 0 { + try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 3) + } + if self.numPacketsTx != 0 { + try visitor.visitSingularUInt32Field(value: self.numPacketsTx, fieldNumber: 4) + } + if self.numPacketsRx != 0 { + try visitor.visitSingularUInt32Field(value: self.numPacketsRx, fieldNumber: 5) + } + if self.numPacketsRxBad != 0 { + try visitor.visitSingularUInt32Field(value: self.numPacketsRxBad, fieldNumber: 6) + } + if self.numOnlineNodes != 0 { + try visitor.visitSingularUInt32Field(value: self.numOnlineNodes, fieldNumber: 7) + } + if self.numTotalNodes != 0 { + try visitor.visitSingularUInt32Field(value: self.numTotalNodes, fieldNumber: 8) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: LocalStats, rhs: LocalStats) -> Bool { + if lhs.uptimeSeconds != rhs.uptimeSeconds {return false} + if lhs.channelUtilization != rhs.channelUtilization {return false} + if lhs.airUtilTx != rhs.airUtilTx {return false} + if lhs.numPacketsTx != rhs.numPacketsTx {return false} + if lhs.numPacketsRx != rhs.numPacketsRx {return false} + if lhs.numPacketsRxBad != rhs.numPacketsRxBad {return false} + if lhs.numOnlineNodes != rhs.numOnlineNodes {return false} + if lhs.numTotalNodes != rhs.numTotalNodes {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Telemetry" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ @@ -1341,6 +1520,7 @@ extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation 3: .standard(proto: "environment_metrics"), 4: .standard(proto: "air_quality_metrics"), 5: .standard(proto: "power_metrics"), + 6: .standard(proto: "local_stats"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -1402,6 +1582,19 @@ extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation self.variant = .powerMetrics(v) } }() + case 6: try { + var v: LocalStats? + var hadOneofValue = false + if let current = self.variant { + hadOneofValue = true + if case .localStats(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.variant = .localStats(v) + } + }() default: break } } @@ -1432,6 +1625,10 @@ extension Telemetry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation guard case .powerMetrics(let v)? = self.variant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 5) }() + case .localStats?: try { + guard case .localStats(let v)? = self.variant else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -1469,7 +1666,7 @@ extension Nau7802Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.zeroOffset != 0 { try visitor.visitSingularInt32Field(value: self.zeroOffset, fieldNumber: 1) } - if self.calibrationFactor.bitPattern != 0 { + if self.calibrationFactor != 0 { try visitor.visitSingularFloatField(value: self.calibrationFactor, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift index 89d0097c..1f41fe0b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct XModem: @unchecked Sendable { +public struct XModem { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -35,7 +35,7 @@ public struct XModem: @unchecked Sendable { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum Control: SwiftProtobuf.Enum, Swift.CaseIterable { + public enum Control: SwiftProtobuf.Enum { public typealias RawValue = Int case nul // = 0 case soh // = 1 @@ -79,23 +79,34 @@ public struct XModem: @unchecked Sendable { } } - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [XModem.Control] = [ - .nul, - .soh, - .stx, - .eot, - .ack, - .nak, - .can, - .ctrlz, - ] - } public init() {} } +#if swift(>=4.2) + +extension XModem.Control: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [XModem.Control] = [ + .nul, + .soh, + .stx, + .eot, + .ack, + .nak, + .can, + .ctrlz, + ] +} + +#endif // swift(>=4.2) + +#if swift(>=5.5) && canImport(_Concurrency) +extension XModem: @unchecked Sendable {} +extension XModem.Control: @unchecked Sendable {} +#endif // swift(>=5.5) && canImport(_Concurrency) + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/protobufs b/protobufs index 3e753697..59d035a3 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 3e753697aa1140d2c998cb63739729e733002874 +Subproject commit 59d035a37dbeadb28db97acce5f738ba52ee9d3a From bb4967fbf419696f6bedaa3f24a5a73e42d546fc Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 17 Aug 2024 13:12:13 -0700 Subject: [PATCH 60/75] Use new set time method after want config is complete --- Meshtastic/Helpers/BLEManager.swift | 25 +++++++++++ .../Weather/LocalWeatherConditions.swift | 18 ++++---- .../Nodes/Helpers/Map/PositionPopover.swift | 31 +++++++------- .../Views/Nodes/Helpers/NodeListItem.swift | 4 +- Meshtastic/Views/Nodes/MeshMap.swift | 25 ++++++----- .../Sources/meshtastic/mesh.pb.swift | 42 ++++++++++++++++++- .../Sources/meshtastic/module_config.pb.swift | 2 +- .../Sources/meshtastic/portnums.pb.swift | 2 +- protobufs | 2 +- 9 files changed, 105 insertions(+), 46 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 4e7489dc..7e08ccfa 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -893,6 +893,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate lastConnectionError = "" isSubscribed = true Logger.mesh.info("🤜 [BLE] Want Config Complete. ID:\(decodedInfo.configCompleteID)") + sendTime() peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected }) // Config conplete returns so we don't read the characteristic again @@ -1298,6 +1299,30 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } } + public func sendTime() -> Bool { + var adminPacket = AdminMessage() + adminPacket.setTimeOnly = UInt32(Date().timeIntervalSince1970) + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = 0 + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { var adminPacket = AdminMessage() adminPacket.shutdownSeconds = 5 diff --git a/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift b/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift index 8f057610..27675141 100644 --- a/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift +++ b/Meshtastic/Views/Helpers/Weather/LocalWeatherConditions.swift @@ -101,7 +101,7 @@ struct WeatherConditionsCompactWidget: View { .font(temperature.length < 4 ? .system(size: 90) : .system(size: 60) ) } .frame(maxWidth: .infinity) - .frame(height: 175) + .frame(height: 150) .background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous)) } } @@ -123,7 +123,7 @@ struct HumidityCompactWidget: View { } .padding(.horizontal) .frame(maxWidth: .infinity) - .frame(height: 175) + .frame(height: 150) .background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous)) } } @@ -135,16 +135,15 @@ struct PressureCompactWidget: View { var body: some View { VStack(alignment: .leading) { Label { Text("PRESSURE") } icon: { Image(systemName: "gauge").symbolRenderingMode(.multicolor) } - .font(.caption2) + .font(.callout) Text(pressure) .font(pressure.length < 7 ? .system(size: 35) : .system(size: 30) ) Text(low ? "LOW" : "HIGH") .padding(.bottom) Text(unit) } - .padding(.horizontal) - .frame(maxWidth: .infinity) - .frame(height: 175) + .padding(.horizontal, 5) + .frame(width: 175, height: 175) .background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous)) } } @@ -156,17 +155,14 @@ struct WindCompactWidget: View { var body: some View { VStack(alignment: .leading) { Label { Text("WIND") } icon: { Image(systemName: "wind").foregroundColor(.accentColor) } - .font(.caption) Text("\(direction)") - .font(.caption) .padding(.bottom, 10) Text(speed) .font(.system(size: 35)) Text("Gusts \(gust)") } - .padding(.horizontal) - .frame(maxWidth: .infinity) - .frame(height: 175) + //.padding(.horizontal) + .frame(width: 175, height: 175) .background(.tertiary, in: RoundedRectangle(cornerRadius: 20, style: .continuous)) } } diff --git a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift index 0c708058..6a717629 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/PositionPopover.swift @@ -154,6 +154,22 @@ struct PositionPopover: View { .rotationEffect(degrees) } .padding(.bottom, 5) + /// Distance + if let lastLocation = locationsHandler.locationsArray.last { + /// Distance + if lastLocation.distance(from: CLLocation(latitude: LocationsHandler.DefaultLocation.latitude, longitude: LocationsHandler.DefaultLocation.longitude)) > 0.0 { + let metersAway = position.coordinate.distance(from: CLLocationCoordinate2D(latitude: lastLocation.coordinate.latitude, longitude: lastLocation.coordinate.longitude)) + Label { + Text("distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway)))") + .foregroundColor(.primary) + .font(idiom == .phone ? .callout : .body) + } icon: { + Image(systemName: "lines.measurement.horizontal") + .symbolRenderingMode(.hierarchical) + .frame(width: 35) + } + } + } /// Speed let speed = Measurement(value: Double(position.speed), unit: UnitSpeed.kilometersPerHour) Label { @@ -179,21 +195,6 @@ struct PositionPopover: View { } .padding(.bottom, 5) } - if let lastLocation = locationsHandler.locationsArray.last { - /// Distance - if lastLocation.distance(from: CLLocation(latitude: LocationsHandler.DefaultLocation.latitude, longitude: LocationsHandler.DefaultLocation.longitude)) > 0.0 { - let metersAway = position.coordinate.distance(from: CLLocationCoordinate2D(latitude: lastLocation.coordinate.latitude, longitude: lastLocation.coordinate.longitude)) - Label { - Text("distance".localized + ": \(distanceFormatter.string(fromDistance: Double(metersAway)))") - .foregroundColor(.primary) - .font(idiom == .phone ? .callout : .body) - } icon: { - Image(systemName: "lines.measurement.horizontal") - .symbolRenderingMode(.hierarchical) - .frame(width: 35) - } - } - } Spacer() } Spacer() diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index 5d46806c..3013e8df 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -98,7 +98,7 @@ struct NodeListItem: View { DistanceText(meters: metersAway) .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.gray) - let trueBearing = getBearingBetweenTwoPoints(point1: myCoord, point2: CLLocation(latitude: lastPostion.coordinate.latitude, longitude: lastPostion.coordinate.longitude)) + let trueBearing = getBearingBetweenTwoPoints(point1: myCoord, point2: nodeCoord) let headingDegrees = Angle.degrees(trueBearing) Image(systemName: "location.north") .font(.callout) @@ -124,7 +124,7 @@ struct NodeListItem: View { DistanceText(meters: metersAway) .font(UIDevice.current.userInterfaceIdiom == .phone ? .callout : .caption) .foregroundColor(.secondary) - let trueBearing = getBearingBetweenTwoPoints(point1: myCoord, point2: CLLocation(latitude: lastPostion.coordinate.latitude, longitude: lastPostion.coordinate.longitude)) + let trueBearing = getBearingBetweenTwoPoints(point1: myCoord, point2: nodeCoord) let headingDegrees = Angle.degrees(trueBearing) Image(systemName: "location.north") .font(.callout) diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index 31923562..9e09a0c0 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -62,7 +62,6 @@ struct MeshMap: View { MapReader { reader in Map(position: $position, bounds: MapCameraBounds(minimumDistance: 1, maximumDistance: .infinity), scope: mapScope) { MeshMapContent(showUserLocation: $showUserLocation, showTraffic: $showTraffic, showPointsOfInterest: $showPointsOfInterest, selectedMapLayer: $selectedMapLayer, selectedPosition: $selectedPosition, selectedWaypoint: $selectedWaypoint) - } .mapScope(mapScope) .mapStyle(mapStyle) @@ -159,6 +158,7 @@ struct MeshMap: View { } .safeAreaInset(edge: .bottom, alignment: .trailing) { HStack { + Spacer() Button(action: { withAnimation { editingSettings = !editingSettings @@ -170,18 +170,17 @@ struct MeshMap: View { .tint(Color(UIColor.secondarySystemBackground)) .foregroundColor(.accentColor) .buttonStyle(.borderedProminent) - Spacer() - Button(action: { - withAnimation { - editingFilters = !editingFilters - } - }) { - Image(systemName: !editingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill") - .padding(.vertical, 5) - } - .tint(Color(UIColor.secondarySystemBackground)) - .foregroundColor(.accentColor) - .buttonStyle(.borderedProminent) +// Button(action: { +// withAnimation { +// editingFilters = !editingFilters +// } +// }) { +// Image(systemName: !editingFilters ? "line.3.horizontal.decrease.circle" : "line.3.horizontal.decrease.circle.fill") +// .padding(.vertical, 5) +// } +// .tint(Color(UIColor.secondarySystemBackground)) +// .foregroundColor(.accentColor) +// .buttonStyle(.borderedProminent) } .controlSize(.regular) .padding(5) diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index 1f4c60a5..ba12908d 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -342,6 +342,10 @@ public enum HardwareModel: SwiftProtobuf.Enum { /// SSD1306 OLED and No GPS case radiomaster900Bandit // = 74 + /// + /// Minewsemi ME25LS01 (ME25LE01_V1.0). NRF52840 w/ LR1110 radio, buttons and leds and pins. + case me25Ls014Y10Td // = 75 + /// /// ------------------------------------------------------------------------------------------------------------------------------------------ /// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. @@ -429,6 +433,7 @@ public enum HardwareModel: SwiftProtobuf.Enum { case 72: self = .rak3172 case 73: self = .wioE5 case 74: self = .radiomaster900Bandit + case 75: self = .me25Ls014Y10Td case 255: self = .privateHw default: self = .UNRECOGNIZED(rawValue) } @@ -510,6 +515,7 @@ public enum HardwareModel: SwiftProtobuf.Enum { case .rak3172: return 72 case .wioE5: return 73 case .radiomaster900Bandit: return 74 + case .me25Ls014Y10Td: return 75 case .privateHw: return 255 case .UNRECOGNIZED(let i): return i } @@ -596,6 +602,7 @@ extension HardwareModel: CaseIterable { .rak3172, .wioE5, .radiomaster900Bandit, + .me25Ls014Y10Td, .privateHw, ] } @@ -1219,16 +1226,28 @@ public struct User { } /// -/// A message used in our Dynamic Source Routing protocol (RFC 4728 based) +/// A message used in a traceroute public struct RouteDiscovery { // 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 list of nodenums this packet has visited so far + /// The list of nodenums this packet has visited so far to the destination. public var route: [UInt32] = [] + /// + /// The list of SNRs (in dB, scaled by 4) in the route towards the destination. + public var snrTowards: [Int32] = [] + + /// + /// The list of nodenums the packet has visited on the way back from the destination. + public var routeBack: [UInt32] = [] + + /// + /// The list of SNRs (in dB, scaled by 4) in the route back from the destination. + public var snrBack: [Int32] = [] + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -3221,6 +3240,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 72: .same(proto: "RAK3172"), 73: .same(proto: "WIO_E5"), 74: .same(proto: "RADIOMASTER_900_BANDIT"), + 75: .same(proto: "ME25LS01_4Y10TD"), 255: .same(proto: "PRIVATE_HW"), ] } @@ -3600,6 +3620,9 @@ extension RouteDiscovery: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement public static let protoMessageName: String = _protobuf_package + ".RouteDiscovery" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "route"), + 2: .standard(proto: "snr_towards"), + 3: .standard(proto: "route_back"), + 4: .standard(proto: "snr_back"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -3609,6 +3632,9 @@ extension RouteDiscovery: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeRepeatedFixed32Field(value: &self.route) }() + case 2: try { try decoder.decodeRepeatedInt32Field(value: &self.snrTowards) }() + case 3: try { try decoder.decodeRepeatedFixed32Field(value: &self.routeBack) }() + case 4: try { try decoder.decodeRepeatedInt32Field(value: &self.snrBack) }() default: break } } @@ -3618,11 +3644,23 @@ extension RouteDiscovery: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement if !self.route.isEmpty { try visitor.visitPackedFixed32Field(value: self.route, fieldNumber: 1) } + if !self.snrTowards.isEmpty { + try visitor.visitPackedInt32Field(value: self.snrTowards, fieldNumber: 2) + } + if !self.routeBack.isEmpty { + try visitor.visitPackedFixed32Field(value: self.routeBack, fieldNumber: 3) + } + if !self.snrBack.isEmpty { + try visitor.visitPackedInt32Field(value: self.snrBack, fieldNumber: 4) + } try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: RouteDiscovery, rhs: RouteDiscovery) -> Bool { if lhs.route != rhs.route {return false} + if lhs.snrTowards != rhs.snrTowards {return false} + if lhs.routeBack != rhs.routeBack {return false} + if lhs.snrBack != rhs.snrBack {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index c68ffd83..3186c349 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -1044,7 +1044,7 @@ public struct ModuleConfig { /// /// Input event origin accepted by the canned message module. - /// Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any" + /// Can be e.g. "rotEnc1", "upDownEnc1", "scanAndSelect", "cardkb", "serialkb", or keyword "_any" public var allowInputSource: String = String() /// diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index c728c961..dd7e036f 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -167,7 +167,7 @@ public enum PortNum: SwiftProtobuf.Enum { /// /// Provides a traceroute functionality to show the route a packet towards - /// a certain destination would take on the mesh. + /// a certain destination would take on the mesh. Contains a RouteDiscovery message as payload. /// ENCODING: Protobuf case tracerouteApp // = 70 diff --git a/protobufs b/protobufs index 59d035a3..b6237629 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 59d035a37dbeadb28db97acce5f738ba52ee9d3a +Subproject commit b623762940ebdb1887a3b31b86f4d9cdaa7e6ecf From b260b644e41580acc10dbb1953ee99887b57cf49 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 17 Aug 2024 15:31:35 -0700 Subject: [PATCH 61/75] Fix node list battery level update bug --- Meshtastic.xcodeproj/project.pbxproj | 4 --- .../CoreData/NodeInfoEntityExtension.swift | 4 +++ Meshtastic/Views/Helpers/BatteryCompact.swift | 2 +- .../Views/Helpers/BatteryLevelCompact.swift | 25 ------------------- .../Views/Nodes/Helpers/NodeListItem.swift | 6 +++-- 5 files changed, 9 insertions(+), 32 deletions(-) delete mode 100644 Meshtastic/Views/Helpers/BatteryLevelCompact.swift diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 2c59e43b..7d5f9023 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -152,7 +152,6 @@ DDB75A1A2A05EB67006ED576 /* alpha.png in Resources */ = {isa = PBXBuildFile; fileRef = DDB75A192A05EB67006ED576 /* alpha.png */; }; DDB75A1E2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */; }; DDB75A212A12B954006ED576 /* LoRaSignalStrength.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB75A202A12B954006ED576 /* LoRaSignalStrength.swift */; }; - DDB75A232A13CDA9006ED576 /* BatteryLevelCompact.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */; }; DDB8F4102A9EE5B400230ECE /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F40F2A9EE5B400230ECE /* Messages.swift */; }; DDB8F4122A9EE5DD00230ECE /* UserList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F4112A9EE5DD00230ECE /* UserList.swift */; }; DDB8F4142A9EE5F000230ECE /* ChannelList.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8F4132A9EE5F000230ECE /* ChannelList.swift */; }; @@ -418,7 +417,6 @@ DDB75A1D2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoRaSignalStrengthIndicator.swift; sourceTree = ""; }; DDB75A1F2A10766D006ED576 /* MeshtasticDataModelV13.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV13.xcdatamodel; sourceTree = ""; }; DDB75A202A12B954006ED576 /* LoRaSignalStrength.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoRaSignalStrength.swift; sourceTree = ""; }; - DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryLevelCompact.swift; sourceTree = ""; }; DDB8F40F2A9EE5B400230ECE /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = ""; }; DDB8F4112A9EE5DD00230ECE /* UserList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserList.swift; sourceTree = ""; }; DDB8F4132A9EE5F000230ECE /* ChannelList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelList.swift; sourceTree = ""; }; @@ -921,7 +919,6 @@ DD6F65772C6EAB860053C113 /* Help */, DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */, DD3CC24B2C498D6C001BD3A2 /* BatteryCompact.swift */, - DDB75A222A13CDA9006ED576 /* BatteryLevelCompact.swift */, DD457187293C7E63000C49FB /* BLESignalStrengthIndicator.swift */, DD47E3D526F17ED900029299 /* CircleText.swift */, DDF924C926FBB953009FE055 /* ConnectedDevice.swift */, @@ -1310,7 +1307,6 @@ DDDB444229F8A88700EE2349 /* Double.swift in Sources */, DDF45C342BC1A48E005ED5F2 /* MQTTIcon.swift in Sources */, DDA9515A2BC6624100CEA535 /* TelemetryWeather.swift in Sources */, - DDB75A232A13CDA9006ED576 /* BatteryLevelCompact.swift in Sources */, DDB75A162A0594AD006ED576 /* TileOverlay.swift in Sources */, DD1BD0EB2C601795008C0C70 /* CLLocation.swift in Sources */, DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */, diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index 66c915df..eb0086c7 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -14,6 +14,10 @@ extension NodeInfoEntity { return self.positions?.lastObject as? PositionEntity } + var latestDeviceMetrics: TelemetryEntity? { + return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")).lastObject as? TelemetryEntity + } + var latestEnvironmentMetrics: TelemetryEntity? { return self.telemetries?.filtered(using: NSPredicate(format: "metricsType == 1")).lastObject as? TelemetryEntity } diff --git a/Meshtastic/Views/Helpers/BatteryCompact.swift b/Meshtastic/Views/Helpers/BatteryCompact.swift index 28f62a57..bc714da6 100644 --- a/Meshtastic/Views/Helpers/BatteryCompact.swift +++ b/Meshtastic/Views/Helpers/BatteryCompact.swift @@ -7,7 +7,7 @@ import SwiftUI struct BatteryCompact: View { - @State var batteryLevel: Int32 + var batteryLevel: Int32 var font: Font var iconFont: Font var color: Color diff --git a/Meshtastic/Views/Helpers/BatteryLevelCompact.swift b/Meshtastic/Views/Helpers/BatteryLevelCompact.swift deleted file mode 100644 index e1354e23..00000000 --- a/Meshtastic/Views/Helpers/BatteryLevelCompact.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// BatteryIcon.swift -// Meshtastic -// -// Copyright Garth Vander Houwen 3/24/23. -// -import SwiftUI - -struct BatteryLevelCompact: View { - - @ObservedObject var node: NodeInfoEntity - - var font: Font - var iconFont: Font - var color: Color - - var body: some View { - let deviceMetrics = node.telemetries?.filtered(using: NSPredicate(format: "metricsType == 0")) - let mostRecent = deviceMetrics?.lastObject as? TelemetryEntity - let batteryLevel = mostRecent?.batteryLevel ?? 0 - if deviceMetrics?.count ?? 0 > 0 { - BatteryCompact(batteryLevel: batteryLevel, font: font, iconFont: iconFont, color: color) - } - } -} diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift index 3013e8df..63aff338 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListItem.swift @@ -23,8 +23,10 @@ struct NodeListItem: View { VStack(alignment: .leading) { CircleText(text: node.user?.shortName ?? "?", color: Color(UIColor(hex: UInt32(node.num))), circleSize: 70) .padding(.trailing, 5) - BatteryLevelCompact(node: node, font: .caption, iconFont: .callout, color: .accentColor) - .padding(.trailing, 5) + if node.latestDeviceMetrics != nil { + BatteryCompact(batteryLevel: node.latestDeviceMetrics?.batteryLevel ?? 0, font: .caption, iconFont: .callout, color: .accentColor) + .padding(.trailing, 5) + } } VStack(alignment: .leading) { HStack { From fe9e0d73b8d6f3aef990288326c3395ec08641eb Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 17 Aug 2024 15:36:23 -0700 Subject: [PATCH 62/75] Add firmware version requirement to encryption help --- Meshtastic/Views/Helpers/Help/LockLegend.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Views/Helpers/Help/LockLegend.swift b/Meshtastic/Views/Helpers/Help/LockLegend.swift index 9c5d216b..36716798 100644 --- a/Meshtastic/Views/Helpers/Help/LockLegend.swift +++ b/Meshtastic/Views/Helpers/Help/LockLegend.swift @@ -34,7 +34,7 @@ struct LockLegend: View { Text("Public Key Encryption") .fontWeight(.semibold) } - Text("Direct messages are using the new public key infrastructure for encryption.") + Text("Direct messages are using the new public key infrastructure for encryption. Reguires firmware version 2.5 or greater.") .allowsTightening(/*@START_MENU_TOKEN@*/true/*@END_MENU_TOKEN@*/) .font(.callout) .fixedSize(horizontal: false, vertical: true) From ec704e2c2b4e38b5a3520a664b7f5b41661df207 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 08:36:30 -0700 Subject: [PATCH 63/75] Admin message session passkeys --- Localizable.xcstrings | 2 +- Meshtastic/Helpers/BLEManager.swift | 181 ++++++++++++++---- .../contents | 2 + Meshtastic/Persistence/UpdateCoreData.swift | 133 +++++++------ 4 files changed, 222 insertions(+), 96 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 16d61fea..21466cc5 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -6316,7 +6316,7 @@ "Direct Message Help" : { }, - "Direct messages are using the new public key infrastructure for encryption." : { + "Direct messages are using the new public key infrastructure for encryption. Reguires firmware version 2.5 or greater." : { }, "Direct messages are using the shared key for the channel." : { diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 7e08ccfa..49e43d54 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -392,6 +392,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.getDeviceMetadataRequest = true + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { var adminPacket = AdminMessage() adminPacket.shutdownSeconds = 5 + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1351,6 +1357,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendReboot(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool { var adminPacket = AdminMessage() adminPacket.rebootSeconds = 5 + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1376,6 +1385,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendRebootOta(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool { var adminPacket = AdminMessage() adminPacket.rebootOtaSeconds = 5 + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1401,6 +1413,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendEnterDfuMode(fromUser: UserEntity, toUser: UserEntity) -> Bool { var adminPacket = AdminMessage() adminPacket.enterDfuModeRequest = true + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1427,6 +1442,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendFactoryReset(fromUser: UserEntity, toUser: UserEntity) -> Bool { var adminPacket = AdminMessage() adminPacket.factoryResetConfig = 5 + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1452,6 +1470,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func sendNodeDBReset(fromUser: UserEntity, toUser: UserEntity) -> Bool { var adminPacket = AdminMessage() adminPacket.nodedbReset = 5 + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = 0 // UInt32(fromUser.num) @@ -1664,6 +1685,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func saveUser(config: User, fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Int64 { var adminPacket = AdminMessage() adminPacket.setOwner = config + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1786,6 +1810,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func saveLicensedUser(ham: HamParameters, fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Int64 { var adminPacket = AdminMessage() adminPacket.setHamMode = ham + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1809,6 +1836,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func saveBluetoothConfig(config: Config.BluetoothConfig, fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Int64 { var adminPacket = AdminMessage() adminPacket.setConfig.bluetooth = config + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1826,7 +1856,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate let messageDescription = "🛟 Saved Bluetooth Config for \(toUser.longName ?? "unknown".localized)" if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) { - upsertBluetoothConfigPacket(config: config, nodeNum: toUser.num, context: context) + upsertBluetoothConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey, context: context) return Int64(meshPacket.id) } @@ -1837,7 +1867,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setConfig.device = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1854,7 +1886,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate meshPacket.decoded = dataMessage let messageDescription = "🛟 Saved Device Config for \(toUser.longName ?? "unknown".localized)" if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) { - upsertDeviceConfigPacket(config: config, nodeNum: toUser.num, context: context) + upsertDeviceConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey, context: context) return Int64(meshPacket.id) } return 0 @@ -1863,6 +1895,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate public func saveDisplayConfig(config: Config.DisplayConfig, fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Int64 { var adminPacket = AdminMessage() adminPacket.setConfig.display = config + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1881,7 +1916,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate meshPacket.decoded = dataMessage let messageDescription = "🛟 Saved Display Config for \(toUser.longName ?? "unknown".localized)" if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) { - upsertDisplayConfigPacket(config: config, nodeNum: toUser.num, context: context) + upsertDisplayConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey, context: context) return Int64(meshPacket.id) } return 0 @@ -1891,6 +1926,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setConfig.lora = config + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1908,7 +1946,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate let messageDescription = "🛟 Saved LoRa Config for \(toUser.longName ?? "unknown".localized)" if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription) { - upsertLoRaConfigPacket(config: config, nodeNum: toUser.num, context: context) + upsertLoRaConfigPacket(config: config, nodeNum: toUser.num, sessionPasskey: toUser.userNode?.sessionPasskey,context: context) return Int64(meshPacket.id) } @@ -1919,7 +1957,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setConfig.position = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -1981,7 +2021,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setConfig.network = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -2012,7 +2054,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setConfig.security = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -2043,7 +2087,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setModuleConfig.ambientLighting = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -2073,7 +2119,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setModuleConfig.cannedMessage = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -2103,7 +2151,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setCannedMessageModuleMessages = messages - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(toUser.num) meshPacket.from = UInt32(fromUser.num) @@ -2134,7 +2184,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.setModuleConfig.detectionSensor = config - + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } var meshPacket: MeshPacket = MeshPacket() meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. + + diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index ba391495..009b9d20 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -397,7 +397,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) } } -func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.bluetooth.config %@".localized, String(nodeNum)) MeshLogger.log("📶 \(logString)") @@ -422,6 +422,9 @@ func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.fixedPin) fetchedNode[0].bluetoothConfig?.deviceLoggingEnabled = config.deviceLoggingEnabled } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [BluetoothConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -439,7 +442,7 @@ func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, } } -func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.device.config %@".localized, String(nodeNum)) MeshLogger.log("📟 \(logString)") @@ -477,6 +480,9 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, conte fetchedNode[0].deviceConfig?.isManaged = config.isManaged fetchedNode[0].deviceConfig?.tzdef = config.tzdef } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [DeviceConfigEntity] Updated Device Config for node number: \(nodeNum.toHex(), privacy: .public)") @@ -492,7 +498,7 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, conte } } -func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.display.config %@".localized, nodeNum.toHex()) MeshLogger.log("🖥️ \(logString)") @@ -518,7 +524,6 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, con newDisplayConfig.units = Int32(config.units.rawValue) newDisplayConfig.headingBold = config.headingBold fetchedNode[0].displayConfig = newDisplayConfig - } else { fetchedNode[0].displayConfig?.gpsFormat = Int32(config.gpsFormat.rawValue) @@ -531,7 +536,9 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, con fetchedNode[0].displayConfig?.units = Int32(config.units.rawValue) fetchedNode[0].displayConfig?.headingBold = config.headingBold } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() @@ -556,7 +563,7 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, con } } -func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.lora.config %@".localized, nodeNum.toHex()) MeshLogger.log("📻 \(logString)") @@ -604,6 +611,9 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, context: fetchedNode[0].loRaConfig?.ignoreMqtt = config.ignoreMqtt fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [LoRaConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -621,7 +631,7 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, context: } } -func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.network.config %@".localized, String(nodeNum)) MeshLogger.log("🌐 \(logString)") @@ -646,7 +656,9 @@ func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, con fetchedNode[0].networkConfig?.wifiSsid = config.wifiSsid fetchedNode[0].networkConfig?.wifiPsk = config.wifiPsk } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [NetworkConfigEntity] Updated Network Config for node: \(nodeNum.toHex(), privacy: .public)") @@ -665,7 +677,7 @@ func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, con } } -func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.position.config %@".localized, String(nodeNum)) MeshLogger.log("🗺️ \(logString)") @@ -708,6 +720,9 @@ func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, c fetchedNode[0].positionConfig?.gpsUpdateInterval = Int32(config.gpsUpdateInterval) fetchedNode[0].positionConfig?.positionFlags = Int32(config.positionFlags) } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [PositionConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -725,7 +740,7 @@ func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, c } } -func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.power.config %@".localized, String(nodeNum)) MeshLogger.log("🗺️ \(logString)") @@ -755,6 +770,9 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context fetchedNode[0].powerConfig?.onBatteryShutdownAfterSecs = Int32(truncatingIfNeeded: config.onBatteryShutdownAfterSecs) fetchedNode[0].powerConfig?.waitBluetoothSecs = Int32(truncatingIfNeeded: config.waitBluetoothSecs) } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [PowerConfigEntity] Updated Power Config for node: \(nodeNum.toHex(), privacy: .public)") @@ -772,7 +790,7 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, context } } -func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.security.config %@".localized, String(nodeNum)) MeshLogger.log("🛡️ \(logString)") @@ -803,7 +821,9 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c fetchedNode[0].securityConfig?.debugLogApiEnabled = config.debugLogApiEnabled fetchedNode[0].securityConfig?.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [SecurityConfigEntity] Updated Security Config for node: \(nodeNum.toHex(), privacy: .public)") @@ -822,7 +842,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, c } } -func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightingConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightingConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.ambientlighting.config %@".localized, String(nodeNum)) MeshLogger.log("🏮 \(logString)") @@ -836,16 +856,13 @@ func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightin if !fetchedNode.isEmpty { if fetchedNode[0].cannedMessageConfig == nil { - let newAmbientLightingConfig = AmbientLightingConfigEntity(context: context) - newAmbientLightingConfig.ledState = config.ledState newAmbientLightingConfig.current = Int32(config.current) newAmbientLightingConfig.red = Int32(config.red) newAmbientLightingConfig.green = Int32(config.green) newAmbientLightingConfig.blue = Int32(config.blue) fetchedNode[0].ambientLightingConfig = newAmbientLightingConfig - } else { if fetchedNode[0].ambientLightingConfig == nil { @@ -857,7 +874,9 @@ func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightin fetchedNode[0].ambientLightingConfig?.green = Int32(config.green) fetchedNode[0].ambientLightingConfig?.blue = Int32(config.blue) } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [AmbientLightingConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -875,7 +894,7 @@ func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightin } } -func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.cannedmessage.config %@".localized, String(nodeNum)) MeshLogger.log("🥫 \(logString)") @@ -889,9 +908,7 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo if !fetchedNode.isEmpty { if fetchedNode[0].cannedMessageConfig == nil { - let newCannedMessageConfig = CannedMessageConfigEntity(context: context) - newCannedMessageConfig.enabled = config.enabled newCannedMessageConfig.sendBell = config.sendBell newCannedMessageConfig.rotary1Enabled = config.rotary1Enabled @@ -902,11 +919,8 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo newCannedMessageConfig.inputbrokerEventCw = Int32(config.inputbrokerEventCw.rawValue) newCannedMessageConfig.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue) newCannedMessageConfig.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue) - fetchedNode[0].cannedMessageConfig = newCannedMessageConfig - } else { - fetchedNode[0].cannedMessageConfig?.enabled = config.enabled fetchedNode[0].cannedMessageConfig?.sendBell = config.sendBell fetchedNode[0].cannedMessageConfig?.rotary1Enabled = config.rotary1Enabled @@ -918,7 +932,9 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo fetchedNode[0].cannedMessageConfig?.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue) fetchedNode[0].cannedMessageConfig?.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue) } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [CannedMessageConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -936,7 +952,7 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo } } -func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSensorConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSensorConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.detectionsensor.config %@".localized, String(nodeNum)) MeshLogger.log("🕵️ \(logString)") @@ -948,21 +964,17 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save Detection Sensor Config if !fetchedNode.isEmpty { - if fetchedNode[0].detectionSensorConfig == nil { - let newConfig = DetectionSensorConfigEntity(context: context) newConfig.enabled = config.enabled newConfig.sendBell = config.sendBell newConfig.name = config.name - newConfig.monitorPin = Int32(config.monitorPin) newConfig.detectionTriggeredHigh = config.detectionTriggeredHigh newConfig.usePullup = config.usePullup newConfig.minimumBroadcastSecs = Int32(truncatingIfNeeded: config.minimumBroadcastSecs) newConfig.stateBroadcastSecs = Int32(truncatingIfNeeded: config.stateBroadcastSecs) fetchedNode[0].detectionSensorConfig = newConfig - } else { fetchedNode[0].detectionSensorConfig?.enabled = config.enabled fetchedNode[0].detectionSensorConfig?.sendBell = config.sendBell @@ -973,7 +985,9 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso fetchedNode[0].detectionSensorConfig?.minimumBroadcastSecs = Int32(truncatingIfNeeded: config.minimumBroadcastSecs) fetchedNode[0].detectionSensorConfig?.stateBroadcastSecs = Int32(truncatingIfNeeded: config.stateBroadcastSecs) } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [DetectionSensorConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -994,7 +1008,7 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso } } -func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.externalnotification.config %@".localized, String(nodeNum)) MeshLogger.log("📣 \(logString)") @@ -1025,7 +1039,6 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN newExternalNotificationConfig.nagTimeout = Int32(config.nagTimeout) newExternalNotificationConfig.useI2SAsBuzzer = config.useI2SAsBuzzer fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig - } else { fetchedNode[0].externalNotificationConfig?.enabled = config.enabled fetchedNode[0].externalNotificationConfig?.usePWM = config.usePwm @@ -1043,7 +1056,9 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN fetchedNode[0].externalNotificationConfig?.nagTimeout = Int32(config.nagTimeout) fetchedNode[0].externalNotificationConfig?.useI2SAsBuzzer = config.useI2SAsBuzzer } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [ExternalNotificationConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -1061,7 +1076,7 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN } } -func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.paxcounter.config %@".localized, String(nodeNum)) MeshLogger.log("🧑‍🤝‍🧑 \(logString)") @@ -1073,19 +1088,18 @@ func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, n let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save PAX Counter Config if !fetchedNode.isEmpty { - if fetchedNode[0].paxCounterConfig == nil { let newPaxCounterConfig = PaxCounterConfigEntity(context: context) newPaxCounterConfig.enabled = config.enabled newPaxCounterConfig.updateInterval = Int32(config.paxcounterUpdateInterval) - fetchedNode[0].paxCounterConfig = newPaxCounterConfig - } else { fetchedNode[0].paxCounterConfig?.enabled = config.enabled fetchedNode[0].paxCounterConfig?.updateInterval = Int32(config.paxcounterUpdateInterval) } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [PaxCounterConfigEntity] Updated for node number: \(nodeNum.toHex(), privacy: .public)") @@ -1103,7 +1117,7 @@ func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, n } } -func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.ringtone.config %@".localized, String(nodeNum)) MeshLogger.log("⛰️ \(logString)") @@ -1122,6 +1136,9 @@ func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, context: NSManage } else { fetchedNode[0].rtttlConfig?.ringtone = ringtone } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [RtttlConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -1139,7 +1156,7 @@ func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, context: NSManage } } -func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.mqtt.config %@".localized, String(nodeNum)) MeshLogger.log("🌉 \(logString)") @@ -1151,7 +1168,6 @@ func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int6 let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save MQTT Config if !fetchedNode.isEmpty { - if fetchedNode[0].mqttConfig == nil { let newMQTTConfig = MQTTConfigEntity(context: context) newMQTTConfig.enabled = config.enabled @@ -1181,6 +1197,9 @@ func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int6 fetchedNode[0].mqttConfig?.mapPositionPrecision = Int32(config.mapReportSettings.positionPrecision) fetchedNode[0].mqttConfig?.mapPublishIntervalSecs = Int32(config.mapReportSettings.publishIntervalSecs) } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [MQTTConfigEntity] Updated for node number: \(nodeNum.toHex(), privacy: .public)") @@ -1198,7 +1217,7 @@ func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int6 } } -func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.rangetest.config %@".localized, String(nodeNum)) MeshLogger.log("⛰️ \(logString)") @@ -1221,6 +1240,9 @@ func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nod fetchedNode[0].rangeTestConfig?.enabled = config.enabled fetchedNode[0].rangeTestConfig?.save = config.save } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [RangeTestConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -1238,7 +1260,7 @@ func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nod } } -func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.serial.config %@".localized, String(nodeNum)) MeshLogger.log("🤖 \(logString)") @@ -1250,9 +1272,7 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save Device Config if !fetchedNode.isEmpty { - if fetchedNode[0].serialConfig == nil { - let newSerialConfig = SerialConfigEntity(context: context) newSerialConfig.enabled = config.enabled newSerialConfig.echo = config.echo @@ -1262,7 +1282,6 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: newSerialConfig.timeout = Int32(config.timeout) newSerialConfig.mode = Int32(config.mode.rawValue) fetchedNode[0].serialConfig = newSerialConfig - } else { fetchedNode[0].serialConfig?.enabled = config.enabled fetchedNode[0].serialConfig?.echo = config.echo @@ -1272,7 +1291,9 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: fetchedNode[0].serialConfig?.timeout = Int32(config.timeout) fetchedNode[0].serialConfig?.mode = Int32(config.mode.rawValue) } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [SerialConfigEntity]Updated Serial Module Config for node: \(nodeNum.toHex(), privacy: .public)") @@ -1293,7 +1314,7 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: } } -func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.storeforward.config %@".localized, String(nodeNum)) MeshLogger.log("📬 \(logString)") @@ -1305,9 +1326,7 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save Store & Forward Sensor Config if !fetchedNode.isEmpty { - if fetchedNode[0].storeForwardConfig == nil { - let newConfig = StoreForwardConfigEntity(context: context) newConfig.enabled = config.enabled newConfig.heartbeat = config.heartbeat @@ -1315,7 +1334,6 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi newConfig.historyReturnMax = Int32(config.historyReturnMax) newConfig.historyReturnWindow = Int32(config.historyReturnWindow) fetchedNode[0].storeForwardConfig = newConfig - } else { fetchedNode[0].storeForwardConfig?.enabled = config.enabled fetchedNode[0].storeForwardConfig?.heartbeat = config.heartbeat @@ -1323,6 +1341,9 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi fetchedNode[0].storeForwardConfig?.historyReturnMax = Int32(config.historyReturnMax) fetchedNode[0].storeForwardConfig?.historyReturnWindow = Int32(config.historyReturnWindow) } + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [StoreForwardConfigEntity] Updated for node: \(nodeNum.toHex(), privacy: .public)") @@ -1340,21 +1361,18 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi } } -func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nodeNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat("mesh.log.telemetry.config %@".localized, String(nodeNum)) MeshLogger.log("📈 \(logString)") let fetchNodeInfoRequest = NodeInfoEntity.fetchRequest() fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) - do { let fetchedNode = try context.fetch(fetchNodeInfoRequest) // Found a node, save Telemetry Config if !fetchedNode.isEmpty { - if fetchedNode[0].telemetryConfig == nil { - let newTelemetryConfig = TelemetryConfigEntity(context: context) newTelemetryConfig.deviceUpdateInterval = Int32(config.deviceUpdateInterval) newTelemetryConfig.environmentUpdateInterval = Int32(config.environmentUpdateInterval) @@ -1365,7 +1383,6 @@ func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nod newTelemetryConfig.powerUpdateInterval = Int32(config.powerUpdateInterval) newTelemetryConfig.powerScreenEnabled = config.powerScreenEnabled fetchedNode[0].telemetryConfig = newTelemetryConfig - } else { fetchedNode[0].telemetryConfig?.deviceUpdateInterval = Int32(config.deviceUpdateInterval) fetchedNode[0].telemetryConfig?.environmentUpdateInterval = Int32(config.environmentUpdateInterval) @@ -1376,7 +1393,9 @@ func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nod fetchedNode[0].telemetryConfig?.powerUpdateInterval = Int32(config.powerUpdateInterval) fetchedNode[0].telemetryConfig?.powerScreenEnabled = config.powerScreenEnabled } - + if sessionPasskey != nil { + fetchedNode[0].sessionPasskey = sessionPasskey + } do { try context.save() Logger.data.info("💾 [TelemetryConfigEntity] Updated Telemetry Module Config for node: \(nodeNum.toHex(), privacy: .public)") From 45d4cb64f5a8cb7d8153831b96bb3eea3892a1f4 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 08:44:33 -0700 Subject: [PATCH 64/75] Allow saving of admin key --- Meshtastic/Views/Settings/Config/SecurityConfig.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index d031306b..642a8fb7 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -131,7 +131,7 @@ struct SecurityConfig: View { var config = Config.SecurityConfig() //config.publicKey = publicKey //config.privateKey = privateKey - //config.adminKey = adminKey + config.adminKey = Data(base64Encoded: adminKey) ?? Data() config.isManaged = isManaged config.serialEnabled = serialEnabled config.debugLogApiEnabled = debugLogApiEnabled From 9f5414159ba3db2ed59d5d0e0f35a93c08174061 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 08:53:59 -0700 Subject: [PATCH 65/75] Add timeout field for session passcode --- Meshtastic/Persistence/UpdateCoreData.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 009b9d20..98acc96b 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -424,6 +424,7 @@ func upsertBluetoothConfigPacket(config: Config.BluetoothConfig, nodeNum: Int64, } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -482,6 +483,7 @@ func upsertDeviceConfigPacket(config: Config.DeviceConfig, nodeNum: Int64, sessi } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -538,6 +540,7 @@ func upsertDisplayConfigPacket(config: Config.DisplayConfig, nodeNum: Int64, ses } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { @@ -613,6 +616,7 @@ func upsertLoRaConfigPacket(config: Config.LoRaConfig, nodeNum: Int64, sessionPa } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -658,6 +662,7 @@ func upsertNetworkConfigPacket(config: Config.NetworkConfig, nodeNum: Int64, ses } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -722,6 +727,7 @@ func upsertPositionConfigPacket(config: Config.PositionConfig, nodeNum: Int64, s } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -772,6 +778,7 @@ func upsertPowerConfigPacket(config: Config.PowerConfig, nodeNum: Int64, session } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -823,6 +830,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, s } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -876,6 +884,7 @@ func upsertAmbientLightingModuleConfigPacket(config: ModuleConfig.AmbientLightin } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -934,6 +943,7 @@ func upsertCannedMessagesModuleConfigPacket(config: ModuleConfig.CannedMessageCo } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -987,6 +997,7 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1058,6 +1069,7 @@ func upsertExternalNotificationModuleConfigPacket(config: ModuleConfig.ExternalN } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1099,6 +1111,7 @@ func upsertPaxCounterModuleConfigPacket(config: ModuleConfig.PaxcounterConfig, n } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1138,6 +1151,7 @@ func upsertRtttlConfigPacket(ringtone: String, nodeNum: Int64, sessionPasskey: D } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1199,6 +1213,7 @@ func upsertMqttModuleConfigPacket(config: ModuleConfig.MQTTConfig, nodeNum: Int6 } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1242,6 +1257,7 @@ func upsertRangeTestModuleConfigPacket(config: ModuleConfig.RangeTestConfig, nod } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1293,6 +1309,7 @@ func upsertSerialModuleConfigPacket(config: ModuleConfig.SerialConfig, nodeNum: } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1343,6 +1360,7 @@ func upsertStoreForwardModuleConfigPacket(config: ModuleConfig.StoreForwardConfi } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() @@ -1395,6 +1413,7 @@ func upsertTelemetryModuleConfigPacket(config: ModuleConfig.TelemetryConfig, nod } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } do { try context.save() From e44003907cc3472847463c68e65a982f690e842b Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 09:09:45 -0700 Subject: [PATCH 66/75] moor retry --- Meshtastic/Enums/RoutingError.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meshtastic/Enums/RoutingError.swift b/Meshtastic/Enums/RoutingError.swift index 3af6e9b2..108fedd2 100644 --- a/Meshtastic/Enums/RoutingError.swift +++ b/Meshtastic/Enums/RoutingError.swift @@ -81,9 +81,9 @@ enum RoutingError: Int, CaseIterable, Identifiable { case .noInterface: return true case .maxRetransmit: - return false + return true case .noChannel: - return false + return true case .tooLarge: return false case .noResponse: From 9b50626ebe0a3141180771becde45902b4754454 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 10:00:15 -0700 Subject: [PATCH 67/75] Clean up admin drop down --- .../CoreData/NodeInfoEntityExtension.swift | 9 +++++++++ .../Views/Settings/Config/SecurityConfig.swift | 3 +++ Meshtastic/Views/Settings/Settings.swift | 13 ++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index eb0086c7..c7a03e33 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -58,6 +58,15 @@ extension NodeInfoEntity { } return false } + + var canRemoteAdmin: Bool { + if !(securityConfig?.adminKey?.isEmpty ?? true) { + return true + } else { + let adminChannel = myInfo?.channels?.filter { ($0 as AnyObject).name?.lowercased() == "admin" } + return adminChannel?.count ?? 0 > 0 + } + } } public func createNodeInfo(num: Int64, context: NSManagedObjectContext) -> NodeInfoEntity { diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 642a8fb7..81672a15 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -120,6 +120,9 @@ struct SecurityConfig: View { .onChange(of: adminChannelEnabled) { if $0 != node?.securityConfig?.adminChannelEnabled { hasChanges = true } } + .onChange(of: adminKey) { _ in + hasChanges = true + } SaveConfigButton(node: node, hasChanges: $hasChanges) { guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context), diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 85aafd8f..3bf91f3c 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -348,13 +348,13 @@ struct Settings: View { if !(node?.deviceConfig?.isManaged ?? false) { if bleManager.connectedPeripheral != nil { Section("Configure") { - if hasAdmin { + if node?.canRemoteAdmin ?? false { Picker("Configuring Node", selection: $selectedNode) { if selectedNode == 0 { Text("Connect to a Node").tag(0) } - ForEach(nodes) { node in + /// Connected Node if node.num == bleManager.connectedPeripheral?.num ?? 0 { Label { Text("BLE: \(node.user?.longName ?? "unknown".localized)") @@ -362,7 +362,14 @@ struct Settings: View { Image(systemName: "antenna.radiowaves.left.and.right") } .tag(Int(node.num)) - } else if node.metadata != nil { + } else if node.canRemoteAdmin { /// Nodes using the new PKI system + Label { + Text("Remote: \(node.user?.longName ?? "unknown".localized)") + } icon: { + Image(systemName: "av.remote") + } + .tag(Int(node.num)) + } else if node.metadata != nil { /// Nodes using the old admin system Label { Text("Remote: \(node.user?.longName ?? "unknown".localized)") } icon: { From aad3bd4f891045887d87a7ab88b6b382ff722b57 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 11:39:41 -0700 Subject: [PATCH 68/75] Pass keys around better --- Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift | 2 +- Meshtastic/Views/Settings/Config/NetworkConfig.swift | 1 - Meshtastic/Views/Settings/Config/SecurityConfig.swift | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index c7a03e33..7c7a3e27 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -58,7 +58,7 @@ extension NodeInfoEntity { } return false } - + var canRemoteAdmin: Bool { if !(securityConfig?.adminKey?.isEmpty ?? true) { return true diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index 51981606..0554c766 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -133,7 +133,6 @@ struct NetworkConfig: View { } .onChange(of: wifiSsid) { newSSID in if newSSID != node?.networkConfig?.wifiSsid { hasChanges = true } - } .onChange(of: wifiPsk) { newPsk in if newPsk != node?.networkConfig?.wifiPsk { hasChanges = true } diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 81672a15..6e4c1168 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -132,8 +132,8 @@ struct SecurityConfig: View { } var config = Config.SecurityConfig() - //config.publicKey = publicKey - //config.privateKey = privateKey + config.publicKey = Data(base64Encoded: publicKey) ?? Data() + config.privateKey = Data(base64Encoded: privateKey) ?? Data() config.adminKey = Data(base64Encoded: adminKey) ?? Data() config.isManaged = isManaged config.serialEnabled = serialEnabled From 8b2bc246dd328d21eeb363af5524277f7ff7cdd7 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 11:43:42 -0700 Subject: [PATCH 69/75] Add change events for all keys --- Meshtastic/Views/Settings/Config/SecurityConfig.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 6e4c1168..94f3da04 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -120,6 +120,12 @@ struct SecurityConfig: View { .onChange(of: adminChannelEnabled) { if $0 != node?.securityConfig?.adminChannelEnabled { hasChanges = true } } + .onChange(of: publicKey) { _ in + hasChanges = true + } + .onChange(of: privateKey) { _ in + hasChanges = true + } .onChange(of: adminKey) { _ in hasChanges = true } From dee96175bf3fc12bb035c0794974305d59d8829d Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 17:15:55 -0700 Subject: [PATCH 70/75] Update admin drop down --- .../CoreData/NodeInfoEntityExtension.swift | 2 +- Meshtastic/Extensions/UserDefaults.swift | 4 +++ Meshtastic/Views/Settings/AppSettings.swift | 5 ++++ .../Views/Settings/SaveChannelQRCode.swift | 25 +++++++++---------- Meshtastic/Views/Settings/Settings.swift | 4 +-- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift index 7c7a3e27..07ee9117 100644 --- a/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/NodeInfoEntityExtension.swift @@ -60,7 +60,7 @@ extension NodeInfoEntity { } var canRemoteAdmin: Bool { - if !(securityConfig?.adminKey?.isEmpty ?? true) { + if UserDefaults.enableAdministration { return true } else { let adminChannel = myInfo?.channels?.filter { ($0 as AnyObject).name?.lowercased() == "admin" } diff --git a/Meshtastic/Extensions/UserDefaults.swift b/Meshtastic/Extensions/UserDefaults.swift index ca8441be..740f04e2 100644 --- a/Meshtastic/Extensions/UserDefaults.swift +++ b/Meshtastic/Extensions/UserDefaults.swift @@ -71,6 +71,7 @@ extension UserDefaults { case modemPreset case firmwareVersion case environmentEnableWeatherKit + case enableAdministration case testIntEnum } @@ -162,6 +163,9 @@ extension UserDefaults { @UserDefault(.environmentEnableWeatherKit, defaultValue: true) static var environmentEnableWeatherKit: Bool + @UserDefault(.enableAdministration, defaultValue: false) + static var enableAdministration: Bool + @UserDefault(.testIntEnum, defaultValue: .one) static var testIntEnum: TestIntEnum } diff --git a/Meshtastic/Views/Settings/AppSettings.swift b/Meshtastic/Views/Settings/AppSettings.swift index f9f46cbc..ef3bc384 100644 --- a/Meshtastic/Views/Settings/AppSettings.swift +++ b/Meshtastic/Views/Settings/AppSettings.swift @@ -13,6 +13,7 @@ struct AppSettings: View { @State private var isPresentingCoreDataResetConfirm = false @State private var isPresentingDeleteMapTilesConfirm = false @AppStorage("environmentEnableWeatherKit") private var environmentEnableWeatherKit: Bool = true + @AppStorage("enableAdministration") private var enableAdministration: Bool = false var body: some View { VStack { Form { @@ -23,6 +24,10 @@ struct AppSettings: View { UIApplication.shared.open(url) } } + Toggle(isOn: $enableAdministration) { + Label("Administration", systemImage: "gearshape.2") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) } Section(header: Text("environment")) { VStack(alignment: .leading) { diff --git a/Meshtastic/Views/Settings/SaveChannelQRCode.swift b/Meshtastic/Views/Settings/SaveChannelQRCode.swift index fee7877b..ac8138fa 100644 --- a/Meshtastic/Views/Settings/SaveChannelQRCode.swift +++ b/Meshtastic/Views/Settings/SaveChannelQRCode.swift @@ -50,6 +50,18 @@ struct SaveChannelQRCode: View { .controlSize(.large) .padding() .disabled(!connectedToDevice) +#if targetEnvironment(macCatalyst) + Button { + dismiss() + } label: { + Label("cancel", systemImage: "xmark") + + } + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() +#endif } else { Button { dismiss() @@ -62,19 +74,6 @@ struct SaveChannelQRCode: View { .controlSize(.large) .padding() } - - #if targetEnvironment(macCatalyst) - Button { - dismiss() - } label: { - Label("cancel", systemImage: "xmark") - - } - .buttonStyle(.bordered) - .buttonBorderShape(.capsule) - .controlSize(.large) - .padding() - #endif } } .onAppear { diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 3bf91f3c..510e56d3 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -362,7 +362,7 @@ struct Settings: View { Image(systemName: "antenna.radiowaves.left.and.right") } .tag(Int(node.num)) - } else if node.canRemoteAdmin { /// Nodes using the new PKI system + } else if node.canRemoteAdmin && UserDefaults.enableAdministration && node.sessionPasskey != nil { /// Nodes using the new PKI system Label { Text("Remote: \(node.user?.longName ?? "unknown".localized)") } icon: { @@ -376,7 +376,7 @@ struct Settings: View { Image(systemName: "av.remote") } .tag(Int(node.num)) - } else if hasAdmin { + } else if hasAdmin || node.user?.pkiEncrypted ?? false { Label { Text("Request Admin: \(node.user?.longName ?? "unknown".localized)") } icon: { From 758ab6315a04b15457161cda50955a3b1538d7b0 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sun, 18 Aug 2024 17:38:13 -0700 Subject: [PATCH 71/75] allow request metadata for all unmanaged nodes --- Meshtastic/Views/Settings/Settings.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 510e56d3..7bc3643c 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -343,8 +343,6 @@ struct Settings: View { } } - let hasAdmin = node?.myInfo?.adminIndex ?? 0 > 0 - if !(node?.deviceConfig?.isManaged ?? false) { if bleManager.connectedPeripheral != nil { Section("Configure") { @@ -376,7 +374,7 @@ struct Settings: View { Image(systemName: "av.remote") } .tag(Int(node.num)) - } else if hasAdmin || node.user?.pkiEncrypted ?? false { + } else { Label { Text("Request Admin: \(node.user?.longName ?? "unknown".localized)") } icon: { From 10157ed5477704da2caff8f884c90cc9548e3945 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 19 Aug 2024 00:27:26 -0700 Subject: [PATCH 72/75] Update admin node list sort to be less infurating --- Meshtastic/Helpers/BLEManager.swift | 32 +++++++++++++++++++ .../Settings/Config/SecurityConfig.swift | 9 ++++++ Meshtastic/Views/Settings/Settings.swift | 2 ++ 3 files changed, 43 insertions(+) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 49e43d54..4280533a 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -2766,6 +2766,38 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate return false } + public func requestSecurityConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool { + + var adminPacket = AdminMessage() + adminPacket.getConfigRequest = AdminMessage.ConfigType.securityConfig + if fromUser != toUser { + adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() + } + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { var adminPacket = AdminMessage() diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 94f3da04..caf64e57 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -129,6 +129,15 @@ struct SecurityConfig: View { .onChange(of: adminKey) { _ in hasChanges = true } + .onFirstAppear { + // Need to request a Power config from the remote node before allowing changes + if bleManager.connectedPeripheral != nil && node?.securityConfig == nil { + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? 0, context: context) + if node != nil && connectedNode != nil { + _ = bleManager.requestSecurityConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) + } + } + } SaveConfigButton(node: node, hasChanges: $hasChanges) { guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context), diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 7bc3643c..b28cdd21 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -17,6 +17,8 @@ struct Settings: View { @FetchRequest( sortDescriptors: [ NSSortDescriptor(key: "favorite", ascending: false), + NSSortDescriptor(key: "user.pkiEncrypted", ascending: false), + NSSortDescriptor(key: "viaMqtt", ascending: true), NSSortDescriptor(key: "user.longName", ascending: true) ], animation: .default From 0ff613ec68d93f42ce6053163a07b656fad3ed5e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 19 Aug 2024 09:30:21 -0700 Subject: [PATCH 73/75] dont send session passkey with requests --- Meshtastic/Helpers/BLEManager.swift | 64 +---------------------------- 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 4280533a..326f7966 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -392,9 +392,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var adminPacket = AdminMessage() adminPacket.getDeviceMetadataRequest = true - if fromUser != toUser { - adminPacket.sessionPasskey = toUser.userNode?.sessionPasskey ?? Data() - } var meshPacket: MeshPacket = MeshPacket() meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Date: Mon, 19 Aug 2024 12:30:26 -0700 Subject: [PATCH 74/75] Agressive metadata requests --- Localizable.xcstrings | 6 ++++++ Meshtastic/Helpers/MeshPackets.swift | 10 +++++++--- Meshtastic/Persistence/UpdateCoreData.swift | 2 +- Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift | 6 ++++++ Meshtastic/Views/Settings/Settings.swift | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 21466cc5..b9858fe8 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -22561,6 +22561,12 @@ }, "WIND" : { + }, + "Wind Direction" : { + + }, + "Wind Speed" : { + }, "x" : { diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 87ada50b..d3bef97a 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -198,7 +198,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo } } -func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) { +func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, sessionPasskey: Data? = Data(), context: NSManagedObjectContext) { if metadata.isInitialized { let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, fromNum.toHex()) @@ -232,6 +232,10 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS newNode.metadata = newMetadata } } + if sessionPasskey?.count != 0 { + fetchedNode[0].sessionPasskey = sessionPasskey + fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) + } do { try context.save() } catch { @@ -488,7 +492,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getChannelResponse(adminMessage.getChannelResponse) { channelPacket(channel: adminMessage.getChannelResponse, fromNum: Int64(packet.from), context: context) } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getDeviceMetadataResponse(adminMessage.getDeviceMetadataResponse) { - deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context) + deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), sessionPasskey: adminMessage.sessionPasskey, context: context) } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) { let config = adminMessage.getConfigResponse if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { @@ -506,7 +510,7 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { } else if config.payloadVariant == Config.OneOf_PayloadVariant.power(config.power) { upsertPowerConfigPacket(config: config.power, nodeNum: Int64(packet.from), context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.security(config.security) { - upsertSecurityConfigPacket(config: config.security, nodeNum: Int64(packet.from), context: context) + upsertSecurityConfigPacket(config: config.security, nodeNum: Int64(packet.from), sessionPasskey: adminMessage.sessionPasskey, context: context) } } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) { let moduleConfig = adminMessage.getModuleConfigResponse diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 98acc96b..6f2520ee 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -828,7 +828,7 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, s fetchedNode[0].securityConfig?.debugLogApiEnabled = config.debugLogApiEnabled fetchedNode[0].securityConfig?.bluetoothLoggingEnabled = config.bluetoothLoggingEnabled } - if sessionPasskey != nil { + if sessionPasskey?.count != 0 { fetchedNode[0].sessionPasskey = sessionPasskey fetchedNode[0].sessionExpiration = Date().addingTimeInterval(300) } diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index f0d2dd04..571511cf 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -93,6 +93,12 @@ struct EnvironmentMetricsLog: View { IndoorAirQuality(iaq: Int(em.iaq), displayMode: IaqDisplayMode.dot ) } } + TableColumn("Wind Speed") { em in + Text("\(String(format: "%.1f", em.windSpeed)) hPa") + } + TableColumn("Wind Direction") { em in + Text("\(String(format: "%.1f", em.windDirection)) hPa") + } TableColumn("timestamp") { em in Text(em.time?.formattedDate(format: dateFormatString) ?? "unknown.age".localized) } diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index b28cdd21..4bf75555 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -393,7 +393,7 @@ struct Settings: View { let node = nodes.first(where: { $0.num == newValue }) let connectedNode = nodes.first(where: { $0.num == preferredNodeNum }) preferredNodeNum = Int(connectedNode?.num ?? 0)// Int(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral?.num ?? 0 : 0) - if connectedNode != nil && connectedNode?.user != nil && connectedNode?.myInfo != nil && node?.user != 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 { Logger.mesh.info("Sent node metadata request from node details") From 5852aa31f5142133597d6885febd81af80888607 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 19 Aug 2024 15:06:53 -0700 Subject: [PATCH 75/75] Admin drop down updates to redice the number of nodes. --- Localizable.xcstrings | 10 ++++++++-- Meshtastic/Views/Settings/Settings.swift | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Localizable.xcstrings b/Localizable.xcstrings index b9858fe8..c518a26f 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -17261,7 +17261,10 @@ "Remote administration for: %@" : { }, - "Remote: %@" : { + "Remote Legacy Admin: %@" : { + + }, + "Remote PKI Admin: %@" : { }, "Remove" : { @@ -17331,7 +17334,10 @@ } } }, - "Request Admin: %@" : { + "Request Legacy Admin: %@" : { + + }, + "Request PKI Admin: %@" : { }, "Requires that there be an accelerometer on your device." : { diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 4bf75555..814f3ab9 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -364,21 +364,28 @@ struct Settings: View { .tag(Int(node.num)) } else if node.canRemoteAdmin && UserDefaults.enableAdministration && node.sessionPasskey != nil { /// Nodes using the new PKI system Label { - Text("Remote: \(node.user?.longName ?? "unknown".localized)") + Text("Remote PKI Admin: \(node.user?.longName ?? "unknown".localized)") } icon: { Image(systemName: "av.remote") } .tag(Int(node.num)) - } else if node.metadata != nil { /// Nodes using the old admin system + } else if !UserDefaults.enableAdministration && node.metadata != nil { /// Nodes using the old admin system Label { - Text("Remote: \(node.user?.longName ?? "unknown".localized)") + Text("Remote Legacy Admin: \(node.user?.longName ?? "unknown".localized)") } icon: { Image(systemName: "av.remote") } .tag(Int(node.num)) - } else { + } else if UserDefaults.enableAdministration && node.user?.pkiEncrypted ?? false { Label { - Text("Request Admin: \(node.user?.longName ?? "unknown".localized)") + Text("Request PKI Admin: \(node.user?.longName ?? "unknown".localized)") + } icon: { + Image(systemName: "rectangle.and.hand.point.up.left") + } + .tag(Int(node.num)) + } else if !UserDefaults.enableAdministration { + Label { + Text("Request Legacy Admin: \(node.user?.longName ?? "unknown".localized)") } icon: { Image(systemName: "rectangle.and.hand.point.up.left") }