From 2cb61a30228a2dd5a9204012bd37d4e97f4cc294 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 26 Oct 2022 13:53:35 -0700 Subject: [PATCH 1/3] proto updates --- Meshtastic/Protobufs/config.pb.swift | 184 ++++++++++++++++++--------- 1 file changed, 123 insertions(+), 61 deletions(-) diff --git a/Meshtastic/Protobufs/config.pb.swift b/Meshtastic/Protobufs/config.pb.swift index 0d7d062e..22774a27 100644 --- a/Meshtastic/Protobufs/config.pb.swift +++ b/Meshtastic/Protobufs/config.pb.swift @@ -435,39 +435,57 @@ struct Config { /// /// Enable WiFi (disables Bluetooth) - var wifiEnabled: Bool = false + var wifiEnabled: Bool { + get {return _storage._wifiEnabled} + set {_uniqueStorage()._wifiEnabled = newValue} + } /// /// If set, this node will try to join the specified wifi network and /// acquire an address via DHCP - var wifiSsid: String = String() + var wifiSsid: String { + get {return _storage._wifiSsid} + set {_uniqueStorage()._wifiSsid = newValue} + } /// /// If set, will be use to authenticate to the named wifi - var wifiPsk: String = String() + var wifiPsk: String { + get {return _storage._wifiPsk} + set {_uniqueStorage()._wifiPsk = newValue} + } /// /// NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org` - var ntpServer: String = String() + var ntpServer: String { + get {return _storage._ntpServer} + set {_uniqueStorage()._ntpServer = newValue} + } /// /// Enable Ethernet - var ethEnabled: Bool = false + var ethEnabled: Bool { + get {return _storage._ethEnabled} + set {_uniqueStorage()._ethEnabled = newValue} + } /// /// acquire an address via DHCP or assign static - var ethMode: Config.NetworkConfig.EthMode = .dhcp + var ethMode: Config.NetworkConfig.EthMode { + get {return _storage._ethMode} + set {_uniqueStorage()._ethMode = newValue} + } /// /// struct to keep static address - var ethConfig: Config.NetworkConfig.NetworkConfig { - get {return _ethConfig ?? Config.NetworkConfig.NetworkConfig()} - set {_ethConfig = newValue} + var ethConfig: Config.NetworkConfig { + get {return _storage._ethConfig ?? Config.NetworkConfig()} + set {_uniqueStorage()._ethConfig = newValue} } /// Returns true if `ethConfig` has been explicitly set. - var hasEthConfig: Bool {return self._ethConfig != nil} + var hasEthConfig: Bool {return _storage._ethConfig != nil} /// Clears the value of `ethConfig`. Subsequent reads from it will return its default value. - mutating func clearEthConfig() {self._ethConfig = nil} + mutating func clearEthConfig() {_uniqueStorage()._ethConfig = nil} var unknownFields = SwiftProtobuf.UnknownStorage() @@ -545,7 +563,7 @@ struct Config { } - struct NetworkConfig { + struct TcpConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -573,7 +591,7 @@ struct Config { init() {} - fileprivate var _ethConfig: Config.NetworkConfig.NetworkConfig? = nil + fileprivate var _storage = _StorageClass.defaultInstance } /// @@ -1161,7 +1179,7 @@ extension Config.PowerConfig: @unchecked Sendable {} extension Config.NetworkConfig: @unchecked Sendable {} extension Config.NetworkConfig.WiFiMode: @unchecked Sendable {} extension Config.NetworkConfig.EthMode: @unchecked Sendable {} -extension Config.NetworkConfig.NetworkConfig: @unchecked Sendable {} +extension Config.NetworkConfig.TcpConfig: @unchecked Sendable {} extension Config.DisplayConfig: @unchecked Sendable {} extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} @@ -1557,61 +1575,105 @@ extension Config.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp 8: .standard(proto: "eth_config"), ] + fileprivate class _StorageClass { + var _wifiEnabled: Bool = false + var _wifiSsid: String = String() + var _wifiPsk: String = String() + var _ntpServer: String = String() + var _ethEnabled: Bool = false + var _ethMode: Config.NetworkConfig.EthMode = .dhcp + var _ethConfig: Config.NetworkConfig? = nil + + static let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _wifiEnabled = source._wifiEnabled + _wifiSsid = source._wifiSsid + _wifiPsk = source._wifiPsk + _ntpServer = source._ntpServer + _ethEnabled = source._ethEnabled + _ethMode = source._ethMode + _ethConfig = source._ethConfig + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + 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.decodeSingularBoolField(value: &self.wifiEnabled) }() - case 3: try { try decoder.decodeSingularStringField(value: &self.wifiSsid) }() - case 4: try { try decoder.decodeSingularStringField(value: &self.wifiPsk) }() - case 5: try { try decoder.decodeSingularStringField(value: &self.ntpServer) }() - case 6: try { try decoder.decodeSingularBoolField(value: &self.ethEnabled) }() - case 7: try { try decoder.decodeSingularEnumField(value: &self.ethMode) }() - case 8: try { try decoder.decodeSingularMessageField(value: &self._ethConfig) }() - default: break + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularBoolField(value: &_storage._wifiEnabled) }() + case 3: try { try decoder.decodeSingularStringField(value: &_storage._wifiSsid) }() + case 4: try { try decoder.decodeSingularStringField(value: &_storage._wifiPsk) }() + case 5: try { try decoder.decodeSingularStringField(value: &_storage._ntpServer) }() + case 6: try { try decoder.decodeSingularBoolField(value: &_storage._ethEnabled) }() + case 7: try { try decoder.decodeSingularEnumField(value: &_storage._ethMode) }() + case 8: try { try decoder.decodeSingularMessageField(value: &_storage._ethConfig) }() + default: break + } } } } func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if self.wifiEnabled != false { - try visitor.visitSingularBoolField(value: self.wifiEnabled, fieldNumber: 1) + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if _storage._wifiEnabled != false { + try visitor.visitSingularBoolField(value: _storage._wifiEnabled, fieldNumber: 1) + } + if !_storage._wifiSsid.isEmpty { + try visitor.visitSingularStringField(value: _storage._wifiSsid, fieldNumber: 3) + } + if !_storage._wifiPsk.isEmpty { + try visitor.visitSingularStringField(value: _storage._wifiPsk, fieldNumber: 4) + } + if !_storage._ntpServer.isEmpty { + try visitor.visitSingularStringField(value: _storage._ntpServer, fieldNumber: 5) + } + if _storage._ethEnabled != false { + try visitor.visitSingularBoolField(value: _storage._ethEnabled, fieldNumber: 6) + } + if _storage._ethMode != .dhcp { + try visitor.visitSingularEnumField(value: _storage._ethMode, fieldNumber: 7) + } + try { if let v = _storage._ethConfig { + try visitor.visitSingularMessageField(value: v, fieldNumber: 8) + } }() } - if !self.wifiSsid.isEmpty { - try visitor.visitSingularStringField(value: self.wifiSsid, fieldNumber: 3) - } - if !self.wifiPsk.isEmpty { - try visitor.visitSingularStringField(value: self.wifiPsk, fieldNumber: 4) - } - if !self.ntpServer.isEmpty { - try visitor.visitSingularStringField(value: self.ntpServer, fieldNumber: 5) - } - if self.ethEnabled != false { - try visitor.visitSingularBoolField(value: self.ethEnabled, fieldNumber: 6) - } - if self.ethMode != .dhcp { - try visitor.visitSingularEnumField(value: self.ethMode, fieldNumber: 7) - } - try { if let v = self._ethConfig { - try visitor.visitSingularMessageField(value: v, fieldNumber: 8) - } }() try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: Config.NetworkConfig, rhs: Config.NetworkConfig) -> Bool { - if lhs.wifiEnabled != rhs.wifiEnabled {return false} - if lhs.wifiSsid != rhs.wifiSsid {return false} - if lhs.wifiPsk != rhs.wifiPsk {return false} - if lhs.ntpServer != rhs.ntpServer {return false} - if lhs.ethEnabled != rhs.ethEnabled {return false} - if lhs.ethMode != rhs.ethMode {return false} - if lhs._ethConfig != rhs._ethConfig {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._wifiEnabled != rhs_storage._wifiEnabled {return false} + if _storage._wifiSsid != rhs_storage._wifiSsid {return false} + if _storage._wifiPsk != rhs_storage._wifiPsk {return false} + if _storage._ntpServer != rhs_storage._ntpServer {return false} + if _storage._ethEnabled != rhs_storage._ethEnabled {return false} + if _storage._ethMode != rhs_storage._ethMode {return false} + if _storage._ethConfig != rhs_storage._ethConfig {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -1632,8 +1694,8 @@ extension Config.NetworkConfig.EthMode: SwiftProtobuf._ProtoNameProviding { ] } -extension Config.NetworkConfig.NetworkConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = Config.NetworkConfig.protoMessageName + ".NetworkConfig" +extension Config.NetworkConfig.TcpConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = Config.NetworkConfig.protoMessageName + ".TcpConfig" static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "ip"), 2: .same(proto: "gateway"), @@ -1672,7 +1734,7 @@ extension Config.NetworkConfig.NetworkConfig: SwiftProtobuf.Message, SwiftProtob try unknownFields.traverse(visitor: &visitor) } - static func ==(lhs: Config.NetworkConfig.NetworkConfig, rhs: Config.NetworkConfig.NetworkConfig) -> Bool { + static func ==(lhs: Config.NetworkConfig.TcpConfig, rhs: Config.NetworkConfig.TcpConfig) -> Bool { if lhs.ip != rhs.ip {return false} if lhs.gateway != rhs.gateway {return false} if lhs.subnet != rhs.subnet {return false} From 45944ba61e4fc678c7af1cc33bac2eb1ced5c6ed Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 28 Oct 2022 05:45:44 -0700 Subject: [PATCH 2/3] Handle packets from other networks --- Meshtastic/Helpers/BLEManager.swift | 2 +- Meshtastic/Helpers/MeshPackets.swift | 6 ++++++ .../MeshtasticDataModel.xcdatamodel/contents | 3 ++- Meshtastic/Views/Nodes/PositionLog.swift | 10 +++++----- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index c044a005..fb492afd 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1105,7 +1105,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. - + @@ -77,6 +77,7 @@ + diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index 0b7fd7b7..87cec4a2 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -26,10 +26,10 @@ struct PositionLog: View { //Add a table for mac and ipad VStack { Table(node.positions!.reversed() as! [PositionEntity]) { - TableColumn("SeqNo") { position in + TableColumn("Seq No") { position in Text(String(position.seqNo)) } - .width(75) + //.width(75) TableColumn("Latitude") { position in Text(String(format: "%.6f", position.latitude ?? 0)) } @@ -39,15 +39,15 @@ struct PositionLog: View { TableColumn("Altitude") { position in Text(String(position.altitude)) } - .width(75) + //.width(75) TableColumn("Sats") { position in Text(String(position.satsInView)) } - .width(75) + //.width(75) TableColumn("Speed") { position in Text(String(position.speed)) } - .width(75) + //.width(75) TableColumn("Heading") { position in Text(String(position.heading)) } From b03881798ac268ee1814407d34661187385c03c1 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Fri, 28 Oct 2022 09:02:37 -0700 Subject: [PATCH 3/3] Channel cleanup --- Meshtastic/Helpers/BLEManager.swift | 43 +++++++++++++------ Meshtastic/Helpers/MeshPackets.swift | 10 ++--- Meshtastic/Views/Settings/ShareChannels.swift | 14 +++--- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index fb492afd..c6842e33 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1054,22 +1054,44 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph public func saveChannelSet(base64UrlString: String) -> Bool { if isConnected { - var decodedString = base64UrlString.base64urlToBase64() + + //Before we get started delete the existing channels from the myNodeInfo + let fetchMyInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "MyInfoEntity") + fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedPeripheral.num)) + + do { + let fetchedMyInfo = try context!.fetch(fetchMyInfoRequest) as! [MyInfoEntity] + if fetchedMyInfo.count == 1 { + + let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as! NSMutableOrderedSet + mutableChannels.removeAllObjects() + fetchedMyInfo[0].channels = mutableChannels + fetchedMyInfo[0].objectWillChange.send() + do { + try context!.save() + + } catch { + print("Failed to clear existing channels from local app database") + } + } + + } catch { + + } + + + let decodedString = base64UrlString.base64urlToBase64() if let decodedData = Data(base64Encoded: decodedString) { do { var channelSet: ChannelSet = try ChannelSet(serializedData: decodedData) print(channelSet) var i:Int32 = 0 for cs in channelSet.settings { - i += 1 var chan = Channel() + i += 1 chan.settings = cs chan.index = i - if i == 1 { - chan.role = Channel.Role.primary - } else { - chan.role = Channel.Role.secondary - } + var adminPacket = AdminMessage() adminPacket.setChannel = chan var meshPacket: MeshPacket = MeshPacket() @@ -1088,12 +1110,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph toRadio.packet = meshPacket let binaryData: Data = try! toRadio.serializedData() if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { - //let timer1 = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { timer in self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse) MeshLogger.log("💾 Saved a Channel for: \(String(self.connectedPeripheral.num))") - //} } - print(chan) } // Save the LoRa Config and the device will reboot var adminPacket = AdminMessage() @@ -1118,10 +1137,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph toRadio.packet = meshPacket let binaryData: Data = try! toRadio.serializedData() if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { - // let timer1 = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in - self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse) + self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse) MeshLogger.log("💾 Saved a LoRaConfig for: \(String(self.connectedPeripheral.num))") - // } } return true diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index b82804c7..21a9ccaf 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -752,7 +752,7 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) { - if channel.isInitialized && channel.hasSettings { + if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled { let fetchedMyInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "MyInfoEntity") fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum) @@ -770,13 +770,11 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo newChannel.name = channel.settings.name newChannel.role = Int32(channel.role.rawValue) newChannel.psk = channel.settings.psk - let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as! NSMutableOrderedSet -// if channel.role.rawValue == 1 { -// mutableChannels.removeAllObjects() -// } - + if channel.index == 1 { + //mutableChannels.removeAllObjects() + } mutableChannels.add(newChannel) fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet diff --git a/Meshtastic/Views/Settings/ShareChannels.swift b/Meshtastic/Views/Settings/ShareChannels.swift index dc9d3eb8..413f3197 100644 --- a/Meshtastic/Views/Settings/ShareChannels.swift +++ b/Meshtastic/Views/Settings/ShareChannels.swift @@ -90,7 +90,7 @@ struct ShareChannels: View { Toggle("Channel 1 Included", isOn: $includeChannel1) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -103,7 +103,7 @@ struct ShareChannels: View { Toggle("Channel 2 Included", isOn: $includeChannel2) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -116,7 +116,7 @@ struct ShareChannels: View { Toggle("Channel 3 Included", isOn: $includeChannel3) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -129,7 +129,7 @@ struct ShareChannels: View { Toggle("Channel 4 Included", isOn: $includeChannel4) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -142,7 +142,7 @@ struct ShareChannels: View { Toggle("Channel 5 Included", isOn: $includeChannel5) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -155,7 +155,7 @@ struct ShareChannels: View { Toggle("Channel 6 Included", isOn: $includeChannel6) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash") @@ -168,7 +168,7 @@ struct ShareChannels: View { Toggle("Channel 7 Included", isOn: $includeChannel7) .toggleStyle(.switch) .labelsHidden() - .disabled(channel.role == 0) + .disabled(channel.role == 1) Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)") if channel.psk?.hexDescription.count ?? 0 < 3 { Image(systemName: "lock.slash")