Assorted updates

This commit is contained in:
Garth Vander Houwen 2023-01-31 10:50:17 -08:00
parent 0108080c87
commit 921f95cc63
11 changed files with 227 additions and 45 deletions

View file

@ -22,6 +22,8 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
case `in` = 10
case nz865 = 11
case th = 12
case ua433 = 14
case ua868 = 15
case lora24 = 13
var id: Int { self.rawValue }
@ -54,6 +56,10 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
return "New Zealand 865mhz"
case .th:
return "Thailand"
case .ua433:
return "Ukraine 433mhz"
case .ua868:
return "Ukraine 868mhz"
case .lora24:
return "2.4 GHZ"
}
@ -90,6 +96,10 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
return Config.LoRaConfig.RegionCode.nz865
case .th:
return Config.LoRaConfig.RegionCode.th
case .ua433:
return Config.LoRaConfig.RegionCode.ua433
case .ua868:
return Config.LoRaConfig.RegionCode.ua868
case .lora24:
return Config.LoRaConfig.RegionCode.lora24
}
@ -100,6 +110,7 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
case LongFast = 0
case LongSlow = 1
case LongModerate = 7
case VLongSlow = 2
case MedSlow = 3
case MedFast = 4
@ -115,6 +126,8 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
return "Long Range - Fast"
case .LongSlow:
return "Long Range - Slow"
case .LongModerate:
return "Long Range - Moderate"
case .VLongSlow:
return "Very Long Range - Slow"
case .MedSlow:
@ -136,10 +149,12 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
return Config.LoRaConfig.ModemPreset.longFast
case .LongSlow:
return Config.LoRaConfig.ModemPreset.longSlow
case .LongModerate:
return Config.LoRaConfig.ModemPreset.longModerate
case .VLongSlow:
return Config.LoRaConfig.ModemPreset.veryLongSlow
return Config.LoRaConfig.ModemPreset.veryLongSlow
case .MedSlow:
return Config.LoRaConfig.ModemPreset.mediumSlow
return Config.LoRaConfig.ModemPreset.mediumSlow
case .MedFast:
return Config.LoRaConfig.ModemPreset.mediumFast
case .ShortSlow:

View file

