From 31005c1a4fd42c70440cc95443a76d901f0bc54e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 27 Dec 2022 17:44:27 -0800 Subject: [PATCH] Trace route context menu item Lazy grid for all 3 node logs (position, device metrics, environment metrics) --- Meshtastic/Helpers/BLEManager.swift | 43 ++++++++++++++++++- Meshtastic/Views/Messages/Contacts.swift | 20 ++++++++- Meshtastic/Views/Nodes/DeviceMetricsLog.swift | 33 ++++++++------ .../Views/Nodes/EnvironmentMetricsLog.swift | 21 ++++----- Meshtastic/Views/Nodes/PositionLog.swift | 10 ++++- 5 files changed, 97 insertions(+), 30 deletions(-) diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 85eb1717..618ed01a 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -313,6 +313,35 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { connectedPeripheral!.peripheral.readValue(for: FROMRADIO_characteristic) } + func sendTraceRouteRequest(destNum: Int64, wantResponse: Bool) -> Bool { + + var success = false + let fromNodeNum = connectedPeripheral.num + + let routePacket = RouteDiscovery() + + var meshPacket = MeshPacket() + meshPacket.to = UInt32(destNum) + meshPacket.from = UInt32(fromNodeNum)//0 // Send 0 as from from phone to device to avoid warning about client trying to set node num + var dataMessage = DataMessage() + dataMessage.payload = try! routePacket.serializedData() + dataMessage.portnum = PortNum.tracerouteApp + dataMessage.wantResponse = wantResponse + meshPacket.decoded = dataMessage + + var toRadio: ToRadio! + toRadio = ToRadio() + toRadio.packet = meshPacket + let binaryData: Data = try! toRadio.serializedData() + + if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { + connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) + success = true + MeshLogger.log("🪧 Sent a Trace Route Packet to node: \(destNum).") + } + return success + } + func sendWantConfig() { guard (connectedPeripheral!.peripheral.state == CBPeripheralState.connected) else { return } @@ -504,7 +533,19 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { case .audioApp: MeshLogger.log("ℹ️ MESH PACKET received for Audio App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .tracerouteApp: - MeshLogger.log("ℹ️ MESH PACKET received for Trace Route App UNHANDLED \(try! decodedInfo.packet.jsonString())") + if let routingMessage = try? RouteDiscovery(serializedData: decodedInfo.packet.decoded.payload) { + + if routingMessage.route.count == 0 { + MeshLogger.log("🪧 Trace Route request sent to \(decodedInfo.packet.from) was recieived directly.") + } else { + + var routeString = "🪧 Trace Route request returned: \(decodedInfo.packet.to) --> " + for node in routingMessage.route { + routeString += "\(node) --> " + } + routeString += "\(decodedInfo.packet.from)" + } + } case .UNRECOGNIZED(_): MeshLogger.log("ℹ️ MESH PACKET received for Other App UNHANDLED \(try! decodedInfo.packet.jsonString())") case .max: diff --git a/Meshtastic/Views/Messages/Contacts.swift b/Meshtastic/Views/Messages/Contacts.swift index 308e4188..d009d5f6 100644 --- a/Meshtastic/Views/Messages/Contacts.swift +++ b/Meshtastic/Views/Messages/Contacts.swift @@ -23,6 +23,7 @@ struct Contacts: View { @State private var selection: UserEntity? = nil // Nothing selected by default. @State private var isPresentingDeleteChannelMessagesConfirm: Bool = false @State private var isPresentingDeleteUserMessagesConfirm: Bool = false + @State private var isPresentingTraceRouteSentAlert = false var body: some View { @@ -194,6 +195,14 @@ struct Contacts: View { } label: { Label(user.mute ? "Show Alerts" : "Hide Alerts", systemImage: user.mute ? "bell" : "bell.slash") } + Button { + let success = bleManager.sendTraceRouteRequest(destNum: user.num, wantResponse: true) + if success { + isPresentingTraceRouteSentAlert = true + } + } label: { + Label("Trace Route", systemImage: "signpost.right.and.left") + } if user.messageList.count > 0 { Button(role: .destructive) { isPresentingDeleteUserMessagesConfirm = true @@ -202,12 +211,21 @@ struct Contacts: View { } } } + .alert( + "Trace Route Sent", + isPresented: $isPresentingTraceRouteSentAlert + ) + { + Button("OK", role: .cancel) { } + } + message: { + Text("This could take a while, response will appear in the mesh log.") + } .confirmationDialog( "This conversation will be deleted.", isPresented: $isPresentingDeleteUserMessagesConfirm, titleVisibility: .visible ) { - Button(role: .destructive) { deleteUserMessages(user: user, context: context) context.refresh(node!.user!, mergeChanges: true) diff --git a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift index 198f1f72..903d94b3 100644 --- a/Meshtastic/Views/Nodes/DeviceMetricsLog.swift +++ b/Meshtastic/Views/Nodes/DeviceMetricsLog.swift @@ -75,43 +75,50 @@ struct DeviceMetricsLog: View { } else { ScrollView { - Grid(alignment: .topLeading, horizontalSpacing: 2) { + + let columns = [ + GridItem(), + GridItem(), + GridItem(), + GridItem(), + GridItem(.fixed(120)) + ] + LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { GridRow { Text("Batt") - .font(.callout) + .font(.caption) .fontWeight(.bold) Text("Voltage") - .font(.callout) + .font(.caption) .fontWeight(.bold) Text("ChUtil") - .font(.callout) + .font(.caption) .fontWeight(.bold) Text("AirTm") - .font(.callout) + .font(.caption) .fontWeight(.bold) Text("Timestamp") - .font(.callout) + .font(.caption) .fontWeight(.bold) } - Divider() ForEach(node.telemetries!.reversed() as! [TelemetryEntity], id: \.self) { (dm: TelemetryEntity) in if dm.metricsType == 0 { GridRow { if dm.batteryLevel == 0 { Text("USB") - .font(.callout) + .font(.caption) } else { Text("\(String(dm.batteryLevel))%") - .font(.callout) + .font(.caption) } Text(String(dm.voltage)) - .font(.callout) + .font(.caption) Text("\(String(format: "%.2f", dm.channelUtilization))%") - .font(.callout) + .font(.caption) Text("\(String(format: "%.2f", dm.airUtilTx))%") - .font(.callout) + .font(.caption) Text(dm.time?.formattedDate(format: "MM/dd/yy hh:mm") ?? "Unknown time") - .font(.callout) + .font(.caption) } } } diff --git a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift index 9b8c803a..18f72249 100644 --- a/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift +++ b/Meshtastic/Views/Nodes/EnvironmentMetricsLog.swift @@ -63,8 +63,14 @@ struct EnvironmentMetricsLog: View { } } else { ScrollView { - - Grid(alignment: .topLeading, horizontalSpacing: 2) { + let columns = [ + GridItem(), + GridItem(), + GridItem(), + GridItem(), + GridItem(.fixed(115)) + ] + LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { GridRow { @@ -80,17 +86,10 @@ struct EnvironmentMetricsLog: View { Text("Gas") .font(.caption) .fontWeight(.bold) - Text("DC") - .font(.caption) - .fontWeight(.bold) - Text("Volt") - .font(.caption) - .fontWeight(.bold) Text("Timestamp") .font(.caption) .fontWeight(.bold) } - Divider() ForEach(node.telemetries!.reversed() as! [TelemetryEntity], id: \.self) { (em: TelemetryEntity) in if em.metricsType == 1 { @@ -105,10 +104,6 @@ struct EnvironmentMetricsLog: View { .font(.caption) Text("\(String(format: "%.2f", em.gasResistance))") .font(.caption) - Text("\(String(format: "%.2f", em.current))") - .font(.caption) - Text("\(String(format: "%.2f", em.voltage))") - .font(.caption) Text(em.time?.formattedDate(format: "MM/dd/yy hh:mm") ?? "Unknown time") .font(.caption) } diff --git a/Meshtastic/Views/Nodes/PositionLog.swift b/Meshtastic/Views/Nodes/PositionLog.swift index 46333fe1..4554c7b9 100644 --- a/Meshtastic/Views/Nodes/PositionLog.swift +++ b/Meshtastic/Views/Nodes/PositionLog.swift @@ -58,7 +58,14 @@ struct PositionLog: View { ScrollView { // Use a grid on iOS as a table only shows a single column - Grid(alignment: .topLeading, horizontalSpacing: 2) { + let columns = [ + GridItem(.fixed(95)), + GridItem(.fixed(95)), + GridItem(), + GridItem(), + GridItem(.fixed(115)) + ] + LazyVGrid(columns: columns, alignment: .leading, spacing: 1) { GridRow { @@ -78,7 +85,6 @@ struct PositionLog: View { .font(.caption2) .fontWeight(.bold) } - Divider() ForEach(node.positions!.reversed() as! [PositionEntity], id: \.self) { (mappin: PositionEntity) in GridRow { Text(String(format: "%.6f", mappin.latitude ?? 0))