diff --git a/Meshtastic Apple.xcodeproj/project.pbxproj b/Meshtastic Apple.xcodeproj/project.pbxproj index 2d2a36f9..edbac879 100644 --- a/Meshtastic Apple.xcodeproj/project.pbxproj +++ b/Meshtastic Apple.xcodeproj/project.pbxproj @@ -117,6 +117,7 @@ DD4DED8F27AD2975004BA27E /* cannedmessages.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = cannedmessages.pb.swift; sourceTree = ""; }; DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = ""; }; DD539501276DAA6A00AD86B1 /* MapLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLocation.swift; sourceTree = ""; }; + DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 4.xcdatamodel"; sourceTree = ""; }; DD6B85A728009258000ACD6B /* ShareChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannel.swift; sourceTree = ""; }; DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = ""; }; DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = ""; }; @@ -809,7 +810,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.19; + MARKETING_VERSION = 1.3.20; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -840,7 +841,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.3.19; + MARKETING_VERSION = 1.3.20; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1013,11 +1014,12 @@ DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */, DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */, DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */, DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */, ); - currentVersion = DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */; + currentVersion = DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = MeshtasticApple/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/MeshtasticApple/Helpers/BLEManager.swift b/MeshtasticApple/Helpers/BLEManager.swift index 1d897de1..d442b3a0 100644 --- a/MeshtasticApple/Helpers/BLEManager.swift +++ b/MeshtasticApple/Helpers/BLEManager.swift @@ -179,7 +179,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph peripheralName = name } - let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: String(peripheralName.suffix(3)), longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral) + let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: last4Code, longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), subscribed: false, peripheral: peripheral) let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id }) if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected { @@ -409,6 +409,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph lastConnnectionVersion = myInfo?.firmwareVersion ?? myInfo!.firmwareVersion ?? "Unknown" self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown" self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown" + } } else if decodedInfo.nodeInfo.num != 0 { @@ -425,17 +426,22 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if nodeInfo!.user != nil { connectedPeripheral.name = nodeInfo!.user!.longName ?? "Unknown" + connectedPeripheral.shortName = nodeInfo!.user!.shortName ?? "?????" + connectedPeripheral.longName = nodeInfo!.user!.longName ?? "Unknown" } } } - } else if decodedInfo.config.version == 13 { + } else if decodedInfo.config.isInitialized { - localConfig(config: decodedInfo.config, meshlogging: meshLoggingEnabled, context: context!, nodeLongName: self.connectedPeripheral.longName) + localConfig(config: decodedInfo.config, meshlogging: meshLoggingEnabled, context: context!, nodeNum: self.connectedPeripheral.num, nodeLongName: self.connectedPeripheral.longName) } else { - if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Unknown App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + if decodedInfo.configCompleteID == 0 { + + if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Unknown App UNHANDLED \(try! decodedInfo.packet.jsonString())") } + } } case .textMessageApp: textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) @@ -805,26 +811,60 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph return false } - public func getConfig(destNum: Int64, wantResponse: Bool) -> Bool { + public func sendFactoryReset(destNum: Int64, wantResponse: Bool) -> Bool { + + var deviceConfig = Config.DeviceConfig() + deviceConfig.factoryReset = true var adminPacket = AdminMessage() - adminPacket.getConfigRequest = AdminMessage.ConfigType.deviceConfig - - adminPacket.variant = AdminMessage.OneOf_Variant.getConfigRequest(AdminMessage.ConfigType.loraConfig) - + adminPacket.setConfig.device = deviceConfig var meshPacket: MeshPacket = MeshPacket() meshPacket.to = UInt32(connectedPeripheral.num) - meshPacket.from = UInt32(connectedPeripheral.num) + meshPacket.from = 0 //UInt32(connectedPeripheral.num) meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { + + var adminPacket = AdminMessage() + adminPacket.setConfig.lora = config + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(connectedPeripheral.num) + meshPacket.from = 0 //UInt32(connectedPeripheral.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) - } else { - - print("🖥️ Has Display config") - } - - if (try! config.lora.jsonString()) == "{}" { - - print("📡 Default LoRa config") - - } else { - - print("📡 Has LoRa config") - } - - if (try! config.position.jsonString()) == "{}" { - - print("📍 Default Position config") - - } else { - - print("📍 Has Position config") + do { + + let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity] + // Found a node, save LoRa Config + if !fetchedNode.isEmpty { + + if fetchedNode[0].loRaConfig == nil { + + let newLoRaConfig = LoRaConfigEntity(context: context) + + if isDefault { + + // UNSET default protobuf value of 0 + newLoRaConfig.regionCode = 0 + // LongFast default protobuf value of 0 + newLoRaConfig.modemPreset = 0 + // 3 Hops default protobuf value of 0 + newLoRaConfig.hopLimit = 0 + } else { + + // UNSET default protobuf value of 0 + newLoRaConfig.regionCode = Int32(config.lora.region.rawValue) + // LongFast default protobuf value of 0 + newLoRaConfig.modemPreset = Int32(config.lora.modemPreset.rawValue) + // 3 Hops default protobuf value of 0 + newLoRaConfig.hopLimit = Int32(config.lora.hopLimit) + } + + fetchedNode[0].loRaConfig = newLoRaConfig + + } else { + + if isDefault { + + // UNSET default protobuf value of 0 + fetchedNode[0].loRaConfig?.regionCode = 0 + // LongFast default protobuf value of 0 + fetchedNode[0].loRaConfig?.modemPreset = 0 + // 3 Hops default protobuf value of 0 + fetchedNode[0].loRaConfig?.hopLimit = 0 + + } else { + // UNSET default protobuf value of 0 + fetchedNode[0].loRaConfig?.regionCode = Int32(config.lora.region.rawValue) + // LongFast default protobuf value of 0 + fetchedNode[0].loRaConfig?.modemPreset = Int32(config.lora.modemPreset.rawValue) + // 3 Hops default protobuf value of 0 + fetchedNode[0].loRaConfig?.hopLimit = Int32(config.lora.hopLimit) + } + } + + do { + + try context.save() + if meshlogging { MeshLogger.log("💾 Updated LoRaConfig for node number: \(String(nodeNum))") } + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Updating Core Data MyInfoEntity: \(nsError)") + } + } + + } catch { + + } } } diff --git a/MeshtasticApple/Meshtastic.xcdatamodeld/.xccurrentversion b/MeshtasticApple/Meshtastic.xcdatamodeld/.xccurrentversion index 0ef73013..5d3a865e 100644 --- a/MeshtasticApple/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/MeshtasticApple/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModel v 3.xcdatamodel + MeshtasticDataModel v 4.xcdatamodel diff --git a/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents b/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents index 7d5d50e1..2be97c35 100644 --- a/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents +++ b/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 3.xcdatamodel/contents @@ -1,10 +1,5 @@ - - - - - @@ -104,6 +99,5 @@ - \ No newline at end of file diff --git a/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents b/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents new file mode 100644 index 00000000..3039ae3b --- /dev/null +++ b/MeshtasticApple/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MeshtasticApple/Protobufs/config.pb.swift b/MeshtasticApple/Protobufs/config.pb.swift index f4ab0e9d..b93e2a68 100644 --- a/MeshtasticApple/Protobufs/config.pb.swift +++ b/MeshtasticApple/Protobufs/config.pb.swift @@ -26,11 +26,9 @@ struct Config { // methods supported on all messages. /// - /// TODO: REPLACE + /// Payload Variant var payloadVariant: Config.OneOf_PayloadVariant? = nil - /// - /// TODO: REPLACE var device: Config.DeviceConfig { get { if case .device(let v)? = payloadVariant {return v} @@ -39,8 +37,6 @@ struct Config { set {payloadVariant = .device(newValue)} } - /// - /// TODO: REPLACE var position: Config.PositionConfig { get { if case .position(let v)? = payloadVariant {return v} @@ -49,8 +45,6 @@ struct Config { set {payloadVariant = .position(newValue)} } - /// - /// TODO: REPLACE var power: Config.PowerConfig { get { if case .power(let v)? = payloadVariant {return v} @@ -59,8 +53,6 @@ struct Config { set {payloadVariant = .power(newValue)} } - /// - /// TODO: REPLACE var wifi: Config.WiFiConfig { get { if case .wifi(let v)? = payloadVariant {return v} @@ -69,8 +61,6 @@ struct Config { set {payloadVariant = .wifi(newValue)} } - /// - /// TODO: REPLACE var display: Config.DisplayConfig { get { if case .display(let v)? = payloadVariant {return v} @@ -79,8 +69,6 @@ struct Config { set {payloadVariant = .display(newValue)} } - /// - /// TODO: REPLACE var lora: Config.LoRaConfig { get { if case .lora(let v)? = payloadVariant {return v} @@ -92,25 +80,13 @@ struct Config { var unknownFields = SwiftProtobuf.UnknownStorage() /// - /// TODO: REPLACE + /// Payload Variant enum OneOf_PayloadVariant: Equatable { - /// - /// TODO: REPLACE case device(Config.DeviceConfig) - /// - /// TODO: REPLACE case position(Config.PositionConfig) - /// - /// TODO: REPLACE case power(Config.PowerConfig) - /// - /// TODO: REPLACE case wifi(Config.WiFiConfig) - /// - /// TODO: REPLACE case display(Config.DisplayConfig) - /// - /// TODO: REPLACE case lora(Config.LoRaConfig) #if !swift(>=4.1) @@ -166,7 +142,6 @@ struct Config { /// /// This setting is never saved to disk, but if set, all device settings will be returned to factory defaults. - /// (Region, serial number etc... will be preserved) var factoryReset: Bool = false /// @@ -182,7 +157,6 @@ struct Config { /// /// Defines the device's role on the Mesh network - /// unset - 0 enum Role: SwiftProtobuf.Enum { typealias RawValue = Int @@ -191,24 +165,19 @@ struct Config { case client // = 0 /// - /// ClientMute device role - /// This is like the client but packets will not hop over this node. Would be - /// useful if you want to save power by not contributing to the mesh. + /// Client Mute device role + /// Same as a client except packets will not hop over this node, does not contribute to routing packets for mesh. case clientMute // = 1 /// /// Router device role. - /// Uses an agressive algirithem for the flood networking so packets will - /// prefer to be routed over this node. Also assume that this will be - /// unattended and so will turn off the wifi/ble radio as well as the oled screen. + /// Mesh packets will prefer to be routed over this node. This node will not be used by client apps. + /// The wifi/ble radios and the oled screen will be put to sleep. case router // = 2 /// - /// RouterClient device role - /// Uses an agressive algirithem for the flood networking so packets will - /// prefer to be routed over this node. Similiar power management as a regular - /// client, so the RouterClient can be used as both a Router and a Client. Useful - /// as a well placed base station that you could also use to send messages. + /// Router Client device role + /// Mesh packets will prefer to be routed over this node. The Router Client can be used as both a Router and an app connected Client. case routerClient // = 3 case UNRECOGNIZED(Int) @@ -331,6 +300,18 @@ struct Config { /// /// Include positional timestamp (from GPS solution) case posTimestamp // = 128 + + /// + /// Include positional heading + /// Intended for use with vehicle not walking speeds + /// walking speeds are likely to be error prone like the compass + case posHeading // = 256 + + /// + /// Include positional speed + /// Intended for use with vehicle not walking speeds + /// walking speeds are likely to be error prone like the compass + case posSpeed // = 512 case UNRECOGNIZED(Int) init() { @@ -348,6 +329,8 @@ struct Config { case 32: self = .posSatinview case 64: self = .posSeqNos case 128: self = .posTimestamp + case 256: self = .posHeading + case 512: self = .posSpeed default: self = .UNRECOGNIZED(rawValue) } } @@ -363,6 +346,8 @@ struct Config { case .posSatinview: return 32 case .posSeqNos: return 64 case .posTimestamp: return 128 + case .posHeading: return 256 + case .posSpeed: return 512 case .UNRECOGNIZED(let i): return i } } @@ -389,14 +374,9 @@ struct Config { /// If set, we are powered from a low-current source (i.e. solar), so even if it looks like we have power flowing in /// we should try to minimize power consumption as much as possible. /// YOU DO NOT NEED TO SET THIS IF YOU'VE set is_router (it is implied in that case). - /// CLI Only Option + /// Advanced Option var isPowerSaving: Bool = false - /// - /// Circumvents the logic block for determining whether the device is powered or not. - /// Useful for devices with finicky ADC issues on the battery sense pins. - var isAlwaysPowered: Bool = false - /// /// If non-zero, the device will fully power off this many seconds after external power is removed. var onBatteryShutdownAfterSecs: UInt32 = 0 @@ -404,11 +384,13 @@ struct Config { /// /// Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k) /// Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation. + /// Should be set to floating point value between 2 and 4 + /// Fixes issues on Heltec v2 var adcMultiplierOverride: Float = 0 /// /// Wait Bluetooth Seconds - /// The number of seconds for to wait before turning of BLE in No Bluetooth states\ + /// The number of seconds for to wait before turning off BLE in No Bluetooth states /// 0 for default of 1 minute var waitBluetoothSecs: UInt32 = 0 @@ -430,7 +412,7 @@ struct Config { /// Light Sleep Seconds /// In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on /// ESP32 Only - /// 0 for default of 3600 + /// 0 for default of 300 var lsSecs: UInt32 = 0 /// @@ -446,73 +428,22 @@ struct Config { /// **TBEAM 1.1 Only** enum ChargeCurrent: SwiftProtobuf.Enum { typealias RawValue = Int - - /// - /// TODO: REPLACE case maunset // = 0 - - /// - /// TODO: REPLACE case ma100 // = 1 - - /// - /// TODO: REPLACE case ma190 // = 2 - - /// - /// TODO: REPLACE case ma280 // = 3 - - /// - /// TODO: REPLACE case ma360 // = 4 - - /// - /// TODO: REPLACE case ma450 // = 5 - - /// - /// TODO: REPLACE case ma550 // = 6 - - /// - /// TODO: REPLACE case ma630 // = 7 - - /// - /// TODO: REPLACE case ma700 // = 8 - - /// - /// TODO: REPLACE case ma780 // = 9 - - /// - /// TODO: REPLACE case ma880 // = 10 - - /// - /// TODO: REPLACE case ma960 // = 11 - - /// - /// TODO: REPLACE case ma1000 // = 12 - - /// - /// TODO: REPLACE case ma1080 // = 13 - - /// - /// TODO: REPLACE case ma1160 // = 14 - - /// - /// TODO: REPLACE case ma1240 // = 15 - - /// - /// TODO: REPLACE case ma1320 // = 16 case UNRECOGNIZED(Int) @@ -572,7 +503,7 @@ struct Config { } /// - /// TODO: REPLACE + /// WiFi Config struct WiFiConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -609,13 +540,12 @@ struct Config { // methods supported on all messages. /// - /// Power management state machine option. - /// See [power management](/docs/software/other/power) for details. - /// 0 for default of one minute + /// Number of seconds the screen stays on after pressing the user button or receiving a message + /// 0 for default of one minute MAXUINT for always on var screenOnSecs: UInt32 = 0 /// - /// How the GPS coordinates are displayed on the OLED screen. + /// How the GPS coordinates are formatted on the OLED screen. var gpsFormat: Config.DisplayConfig.GpsCoordinateFormat = .gpsFormatDec /// @@ -641,24 +571,24 @@ struct Config { case gpsFormatDms // = 1 /// - /// GPS coordinates are displayed in Universal Transverse Mercator format: + /// Universal Transverse Mercator format: /// ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing case gpsFormatUtm // = 2 /// - /// GPS coordinates are displayed in Military Grid Reference System format: + /// Military Grid Reference System format: /// ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square, /// E is easting, N is northing case gpsFormatMgrs // = 3 /// - /// GPS coordinates are displayed in Open Location Code (aka Plus Codes). + /// Open Location Code (aka Plus Codes). case gpsFormatOlc // = 4 /// - /// GPS coordinates are displayed in Ordnance Survey Grid Reference (the National Grid System of the UK). - /// Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, E is the easting, - /// N is the northing + /// Ordnance Survey Grid Reference (the National Grid System of the UK). + /// Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square, + /// E is the easting, N is the northing case gpsFormatOsgr // = 5 case UNRECOGNIZED(Int) @@ -696,7 +626,7 @@ struct Config { } /// - /// TODO: REPLACE + /// Lora Config struct LoRaConfig { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -710,7 +640,6 @@ struct Config { var txPower: Int32 = 0 /// - /// Note: This is the 'old' mechanism for specifying channel parameters. /// Either modem_config or bandwidth/spreading/coding will be specified - NOT BOTH. /// As a heuristic: If bandwidth is specified, do not use modem_config. /// Because protobufs take ZERO space when the value is zero this works out nicely. @@ -741,11 +670,12 @@ struct Config { var frequencyOffset: Float = 0 /// - /// The region code for my radio (US, CN, EU433, etc...) + /// The region code for the radio (US, CN, EU433, etc...) var region: Config.LoRaConfig.RegionCode = .unset /// /// Overrides HOPS_RELIABLE and sets the maximum number of hops. This can't be greater than 7. + /// 0 for default of 3 var hopLimit: UInt32 = 0 /// @@ -761,66 +691,59 @@ struct Config { var unknownFields = SwiftProtobuf.UnknownStorage() - /// - /// The frequency/regulatory region the user has selected. - /// Note: In 1.0 builds (which must still be supported by the android app for a - /// long time) this field will be unpopulated. - /// If firmware is ever upgraded from an old 1.0ish build, the old - /// MyNodeInfo.region string will be used to set UserPreferences.region and the - /// old value will be no longer set. enum RegionCode: SwiftProtobuf.Enum { typealias RawValue = Int /// - /// TODO: REPLACE + /// Region is not set case unset // = 0 /// - /// TODO: REPLACE + /// United States case us // = 1 /// - /// TODO: REPLACE + /// European Union 433mhz case eu433 // = 2 /// - /// TODO: REPLACE + /// European Union 433mhz case eu868 // = 3 /// - /// TODO: REPLACE + /// China case cn // = 4 /// - /// TODO: REPLACE + /// Japan case jp // = 5 /// - /// TODO: REPLACE + /// Australia / New Zealand case anz // = 6 /// - /// TODO: REPLACE + /// Korea case kr // = 7 /// - /// TODO: REPLACE + /// Taiwan case tw // = 8 /// - /// TODO: REPLACE + /// Russia case ru // = 9 /// - /// TODO: REPLACE + /// India case `in` // = 10 /// - /// TODO: REPLACE + /// New Zealand 865mhz case nz865 // = 11 /// - /// TODO: REPLACE + /// Thailand case th // = 12 case UNRECOGNIZED(Int) @@ -875,31 +798,31 @@ struct Config { typealias RawValue = Int /// - /// TODO: REPLACE + /// Long Range - Fast case longFast // = 0 /// - /// TODO: REPLACE + /// Long Range - Slow case longSlow // = 1 /// - /// TODO: REPLACE + /// Very Long Range - Slow case vlongSlow // = 2 /// - /// TODO: REPLACE + /// Medium Range - Slow case midSlow // = 3 /// - /// TODO: REPLACE + /// Medium Range - Fast case midFast // = 4 /// - /// TODO: REPLACE + /// Short Range - Slow case shortSlow // = 5 /// - /// TODO: REPLACE + /// Short Range - Fast case shortFast // = 6 case UNRECOGNIZED(Int) @@ -965,6 +888,8 @@ extension Config.PositionConfig.PositionFlags: CaseIterable { .posSatinview, .posSeqNos, .posTimestamp, + .posHeading, + .posSpeed, ] } @@ -1342,6 +1267,8 @@ extension Config.PositionConfig.PositionFlags: SwiftProtobuf._ProtoNameProviding 32: .same(proto: "POS_SATINVIEW"), 64: .same(proto: "POS_SEQ_NOS"), 128: .same(proto: "POS_TIMESTAMP"), + 256: .same(proto: "POS_HEADING"), + 512: .same(proto: "POS_SPEED"), ] } @@ -1350,7 +1277,6 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .standard(proto: "charge_current"), 2: .standard(proto: "is_power_saving"), - 3: .standard(proto: "is_always_powered"), 4: .standard(proto: "on_battery_shutdown_after_secs"), 6: .standard(proto: "adc_multiplier_override"), 7: .standard(proto: "wait_bluetooth_secs"), @@ -1368,7 +1294,6 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple switch fieldNumber { case 1: try { try decoder.decodeSingularEnumField(value: &self.chargeCurrent) }() case 2: try { try decoder.decodeSingularBoolField(value: &self.isPowerSaving) }() - case 3: try { try decoder.decodeSingularBoolField(value: &self.isAlwaysPowered) }() case 4: try { try decoder.decodeSingularUInt32Field(value: &self.onBatteryShutdownAfterSecs) }() case 6: try { try decoder.decodeSingularFloatField(value: &self.adcMultiplierOverride) }() case 7: try { try decoder.decodeSingularUInt32Field(value: &self.waitBluetoothSecs) }() @@ -1388,9 +1313,6 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.isPowerSaving != false { try visitor.visitSingularBoolField(value: self.isPowerSaving, fieldNumber: 2) } - if self.isAlwaysPowered != false { - try visitor.visitSingularBoolField(value: self.isAlwaysPowered, fieldNumber: 3) - } if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 4) } @@ -1418,7 +1340,6 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple static func ==(lhs: Config.PowerConfig, rhs: Config.PowerConfig) -> Bool { if lhs.chargeCurrent != rhs.chargeCurrent {return false} if lhs.isPowerSaving != rhs.isPowerSaving {return false} - if lhs.isAlwaysPowered != rhs.isAlwaysPowered {return false} if lhs.onBatteryShutdownAfterSecs != rhs.onBatteryShutdownAfterSecs {return false} if lhs.adcMultiplierOverride != rhs.adcMultiplierOverride {return false} if lhs.waitBluetoothSecs != rhs.waitBluetoothSecs {return false} diff --git a/MeshtasticApple/Protobufs/mesh.pb.swift b/MeshtasticApple/Protobufs/mesh.pb.swift index 0d2fc06a..b1f4484d 100644 --- a/MeshtasticApple/Protobufs/mesh.pb.swift +++ b/MeshtasticApple/Protobufs/mesh.pb.swift @@ -1810,11 +1810,11 @@ struct FromRadio { } /// - /// Include the entire config (was: RadioConfig radio) - var config: LocalConfig { + /// Include a part of the config (was: RadioConfig radio) + var config: Config { get { if case .config(let v)? = _storage._payloadVariant {return v} - return LocalConfig() + return Config() } set {_uniqueStorage()._payloadVariant = .config(newValue)} } @@ -1872,8 +1872,8 @@ struct FromRadio { /// starts over with the first node in our DB case nodeInfo(NodeInfo) /// - /// Include the entire config (was: RadioConfig radio) - case config(LocalConfig) + /// Include a part of the config (was: RadioConfig radio) + case config(Config) /// /// Set to send debug console output over our protobuf stream case logRecord(LogRecord) @@ -3356,7 +3356,7 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation } }() case 6: try { - var v: LocalConfig? + var v: Config? var hadOneofValue = false if let current = _storage._payloadVariant { hadOneofValue = true diff --git a/MeshtasticApple/Views/Bluetooth/Connect.swift b/MeshtasticApple/Views/Bluetooth/Connect.swift index 98578eea..ec6743a3 100644 --- a/MeshtasticApple/Views/Bluetooth/Connect.swift +++ b/MeshtasticApple/Views/Bluetooth/Connect.swift @@ -265,8 +265,8 @@ struct Connect: View { ConnectedDevice( bluetoothOn: self.bleManager.isSwitchedOn, deviceConnected: self.bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.lastFourCode : - "????") + name: (bleManager.connectedPeripheral != nil) ? self.bleManager.connectedPeripheral.shortName : + "?????") } ) } diff --git a/MeshtasticApple/Views/Helpers/ConnectedDevice.swift b/MeshtasticApple/Views/Helpers/ConnectedDevice.swift index 4d73f9de..e3552229 100644 --- a/MeshtasticApple/Views/Helpers/ConnectedDevice.swift +++ b/MeshtasticApple/Views/Helpers/ConnectedDevice.swift @@ -17,10 +17,10 @@ struct ConnectedDevice: View { if bluetoothOn { if deviceConnected { Image(systemName: "antenna.radiowaves.left.and.right.circle.fill") - .imageScale(.large) + .imageScale(.large) .foregroundColor(.green) .symbolRenderingMode(.hierarchical) - Text(name!).font(.subheadline).foregroundColor(.gray) + Text(name!).font(.callout).foregroundColor(.gray) } else { Image(systemName: "antenna.radiowaves.left.and.right.slash") diff --git a/MeshtasticApple/Views/Messages/UserMessageList.swift b/MeshtasticApple/Views/Messages/UserMessageList.swift index d70a18ec..c6dfd2d1 100644 --- a/MeshtasticApple/Views/Messages/UserMessageList.swift +++ b/MeshtasticApple/Views/Messages/UserMessageList.swift @@ -457,7 +457,7 @@ struct UserMessageList: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") } } } diff --git a/MeshtasticApple/Views/Nodes/NodeDetail.swift b/MeshtasticApple/Views/Nodes/NodeDetail.swift index 5d7a3699..6369b514 100644 --- a/MeshtasticApple/Views/Nodes/NodeDetail.swift +++ b/MeshtasticApple/Views/Nodes/NodeDetail.swift @@ -352,7 +352,7 @@ struct NodeDetail: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") } ) .onAppear(perform: { diff --git a/MeshtasticApple/Views/Nodes/NodeList.swift b/MeshtasticApple/Views/Nodes/NodeList.swift index 0a3d2916..f1a7762e 100644 --- a/MeshtasticApple/Views/Nodes/NodeList.swift +++ b/MeshtasticApple/Views/Nodes/NodeList.swift @@ -105,7 +105,8 @@ struct NodeList: View { self.bleManager.context = context self.bleManager.userSettings = userSettings - if UIDevice.current.userInterfaceIdiom == .pad { + if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { + if nodes.count > 0 { selection = "0" } diff --git a/MeshtasticApple/Views/Nodes/NodeMap.swift b/MeshtasticApple/Views/Nodes/NodeMap.swift index 0aa4516d..061852db 100644 --- a/MeshtasticApple/Views/Nodes/NodeMap.swift +++ b/MeshtasticApple/Views/Nodes/NodeMap.swift @@ -125,8 +125,8 @@ struct NodeMap: View { ConnectedDevice( bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, - name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : - "????") + name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : + "?????") }) .onAppear(perform: { diff --git a/MeshtasticApple/Views/Settings/AppSettings.swift b/MeshtasticApple/Views/Settings/AppSettings.swift index e5c14e1a..6e6aa954 100644 --- a/MeshtasticApple/Views/Settings/AppSettings.swift +++ b/MeshtasticApple/Views/Settings/AppSettings.swift @@ -176,7 +176,7 @@ struct AppSettings: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { diff --git a/MeshtasticApple/Views/Settings/DeviceConfig.swift b/MeshtasticApple/Views/Settings/DeviceConfig.swift index ae734c68..75099874 100644 --- a/MeshtasticApple/Views/Settings/DeviceConfig.swift +++ b/MeshtasticApple/Views/Settings/DeviceConfig.swift @@ -22,7 +22,7 @@ enum DeviceRoles: Int, CaseIterable, Identifiable { case .client: return "Client (default)" case .clientMute: - return "Client Mute - Packets will not hop over this node, does not contribute to routing packets for mesh." + return "Client Mute - Same as a client except packets will not hop over this node, does not contribute to routing packets for mesh." case .router: return "Router - Mesh packets will prefer to be routed over this node. This node will not be used by client apps. The wifi/ble radios and the oled screen will be put to sleep." case .routerClient: @@ -41,8 +41,10 @@ struct DeviceConfig: View { @State var serialEnabled = true @State var debugLogEnabled = false + @State private var isPresentingFactoryResetConfirm: Bool = false + var body: some View { - + VStack { Form { @@ -74,18 +76,42 @@ struct DeviceConfig: View { .toggleStyle(SwitchToggleStyle(tint: .accentColor)) } } - .navigationTitle("Device Config") - .navigationBarItems(trailing: - - ZStack { - - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") - }) - .onAppear { - - self.bleManager.context = context + + Button("Factory Reset", role: .destructive) { + + isPresentingFactoryResetConfirm = true } - .navigationViewStyle(StackNavigationViewStyle()) + .disabled(bleManager.connectedPeripheral == nil) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + "Are you sure?", + isPresented: $isPresentingFactoryResetConfirm + ) { + Button("Erase all device settings?", role: .destructive) { + + if !bleManager.sendFactoryReset(destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + + print("Factory Reset Failed") + } + } + } + Spacer() } + + .navigationTitle("Device Config") + .navigationBarItems(trailing: + + ZStack { + + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") + }) + .onAppear { + + self.bleManager.context = context + } + .navigationViewStyle(StackNavigationViewStyle()) } } diff --git a/MeshtasticApple/Views/Settings/DisplayConfig.swift b/MeshtasticApple/Views/Settings/DisplayConfig.swift index 35e4ce92..d7c9936f 100644 --- a/MeshtasticApple/Views/Settings/DisplayConfig.swift +++ b/MeshtasticApple/Views/Settings/DisplayConfig.swift @@ -163,7 +163,7 @@ struct DisplayConfig: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { diff --git a/MeshtasticApple/Views/Settings/LoRaConfig.swift b/MeshtasticApple/Views/Settings/LoRaConfig.swift index f17e66d9..19e16043 100644 --- a/MeshtasticApple/Views/Settings/LoRaConfig.swift +++ b/MeshtasticApple/Views/Settings/LoRaConfig.swift @@ -19,7 +19,7 @@ enum RegionCodes : Int, CaseIterable, Identifiable { case kr = 7 case tw = 8 case ru = 9 - //case in = 10 + case `in` = 10 case nz865 case th @@ -28,7 +28,7 @@ enum RegionCodes : Int, CaseIterable, Identifiable { get { switch self { case .unset: - return "UNSET - Please set a Region" + return "Please set a region" case .us: return "United States" case .eu433: @@ -47,13 +47,48 @@ enum RegionCodes : Int, CaseIterable, Identifiable { return "Taiwan" case .ru: return "Russia" + case .in: + return "India" case .nz865: return "New Zealand 865mhz" case .th: - return "TH" + return "Thailand" } } } + + func protoEnumValue() -> Config.LoRaConfig.RegionCode { + + switch self { + + case .unset: + return Config.LoRaConfig.RegionCode.unset + case .us: + return Config.LoRaConfig.RegionCode.us + case .eu433: + return Config.LoRaConfig.RegionCode.eu433 + case .eu868: + return Config.LoRaConfig.RegionCode.eu868 + case .cn: + return Config.LoRaConfig.RegionCode.cn + case .jp: + return Config.LoRaConfig.RegionCode.jp + case .anz: + return Config.LoRaConfig.RegionCode.anz + case .kr: + return Config.LoRaConfig.RegionCode.kr + case .tw: + return Config.LoRaConfig.RegionCode.tw + case .ru: + return Config.LoRaConfig.RegionCode.ru + case .in: + return Config.LoRaConfig.RegionCode.in + case .nz865: + return Config.LoRaConfig.RegionCode.nz865 + case .th: + return Config.LoRaConfig.RegionCode.th + } + } } enum ModemPresets : Int, CaseIterable, Identifiable { @@ -72,19 +107,74 @@ enum ModemPresets : Int, CaseIterable, Identifiable { switch self { case .LongFast: - return "Long Fast" + return "Long Range - Fast" case .LongSlow: - return "Long Slow" + return "Long Range - Slow" case .VLongSlow: - return "Very Long Slow" + return "Very Long Range - Slow" case .MidSlow: - return "Mid Slow" + return "Medium Range - Slow" case .MidFast: - return "Mid Fast" + return "Medium Range - Fast" case .ShortSlow: - return "Short Slow" + return "Short Range - Slow" case .ShortFast: - return "Short Fast" + return "Short Range - Fast" + } + } + } + func protoEnumValue() -> Config.LoRaConfig.ModemPreset { + + switch self { + + case .LongFast: + return Config.LoRaConfig.ModemPreset.longFast + case .LongSlow: + return Config.LoRaConfig.ModemPreset.longSlow + case .VLongSlow: + return Config.LoRaConfig.ModemPreset.vlongSlow + case .MidSlow: + return Config.LoRaConfig.ModemPreset.midSlow + case .MidFast: + return Config.LoRaConfig.ModemPreset.midFast + case .ShortSlow: + return Config.LoRaConfig.ModemPreset.shortSlow + case .ShortFast: + return Config.LoRaConfig.ModemPreset.shortFast + + } + } +} + +enum HopValues : Int, CaseIterable, Identifiable { + + case oneHop = 1 + case twoHops = 2 + case threeHops = 0 + case fourHops = 4 + case fiveHops = 5 + case sixHops = 6 + case sevenHops = 7 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + + case .oneHop: + return "One Hop" + case .twoHops: + return "Two Hops" + case .threeHops: + return "Three Hops" + case .fourHops: + return "Four Hops" + case .fiveHops: + return "Five Hops" + case .sixHops: + return "Six Hops" + case .sevenHops: + return "Seven Hops" } } } @@ -95,9 +185,13 @@ struct LoRaConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager - @State var region = 1 - @State var modemPreset = 0 - @State var numberOfHops = 0 + var node: NodeInfoEntity + + @State private var isPresentingSaveConfirm: Bool = false + @State var region = 0 + @State var modemPreset = 0 + @State var hopLimit = 0 + @State var hasChanges = false var body: some View { @@ -112,49 +206,106 @@ struct LoRaConfig: View { } } .pickerStyle(DefaultPickerStyle()) - Text("The region where you will be using your Meshtastic LoRa radios.") + Text("The region where you will be using your radios.") .font(.caption) .listRowSeparator(.visible) - .listRowSeparator(.visible) } Section(header: Text("Modem")) { - Picker("Presets", selection: $region ) { + Picker("Presets", selection: $modemPreset ) { ForEach(ModemPresets.allCases) { m in Text(m.description) } } .pickerStyle(DefaultPickerStyle()) - Text("Available modem presets.") + Text("Available modem presets, default is Long Fast.") .font(.caption) .listRowSeparator(.visible) - .listRowSeparator(.visible) } Section(header: Text("Mesh Options")) { - Picker("Number of hops", selection: $numberOfHops) { - ForEach(0..<8) { - if $0 == 0 { - Text("Default") - } else { - Text("\($0) Hops") - } + Picker("Number of hops", selection: $hopLimit) { + ForEach(HopValues.allCases) { hop in + Text(hop.description) } } .pickerStyle(DefaultPickerStyle()) + Text("Sets the maximum number of hops, default is 3.") + .font(.caption) + .listRowSeparator(.visible) } } + + Button { + + isPresentingSaveConfirm = true + + } label: { + Label("Save", systemImage: "square.and.arrow.down") + } + .disabled(bleManager.connectedPeripheral == nil || !hasChanges) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + "Are you sure?", + isPresented: $isPresentingSaveConfirm + ) { + Button("Save LoRa Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var lc = Config.LoRaConfig() + lc.hopLimit = UInt32(hopLimit) + lc.region = RegionCodes(rawValue: region)!.protoEnumValue() + lc.modemPreset = ModemPresets(rawValue: modemPreset)!.protoEnumValue() + + if bleManager.saveLoRaConfig(config: lc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + + // 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 + + } else { + + } + } + } + } .navigationTitle("LoRa Config") .navigationBarItems(trailing: ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { self.bleManager.context = context } + .task { + do { + print("got hops \(node.loRaConfig?.hopLimit ?? 0)") + self.hopLimit = Int(node.loRaConfig?.hopLimit ?? 0) + self.region = Int(node.loRaConfig?.regionCode ?? 0) + self.modemPreset = Int(node.loRaConfig?.modemPreset ?? 0) + self.hasChanges = false + } catch { + print("Failed to load node data") + } + } + .onChange(of: region) { newRegion in + + hasChanges = true + } + .onChange(of: modemPreset) { newModemPreset in + + hasChanges = true + } + .onChange(of: hopLimit) { newHopLimit in + + hasChanges = true + } + .navigationViewStyle(StackNavigationViewStyle()) } } diff --git a/MeshtasticApple/Views/Settings/PositionConfig.swift b/MeshtasticApple/Views/Settings/PositionConfig.swift index 43cf0af4..05c27867 100644 --- a/MeshtasticApple/Views/Settings/PositionConfig.swift +++ b/MeshtasticApple/Views/Settings/PositionConfig.swift @@ -118,8 +118,14 @@ struct PositionConfig: View { @State var gpsAttemptTime = 0 @State var positionBroadcastSeconds = 0 - @State var includeAltitude = false - @State var includeSatInView = false + @State var includePosAltitude = false + @State var includePosSatsinview = false + @State var includePosSeqNos = false + @State var includePosTimestamp = false + @State var includePosSpeed = false + @State var includePosHeading = false + + var body: some View { @@ -203,30 +209,44 @@ struct PositionConfig: View { .font(.caption) .listRowSeparator(.visible) - Toggle(isOn: $includeAltitude) { + Toggle(isOn: $includePosAltitude) { - Label("Include Altitude", systemImage: "arrow.up") + Label("Altitude", systemImage: "arrow.up") } .toggleStyle(DefaultToggleStyle()) .listRowSeparator(.visible) - Toggle(isOn: $includeSatInView) { + Toggle(isOn: $includePosSatsinview) { - Label("Include number of satellites in view", systemImage: "skew") + Label("Number of satellites", systemImage: "skew") } .toggleStyle(DefaultToggleStyle()) .listRowSeparator(.visible) - Toggle(isOn: $includeSatInView) { //64 + Toggle(isOn: $includePosSeqNos) { //64 - Label("Include a sequence number incremented per packet", systemImage: "number") + Label("Sequence number", systemImage: "number") } .toggleStyle(DefaultToggleStyle()) .listRowSeparator(.visible) - Toggle(isOn: $includeSatInView) { //128 + Toggle(isOn: $includePosTimestamp) { //128 - Label("Include positional timestamp", systemImage: "clock") + Label("Timestamp", systemImage: "clock") + } + .toggleStyle(DefaultToggleStyle()) + .listRowSeparator(.visible) + + Toggle(isOn: $includePosHeading) { //128 + + Label("Vehicle heading", systemImage: "location.circle") + } + .toggleStyle(DefaultToggleStyle()) + .listRowSeparator(.visible) + + Toggle(isOn: $includePosSpeed) { //128 + + Label("Vehicle speed", systemImage: "speedometer") } .toggleStyle(DefaultToggleStyle()) .listRowSeparator(.visible) @@ -239,7 +259,7 @@ struct PositionConfig: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { diff --git a/MeshtasticApple/Views/Settings/RangeTestConfig.swift b/MeshtasticApple/Views/Settings/RangeTestConfig.swift index 0723954e..ef86378a 100644 --- a/MeshtasticApple/Views/Settings/RangeTestConfig.swift +++ b/MeshtasticApple/Views/Settings/RangeTestConfig.swift @@ -55,7 +55,7 @@ struct RangeTestConfig: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { diff --git a/MeshtasticApple/Views/Settings/Settings.swift b/MeshtasticApple/Views/Settings/Settings.swift index 4e8db7ea..882efb64 100644 --- a/MeshtasticApple/Views/Settings/Settings.swift +++ b/MeshtasticApple/Views/Settings/Settings.swift @@ -13,6 +13,14 @@ struct Settings: View { @EnvironmentObject var bleManager: BLEManager @EnvironmentObject var userSettings: UserSettings + + + @FetchRequest( + sortDescriptors: [NSSortDescriptor(key: "lastHeard", ascending: false)], + animation: .default) + + private var nodes: FetchedResults + var body: some View { NavigationView { List { @@ -53,8 +61,12 @@ struct Settings: View { .symbolRenderingMode(.hierarchical) Text("Display (Device Screen)") } - NavigationLink { - LoRaConfig() + + let connectedNodeNum = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.num : 0 + + NavigationLink() { + + LoRaConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) } label: { Image(systemName: "dot.radiowaves.left.and.right") @@ -62,6 +74,8 @@ struct Settings: View { Text("LoRa") } + .disabled(bleManager.connectedPeripheral == nil) + NavigationLink { PositionConfig() } label: { diff --git a/MeshtasticApple/Views/Settings/ShareChannel.swift b/MeshtasticApple/Views/Settings/ShareChannel.swift index 7b41486b..3a7b2bfe 100644 --- a/MeshtasticApple/Views/Settings/ShareChannel.swift +++ b/MeshtasticApple/Views/Settings/ShareChannel.swift @@ -81,7 +81,7 @@ struct ShareChannel: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear { diff --git a/MeshtasticApple/Views/Settings/TelemetryConfig.swift b/MeshtasticApple/Views/Settings/TelemetryConfig.swift index aa22679f..78eb78a6 100644 --- a/MeshtasticApple/Views/Settings/TelemetryConfig.swift +++ b/MeshtasticApple/Views/Settings/TelemetryConfig.swift @@ -26,7 +26,7 @@ struct TelemetryConfig: View { ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.lastFourCode : "????") + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") }) .onAppear {