Start of connection timer UI

This commit is contained in:
Garth Vander Houwen 2022-10-12 15:26:25 -07:00
parent c3bd5a7300
commit 5790839022
5 changed files with 85 additions and 55 deletions

View file

@ -36,6 +36,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
@Published var isSwitchedOn: Bool = false
@Published var isScanning: Bool = false
@Published var isConnecting: Bool = false
@Published var isConnected: Bool = false
/// Used to make sure we never get foold by old BLE packets
@ -44,7 +45,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
var timeoutTimer: Timer?
var timeoutTimerCount = 0
var positionTimer: Timer?
let broadcastNodeNum: UInt32 = 4294967295
/* Meshtastic Service Details */
@ -133,6 +133,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
let name: String = timerContext["name", default: "Unknown"]
self.timeoutTimerCount += 1
self.isConnecting = true
self.lastConnectionError = ""
if timeoutTimerCount == 10 {
@ -141,17 +143,20 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
self.centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral)
}
connectedPeripheral = nil
self.isConnected = false
self.lastConnectionError = "🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(name)."
if meshLoggingEnabled { MeshLogger.log(self.lastConnectionError + " This can occur when a device has been taken out of BLE range, or if a device is already connected to another phone, tablet or computer.") }
self.timeoutTimerCount = 0
if self.timeoutTimer != nil {
self.timeoutTimer!.invalidate()
}
self.isConnected = false
self.isConnecting = false
self.lastConnectionError = "🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(name). If you continue to get this message you may need to forget your device under settings > bluetooth."
if meshLoggingEnabled { MeshLogger.log("🚨 BLE Connection Timeout after making \(timeoutTimerCount) attempts to connect to \(name). If you continue to get this message you may need to forget your device under settings > bluetooth.") }
self.timeoutTimerCount = 0
self.startScanning()
} else {
@ -165,6 +170,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
if meshLoggingEnabled { MeshLogger.log("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") }
stopScanning()
self.isConnecting = true
self.lastConnectionError = ""
if self.connectedPeripheral != nil {
@ -184,7 +191,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Use a timer to keep track of connecting peripherals, context to pass the radio name with the timer and the RunLoop to prevent
// the timer from running on the main UI thread
let context = ["name": "@\(peripheral.name ?? "Unknown")"]
self.timeoutTimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true)
self.timeoutTimer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(timeoutTimerFired), userInfo: context, repeats: true)
RunLoop.current.add(self.timeoutTimer!, forMode: .common)
}
@ -235,6 +242,7 @@ 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
if userSettings?.preferredPeripheralId.count ?? 0 < 1 {
@ -287,6 +295,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
// Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake
self.startScanning()
self.connectedPeripheral = nil
self.isConnecting = false
if let e = error {
@ -378,9 +387,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
for characteristic in characteristics {
switch characteristic.uuid {
case EOL_FROMRADIO_UUID:
if meshLoggingEnabled { MeshLogger.log("🚨 BLE did discover EOL_TORADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")") }
invalidVersion = true
case TORADIO_UUID:
@ -474,6 +480,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
guard (connectedPeripheral!.peripheral.state == CBPeripheralState.connected) else { return }
if FROMRADIO_characteristic == nil {
if meshLoggingEnabled { MeshLogger.log("🚨 Unsupported Firmware Version Detected, unable to connect to device.") }
invalidVersion = true
return

View file

@ -23,6 +23,12 @@ struct MeshtasticAppleApp: App {
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environmentObject(bleManager)
.environmentObject(userSettings)
.sheet(isPresented: $saveChannels) {
SaveChannelQRCode(channelHash: channelSettings ?? "Empty Channel URL", validUrl: true)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
@ -41,12 +47,7 @@ struct MeshtasticAppleApp: App {
print("User wants to open Channel Settings URL: \(String(describing: incomingUrl!.relativeString))")
}
}
.sheet(isPresented: $saveChannels) {
SaveChannelQRCode(channelHash: channelSettings ?? "Empty Channel URL", validUrl: true)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.visible)
}
.onOpenURL(perform: { (url) in
print("Some sort of URL was received \(url)")

View file

@ -35,13 +35,13 @@ struct Connect: View {
Section(header: Text("Connection Error").font(.title)) {
Text(bleManager.lastConnectionError).font(.title3).foregroundColor(.red)
Text(bleManager.lastConnectionError).font(.callout).foregroundColor(.red)
}
.textCase(nil)
}
Section(header: Text("Connected Radio").font(.title)) {
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected {
HStack {
@ -65,10 +65,10 @@ struct Connect: View {
.font(.caption).foregroundColor(Color.gray)
}
if bleManager.connectedPeripheral.subscribed {
Text("Properly Subscribed").font(.caption)
Text("Subscribed to mesh").font(.caption)
.foregroundColor(.green)
} else {
Text("Attempting to connect. . . ").font(.caption)
Text("Communicating with device. . . ").font(.caption)
.foregroundColor(.orange)
}
@ -135,20 +135,44 @@ struct Connect: View {
}
} else {
HStack {
Image(systemName: "antenna.radiowaves.left.and.right.slash")
.symbolRenderingMode(.hierarchical)
.imageScale(.large).foregroundColor(.red)
.padding(.trailing)
Text("No device connected").font(.title3)
}
.padding()
}
if bleManager.isConnecting {
HStack {
Image(systemName: "antenna.radiowaves.left.and.right")
.symbolRenderingMode(.hierarchical)
.imageScale(.large).foregroundColor(.orange)
.padding(.trailing)
if bleManager.timeoutTimerCount == 0 {
Text("Connecting . . .")
.font(.title3)
.foregroundColor(.orange)
} else {
VStack {
Text("Connection Attempt \(bleManager.timeoutTimerCount) of 10")
.font(.callout)
.foregroundColor(.orange)
}
}
}
.padding()
} else {
HStack {
Image(systemName: "antenna.radiowaves.left.and.right.slash")
.symbolRenderingMode(.hierarchical)
.imageScale(.large).foregroundColor(.red)
.padding(.trailing)
Text("No device connected").font(.title3)
}
.padding()
}
}
}
.textCase(nil)
if bleManager.peripherals.count > 0 {
if self.bleManager.isScanning {
Section(header: Text("Available Radios").font(.title)) {
ForEach(bleManager.peripherals.filter({ $0.peripheral.state == CBPeripheralState.disconnected }).sorted(by: { $0.rssi > $1.rssi })) { peripheral in
HStack {

View file

@ -28,8 +28,8 @@ struct Contacts: View {
// Display Contacts for DM's on the Primary Channel
// Display Contacts for the rest of the non admin channels
List(users) { (user: UserEntity) in
List {
ForEach(users) { (user: UserEntity) in
let connectedNodeNum = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.num : 0
@ -131,6 +131,7 @@ struct Contacts: View {
}
}
}
}
.navigationTitle("Contacts")
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(leading:
@ -140,9 +141,3 @@ struct Contacts: View {
.listStyle(PlainListStyle())
}
}
struct Contacts_Previews: PreviewProvider {
static var previews: some View {
Contacts()
}
}

View file

@ -77,7 +77,7 @@ struct ShareChannels: View {
.font(.caption)
.fontWeight(.bold)
.padding(.trailing)
Text("Channel Name")
Text("Channel")
.font(.caption)
.fontWeight(.bold)
.padding(.trailing)
@ -96,57 +96,59 @@ struct ShareChannels: View {
.toggleStyle(.switch)
.labelsHidden()
.disabled(channel.role == 1)
Text((channel.name!.isEmpty ? "primary" : channel.name) ?? "primary")
Text((channel.name!.isEmpty ? "Primary" : channel.name) ?? "Primary")
} else if channel.index == 1 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 2 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 3 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 4 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 5 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 6 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
} else if channel.index == 7 {
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)")
Text((channel.name!.isEmpty ? "Channel\(channel.index)" : channel.name) ?? "Channel\(channel.index)")
}
if channel.role > 0 {
Image(systemName: "lock.fill")
.foregroundColor(.green)
} else {
if channel.role == 0 {
Image(systemName: "lock.slash")
.foregroundColor(.gray)
}
else if channel.role > 0 {
Image(systemName: "lock.fill")
.foregroundColor(.green)
}
Spacer()
}
}
@ -285,7 +287,7 @@ struct ShareChannels: View {
var channelSettings = ChannelSettings()
channelSettings.name = ch.name!
channelSettings.psk = ch.psk ?? Data()
channelSettings.psk = ch.psk!
channelSettings.id = UInt32(ch.id)
channelSettings.uplinkEnabled = ch.uplinkEnabled
channelSettings.downlinkEnabled = ch.downlinkEnabled