From 2102b0f31e894a6d575f7bc63bb16324158c5430 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Wed, 28 Sep 2022 15:50:35 -0700 Subject: [PATCH] getChannel cleanup --- Meshtastic/Helpers/BLEManager.swift | 227 ++++++++++++++-------------- 1 file changed, 115 insertions(+), 112 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 4bef22ee..e894917d 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -27,8 +27,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph @Published var peripherals = [Peripheral]() - @Published var connectedPeripheral: Peripheral! - @Published var lastConnectionError: String + @Published var connectedPeripheral: Peripheral! + @Published var lastConnectionError: String @Published var minimumVersion = "1.3.41" @Published var connectedVersion: String @Published var invalidVersion = false @@ -48,17 +48,17 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph var positionTimer: Timer? - let broadcastNodeNum: UInt32 = 4294967295 + let broadcastNodeNum: UInt32 = 4294967295 - /* Meshtastic Service Details */ - var TORADIO_characteristic: CBCharacteristic! - var FROMRADIO_characteristic: CBCharacteristic! - var FROMNUM_characteristic: CBCharacteristic! + /* Meshtastic Service Details */ + var TORADIO_characteristic: CBCharacteristic! + var FROMRADIO_characteristic: CBCharacteristic! + var FROMNUM_characteristic: CBCharacteristic! - let meshtasticServiceCBUUID = CBUUID(string: "0x6BA1B218-15A8-461F-9FA8-5DCAE273EAFD") - let TORADIO_UUID = CBUUID(string: "0xF75C76D2-129E-4DAD-A1DD-7866124401E7") - let FROMRADIO_UUID = CBUUID(string: "0x8BA2BCC2-EE02-4A55-A531-C525C5E454D5") - let FROMNUM_UUID = CBUUID(string: "0xED9DA18C-A800-4F66-A670-AA7547E34453") + let meshtasticServiceCBUUID = CBUUID(string: "0x6BA1B218-15A8-461F-9FA8-5DCAE273EAFD") + let TORADIO_UUID = CBUUID(string: "0xF75C76D2-129E-4DAD-A1DD-7866124401E7") + let FROMRADIO_UUID = CBUUID(string: "0x8BA2BCC2-EE02-4A55-A531-C525C5E454D5") + let FROMNUM_UUID = CBUUID(string: "0xED9DA18C-A800-4F66-A670-AA7547E34453") // Meshtastic DFU details let DFUSERVICE_UUID = CBUUID(string : "cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30") @@ -77,52 +77,52 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph private var meshLoggingEnabled: Bool = true let meshLog = documentsFolder.appendingPathComponent("meshlog.txt") - // MARK: init BLEManager - override init() { + // MARK: init BLEManager + override init() { //self.meshLoggingEnabled = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false - self.lastConnectionError = "" + self.lastConnectionError = "" self.connectedVersion = "0.0.0" - super.init() + super.init() // let bleQueue: DispatchQueue = DispatchQueue(label: "CentralManager") - centralManager = CBCentralManager(delegate: self, queue: nil) - } + centralManager = CBCentralManager(delegate: self, queue: nil) + } // MARK: Bluetooth enabled/disabled for the app - func centralManagerDidUpdateState(_ central: CBCentralManager) { - if central.state == .poweredOn { + func centralManagerDidUpdateState(_ central: CBCentralManager) { + if central.state == .poweredOn { - isSwitchedOn = true + isSwitchedOn = true startScanning() - } else { + } else { - isSwitchedOn = false - } - } + isSwitchedOn = false + } + } // MARK: Scanning for BLE Devices - // Scan for nearby BLE devices using the Meshtastic BLE service ID - func startScanning() { + // Scan for nearby BLE devices using the Meshtastic BLE service ID + func startScanning() { - if isSwitchedOn { + if isSwitchedOn { - centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: nil) + centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: nil) isScanning = centralManager.isScanning - print("✅ Scanning Started") - } - } + print("✅ Scanning Started") + } + } // Stop Scanning For BLE Devices - func stopScanning() { + func stopScanning() { - if centralManager.isScanning { + if centralManager.isScanning { - self.centralManager.stopScan() + centralManager.stopScan() isScanning = centralManager.isScanning - print("🛑 Stopped Scanning") - } - } + print("🛑 Stopped Scanning") + } + } // MARK: BLE Connect functions /// The action after the timeout-timer has fired @@ -175,19 +175,19 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.timeoutTimer!.invalidate() } - // Connect to a specific peripheral - func connectTo(peripheral: CBPeripheral) { + // Connect to a specific peripheral + func connectTo(peripheral: CBPeripheral) { if meshLoggingEnabled { MeshLogger.log("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") } - stopScanning() + stopScanning() if self.connectedPeripheral != nil { if meshLoggingEnabled { MeshLogger.log("â„šī¸ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")") } - self.disconnectPeripheral() - } + self.disconnectPeripheral() + } self.centralManager?.connect(peripheral) @@ -202,27 +202,27 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph let context = ["name": "@\(peripheral.name ?? "Unknown")"] self.timeoutTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true) RunLoop.current.add(self.timeoutTimer!, forMode: .common) - } + } - // Disconnect Connected Peripheral - func disconnectPeripheral() { + // Disconnect Connected Peripheral + func disconnectPeripheral() { guard let connectedPeripheral = connectedPeripheral else { return } - self.centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral) - self.isConnected = false - self.invalidVersion = false - self.connectedVersion = "0.0.0" - } + centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral) + isConnected = false + invalidVersion = false + connectedVersion = "0.0.0" + } - // Called each time a peripheral is discovered - func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { + // Called each time a peripheral is discovered + func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) { - var peripheralName: String = peripheral.name ?? "Unknown" + var peripheralName: String = peripheral.name ?? "Unknown" let last4Code: String = (peripheral.name != nil ? String(peripheral.name!.suffix(4)) : "Unknown") - if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String { - peripheralName = name - } + if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String { + peripheralName = name + } let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: last4Code, longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, maxChannels: 0, lastUpdate: Date(), subscribed: false, peripheral: peripheral) let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id }) @@ -243,12 +243,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } let today = Date() - let visibleDuration = Calendar.current.date(byAdding: .second, value: -2, to: today)! - peripherals.removeAll(where: { $0.lastUpdate <= visibleDuration}) - } + let visibleDuration = Calendar.current.date(byAdding: .second, value: -3, to: today)! + peripherals.removeAll(where: { $0.lastUpdate < visibleDuration}) + } - // Called when a peripheral is connected - func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { + // Called when a peripheral is connected + func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { self.isConnected = true @@ -261,7 +261,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } // Map the peripheral to the connectedPeripheral ObservedObjects - connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first + connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first if connectedPeripheral != nil { @@ -279,7 +279,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph peripheral.discoverServices([meshtasticServiceCBUUID, DFUSERVICE_UUID]) if meshLoggingEnabled { MeshLogger.log("✅ BLE Connected: \(peripheral.name ?? "Unknown")") } - } + } // Called when a Peripheral fails to connect func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { @@ -288,19 +288,19 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph disconnectPeripheral() } - // Disconnect Peripheral Event - func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { - // Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake - self.startScanning() + // Disconnect Peripheral Event + func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { + // Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake + self.startScanning() self.connectedPeripheral = nil - if let e = error { + if let e = error { // https://developer.apple.com/documentation/corebluetooth/cberror/code - let errorCode = (e as NSError).code - // unknown = 0, + let errorCode = (e as NSError).code + // unknown = 0, - if errorCode == 6 { // CBError.Code.connectionTimeout The connection has timed out unexpectedly. + if errorCode == 6 { // CBError.Code.connectionTimeout The connection has timed out unexpectedly. // Happens when device is manually reset / powered off // We will try and re-connect to this device @@ -310,78 +310,78 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.connectTo(peripheral: peripheral) } - } else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us. + } else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us. - // Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work. + // Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work. lastConnectionError = e.localizedDescription if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") } - } else if errorCode == 14 { // Peer removed pairing information + } else if errorCode == 14 { // Peer removed pairing information - // Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that + // Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that lastConnectionError = "🚨 \(e.localizedDescription) This error usually cannot be fixed without forgetting the device unders Settings > Bluetooth and re-connecting to the radio." if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(lastConnectionError)") } - } else { + } else { lastConnectionError = e.localizedDescription if meshLoggingEnabled { MeshLogger.log("🚨 BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") } } - } else { + } else { - // Disconnected without error which indicates user intent to disconnect + // Disconnected without error which indicates user intent to disconnect // Happens when swiping to disconnect if meshLoggingEnabled { MeshLogger.log("â„šī¸ BLE Disconnected: \(peripheral.name ?? "Unknown"): User Initiated Disconnect") } - } - } + } + } - // MARK: Peripheral Services functions - func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { + // MARK: Peripheral Services functions + func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { - if let e = error { + if let e = error { - print("đŸšĢ Discover Services error \(e)") - } + print("đŸšĢ Discover Services error \(e)") + } - guard let services = peripheral.services else { return } + guard let services = peripheral.services else { return } - for service in services { + for service in services { - if service.uuid == meshtasticServiceCBUUID { + if service.uuid == meshtasticServiceCBUUID { if meshLoggingEnabled { MeshLogger.log("✅ BLE Service for Meshtastic discovered by \(peripheral.name ?? "Unknown")") } - //peripheral.discoverCharacteristics(nil, for: service) - peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID], for: service) + //peripheral.discoverCharacteristics(nil, for: service) + peripheral.discoverCharacteristics([TORADIO_UUID, FROMRADIO_UUID, FROMNUM_UUID], for: service) - } else if (service.uuid == DFUSERVICE_UUID) { + } else if (service.uuid == DFUSERVICE_UUID) { print("✅ Meshtastic DFU service discovered OK") if meshLoggingEnabled { MeshLogger.log("✅ BLE Service for Meshtastic DFU discovered by \(peripheral.name ?? "Unknown")") } peripheral.discoverCharacteristics([DFUDATA_UUID, DFUSIZE_UUID, DFUREGION_UUID, DFURESULT_UUID, DFUCRC32_UUID], for: service) } - } - } + } + } func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) { print(invalidatedServices) } - // MARK: Discover Characteristics Event - func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { + // MARK: Discover Characteristics Event + func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { - if let e = error { + if let e = error { if meshLoggingEnabled { MeshLogger.log("đŸšĢ BLE didDiscoverCharacteristicsFor error by \(peripheral.name ?? "Unknown") \(e)") } - } + } - guard let characteristics = service.characteristics else { return } + guard let characteristics = service.characteristics else { return } - for characteristic in characteristics { + for characteristic in characteristics { switch characteristic.uuid { case TORADIO_UUID: @@ -442,7 +442,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.configTimeoutTimer = Timer.scheduledTimer(timeInterval: TimeInterval(15), target: self, selector: #selector(configTimeoutTimerFired), userInfo: context, repeats: false) RunLoop.current.add(self.configTimeoutTimer!, forMode: .common) } - } + } func requestDeviceMetadata() { guard (connectedPeripheral!.peripheral.state == CBPeripheralState.connected) else { return } @@ -498,9 +498,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } } - // MARK: Data Read / Update Characteristic Event - func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { - + // MARK: Data Read / Update Characteristic Event + func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { + if let e = error { print("đŸšĢ didUpdateValueFor Characteristic error \(e)") @@ -523,9 +523,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.centralManager?.cancelPeripheralConnection(peripheral) } - } + } - switch characteristic.uuid { + switch characteristic.uuid { case FROMRADIO_UUID: @@ -632,7 +632,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if meshLoggingEnabled { MeshLogger.log("â„šī¸ MESH PACKET received for Remote Hardware App UNHANDLED \(try! decodedInfo.packet.jsonString())") } case .positionApp: positionPacket(packet: decodedInfo.packet, meshLogging: meshLoggingEnabled, context: context!) - case .waypointApp: + case .waypointApp: if meshLoggingEnabled { MeshLogger.log("â„šī¸ MESH PACKET received for Waypoint App UNHANDLED \(try! decodedInfo.packet.jsonString())") } case .nodeinfoApp: @@ -739,8 +739,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph timer.invalidate() // invalidate the timer } else { - _ = self.getChannel(channelIndex: i, wantResponse: true) - i+=1; + if self.connectedPeripheral != nil { + + _ = self.getChannel(channelIndex: i, nodeNum: self.connectedPeripheral.num, wantResponse: true) + i+=1; + } } } return @@ -754,7 +757,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph default: print("🚨 Unhandled Characteristic UUID: \(characteristic.uuid)") - } + } // Either Read the config complete value or from num notify value peripheral.readValue(for: FROMRADIO_characteristic) @@ -1404,14 +1407,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph return 0 } - public func getChannel(channelIndex: UInt32, wantResponse: Bool) -> Bool { + public func getChannel(channelIndex: UInt32, nodeNum: Int64, wantResponse: Bool) -> Bool { var adminPacket = AdminMessage() adminPacket.getChannelRequest = channelIndex var meshPacket: MeshPacket = MeshPacket() - meshPacket.to = UInt32(connectedPeripheral.num) - meshPacket.from = 0 //UInt32(connectedPeripheral.num) + meshPacket.to = UInt32(nodeNum) + meshPacket.from = 0 //UInt32(cnodeNum) meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..