Updates for channel import and blemanager dispatchque update warnings

This commit is contained in:
Garth Vander Houwen 2022-10-22 07:35:55 -07:00
parent 6263e6fd83
commit edcecd8e0e
6 changed files with 133 additions and 65 deletions

View file

@ -25,8 +25,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
private var centralManager: CBCentralManager!
@Published var peripherals = [Peripheral]()
@Published var peripherals: [Peripheral]
@Published var connectedPeripheral: Peripheral!
@Published var lastConnectionError: String
@Published var minimumVersion = "1.3.43"
@ -79,9 +78,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// MARK: init BLEManager
override init() {
//self.meshLoggingEnabled = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false
self.lastConnectionError = ""
self.connectedVersion = "0.0.0"
self.peripherals = [Peripheral]()
super.init()
// let bleQueue: DispatchQueue = DispatchQueue(label: "CentralManager")
centralManager = CBCentralManager(delegate: self, queue: nil)
@ -102,23 +101,22 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// MARK: Scanning for BLE Devices
// Scan for nearby BLE devices using the Meshtastic BLE service ID
func startScanning() {
if isSwitchedOn {
centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: nil)
isScanning = centralManager.isScanning
DispatchQueue.main.async {
self.isScanning = self.centralManager.isScanning
}
print("✅ Scanning Started")
}
}
// Stop Scanning For BLE Devices
func stopScanning() {
if centralManager.isScanning {
centralManager.stopScan()
isScanning = centralManager.isScanning
DispatchQueue.main.async{
self.isScanning = self.centralManager.isScanning
}
print("🛑 Stopped Scanning")
}
}
@ -159,8 +157,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Connect to a specific peripheral
func connectTo(peripheral: CBPeripheral) {
stopScanning()
isConnecting = true
lastConnectionError = ""
DispatchQueue.main.async {
self.isConnecting = true
self.lastConnectionError = ""
}
if connectedPeripheral != nil {
MeshLogger.log(" BLE Disconnecting from: \(connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")")
disconnectPeripheral()
@ -225,24 +225,31 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Called when a peripheral is connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.isConnecting = false
self.isConnected = true
DispatchQueue.main.async {
self.isConnecting = false
self.isConnected = true
}
if userSettings?.preferredPeripheralId.count ?? 0 < 1 {
self.userSettings?.preferredPeripheralId = peripheral.identifier.uuidString
self.preferredPeripheral = true
DispatchQueue.main.async {
self.userSettings?.preferredPeripheralId = peripheral.identifier.uuidString
self.preferredPeripheral = true
}
} else if userSettings!.preferredPeripheralId == peripheral.identifier.uuidString {
self.preferredPeripheral = true
DispatchQueue.main.async {
self.preferredPeripheral = true
}
} else {
self.preferredPeripheral = false
print("Trying to connect a non prefered peripheral")
}
// Invalidate and reset connection timer count, remove any connection errors
self.lastConnectionError = ""
// Invalidate and reset connection timer count
self.timeoutTimerCount = 0
if self.timeoutTimer != nil {
self.timeoutTimer!.invalidate()
}
// remove any connection errors
self.lastConnectionError = ""
// Map the peripheral to the connectedPeripheral ObservedObjects
connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first
if connectedPeripheral != nil {
@ -485,12 +492,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// MyInfo
if decodedInfo.myInfo.isInitialized && decodedInfo.myInfo.myNodeNum > 0 {
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")
let version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))]
nowKnown = true
connectedVersion = String(version)
DispatchQueue.main.async {
self.connectedVersion = String(version)
}
let supportedVersion = connectedVersion == "0.0.0" || self.minimumVersion.compare(connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(connectedVersion, options: .numeric) == .orderedSame
@ -498,7 +506,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if !supportedVersion {
invalidVersion = true
self.lastConnectionError = "🚨 Update your firmware"
lastConnectionError = "🚨 Update your firmware"
return
@ -506,7 +514,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, peripheralId: self.connectedPeripheral.id, context: context!)
self.userSettings?.preferredNodeNum = myInfo?.myNodeNum ?? 0
userSettings?.preferredNodeNum = myInfo?.myNodeNum ?? 0
if myInfo != nil {
self.connectedPeripheral.num = myInfo!.myNodeNum
@ -632,10 +640,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
if decodedInfo.configCompleteID != 0 && decodedInfo.configCompleteID == configNonce {
invalidVersion = false
lastConnectionError = ""
DispatchQueue.main.async {
self.invalidVersion = false
self.lastConnectionError = ""
self.isSubscribed = true
}
MeshLogger.log("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)")
self.isSubscribed = true
peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected })
// Config conplete returns so we don't read the characteristic again
return
@ -1067,9 +1077,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if let decodedData = Data(base64Encoded: decodedString) {
do {
var channelSet: ChannelSet = try ChannelSet(serializedData: decodedData)
print(channelSet)
var i:Int32 = 0
for cs in channelSet.settings {
i += 1
var chan = Channel()
chan.settings = cs
@ -1086,7 +1096,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
meshPacket.from = 0 //UInt32(connectedPeripheral.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.wantAck = true
meshPacket.wantAck = false
meshPacket.hopLimit = 0
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
@ -1097,8 +1107,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
toRadio.packet = meshPacket
let binaryData: Data = try! toRadio.serializedData()
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
MeshLogger.log("💾 Saved a Channel for: \(String(connectedPeripheral.num))")
//let timer1 = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { timer in
self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse)
MeshLogger.log("💾 Saved a Channel for: \(String(self.connectedPeripheral.num))")
//}
}
print(chan)
}
@ -1125,8 +1140,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
toRadio.packet = meshPacket
let binaryData: Data = try! toRadio.serializedData()
if connectedPeripheral!.peripheral.state == CBPeripheralState.connected {
connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse)
MeshLogger.log("💾 Saved a LoRaConfig for: \(String(connectedPeripheral.num))")
// let timer1 = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in
self.connectedPeripheral.peripheral.writeValue(binaryData, for: self.TORADIO_characteristic, type: .withResponse)
MeshLogger.log("💾 Saved a LoRaConfig for: \(String(self.connectedPeripheral.num))")
// }
}
return true

View file

@ -6,6 +6,9 @@ extension Data {
let mac: String = reduce("") {$0 + String(format: "%02x:", $1)}
return String(mac.dropLast())
}
var hexDescription: String {
return reduce("") {$0 + String(format: "%02x", $1)}
}
}
extension Date {

View file

@ -762,7 +762,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
let fetchedMyInfo = try context.fetch(fetchedMyInfoRequest) as! [MyInfoEntity]
if fetchedMyInfo.count == 1 {
if fetchedMyInfo.count == 1 && channel.role.rawValue > 0 {
let newChannel = ChannelEntity(context: context)
newChannel.index = Int32(channel.index)
@ -776,14 +776,13 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
mutableChannels.add(newChannel)
fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet
try context.save()
MeshLogger.log("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
} else {
} else if channel.role.rawValue > 0 {
print("💥 Trying to save a channel to a MyInfo that does not exist: \(fromNum)")
}
try context.save()
MeshLogger.log("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
} catch {
context.rollback()

View file

@ -82,7 +82,8 @@ struct AppSettings: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var userSettings: UserSettings
@State private var isPresentingCoreDataResetConfirm = false
@State private var preferredDeviceConnected = false
var perferredPeripheral: String {
@ -104,20 +105,6 @@ struct AppSettings: View {
.keyboardType(.asciiCapable)
.disableAutocorrection(true)
.listRowSeparator(.visible)
// HStack {
// Label("Radio", systemImage: "flipphone")
// Text(userSettings.preferredPeripheralName)
// .foregroundColor(.gray)
//
// }
// Text("This option is set via the preferred radio toggle for the connected device on the bluetooth tab.")
// .font(.caption)
// .listRowSeparator(.hidden)
// Text("The preferred radio will automatically reconnect if it becomes disconnected and is still within range.")
// .font(.caption2)
// .foregroundColor(.gray)
}
Section(header: Text("Options")) {
@ -159,6 +146,26 @@ struct AppSettings: View {
}
}
}
HStack {
Button("Clear App Data", role: .destructive) {
isPresentingCoreDataResetConfirm = true
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding()
.confirmationDialog(
"Are you sure?",
isPresented: $isPresentingCoreDataResetConfirm,
titleVisibility: .visible
) {
Button("Erase all app data?", role: .destructive) {
bleManager.disconnectPeripheral()
clearCoreDataDatabase(context: context)
}
}
}
}
.navigationTitle("App Settings")
.navigationBarItems(trailing:

View file

@ -206,6 +206,10 @@ struct PositionConfig: View {
) {
Button("Save Position Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") {
if fixedPosition {
let sendPosition = bleManager.sendPosition(destNum: bleManager.connectedPeripheral.num, wantAck: true)
}
var pc = Config.PositionConfig()
pc.positionBroadcastSmartEnabled = smartPositionEnabled
pc.gpsEnabled = deviceGpsEnabled
@ -225,9 +229,6 @@ struct PositionConfig: View {
if includeSpeed { pf.insert(.Speed) }
if includeHeading { pf.insert(.Heading) }
pc.positionFlags = UInt32(pf.rawValue)
if fixedPosition {
let sendPosition = bleManager.sendPosition(destNum: bleManager.connectedPeripheral.num, wantAck: true)
}
let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: node!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true

View file

@ -79,64 +79,104 @@ struct ShareChannels: View {
.labelsHidden()
.disabled(channel.role == 1)
Text((channel.name!.isEmpty ? "Primary" : channel.name) ?? "Primary")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 1 && channel.role > 0 {
Toggle("Channel 1 Included", isOn: $includeChannel1)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 2 && channel.role > 0 {
Toggle("Channel 2 Included", isOn: $includeChannel2)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 3 && channel.role > 0 {
Toggle("Channel 3 Included", isOn: $includeChannel3)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 4 && channel.role > 0 {
Toggle("Channel 4 Included", isOn: $includeChannel4)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 5 && channel.role > 0 {
Toggle("Channel 5 Included", isOn: $includeChannel5)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 6 && channel.role > 0 {
Toggle("Channel 6 Included", isOn: $includeChannel6)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
} else if channel.index == 7 && channel.role > 0 {
Toggle("Channel 7 Included", isOn: $includeChannel7)
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 0)
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
Image(systemName: "lock.fill")
if channel.psk?.hexDescription.count ?? 0 < 3 {
Image(systemName: "lock.slash")
.foregroundColor(.red)
} else {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
}
Spacer()
}