diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 62d23873..e21580b3 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -70,6 +70,14 @@ DDAF8C6E26ED19040058C060 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAF8C6D26ED19040058C060 /* Extensions.swift */; }; DDB2CC6E27F3EB47009C5FCC /* telemetry.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */; }; DDB3107228A6224100F1DE3D /* device_metadata.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB3107128A6224100F1DE3D /* device_metadata.pb.swift */; }; + 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 */; }; @@ -171,6 +179,15 @@ DDB2CC6D27F3EB47009C5FCC /* telemetry.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = telemetry.pb.swift; sourceTree = ""; }; DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 3.xcdatamodel"; sourceTree = ""; }; DDB3107128A6224100F1DE3D /* device_metadata.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = device_metadata.pb.swift; sourceTree = ""; }; + DDB6ABD528AE742000384BA1 /* BluetoothConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothConfig.swift; sourceTree = ""; }; + 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 = ""; }; @@ -278,6 +295,7 @@ DD61937A2863876A00E59241 /* Config */ = { isa = PBXGroup; children = ( + DDB6ABD528AE742000384BA1 /* BluetoothConfig.swift */, DD41582528582E9B009B0E59 /* DeviceConfig.swift */, DD8EBF42285058FA00426DCA /* DisplayConfig.swift */, DD2553562855B02500E55709 /* LoRaConfig.swift */, @@ -313,7 +331,13 @@ DD8ED9C6289CE4A100B3B0AB /* Enums */ = { isa = PBXGroup; children = ( + DDB6ABD828B0A4BA00384BA1 /* BluetoothModes.swift */, + DDB6ABDF28B13AC700384BA1 /* DeviceRoles.swift */, + DDB6ABE528B1406100384BA1 /* LoraConfigEnums.swift */, + DDB6ABE128B13FB500384BA1 /* GpsFormats.swift */, DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */, + DDB6ABE328B13FFF00384BA1 /* ScreenIntervals.swift */, + DDB6ABE728B141AF00384BA1 /* WiFiModes.swift */, ); path = Enums; sourceTree = ""; @@ -466,6 +490,7 @@ DDC3B273283F411B00AC321C /* LastHeardText.swift */, DDA6B2EA28420A7B003E8C16 /* NodeAnnotation.swift */, DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */, + DDB6ABDA28B0AC6000384BA1 /* DistanceText.swift */, ); path = Helpers; sourceTree = ""; @@ -662,8 +687,10 @@ 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 */, DDAF8C5326EB1DF10058C060 /* BLEManager.swift in Sources */, DDC4D568275499A500A4208E /* Persistence.swift in Sources */, DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */, @@ -680,8 +707,10 @@ 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 */, C9A7BC1027759A9600760B50 /* PositionAnnotationView.swift in Sources */, DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */, DD47E3CE26F103C600029299 /* NodeList.swift in Sources */, @@ -690,11 +719,13 @@ DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */, DD17E5DE277D49D400010EC2 /* storeforward.pb.swift in Sources */, DD2553572855B02500E55709 /* LoRaConfig.swift in Sources */, + DDB6ABD928B0A4BA00384BA1 /* BluetoothModes.swift in Sources */, DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */, C9A88B55278B503C00BD810A /* MapViewModule.swift in Sources */, 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 */, @@ -708,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 */, @@ -1102,6 +1135,7 @@ DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DDB6ABD728AE8F5D00384BA1 /* MeshtasticDataModel v 7.xcdatamodel */, DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */, DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */, DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */, @@ -1109,7 +1143,7 @@ DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */, DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */, ); - currentVersion = DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */; + currentVersion = DDB6ABD728AE8F5D00384BA1 /* MeshtasticDataModel v 7.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Enums/BluetoothModes.swift b/Meshtastic/Enums/BluetoothModes.swift new file mode 100644 index 00000000..c631defa --- /dev/null +++ b/Meshtastic/Enums/BluetoothModes.swift @@ -0,0 +1,39 @@ +// +// BluetoothModes.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/19/22. +// + +enum BluetoothModes: Int, CaseIterable, Identifiable { + + case randomPin = 0 + case fixedPin = 1 + case noPin = 2 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + case .randomPin: + return "Random PIN" + case .fixedPin: + return "Fixed PIN" + case .noPin: + return "No PIN (Just Works)" + } + } + } + func protoEnumValue() -> Config.BluetoothConfig.PairingMode { + + switch self { + + case .randomPin: + return Config.BluetoothConfig.PairingMode.randomPin + case .fixedPin: + return Config.BluetoothConfig.PairingMode.fixedPin + case .noPin: + return Config.BluetoothConfig.PairingMode.noPin + } + } +} 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/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index a6a78c44..08a77c6c 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1048,6 +1048,35 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph return 0 } + public func saveBluetoothConfig(config: Config.BluetoothConfig, fromUser: UserEntity, toUser: UserEntity) -> Int64 { + + var adminPacket = AdminMessage() + adminPacket.setConfig.bluetooth = config + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(connectedPeripheral.num) + meshPacket.from = 0 //UInt32(connectedPeripheral.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Int64 { var adminPacket = AdminMessage() 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..79419d51 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -92,6 +92,91 @@ 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.bluetooth.fixedPin) + + } + fetchedNode[0].bluetoothConfig = newBluetoothConfig + + } else { + + if isDefault { + + fetchedNode[0].bluetoothConfig?.enabled = true + fetchedNode[0].bluetoothConfig?.mode = Int32(config.bluetooth.mode.rawValue) + fetchedNode[0].bluetoothConfig?.fixedPin = Int32("123456") ?? 123456 + + } else { + + fetchedNode[0].bluetoothConfig?.enabled = config.bluetooth.enabled + fetchedNode[0].bluetoothConfig?.mode = Int32(config.bluetooth.mode.rawValue) + fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.bluetooth.fixedPin) + + } + } + + do { + + try context.save() + if meshlogging { MeshLogger.log("💾 Updated Bluetooth Config for node number: \(String(nodeNum))") } + + } catch { + + context.rollback() + + let nsError = error as NSError + print("💥 Error Updating Core Data BluetoothConfigEntity: \(nsError)") + } + } else { + + print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Bluetooth Config") + } + + } catch { + + let nsError = error as NSError + print("💥 Fetching node for core data BluetoothConfigEntity failed: \(nsError)") + } + } + if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) { var isDefault = false @@ -99,11 +184,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/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 319888a5..bf45c105 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModel v 6.xcdatamodel + MeshtasticDataModel v 7.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents index 6f9b7000..22353512 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 6.xcdatamodel/contents @@ -1,5 +1,5 @@ - + diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 7.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 7.xcdatamodel/contents new file mode 100644 index 00000000..d58af5fd --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 7.xcdatamodel/contents @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Views/Helpers/DistanceText.swift b/Meshtastic/Views/Helpers/DistanceText.swift new file mode 100644 index 00000000..1709b5f4 --- /dev/null +++ b/Meshtastic/Views/Helpers/DistanceText.swift @@ -0,0 +1,22 @@ +// +// DistanceText.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/19/22. +// + +import SwiftUI +import CoreLocation +import MapKit + +struct DistanceText: View { + + var meters: CLLocationDistance + + var body: some View { + + let distanceFormatter = MKDistanceFormatter() + + Text("Distance: \(distanceFormatter.string(fromDistance: Double(meters)))") + } +} diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 95755bd4..16009570 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -9,6 +9,7 @@ // A view showing a list of devices that have been seen on the mesh network from the perspective of the connected device. import SwiftUI +import CoreLocation struct NodeList: View { @@ -35,8 +36,8 @@ struct NodeList: View { if nodes.count == 0 { Text("Scan for Radios").font(.largeTitle) - Text("No LoRa Mesh Nodes Found").font(.title2) - Text("Go to the bluetooth section in the bottom right menu and click the Start Scanning button to scan for nearby radios and find your Meshtastic device. Make sure your device is powered on and near your phone or tablet.") + Text("No Meshtastic Nodes Found").font(.title2) + Text("Go to the bluetooth section in the bottom right menu and click the Start Scanning button to scan for nearby radios and find your Meshtastic device. Make sure your device is powered on and near your iPhone, iPad or Mac.") .font(.body) Text("Once the device shows under Available Devices touch the device you want to connect to and it will pull node information over BLE and populate the node list and mesh map in the Meshtastic app.") Text("Views with bluetooth functionality will show an indicator in the upper right hand corner show if bluetooth is on, and if a device is connected.") @@ -87,14 +88,43 @@ struct NodeList: View { Image(systemName: "clock.badge.checkmark.fill").font(.title3) .foregroundColor(.accentColor).symbolRenderingMode(.hierarchical) + if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { LastHeardText(lastHeard: node.lastHeard).font(.subheadline).foregroundColor(.gray) + } else { LastHeardText(lastHeard: node.lastHeard).font(.title3).foregroundColor(.gray) } } + + if node.positions?.count ?? 0 > 0 { + + Spacer() + HStack(alignment: .bottom) { + + let lastPostion = node.positions!.reversed()[0] as! PositionEntity + + let myCoord = CLLocation(latitude: LocationHelper.currentLocation.latitude, longitude: LocationHelper.currentLocation.longitude) + + let nodeCoord = CLLocation(latitude: lastPostion.coordinate!.latitude, longitude: lastPostion.coordinate!.longitude) + + let metersAway = nodeCoord.distance(from: myCoord) + + Image(systemName: "lines.measurement.horizontal").font(.title3) + .foregroundColor(.accentColor).symbolRenderingMode(.hierarchical) + + if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { + + DistanceText(meters: metersAway).font(.subheadline).foregroundColor(.gray) + + } else { + + DistanceText(meters: metersAway).font(.title3).foregroundColor(.gray) + } + } + } } .padding([.leading, .top, .bottom]) } @@ -109,13 +139,6 @@ struct NodeList: View { self.bleManager.userSettings = userSettings self.bleManager.context = context self.initialLoad = false - -// if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { -// -// if nodes.count > 0 { -// selection = "0" -// } -// } } } } diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift new file mode 100644 index 00000000..e75e4f1d --- /dev/null +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -0,0 +1,167 @@ +// +// BluetoothConfig.swift +// Meshtastic Apple +// +// Copyright (c) Garth Vander Houwen 8/18/22. +// + +import SwiftUI + +struct BluetoothConfig: View { + + @Environment(\.managedObjectContext) var context + @EnvironmentObject var bleManager: BLEManager + + var node: NodeInfoEntity? + + @State private var isPresentingSaveConfirm: Bool = false + @State var initialLoad: Bool = true + @State var hasChanges = false + + @State var enabled = true + /// Determines the pairing strategy for the device + @State var mode = 0 + + /// Specified pin for PairingMode.FixedPin + @State var fixedPin = "123456" + + let numberFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.numberStyle = .none + return formatter + }() + + var body: some View { + + VStack { + + Form { + + Section(header: Text("Options")) { + + Toggle(isOn: $enabled) { + + Label("Enabled", systemImage: "antenna.radiowaves.left.and.right") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + + Picker("Pairing Mode", selection: $mode ) { + ForEach(BluetoothModes.allCases) { bm in + Text(bm.description) + } + } + .pickerStyle(DefaultPickerStyle()) + + 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) + } + } + } + .disabled(bleManager.connectedPeripheral == nil) + + 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 Bluetooth Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var bc = Config.BluetoothConfig() + bc.enabled = enabled + bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin + bc.fixedPin = UInt32(fixedPin) ?? 123456 + + let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: node!.user!, toUser: node!.user!) + + if adminMessageId > 0 { + + // Should show a saved successfully alert once I know that to be true + // for now just disable the button after a successful save + hasChanges = false + + } else { + + } + } + } + } + .navigationTitle("Display Config") + .navigationBarItems(trailing: + + ZStack { + + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") + }) + .onAppear { + + if self.initialLoad{ + + self.bleManager.context = context + + self.enabled = node!.bluetoothConfig?.enabled ?? true + self.mode = Int(node!.bluetoothConfig?.mode ?? 0) + //self.fixedPin = (String(node!.bluetoothConfig?.fixedPin) ?? "123456") + self.hasChanges = false + self.initialLoad = false + } + } + .onChange(of: enabled) { newEnabled in + + if node != nil && node!.bluetoothConfig != nil { + + if newEnabled != node!.bluetoothConfig!.enabled { hasChanges = true } + } + } + .onChange(of: mode) { newMode in + + if node != nil && node!.bluetoothConfig != nil { + + if newMode != node!.bluetoothConfig!.mode { hasChanges = true } + } + } + .onChange(of: fixedPin) { newFixedPin in + + if node != nil && node!.bluetoothConfig != nil { + + if newFixedPin != String(node!.bluetoothConfig!.fixedPin) { hasChanges = true } + } + } + + .navigationViewStyle(StackNavigationViewStyle()) + } +} 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/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index a2348bea..19201fda 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -370,6 +370,13 @@ struct PositionConfig: View { if newSmartPosition != node!.positionConfig!.smartPositionEnabled { hasChanges = true } } } + .onChange(of: positionBroadcastSeconds) { newPositionBroadcastSeconds in + + if node != nil && node!.positionConfig != nil { + + if newPositionBroadcastSeconds != node!.positionConfig!.positionBroadcastSeconds { hasChanges = true } + } + } .onChange(of: deviceGpsEnabled) { newDeviceGps in if node != nil && node!.positionConfig != nil { 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 } } }) diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index e1887074..db8d7702 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -69,6 +69,18 @@ struct Settings: View { } .disabled(bleManager.connectedPeripheral == nil) + NavigationLink() { + + BluetoothConfig(node: nodes.first(where: { $0.num == connectedNodeNum })) + } label: { + + Image(systemName: "antenna.radiowaves.left.and.right") + .symbolRenderingMode(.hierarchical) + + Text("Bluetooth (BLE)") + } + .disabled(bleManager.connectedPeripheral == nil) + NavigationLink { DeviceConfig(node: nodes.first(where: { $0.num == connectedNodeNum })) } label: {