diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index c22230c2..e21580b3 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -73,6 +73,11 @@ DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABD528AE742000384BA1 /* BluetoothConfig.swift */; }; DDB6ABD928B0A4BA00384BA1 /* BluetoothModes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABD828B0A4BA00384BA1 /* BluetoothModes.swift */; }; DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABDA28B0AC6000384BA1 /* DistanceText.swift */; }; + DDB6ABE028B13AC700384BA1 /* DeviceRoles.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABDF28B13AC700384BA1 /* DeviceRoles.swift */; }; + DDB6ABE228B13FB500384BA1 /* GpsFormats.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABE128B13FB500384BA1 /* GpsFormats.swift */; }; + DDB6ABE428B13FFF00384BA1 /* ScreenIntervals.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABE328B13FFF00384BA1 /* ScreenIntervals.swift */; }; + DDB6ABE628B1406100384BA1 /* LoraConfigEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABE528B1406100384BA1 /* LoraConfigEnums.swift */; }; + DDB6ABE828B141AF00384BA1 /* WiFiModes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB6ABE728B141AF00384BA1 /* WiFiModes.swift */; }; DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */; }; DDC2E15C26CE248F0042C5E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */; }; DDC2E15F26CE248F0042C5E4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDC2E15E26CE248F0042C5E4 /* Preview Assets.xcassets */; }; @@ -178,6 +183,11 @@ DDB6ABD728AE8F5D00384BA1 /* MeshtasticDataModel v 7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 7.xcdatamodel"; sourceTree = ""; }; DDB6ABD828B0A4BA00384BA1 /* BluetoothModes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothModes.swift; sourceTree = ""; }; DDB6ABDA28B0AC6000384BA1 /* DistanceText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DistanceText.swift; sourceTree = ""; }; + DDB6ABDF28B13AC700384BA1 /* DeviceRoles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRoles.swift; sourceTree = ""; }; + DDB6ABE128B13FB500384BA1 /* GpsFormats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GpsFormats.swift; sourceTree = ""; }; + DDB6ABE328B13FFF00384BA1 /* ScreenIntervals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenIntervals.swift; sourceTree = ""; }; + DDB6ABE528B1406100384BA1 /* LoraConfigEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoraConfigEnums.swift; sourceTree = ""; }; + DDB6ABE728B141AF00384BA1 /* WiFiModes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiModes.swift; sourceTree = ""; }; DDC2E15426CE248E0042C5E4 /* Meshtastic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Meshtastic.app; sourceTree = BUILT_PRODUCTS_DIR; }; DDC2E15726CE248E0042C5E4 /* MeshtasticApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticApp.swift; sourceTree = ""; }; DDC2E15B26CE248F0042C5E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../Assets.xcassets; sourceTree = ""; }; @@ -321,8 +331,13 @@ DD8ED9C6289CE4A100B3B0AB /* Enums */ = { isa = PBXGroup; children = ( - DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */, DDB6ABD828B0A4BA00384BA1 /* BluetoothModes.swift */, + DDB6ABDF28B13AC700384BA1 /* DeviceRoles.swift */, + DDB6ABE528B1406100384BA1 /* LoraConfigEnums.swift */, + DDB6ABE128B13FB500384BA1 /* GpsFormats.swift */, + DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */, + DDB6ABE328B13FFF00384BA1 /* ScreenIntervals.swift */, + DDB6ABE728B141AF00384BA1 /* WiFiModes.swift */, ); path = Enums; sourceTree = ""; @@ -672,6 +687,7 @@ DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */, DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */, DD4C158C2824A91E0032668E /* module_config.pb.swift in Sources */, + DDB6ABE828B141AF00384BA1 /* WiFiModes.swift in Sources */, DD4F23CD28779A3C001D37CB /* TelemetryLog.swift in Sources */, DD6B85A828009258000ACD6B /* ShareChannel.swift in Sources */, DDB6ABD628AE742000384BA1 /* BluetoothConfig.swift in Sources */, @@ -691,6 +707,7 @@ DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */, DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */, DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */, + DDB6ABE628B1406100384BA1 /* LoraConfigEnums.swift in Sources */, DDB2CC6E27F3EB47009C5FCC /* telemetry.pb.swift in Sources */, DD23A50F26FD1B4400D9B90C /* PeripheralModel.swift in Sources */, DDB6ABDB28B0AC6000384BA1 /* DistanceText.swift in Sources */, @@ -708,6 +725,7 @@ DD2553592855B52700E55709 /* PositionConfig.swift in Sources */, DDB3107228A6224100F1DE3D /* device_metadata.pb.swift in Sources */, DDAF8C6326ED0A230058C060 /* admin.pb.swift in Sources */, + DDB6ABE028B13AC700384BA1 /* DeviceRoles.swift in Sources */, DD86D40C287F401000BAEB7A /* SaveChannelQRCode.swift in Sources */, DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */, C9483F6D2773017500998F6B /* MapView.swift in Sources */, @@ -721,11 +739,13 @@ DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */, DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */, DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */, + DDB6ABE428B13FFF00384BA1 /* ScreenIntervals.swift in Sources */, DD86D40A287F04F100BAEB7A /* InvalidVersion.swift in Sources */, DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */, C9A88B57278B559900BD810A /* apponly.pb.swift in Sources */, DD4C158E2824AA7E0032668E /* config.pb.swift in Sources */, DD47E3D926F3093800029299 /* MessageBubble.swift in Sources */, + DDB6ABE228B13FB500384BA1 /* GpsFormats.swift in Sources */, DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */, DD73FD1128750779000852D6 /* LocationHistory.swift in Sources */, C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */, diff --git a/Meshtastic/Enums/BluetoothModes.swift b/Meshtastic/Enums/BluetoothModes.swift index 003b0a3f..c631defa 100644 --- a/Meshtastic/Enums/BluetoothModes.swift +++ b/Meshtastic/Enums/BluetoothModes.swift @@ -16,11 +16,11 @@ enum BluetoothModes: Int, CaseIterable, Identifiable { get { switch self { case .randomPin: - return "Random" + return "Random PIN" case .fixedPin: - return "Fixed" + return "Fixed PIN" case .noPin: - return "None" + return "No PIN (Just Works)" } } } diff --git a/Meshtastic/Enums/DeviceRoles.swift b/Meshtastic/Enums/DeviceRoles.swift new file mode 100644 index 00000000..ba793bd3 --- /dev/null +++ b/Meshtastic/Enums/DeviceRoles.swift @@ -0,0 +1,48 @@ +// +// DeviceRoles.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/20/22. +// + +import Foundation + +// Default of 0 is Client +enum DeviceRoles: Int, CaseIterable, Identifiable { + + case client = 0 + case clientMute = 1 + case router = 2 + case routerClient = 3 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + + case .client: + return "Client (default) - App connected client." + case .clientMute: + 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: + return "Router Client - 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." + } + } + } + func protoEnumValue() -> Config.DeviceConfig.Role { + + switch self { + + case .client: + return Config.DeviceConfig.Role.client + case .clientMute: + return Config.DeviceConfig.Role.clientMute + case .router: + return Config.DeviceConfig.Role.router + case .routerClient: + return Config.DeviceConfig.Role.routerClient + } + } +} diff --git a/Meshtastic/Enums/GpsFormats.swift b/Meshtastic/Enums/GpsFormats.swift new file mode 100644 index 00000000..5f3dd4f6 --- /dev/null +++ b/Meshtastic/Enums/GpsFormats.swift @@ -0,0 +1,56 @@ +// +// GpsFormats.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/20/22. +// + +import Foundation + +enum GpsFormats: Int, CaseIterable, Identifiable { + + case gpsFormatDec = 0 + case gpsFormatDms = 1 + case gpsFormatUtm = 2 + case gpsFormatMgrs = 3 + case gpsFormatOlc = 4 + case gpsFormatOsgr = 5 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .gpsFormatDec: + return "Decimal Degrees Format" + case .gpsFormatDms: + return "Degrees Minutes Seconds" + case .gpsFormatUtm: + return "Universal Transverse Mercator" + case .gpsFormatMgrs: + return "Military Grid Reference System" + case .gpsFormatOlc: + return "Open Location Code (aka Plus Codes)" + case .gpsFormatOsgr: + return "Ordnance Survey Grid Reference" + } + } + } + func protoEnumValue() -> Config.DisplayConfig.GpsCoordinateFormat { + + switch self { + + case .gpsFormatDec: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatDec + case .gpsFormatDms: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatDms + case .gpsFormatUtm: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatUtm + case .gpsFormatMgrs: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatMgrs + case .gpsFormatOlc: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatOlc + case .gpsFormatOsgr: + return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatOsgr + } + } +} diff --git a/Meshtastic/Enums/LoraConfigEnums.swift b/Meshtastic/Enums/LoraConfigEnums.swift new file mode 100644 index 00000000..15615541 --- /dev/null +++ b/Meshtastic/Enums/LoraConfigEnums.swift @@ -0,0 +1,181 @@ +// +// LoraConfig.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/20/22. +// + +import Foundation + +enum RegionCodes : Int, CaseIterable, Identifiable { + + case unset = 0 + case us = 1 + case eu433 = 2 + case eu868 = 3 + case cn = 4 + case jp = 5 + case anz = 6 + case kr = 7 + case tw = 8 + case ru = 9 + case `in` = 10 + case nz865 = 11 + case th = 12 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .unset: + return "Please set a region" + case .us: + return "United States" + case .eu433: + return "European Union 433mhz" + case .eu868: + return "European Union 868mhz" + case .cn: + return "China" + case .jp: + return "Japan" + case .anz: + return "Australia / New Zealand" + case .kr: + return "Korea" + case .tw: + return "Taiwan" + case .ru: + return "Russia" + case .in: + return "India" + case .nz865: + return "New Zealand 865mhz" + case .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 { + + case LongFast = 0 + case LongSlow = 1 + case VLongSlow = 2 + case MedSlow = 3 + case MedFast = 4 + case ShortSlow = 5 + case ShortFast = 6 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + + case .LongFast: + return "Long Range - Fast" + case .LongSlow: + return "Long Range - Slow" + case .VLongSlow: + return "Very Long Range - Slow" + case .MedSlow: + return "Medium Range - Slow" + case .MedFast: + return "Medium Range - Fast" + case .ShortSlow: + return "Short Range - Slow" + case .ShortFast: + 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 .MedSlow: + return Config.LoRaConfig.ModemPreset.medSlow + case .MedFast: + return Config.LoRaConfig.ModemPreset.medFast + 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" + } + } + } +} diff --git a/Meshtastic/Enums/ScreenIntervals.swift b/Meshtastic/Enums/ScreenIntervals.swift new file mode 100644 index 00000000..74731e11 --- /dev/null +++ b/Meshtastic/Enums/ScreenIntervals.swift @@ -0,0 +1,73 @@ +// +// ScreenIntervals.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/20/22. +// + +import Foundation + +// Default of 0 is One Minute +enum ScreenOnIntervals: Int, CaseIterable, Identifiable { + + case oneMinute = 60 + case fiveMinutes = 300 + case tenMinutes = 0 + case fifteenMinutes = 900 + case thirtyMinutes = 1800 + case oneHour = 3600 + case max = 31536000 // One Year + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .oneMinute: + return "One Minute" + case .fiveMinutes: + return "Five Minutes" + case .tenMinutes: + return "Ten Minutes" + case .fifteenMinutes: + return "Fifteen Minutes" + case .thirtyMinutes: + return "Thirty Minutes" + case .oneHour: + return "One Hour" + case .max: + return "Always On" + } + } + } +} + +// Default of 0 is off +enum ScreenCarouselIntervals: Int, CaseIterable, Identifiable { + + case off = 0 + case thirtySeconds = 30 + case oneMinute = 60 + case fiveMinutes = 300 + case tenMinutes = 600 + case fifteenMinutes = 900 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .off: + return "Off" + case .thirtySeconds: + return "Thirty Seconds" + case .oneMinute: + return "One Minute" + case .fiveMinutes: + return "Five Minutes" + case .tenMinutes: + return "Ten Minutes" + case .fifteenMinutes: + return "Fifteen Minutes" + } + } + } +} diff --git a/Meshtastic/Enums/WiFiModes.swift b/Meshtastic/Enums/WiFiModes.swift new file mode 100644 index 00000000..cfb33099 --- /dev/null +++ b/Meshtastic/Enums/WiFiModes.swift @@ -0,0 +1,42 @@ +// +// WiFiModes.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/20/22. +// + +import Foundation + +enum WiFiModes: Int, CaseIterable, Identifiable { + + case client = 0 + case accessPoint = 1 + case accessPointHidden = 2 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .client: + return "Client" + case .accessPoint: + return "Software Access Point" + case .accessPointHidden: + return "Software Access Point (Hidden)" + + } + } + } + func protoEnumValue() -> Config.WiFiConfig.WiFiMode { + + switch self { + + case .client: + return Config.WiFiConfig.WiFiMode.client + case .accessPoint: + return Config.WiFiConfig.WiFiMode.accessPoint + case .accessPointHidden: + return Config.WiFiConfig.WiFiMode.accessPointHidden + } + } +} diff --git a/Meshtastic/Helpers/Extensions.swift b/Meshtastic/Helpers/Extensions.swift index 42b350e0..8f6abe9e 100644 --- a/Meshtastic/Helpers/Extensions.swift +++ b/Meshtastic/Helpers/Extensions.swift @@ -23,6 +23,17 @@ extension Date { } } +extension Int { + + func numberOfDigits() -> Int { + if abs(self) < 10 { + return 1 + } else { + return 1 + (self/10).numberOfDigits() + } + } +} + extension String { /// Create `Data` from hexadecimal string representation diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index dbc7eb0c..1f8fb415 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -92,6 +92,92 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont } } + if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { + + var isDefault = false + + if (try! config.bluetooth.jsonString()) == "{}" { + + isDefault = true + print("📶 Default Bluetooth config") + if meshlogging { MeshLogger.log("🖥️ Default Bluetooth config \(String(nodeNum))") } + + } else { + + if meshlogging { MeshLogger.log("🖥️ Custom Bluetooth config \(String(nodeNum))") } + print("📶 Custom Bluetooth config") + } + + let fetchNodeInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum)) + + do { + + let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity] + // Found a node, save Device Config + if !fetchedNode.isEmpty { + + if fetchedNode[0].bluetoothConfig == nil { + + let newBluetoothConfig = BluetoothConfigEntity(context: context) + + if isDefault { + + newBluetoothConfig.enabled = true + newBluetoothConfig.mode = Int32(config.bluetooth.mode.rawValue) + newBluetoothConfig.fixedPin = Int32("123456") ?? 123456 + + } else { + + newBluetoothConfig.enabled = config.bluetooth.enabled + newBluetoothConfig.mode = Int32(config.bluetooth.mode.rawValue) + newBluetoothConfig.fixedPin = Int32(config.display.autoScreenCarouselSecs) + + } + fetchedNode[0].bluetoothConfig = newBluetoothConfig + + } else { + + if isDefault { + + fetchedNode[0].displayConfig?.screenOnSeconds = 0 + fetchedNode[0].displayConfig?.screenCarouselInterval = 0 + fetchedNode[0].displayConfig?.gpsFormat = 0 + fetchedNode[0].displayConfig?.compassNorthTop = false + + } else { + + fetchedNode[0].displayConfig?.gpsFormat = Int32(config.display.gpsFormat.rawValue) + fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.display.screenOnSecs) + fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.display.autoScreenCarouselSecs) + fetchedNode[0].displayConfig?.compassNorthTop = config.display.compassNorthTop + } + } + + do { + + try context.save() + if meshlogging { MeshLogger.log("💾 Updated Display Config for node number: \(String(nodeNum))") } + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Updating Core Data DisplayConfigEntity: \(nsError)") + } + } else { + + print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Display Config") + } + + } catch { + + let nsError = error as NSError + print("💥 Fetching node for core data DisplayConfigEntity failed: \(nsError)") + } + } + if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) { var isDefault = false @@ -99,11 +185,12 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont if (try! config.display.jsonString()) == "{}" { isDefault = true - print("🖥️ Default Display config") + + if meshlogging { MeshLogger.log("🖥️ Default Display config \(String(nodeNum))") } } else { - print("🖥️ Custom Display config") + if meshlogging { MeshLogger.log("🖥️ Custom Display config \(String(nodeNum))") } } let fetchNodeInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index 5f5c7e8f..7b01ea15 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -23,7 +23,13 @@ struct BluetoothConfig: View { @State var mode = 0 /// Specified pin for PairingMode.FixedPin - @State var fixedPin = 123456 + @State var fixedPin = "123456" + + let numberFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.numberStyle = .none + return formatter + }() var body: some View { @@ -40,16 +46,36 @@ struct BluetoothConfig: View { .toggleStyle(SwitchToggleStyle(tint: .accentColor)) - Picker("Pairing PIN", selection: $mode ) { + Picker("Pairing Mode", selection: $mode ) { ForEach(BluetoothModes.allCases) { bm in Text(bm.description) } } .pickerStyle(DefaultPickerStyle()) - if mode == 2 { - + if mode == 1 { + HStack { + Label("Fixed PIN", systemImage: "wallet.pass") + TextField("Fixed PIN", text: $fixedPin) + .foregroundColor(.gray) + .onChange(of: fixedPin, perform: { value in + + let digitCount = fixedPin.utf8.count + // Only mess with the value if it is too big + if digitCount > 6 || digitCount < 6 { + + fixedPin = "123456" + } + + if digitCount < 6 { + + fixedPin = "123456" + } + }) + .foregroundColor(.gray) + } + .keyboardType(.decimalPad) } } } @@ -78,7 +104,7 @@ struct BluetoothConfig: View { var bc = Config.BluetoothConfig() bc.enabled = enabled bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin - bc.fixedPin = UInt32(fixedPin) + bc.fixedPin = UInt32(fixedPin) ?? 123456 let adminMessageId = 0//bleManager.saveBluetoothConfig(config: bc, fromUser: node!.user!, toUser: node!.user!) @@ -109,7 +135,7 @@ struct BluetoothConfig: View { self.enabled = node!.bluetoothConfig?.enabled ?? true self.mode = Int(node!.bluetoothConfig?.mode ?? 0) - self.fixedPin = Int(node!.bluetoothConfig?.fixedPin ?? 123456) + //self.fixedPin = (String(node!.bluetoothConfig?.fixedPin) ?? "123456") self.hasChanges = false self.initialLoad = false } @@ -132,7 +158,7 @@ struct BluetoothConfig: View { if node != nil && node!.bluetoothConfig != nil { - if newFixedPin != node!.bluetoothConfig!.fixedPin { hasChanges = true } + if newFixedPin != String(node!.bluetoothConfig!.fixedPin) { hasChanges = true } } } diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index 0d17f68f..809b25f8 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -6,46 +6,6 @@ // import SwiftUI -// Default of 0 is Client -enum DeviceRoles: Int, CaseIterable, Identifiable { - - case client = 0 - case clientMute = 1 - case router = 2 - case routerClient = 3 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - - case .client: - return "Client (default) - App connected client." - case .clientMute: - 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: - return "Router Client - 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." - } - } - } - func protoEnumValue() -> Config.DeviceConfig.Role { - - switch self { - - case .client: - return Config.DeviceConfig.Role.client - case .clientMute: - return Config.DeviceConfig.Role.clientMute - case .router: - return Config.DeviceConfig.Role.router - case .routerClient: - return Config.DeviceConfig.Role.routerClient - } - } -} - struct DeviceConfig: View { @Environment(\.managedObjectContext) var context diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 13d9ab13..6a1e6e25 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -7,119 +7,6 @@ import SwiftUI -enum GpsFormats: Int, CaseIterable, Identifiable { - - case gpsFormatDec = 0 - case gpsFormatDms = 1 - case gpsFormatUtm = 2 - case gpsFormatMgrs = 3 - case gpsFormatOlc = 4 - case gpsFormatOsgr = 5 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - case .gpsFormatDec: - return "Decimal Degrees Format" - case .gpsFormatDms: - return "Degrees Minutes Seconds" - case .gpsFormatUtm: - return "Universal Transverse Mercator" - case .gpsFormatMgrs: - return "Military Grid Reference System" - case .gpsFormatOlc: - return "Open Location Code (aka Plus Codes)" - case .gpsFormatOsgr: - return "Ordnance Survey Grid Reference" - } - } - } - func protoEnumValue() -> Config.DisplayConfig.GpsCoordinateFormat { - - switch self { - - case .gpsFormatDec: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatDec - case .gpsFormatDms: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatDms - case .gpsFormatUtm: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatUtm - case .gpsFormatMgrs: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatMgrs - case .gpsFormatOlc: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatOlc - case .gpsFormatOsgr: - return Config.DisplayConfig.GpsCoordinateFormat.gpsFormatOsgr - } - } -} - -// Default of 0 is One Minute -enum ScreenOnIntervals: Int, CaseIterable, Identifiable { - - case oneMinute = 60 - case fiveMinutes = 300 - case tenMinutes = 0 - case fifteenMinutes = 900 - case thirtyMinutes = 1800 - case oneHour = 3600 - case max = 31536000 // One Year - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - case .oneMinute: - return "One Minute" - case .fiveMinutes: - return "Five Minutes" - case .tenMinutes: - return "Ten Minutes" - case .fifteenMinutes: - return "Fifteen Minutes" - case .thirtyMinutes: - return "Thirty Minutes" - case .oneHour: - return "One Hour" - case .max: - return "Always On" - } - } - } -} - -// Default of 0 is off -enum ScreenCarouselIntervals: Int, CaseIterable, Identifiable { - - case off = 0 - case thirtySeconds = 30 - case oneMinute = 60 - case fiveMinutes = 300 - case tenMinutes = 600 - case fifteenMinutes = 900 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - case .off: - return "Off" - case .thirtySeconds: - return "Thirty Seconds" - case .oneMinute: - return "One Minute" - case .fiveMinutes: - return "Five Minutes" - case .tenMinutes: - return "Ten Minutes" - case .fifteenMinutes: - return "Fifteen Minutes" - } - } - } -} - struct DisplayConfig: View { @Environment(\.managedObjectContext) var context diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 9b30f94e..2e63c168 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -7,179 +7,6 @@ import SwiftUI -enum RegionCodes : Int, CaseIterable, Identifiable { - - case unset = 0 - case us = 1 - case eu433 = 2 - case eu868 = 3 - case cn = 4 - case jp = 5 - case anz = 6 - case kr = 7 - case tw = 8 - case ru = 9 - case `in` = 10 - case nz865 = 11 - case th = 12 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - case .unset: - return "Please set a region" - case .us: - return "United States" - case .eu433: - return "European Union 433mhz" - case .eu868: - return "European Union 868mhz" - case .cn: - return "China" - case .jp: - return "Japan" - case .anz: - return "Australia / New Zealand" - case .kr: - return "Korea" - case .tw: - return "Taiwan" - case .ru: - return "Russia" - case .in: - return "India" - case .nz865: - return "New Zealand 865mhz" - case .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 { - - case LongFast = 0 - case LongSlow = 1 - case VLongSlow = 2 - case MedSlow = 3 - case MedFast = 4 - case ShortSlow = 5 - case ShortFast = 6 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - - case .LongFast: - return "Long Range - Fast" - case .LongSlow: - return "Long Range - Slow" - case .VLongSlow: - return "Very Long Range - Slow" - case .MedSlow: - return "Medium Range - Slow" - case .MedFast: - return "Medium Range - Fast" - case .ShortSlow: - return "Short Range - Slow" - case .ShortFast: - 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 .MedSlow: - return Config.LoRaConfig.ModemPreset.medSlow - case .MedFast: - return Config.LoRaConfig.ModemPreset.medFast - 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" - } - } - } -} - struct LoRaConfig: View { @Environment(\.managedObjectContext) var context diff --git a/Meshtastic/Views/Settings/Config/WiFiConfig.swift b/Meshtastic/Views/Settings/Config/WiFiConfig.swift index e322a72a..1378be55 100644 --- a/Meshtastic/Views/Settings/Config/WiFiConfig.swift +++ b/Meshtastic/Views/Settings/Config/WiFiConfig.swift @@ -7,40 +7,6 @@ import SwiftUI -enum WiFiModes: Int, CaseIterable, Identifiable { - - case client = 0 - case accessPoint = 1 - case accessPointHidden = 2 - - var id: Int { self.rawValue } - var description: String { - get { - switch self { - case .client: - return "Client" - case .accessPoint: - return "Software Access Point" - case .accessPointHidden: - return "Software Access Point (Hidden)" - - } - } - } - func protoEnumValue() -> Config.WiFiConfig.WiFiMode { - - switch self { - - case .client: - return Config.WiFiConfig.WiFiMode.client - case .accessPoint: - return Config.WiFiConfig.WiFiMode.accessPoint - case .accessPointHidden: - return Config.WiFiConfig.WiFiMode.accessPointHidden - } - } -} - struct WiFiConfig: View { @Environment(\.managedObjectContext) var context @@ -125,12 +91,12 @@ struct WiFiConfig: View { // Only mess with the value if it is too big if totalBytes > 63 { - let firstNBytes = Data(ssid.utf8.prefix(63)) + let firstNBytes = Data(password.utf8.prefix(63)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { // Set the shortName back to the last place where it was the right size - ssid = maxBytesString + password = maxBytesString } } })