V 1.26.5 2 second Connection timeout for bluetooth, preferred peripheral enhancements

This commit is contained in:
Garth Vander Houwen 2021-10-22 10:03:50 -07:00
parent d447aa1ca7
commit 15608bb976
6 changed files with 103 additions and 33 deletions

View file

@ -668,13 +668,13 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.26.4;
MARKETING_VERSION = 1.26.5;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = "1,2,6";
};
name = Debug;
};
@ -695,13 +695,13 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.26.4;
MARKETING_VERSION = 1.26.5;
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TARGETED_DEVICE_FAMILY = "1,2,6";
};
name = Release;
};

View file

@ -32,6 +32,9 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
@Published var isSwitchedOn = false
@Published var peripherals = [Peripheral]()
var isDisconnectedByUser = false
var timeoutTimer: Timer?
private var meshLoggingEnabled: Bool = true
private var broadcastNodeId: UInt32 = 4294967295
@ -78,7 +81,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if isSwitchedOn {
peripherals.removeAll()
centralManager.scanForPeripherals(withServices: [meshtasticServiceCBUUID], options: nil)
print("Scanning Started")
}
@ -93,15 +95,35 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
print("Stopped Scanning")
}
}
/// The action after the timeout-timer has fired
///
/// - Parameters:
/// - timer: The time that fired the event
///
@objc func timeoutTimerFired(timer: Timer)
{
timer.invalidate()
lastConnectionError = "BLE Connection timed out" //radio \(connectedPeripheral.peripheral.name ?? "Unknown")
if connectedPeripheral != nil {
self.centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral)
connectedNode = nil
connectedPeripheral = nil
}
print("BLE-Timeout-Timer fired!")
Logger.log("BLE-Timeout-Timer fired!")
self.startScanning()
}
// Connect to a specific peripheral
func connectTo(peripheral: CBPeripheral) {
stopScanning()
if connectedPeripheral != nil && connectedPeripheral.peripheral.state == CBPeripheralState.connected {
if self.connectedPeripheral != nil && self.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
self.disconnectDevice()
}
self.timeoutTimer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(timeoutTimerFired), userInfo: nil, repeats: false)
self.centralManager?.connect(peripheral)
if meshLoggingEnabled { Logger.log("BLE Connecting: \(peripheral.name ?? "Unknown")") }
print("BLE Connecting: \(peripheral.name ?? "Unknown")")
@ -125,26 +147,38 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
}
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, name: peripheralName, rssi: RSSI.intValue, peripheral: peripheral, myInfo: nil)
peripherals.append(newPeripheral)
print("Adding peripheral: \(peripheralName)");
let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id })
if peripheralIndex != nil {
peripherals.remove(at: peripheralIndex!)
peripherals.append(newPeripheral)
print("Updating peripheral: \(peripheralName)");
}
else {
peripherals.append(newPeripheral)
print("Adding peripheral: \(peripheralName)");
}
}
// called when a peripheral is connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
stopScanning()
lastConnectionError = ""
timeoutTimer!.invalidate()
peripheral.delegate = self
connectedPeripheral = peripherals.filter({ $0.peripheral.identifier == peripheral.identifier }).first
let deviceName = peripheral.name ?? ""
let peripheralLast4: String = String(deviceName.suffix(4))
print(peripheralLast4)
connectedNode = meshData.nodes.first(where: { $0.user.id.contains(peripheralLast4) })
lastConnectedPeripheral = peripheral.identifier.uuidString
peripheral.discoverServices([meshtasticServiceCBUUID])
if meshLoggingEnabled { Logger.log("BLE Connected: \(peripheral.name ?? "Unknown")") }
print("BLE Connected: \(peripheral.name ?? "Unknown")")
stopScanning()
peripherals.removeAll()
}
@ -158,16 +192,20 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let errorCode = (e as NSError).code
if errorCode == 6 { // The connection has timed out unexpectedly.
if errorCode == 6 {
// Error Code 6: The connection has timed out unexpectedly.
// Happens when device is manually reset / powered off
lastConnectionError = " \(e.localizedDescription) Will automatically attempt to reconnect to the preferred radio if it reappears quickly."
self.connectedNode = nil
self.connectedPeripheral = nil
self.connectTo(peripheral: peripheral)
// Happens when device is manually reset / powered off
// 2 second delay for device to power back on
let _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { (timer) in
//let _ = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (timer) in
//self.connectedPeripheral = nil
self.connectedNode = nil
self.connectTo(peripheral: peripheral)
}
// }
}
else if errorCode == 7 { // The specified device has disconnected from us.
@ -175,6 +213,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Check if the last connected peripheral is still visible and then reconnect
connectedPeripheral = nil
connectedNode = nil
lastConnectionError = e.localizedDescription
}
else if errorCode == 14 { // Peer error that may require forgetting device in settings
@ -182,7 +221,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that
connectedPeripheral = nil
connectedNode = nil
lastConnectionError = (e as NSError).description
lastConnectionError = e.localizedDescription
}
print("Central disconnected because \(e)")
if meshLoggingEnabled { Logger.log("BLE Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode) Error: \(e.localizedDescription)") }

View file

@ -13,6 +13,7 @@ struct MeshtasticClientApp: App {
@ObservedObject private var meshData: MeshData = MeshData()
@ObservedObject private var messageData: MessageData = MessageData()
@ObservedObject private var bleManager: BLEManager = BLEManager()
@ObservedObject private var userSettings: UserSettings = UserSettings()
var body: some Scene {
WindowGroup {
@ -20,6 +21,7 @@ struct MeshtasticClientApp: App {
.environmentObject(meshData)
.environmentObject(messageData)
.environmentObject(bleManager)
.environmentObject(userSettings)
.onAppear{
meshData.load()
messageData.load()

View file

@ -16,9 +16,10 @@ import CoreBluetooth
struct Connect: View {
@EnvironmentObject var meshData: MeshData
@EnvironmentObject var bleManager: BLEManager
@ObservedObject var userSettings = UserSettings()
@EnvironmentObject var userSettings: UserSettings
@State var isPreferredRadio: Bool = false
@ -30,7 +31,17 @@ struct Connect: View {
if bleManager.isSwitchedOn {
List {
if bleManager.lastConnectionError.count > 0 {
Section(header: Text("Connection Error").font(.title)) {
Text(bleManager.lastConnectionError).font(.title2).foregroundColor(.red)
}
.textCase(nil)
}
Section(header: Text("Connected Device").font(.title)) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
HStack {
@ -64,19 +75,20 @@ struct Connect: View {
.labelsHidden()
.onChange(of: isPreferredRadio) { value in
if value {
if bleManager.connectedNode != nil {
let deviceName = "\(bleManager.connectedNode.user.longName) / \(bleManager.connectedPeripheral.peripheral.name ?? "")"
UserDefaults.standard.set(deviceName, forKey: "preferredPeripheralName")
//userSettings.preferredPeripheralName = "\(bleManager.connectedNode.user.longName) / \(bleManager.connectedPeripheral.peripheral.name ?? "")"
userSettings.preferredPeripheralName = deviceName
} else {
UserDefaults.standard.set(bleManager.connectedPeripheral.peripheral.name ?? "Unknown Device", forKey: "preferredPeripheralName")
//userSettings.preferredPeripheralName =
userSettings.preferredPeripheralName = bleManager.connectedPeripheral.peripheral.name ?? "Unknown Device"
}
UserDefaults.standard.set(bleManager.connectedPeripheral!.peripheral.identifier.uuidString, forKey: "preferredPeripheralId")
userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString
} else {
UserDefaults.standard.set("", forKey: "preferredPeripheralId")
UserDefaults.standard.set("", forKey: "preferredPeripheralName")
userSettings.preferredPeripheralId = ""
userSettings.preferredPeripheralName = ""
}
}
}
@ -107,7 +119,8 @@ struct Connect: View {
.padding()
}
}.textCase(nil)
}
.textCase(nil)
Section(header: Text("Available Devices").font(.title)) {
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.rssi > $1.rssi })) { peripheral in

View file

@ -13,6 +13,8 @@ import SwiftUI
struct NodeList: View {
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var meshData: MeshData
@State private var selection: String? = nil
@State private var showLocationOnly = false
@ -47,7 +49,11 @@ struct NodeList: View {
Text("Nodes with location only")
}
ForEach(filteredDevices.sorted(by: { $0.lastHeard > $1.lastHeard })) { node in
NavigationLink(destination: NodeDetail(node: node)) {
let index = filteredDevices.sorted(by: { $0.lastHeard > $1.lastHeard }).firstIndex(where: { $0.id == node.id })
NavigationLink(destination: NodeDetail(node: node), tag: String(index!), selection: $selection) {
if(bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.myInfo != nil) {
@ -75,6 +81,15 @@ struct NodeList: View {
}
}
.navigationTitle("All Nodes")
.onAppear(
perform: {
if UIDevice.current.userInterfaceIdiom == .pad {
if meshData.nodes.count > 0 {
selection = "0"
}
}
}
)
}
.ignoresSafeArea(.all, edges: [.leading, .trailing])
.navigationViewStyle(DoubleColumnNavigationViewStyle())

View file

@ -74,9 +74,10 @@ class UserSettings: ObservableObject {
struct AppSettings: View {
@State private var preferredDeviceConnected = false
@EnvironmentObject var bleManager: BLEManager
@ObservedObject var userSettings = UserSettings()
@EnvironmentObject var userSettings: UserSettings
@State private var preferredDeviceConnected = false
var perferredPeripheral: String {
UserDefaults.standard.object(forKey: "preferredPeripheralName") as? String ?? ""