BLE Cleanup

This commit is contained in:
Garth Vander Houwen 2021-10-12 17:54:10 -07:00
parent 57d1cbc9eb
commit 3827ff816e
5 changed files with 79 additions and 76 deletions

View file

@ -11,16 +11,16 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
@ObservedObject private var meshData : MeshData
@ObservedObject private var messageData : MessageData
@Published private var centralManager: CBCentralManager!
private var centralManager: CBCentralManager!
@Published var connectedPeripheral: Peripheral!
@Published var connectedNode: NodeInfoModel!
@Published var lastConnectedNode: String
@Published var lastConnectionError: String
@Published var isSwitchedOn = false
@Published var peripherals = [Peripheral]()
@Published private var broadcastNodeId: UInt32 = 4294967295
private var broadcastNodeId: UInt32 = 4294967295
/* Meshtastic Service Details */
var TORADIO_characteristic: CBCharacteristic!
var FROMRADIO_characteristic: CBCharacteristic!
@ -33,12 +33,13 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
/* init BLEManager */
override init() {
self.meshData = MeshData()
self.messageData = MessageData()
self.lastConnectedNode = ""
self.lastConnectionError = ""
super.init()
centralManager = CBCentralManager(delegate: self, queue: nil)
//let options = [CBCentralManagerOptionRestoreIdentifierKey: "com.meshtastic.ble-central"]
centralManager = CBCentralManager(delegate: self, queue: nil)//, options: options)
centralManager.delegate = self
meshData.load()
messageData.load()
@ -47,9 +48,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// called when bluetooth is enabled/disabled for the app
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
isSwitchedOn = true
}
else {
isSwitchedOn = false
}
}
@ -58,6 +61,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
func startScanning() {
if isSwitchedOn {
peripherals.removeAll()
centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: nil)
print("Scanning Started")
@ -69,11 +73,23 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if centralManager.isScanning {
self.centralManager.stopScan()
print("Stopped Scanning")
}
}
// Connect to a specific peripheral
func connectTo(peripheral: CBPeripheral) {
stopScanning()
if connectedPeripheral != nil && connectedPeripheral.peripheral.state == CBPeripheralState.connected {
self.disconnectDevice()
}
//connectedPeripheral.peripheral = peripheral
self.centralManager?.connect(peripheral)
print("Connected to: \(peripheral.name ?? "Unknown")")
}
// Disconnect Device function
func disconnectDevice(){
@ -81,38 +97,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
self.centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral)
} else {
connectedNode = nil
connectedPeripheral = nil
}
}
// Connect to a Device via UUID
func connectToDevice(id: String) {
connectedPeripheral = peripherals.filter({ $0.peripheral.identifier.uuidString == id }).first
if connectedPeripheral != nil {
lastConnectedNode = connectedPeripheral.peripheral.identifier.uuidString
self.centralManager?.connect(connectedPeripheral!.peripheral)
print("Connected to: \(connectedPeripheral.peripheral.name ?? "Unknown")")
}
else {
print("Connection failed connectedPeripheral is nil")
}
}
// Connect to a specific peripheral
func connectTo(peripheral: CBPeripheral) {
if connectedPeripheral.peripheral.state == CBPeripheralState.connected {
self.disconnectDevice()
}
connectedPeripheral.peripheral = peripheral
self.centralManager?.connect(connectedPeripheral!.peripheral)
print("Connected to: \(connectedPeripheral.peripheral.name ?? "Unknown")")
}
// Called each time a peripheral is discovered
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
@ -134,9 +124,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first
peripheral.discoverServices([meshtasticServiceCBUUID])
print("Peripheral connected: " + peripheral.name!)
startScanning()
}
// Send Broadcast Message
@ -146,11 +137,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Return false if we are not properly connected to a device, handle retry logic in the view for now
if connectedPeripheral == nil || connectedPeripheral!.peripheral.state != CBPeripheralState.connected || self.connectedNode == nil {
if connectedPeripheral != nil && self.connectedNode == nil {
self.disconnectDevice()
// Lets disconnect and then reconnect a second later when the message retry happens
}
success = false
}
else if message.count < 1 {
@ -191,7 +178,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Disconnect Peripheral Event
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
{
// Start a Scan so the disconnected peripheral is moved to the peripherals[]
// Start a Scan so the disconnected peripheral is moved to the peripherals[] if it is awake
self.startScanning()
if let e = error {
@ -199,35 +186,38 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let errorCode = (e as NSError).code
if errorCode == 6 { // The connection has timed out unexpectedly.
// Happens when device is manually reset / powered off
connectedPeripheral = nil
connectedNode = nil
// Happens when device is manually reset / powered off
// 2 second delay for device to power back on
let _ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { (timer) in
self.connectTo(peripheral: peripheral)
}
}
else if errorCode == 7 { // The specified device has disconnected from us.
// Check if the peripheral is still visible and then reconnect
// Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work.
// Check if the last connected peripheral is still visible and then reconnect
connectedPeripheral = nil
connectedNode = nil
}
else if errorCode == 14 { // Peer error that may require forgetting device in settings
// Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that
lastConnectionError = (e as NSError).description
// Check if the peripheral is still visible and then reconnect
connectedPeripheral = nil
connectedNode = nil
}
} else {
// Disconnected without error which indicates user intent to disconnect
print("Central disconnected! (no error)")
connectedPeripheral = nil
connectedNode = nil
}
print("Peripheral disconnected: " + peripheral.name!)
}
// Discover Services Event
@ -307,9 +297,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
{
case FROMNUM_UUID:
peripheral.readValue(for: FROMNUM_characteristic)
//let byteArrayFromData: [UInt8] = [UInt8](characteristic.value!)
//let stringFromByteArray = String(data: Data(_: byteArrayFromData), encoding: .ascii)
//print(stringFromByteArray)
let byteArrayFromData: [UInt8] = [UInt8](characteristic.value!)
let stringFromByteArray = String(data: Data(_: byteArrayFromData), encoding: .ascii)
print("string array data \(stringFromByteArray)")
//print(characteristic.value?. ?? "no value")
@ -347,9 +337,10 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
connectedNode = meshData.nodes.first(where: {$0.num == myInfoModel.id})
}
// Since the data is from the device itself we save all myInfo objects since they are always the most update
if connectedNode != nil && connectedNode.myInfo == nil {
// Since the data is from the device itself we save all myInfo objects since they are always the most up to date
if connectedNode != nil {
connectedNode.myInfo = myInfoModel
//connectedNode.update(from: connectedNode.data)
let nodeIndex = meshData.nodes.firstIndex(where: { $0.id == decodedInfo.myInfo.myNodeNum })
meshData.nodes.remove(at: nodeIndex!)
meshData.nodes.append(connectedNode)
@ -367,7 +358,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Found a matching node lets update it
let nodeMatch = meshData.nodes.first(where: { $0.id == decodedInfo.nodeInfo.num })
if nodeMatch?.lastHeard ?? 0 < decodedInfo.nodeInfo.lastHeard {
if connectedPeripheral != nil && connectedPeripheral.myInfo?.id == nodeMatch?.num {
connectedNode = nodeMatch
}
if nodeMatch?.lastHeard ?? 0 < decodedInfo.nodeInfo.lastHeard && nodeMatch?.user != nil && nodeMatch?.user.longName.count ?? 0 > 0 {
// The data coming from the device is newer
let nodeIndex = meshData.nodes.firstIndex(where: { $0.id == decodedInfo.nodeInfo.num })
@ -380,7 +375,14 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
return
}
}
// Set the connected node if the nodeInfo is for the connected node.
if connectedPeripheral != nil && connectedPeripheral.myInfo?.id == decodedInfo.nodeInfo.num {
let nodeMatch = meshData.nodes.first(where: { $0.id == decodedInfo.nodeInfo.num })
if nodeMatch != nil {
connectedNode = nodeMatch
}
}
meshData.nodes.append(
NodeInfoModel(
num: decodedInfo.nodeInfo.num,
@ -522,4 +524,5 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
peripheral.readValue(for: FROMRADIO_characteristic)
}
}

View file

@ -17,3 +17,4 @@ final class Peripheral: Identifiable {
self.myInfo = myInfo
}
}

View file

@ -51,19 +51,19 @@ struct Connect: View {
Text((bleManager.connectedPeripheral!.peripheral.name != nil) ? bleManager.connectedPeripheral!.peripheral.name! : "Unknown").font(.title2)
}
}
.padding()
.swipeActions {
Button {
Button(role: .destructive) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected
{
bleManager.disconnectDevice()
bleManager.disconnectDevice()
}
} label: {
Label("Disconnect", systemImage: "antenna.radiowaves.left.and.right.slash")
Label("Delete", systemImage: "antenna.radiowaves.left.and.right.slash")
}
.tint(.red)
}
.padding()
}
else {
HStack{
@ -90,7 +90,7 @@ struct Connect: View {
{
self.bleManager.disconnectDevice()
}
self.bleManager.connectToDevice(id: peripheral.id)
self.bleManager.connectTo(peripheral: peripheral.peripheral)
}) {
Text(peripheral.name).font(.title3)
}
@ -140,16 +140,14 @@ struct Connect: View {
.navigationTitle("Bluetooth Radios")
.navigationBarItems(trailing:
VStack(alignment: .trailing) {
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedNode != nil) ? bleManager.connectedNode.user.shortName : ((bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.name : "Unknown") )
}
)
}.navigationViewStyle(StackNavigationViewStyle())
.onAppear{
bleManager.startScanning()
}
.navigationViewStyle(StackNavigationViewStyle())
.onAppear(perform: { bleManager.startScanning() } )
}
}

View file

@ -3,6 +3,9 @@ import SwiftUI
import CoreBluetooth
struct Channels: View {
// Message Data and Bluetooth
@EnvironmentObject var messageData: MessageData
@EnvironmentObject var bleManager: BLEManager
var body: some View {
NavigationView {
@ -31,6 +34,7 @@ struct Channels: View {
}
.navigationTitle("Channels")
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

View file

@ -91,18 +91,15 @@ struct Messages: View {
typingMessage = ""
}
else {
if bleManager.lastConnectedNode.count > 10 {
if bleManager.peripherals.contains(where: { $0.id == bleManager.lastConnectedNode }) {
bleManager.connectToDevice(id: bleManager.lastConnectedNode)
let timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (timer) in
if bleManager.sendMessage(message: typingMessage) {
typingMessage = ""
}
if bleManager.connectedPeripheral != nil {
let timer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (timer) in
if bleManager.sendMessage(message: typingMessage) {
typingMessage = ""
}
}
}
}
} ) {