@ -46,7 +46,7 @@ func localConfig (config: Config, context:NSManagedObjectContext, nodeNum: Int64
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
upsertDisplayConfigPacket(config: config, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertLoRaConfigPacket(config: config.lora, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
upsertNetworkConfigPacket(config: config, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
@ -759,8 +759,6 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
@ -811,7 +809,9 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
upsertDeviceConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
let lc = try? Config.LoRaConfig(serializedData: packet.decoded.payload)
upsertLoRaConfigPacket(config: lc!, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
upsertNetworkConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)

View file

@ -7,6 +7,38 @@
import CoreData
public func getNodeInfo(id: Int64, context: NSManagedObjectContext) -> NodeInfoEntity {
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
do {
let fetchNodeInfo = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
if fetchNodeInfo.count == 1 {
return fetchNodeInfo[0]
}
} catch {
return NodeInfoEntity(context: context)
}
return NodeInfoEntity(context: context)
}
public func getUser(id: Int64, context: NSManagedObjectContext) -> UserEntity {
let fetchUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
fetchUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
do {
let fetchedUser = try context.fetch(fetchUserRequest) as! [UserEntity]
if fetchedUser.count == 1 {
return fetchedUser[0]
}
} catch {
return UserEntity(context: context)
}
return UserEntity(context: context)
}
public func getWaypoint(id: Int64, context: NSManagedObjectContext) -> WaypointEntity {
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")

View file

@ -304,7 +304,7 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage
}
}
func upsertLoRaConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.lora.config %@", comment: "LoRa config received: %@"), String(nodeNum))
MeshLogger.log("📻 \(logString)")
@ -320,33 +320,34 @@ func upsertLoRaConfigPacket(config: Config, nodeNum: Int64, context: NSManagedOb
if fetchedNode[0].loRaConfig == nil {
// No lora config for node, save a new lora config
let newLoRaConfig = LoRaConfigEntity(context: context)
newLoRaConfig.regionCode = Int32(config.lora.region.rawValue)
newLoRaConfig.usePreset = config.lora.usePreset
newLoRaConfig.modemPreset = Int32(config.lora.modemPreset.rawValue)
newLoRaConfig.bandwidth = Int32(config.lora.bandwidth)
newLoRaConfig.spreadFactor = Int32(config.lora.spreadFactor)
newLoRaConfig.codingRate = Int32(config.lora.codingRate)
newLoRaConfig.frequencyOffset = config.lora.frequencyOffset
newLoRaConfig.hopLimit = Int32(config.lora.hopLimit)
newLoRaConfig.txPower = Int32(config.lora.txPower)
newLoRaConfig.txEnabled = config.lora.txEnabled
newLoRaConfig.channelNum = Int32(config.lora.channelNum)
newLoRaConfig.regionCode = Int32(config.region.rawValue)
newLoRaConfig.usePreset = config.usePreset
newLoRaConfig.modemPreset = Int32(config.modemPreset.rawValue)
newLoRaConfig.bandwidth = Int32(config.bandwidth)
newLoRaConfig.spreadFactor = Int32(config.spreadFactor)
newLoRaConfig.codingRate = Int32(config.codingRate)
newLoRaConfig.frequencyOffset = config.frequencyOffset
newLoRaConfig.hopLimit = Int32(config.hopLimit)
newLoRaConfig.txPower = Int32(config.txPower)
newLoRaConfig.txEnabled = config.txEnabled
newLoRaConfig.channelNum = Int32(config.channelNum)
fetchedNode[0].loRaConfig = newLoRaConfig
} else {
fetchedNode[0].loRaConfig?.regionCode = Int32(config.lora.region.rawValue)
fetchedNode[0].loRaConfig?.usePreset = config.lora.usePreset
fetchedNode[0].loRaConfig?.modemPreset = Int32(config.lora.modemPreset.rawValue)
fetchedNode[0].loRaConfig?.bandwidth = Int32(config.lora.bandwidth)
fetchedNode[0].loRaConfig?.spreadFactor = Int32(config.lora.spreadFactor)
fetchedNode[0].loRaConfig?.codingRate = Int32(config.lora.codingRate)
fetchedNode[0].loRaConfig?.frequencyOffset = config.lora.frequencyOffset
fetchedNode[0].loRaConfig?.hopLimit = Int32(config.lora.hopLimit)
fetchedNode[0].loRaConfig?.txPower = Int32(config.lora.txPower)
fetchedNode[0].loRaConfig?.txEnabled = config.lora.txEnabled
fetchedNode[0].loRaConfig?.channelNum = Int32(config.lora.channelNum)
fetchedNode[0].loRaConfig?.regionCode = Int32(config.region.rawValue)
fetchedNode[0].loRaConfig?.usePreset = config.usePreset
fetchedNode[0].loRaConfig?.modemPreset = Int32(config.modemPreset.rawValue)
fetchedNode[0].loRaConfig?.bandwidth = Int32(config.bandwidth)
fetchedNode[0].loRaConfig?.spreadFactor = Int32(config.spreadFactor)
fetchedNode[0].loRaConfig?.codingRate = Int32(config.codingRate)
fetchedNode[0].loRaConfig?.frequencyOffset = config.frequencyOffset
fetchedNode[0].loRaConfig?.hopLimit = Int32(config.hopLimit)
fetchedNode[0].loRaConfig?.txPower = Int32(config.txPower)
fetchedNode[0].loRaConfig?.txEnabled = config.txEnabled
fetchedNode[0].loRaConfig?.channelNum = Int32(config.channelNum)
}
do {
try context.save()
context.refresh(fetchedNode[0], mergeChanges: true)
print("💾 Updated LoRa Config for node number: \(String(nodeNum))")
} catch {
context.rollback()

View file

@ -168,6 +168,10 @@ struct Config {
/// Defaults to PIN_BUZZER if defined.
var buzzerGpio: UInt32 = 0
///
/// Sets the role of node
var rebroadcastMode: Config.DeviceConfig.RebroadcastMode = .all
var unknownFields = SwiftProtobuf.UnknownStorage()
///
@ -198,13 +202,13 @@ struct Config {
///
/// Repeater device role
/// Mesh packets will simply be rebroadcasted over this node. Nodes under this role node will not originate NodeInfo, Position, Telemetry
/// or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factory, and coding rate.
/// Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry
/// or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate.
case repeater // = 4
///
/// Tracker device role
/// Position Mesh packets for will be higher priority and sent more frequently by default.
/// Position Mesh packets will be prioritized higher and sent more frequently by default.
case tracker // = 5
case UNRECOGNIZED(Int)
@ -238,6 +242,51 @@ struct Config {
}
///
/// Defines the device's behavior for how messages are rebroadcast
enum RebroadcastMode: SwiftProtobuf.Enum {
typealias RawValue = Int
///
/// Default behavior.
/// Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params.
case all // = 0
///
/// Same as behavior as ALL but skips packet decoding and simply rebroadcasts them.
/// Only available in Repeater role. Setting this on any other roles will result in ALL behavior.
case allSkipDecoding // = 1
///
/// Ignores observed messages from foreign meshes that are open or those which it cannot decrypt.
/// Only rebroadcasts message on the nodes local primary / secondary channels.
case localOnly // = 2
case UNRECOGNIZED(Int)
init() {
self = .all
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .all
case 1: self = .allSkipDecoding
case 2: self = .localOnly
default: self = .UNRECOGNIZED(rawValue)
}
}
var rawValue: Int {
switch self {
case .all: return 0
case .allSkipDecoding: return 1
case .localOnly: return 2
case .UNRECOGNIZED(let i): return i
}
}
}
init() {}
}
@ -905,6 +954,14 @@ struct Config {
/// If true, sets RX boosted gain mode on SX126X based radios
var sx126XRxBoostedGain: Bool = false
///
/// This parameter is for advanced users and licensed HAM radio operators.
/// Ignore Channel Calculation and use this frequency instead. The frequency_offset
/// will still be applied. This will allow you to use out-of-band frequencies.
/// Please respect your local laws and regulations. If you are a HAM, make sure you
/// enable HAM mode and turn off encryption.
var overrideFrequency: Float = 0
///
/// For testing it is useful sometimes to force a node to never listen to
/// particular other nodes (simulating radio out of range). All nodenums listed
@ -1186,6 +1243,15 @@ extension Config.DeviceConfig.Role: CaseIterable {
]
}
extension Config.DeviceConfig.RebroadcastMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DeviceConfig.RebroadcastMode] = [
.all,
.allSkipDecoding,
.localOnly,
]
}
extension Config.PositionConfig.PositionFlags: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.PositionConfig.PositionFlags] = [
@ -1303,6 +1369,7 @@ extension Config: @unchecked Sendable {}
extension Config.OneOf_PayloadVariant: @unchecked Sendable {}
extension Config.DeviceConfig: @unchecked Sendable {}
extension Config.DeviceConfig.Role: @unchecked Sendable {}
extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {}
extension Config.PositionConfig: @unchecked Sendable {}
extension Config.PositionConfig.PositionFlags: @unchecked Sendable {}
extension Config.PowerConfig: @unchecked Sendable {}
@ -1491,6 +1558,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
3: .standard(proto: "debug_log_enabled"),
4: .standard(proto: "button_gpio"),
5: .standard(proto: "buzzer_gpio"),
6: .standard(proto: "rebroadcast_mode"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -1504,6 +1572,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
case 3: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }()
case 4: try { try decoder.decodeSingularUInt32Field(value: &self.buttonGpio) }()
case 5: try { try decoder.decodeSingularUInt32Field(value: &self.buzzerGpio) }()
case 6: try { try decoder.decodeSingularEnumField(value: &self.rebroadcastMode) }()
default: break
}
}
@ -1525,6 +1594,9 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
if self.buzzerGpio != 0 {
try visitor.visitSingularUInt32Field(value: self.buzzerGpio, fieldNumber: 5)
}
if self.rebroadcastMode != .all {
try visitor.visitSingularEnumField(value: self.rebroadcastMode, fieldNumber: 6)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -1534,6 +1606,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
if lhs.debugLogEnabled != rhs.debugLogEnabled {return false}
if lhs.buttonGpio != rhs.buttonGpio {return false}
if lhs.buzzerGpio != rhs.buzzerGpio {return false}
if lhs.rebroadcastMode != rhs.rebroadcastMode {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
@ -1550,6 +1623,14 @@ extension Config.DeviceConfig.Role: SwiftProtobuf._ProtoNameProviding {
]
}
extension Config.DeviceConfig.RebroadcastMode: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "ALL"),
1: .same(proto: "ALL_SKIP_DECODING"),
2: .same(proto: "LOCAL_ONLY"),
]
}
extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = Config.protoMessageName + ".PositionConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
@ -1987,6 +2068,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
11: .standard(proto: "channel_num"),
12: .standard(proto: "override_duty_cycle"),
13: .standard(proto: "sx126x_rx_boosted_gain"),
14: .standard(proto: "override_frequency"),
103: .standard(proto: "ignore_incoming"),
]
@ -2009,6 +2091,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
case 11: try { try decoder.decodeSingularUInt32Field(value: &self.channelNum) }()
case 12: try { try decoder.decodeSingularBoolField(value: &self.overrideDutyCycle) }()
case 13: try { try decoder.decodeSingularBoolField(value: &self.sx126XRxBoostedGain) }()
case 14: try { try decoder.decodeSingularFloatField(value: &self.overrideFrequency) }()
case 103: try { try decoder.decodeRepeatedUInt32Field(value: &self.ignoreIncoming) }()
default: break
}
@ -2055,6 +2138,9 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
if self.sx126XRxBoostedGain != false {
try visitor.visitSingularBoolField(value: self.sx126XRxBoostedGain, fieldNumber: 13)
}
if self.overrideFrequency != 0 {
try visitor.visitSingularFloatField(value: self.overrideFrequency, fieldNumber: 14)
}
if !self.ignoreIncoming.isEmpty {
try visitor.visitPackedUInt32Field(value: self.ignoreIncoming, fieldNumber: 103)
}
@ -2075,6 +2161,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
if lhs.channelNum != rhs.channelNum {return false}
if lhs.overrideDutyCycle != rhs.overrideDutyCycle {return false}
if lhs.sx126XRxBoostedGain != rhs.sx126XRxBoostedGain {return false}
if lhs.overrideFrequency != rhs.overrideFrequency {return false}
if lhs.ignoreIncoming != rhs.ignoreIncoming {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true

View file

@ -220,9 +220,34 @@ struct OEMStore {
/// The default device encryption key, 16 or 32 byte
var oemAesKey: Data = Data()
///
/// A Preset LocalConfig to apply during factory reset
var oemLocalConfig: LocalConfig {
get {return _oemLocalConfig ?? LocalConfig()}
set {_oemLocalConfig = newValue}
}
/// Returns true if `oemLocalConfig` has been explicitly set.
var hasOemLocalConfig: Bool {return self._oemLocalConfig != nil}
/// Clears the value of `oemLocalConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalConfig() {self._oemLocalConfig = nil}
///
/// A Preset LocalModuleConfig to apply during factory reset
var oemLocalModuleConfig: LocalModuleConfig {
get {return _oemLocalModuleConfig ?? LocalModuleConfig()}
set {_oemLocalModuleConfig = newValue}
}
/// Returns true if `oemLocalModuleConfig` has been explicitly set.
var hasOemLocalModuleConfig: Bool {return self._oemLocalModuleConfig != nil}
/// Clears the value of `oemLocalModuleConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalModuleConfig() {self._oemLocalModuleConfig = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _oemLocalConfig: LocalConfig? = nil
fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -413,6 +438,8 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
4: .standard(proto: "oem_font"),
5: .standard(proto: "oem_text"),
6: .standard(proto: "oem_aes_key"),
7: .standard(proto: "oem_local_config"),
8: .standard(proto: "oem_local_module_config"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -427,12 +454,18 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
case 4: try { try decoder.decodeSingularEnumField(value: &self.oemFont) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.oemText) }()
case 6: try { try decoder.decodeSingularBytesField(value: &self.oemAesKey) }()
case 7: try { try decoder.decodeSingularMessageField(value: &self._oemLocalConfig) }()
case 8: try { try decoder.decodeSingularMessageField(value: &self._oemLocalModuleConfig) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.oemIconWidth != 0 {
try visitor.visitSingularUInt32Field(value: self.oemIconWidth, fieldNumber: 1)
}
@ -451,6 +484,12 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
if !self.oemAesKey.isEmpty {
try visitor.visitSingularBytesField(value: self.oemAesKey, fieldNumber: 6)
}
try { if let v = self._oemLocalConfig {
try visitor.visitSingularMessageField(value: v, fieldNumber: 7)
} }()
try { if let v = self._oemLocalModuleConfig {
try visitor.visitSingularMessageField(value: v, fieldNumber: 8)
} }()
try unknownFields.traverse(visitor: &visitor)
}
@ -461,6 +500,8 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
if lhs.oemFont != rhs.oemFont {return false}
if lhs.oemText != rhs.oemText {return false}
if lhs.oemAesKey != rhs.oemAesKey {return false}
if lhs._oemLocalConfig != rhs._oemLocalConfig {return false}
if lhs._oemLocalModuleConfig != rhs._oemLocalModuleConfig {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -111,7 +111,7 @@ struct Connect: View {
if isUnsetRegion {
HStack {
NavigationLink {
LoRaConfig(node: node, connectedNode: node)
LoRaConfig(node: node)
} label: {
Label("set.region", systemImage: "globe.americas.fill")
.foregroundColor(.red)

View file

@ -15,7 +15,7 @@ struct NodeMap: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var userSettings: UserSettings
@AppStorage("meshMapType") var type: String = "hybrid"
@AppStorage("meshMapCustomTileServer") var customTileServer: String = "" {
didSet {
if customTileServer == "" {
@ -39,7 +39,7 @@ struct NodeMap: View {
), animation: .easeIn)
private var waypoints: FetchedResults<WaypointEntity>
@State private var mapType: MKMapType = .standard
@State private var mapType: MKMapType?
@State var waypointCoordinate: CLLocationCoordinate2D = LocationHelper.DefaultLocation
@State var editingWaypoint: Int = 0
@State private var presentingWaypointForm = false
@ -68,7 +68,9 @@ struct NodeMap: View {
editingWaypoint = wpId
presentingWaypointForm = true
}
}, positions: Array(positions), waypoints: Array(waypoints), mapViewType: mapType,
}, positions: Array(positions),
waypoints: Array(waypoints),
mapViewType: mapType ?? MKMapType.standard,
centerOnPositionsOnly: false,
customMapOverlay: self.customMapOverlay,
overlays: self.overlays

View file

@ -14,7 +14,6 @@ struct LoRaConfig: View {
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
var connectedNode: NodeInfoEntity?
@State var isPresentingSaveConfirm = false
@State var hasChanges = false
@ -81,13 +80,14 @@ struct LoRaConfig: View {
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var lc = Config.LoRaConfig()
lc.hopLimit = UInt32(hopLimit)
lc.region = RegionCodes(rawValue: region)!.protoEnumValue()
lc.modemPreset = ModemPresets(rawValue: modemPreset)!.protoEnumValue()
lc.usePreset = true
lc.txEnabled = true
let adminMessageId = bleManager.saveLoRaConfig(config: lc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
let adminMessageId = bleManager.saveLoRaConfig(config: lc, fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
@ -116,9 +116,12 @@ struct LoRaConfig: View {
self.hasChanges = false
// Need to request a LoRaConfig from the remote node before allowing changes
if connectedNode != nil && node?.loRaConfig == nil {
if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil {
print("empty lora config")
_ = bleManager.requestLoRaConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestLoRaConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: region) { newRegion in

View file

@ -106,7 +106,7 @@ struct Settings: View {
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
UserConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum }))
UserConfig(node: nodes.first(where: { $0.num == selectedNode }))
} label: {
Image(systemName: "person.crop.rectangle.fill")
@ -116,14 +116,13 @@ struct Settings: View {
.tag(SettingsSidebar.userConfig)
NavigationLink() {
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum }))
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }))
} label: {
Image(systemName: "dot.radiowaves.left.and.right")
.symbolRenderingMode(.hierarchical)
Text("lora")
}
.tag(SettingsSidebar.loraConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink() {
Channels(node: nodes.first(where: { $0.num == connectedNodeNum }))

View file

@ -13,7 +13,6 @@ struct UserConfig: View {
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
var connectedNode: NodeInfoEntity?
@State private var isPresentingFactoryResetConfirm: Bool = false
@State private var isPresentingSaveConfirm: Bool = false
@ -86,10 +85,13 @@ struct UserConfig: View {
titleVisibility: .visible
) {
Button("Save User Config to \(node?.user?.longName ?? "Unknown")?") {
let connectedUser = getUser(id: bleManager.connectedPeripheral.num, context: context)
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var u = User()
u.shortName = shortName
u.longName = longName
let adminMessageId = bleManager.saveUser(config: u, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let adminMessageId = bleManager.saveUser(config: u, fromUser: connectedUser, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
hasChanges = false
goBack()