Skip to content

Commit 38d0e5a

Browse files
committed
Update direct traceroute handling to support two-way traceroutes
1 parent 9b34840 commit 38d0e5a

File tree

3 files changed

+107
-135
lines changed

3 files changed

+107
-135
lines changed

Localizable.xcstrings

+1-11
Original file line numberDiff line numberDiff line change
@@ -14117,7 +14117,7 @@
1411714117
}
1411814118
},
1411914119
"mesh.log.traceroute.received.direct %@" : {
14120-
"extractionState" : "migrated",
14120+
"extractionState" : "manual",
1412114121
"localizations" : {
1412214122
"de" : {
1412314123
"stringUnit" : {
@@ -21850,16 +21850,6 @@
2185021850
},
2185121851
"Trace Route Log" : {
2185221852

21853-
},
21854-
"Trace route received directly by %@ with a SNR of %@ dB" : {
21855-
"localizations" : {
21856-
"en" : {
21857-
"stringUnit" : {
21858-
"state" : "new",
21859-
"value" : "Trace route received directly by %1$@ with a SNR of %2$@ dB"
21860-
}
21861-
}
21862-
}
2186321853
},
2186421854
"Trace Route Sent" : {
2186521855

Meshtastic/Helpers/BLEManager.swift

+104-114
Original file line numberDiff line numberDiff line change
@@ -834,130 +834,120 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
834834
if let routingMessage = try? RouteDiscovery(serializedBytes: decodedInfo.packet.decoded.payload) {
835835
let traceRoute = getTraceRoute(id: Int64(decodedInfo.packet.decoded.requestID), context: context)
836836
traceRoute?.response = true
837-
if routingMessage.route.count == 0 {
838-
// Routing messages snr values are snr * 4 stored as an int
839-
// If a traceroute snr value is unknown this field will contain INT8_MIN or -128
840-
// After converting to a float here, -32 is our unknown value.
841-
let snr = routingMessage.snrBack.count > 0 ? (Float(routingMessage.snrBack[0]) / 4) : -32
842-
traceRoute?.snr = snr
843-
let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.direct %@".localized, String(snr))
844-
MeshLogger.log("🪧 \(logString)")
845-
} else {
846-
guard let connectedNode = getNodeInfo(id: Int64(connectedPeripheral.num), context: context) else {
847-
return
837+
guard let connectedNode = getNodeInfo(id: Int64(connectedPeripheral.num), context: context) else {
838+
return
839+
}
840+
var hopNodes: [TraceRouteHopEntity] = []
841+
let connectedHop = TraceRouteHopEntity(context: context)
842+
connectedHop.time = Date()
843+
connectedHop.num = connectedPeripheral.num
844+
connectedHop.name = connectedNode.user?.longName ?? "???"
845+
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
846+
connectedHop.snr = Float(routingMessage.snrBack.last ?? -128) / 4
847+
if let mostRecent = traceRoute?.node?.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
848+
connectedHop.altitude = mostRecent.altitude
849+
connectedHop.latitudeI = mostRecent.latitudeI
850+
connectedHop.longitudeI = mostRecent.longitudeI
851+
traceRoute?.hasPositions = true
852+
}
853+
var routeString = "\(connectedNode.user?.longName ?? "???") --> "
854+
hopNodes.append(connectedHop)
855+
traceRoute?.hopsTowards = Int32(routingMessage.route.count)
856+
for (index, node) in routingMessage.route.enumerated() {
857+
var hopNode = getNodeInfo(id: Int64(node), context: context)
858+
if hopNode == nil && hopNode?.num ?? 0 > 0 && node != 4294967295 {
859+
hopNode = createNodeInfo(num: Int64(node), context: context)
848860
}
849-
var hopNodes: [TraceRouteHopEntity] = []
850-
let connectedHop = TraceRouteHopEntity(context: context)
851-
connectedHop.time = Date()
852-
connectedHop.num = connectedPeripheral.num
853-
connectedHop.name = connectedNode.user?.longName ?? "???"
854-
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
855-
connectedHop.snr = Float(routingMessage.snrBack.last ?? -128) / 4
856-
if let mostRecent = traceRoute?.node?.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
857-
connectedHop.altitude = mostRecent.altitude
858-
connectedHop.latitudeI = mostRecent.latitudeI
859-
connectedHop.longitudeI = mostRecent.longitudeI
860-
traceRoute?.hasPositions = true
861+
let traceRouteHop = TraceRouteHopEntity(context: context)
862+
traceRouteHop.time = Date()
863+
if routingMessage.snrTowards.count >= index + 1 {
864+
traceRouteHop.snr = Float(routingMessage.snrTowards[index]) / 4
865+
} else {
866+
// If no snr in route, set unknown
867+
traceRouteHop.snr = -32
861868
}
862-
var routeString = "\(connectedNode.user?.longName ?? "???") --> "
863-
hopNodes.append(connectedHop)
864-
traceRoute?.hopsTowards = Int32(routingMessage.route.count)
865-
for (index, node) in routingMessage.route.enumerated() {
866-
var hopNode = getNodeInfo(id: Int64(node), context: context)
867-
if hopNode == nil && hopNode?.num ?? 0 > 0 && node != 4294967295 {
868-
hopNode = createNodeInfo(num: Int64(node), context: context)
869-
}
870-
let traceRouteHop = TraceRouteHopEntity(context: context)
871-
traceRouteHop.time = Date()
872-
if routingMessage.snrTowards.count >= index + 1 {
873-
traceRouteHop.snr = Float(routingMessage.snrTowards[index]) / 4
874-
} else {
875-
// If no snr in route, set unknown
876-
traceRouteHop.snr = -32
877-
}
878-
if let hn = hopNode, hn.hasPositions {
879-
if let mostRecent = hn.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
880-
traceRouteHop.altitude = mostRecent.altitude
881-
traceRouteHop.latitudeI = mostRecent.latitudeI
882-
traceRouteHop.longitudeI = mostRecent.longitudeI
883-
traceRoute?.hasPositions = true
884-
}
869+
if let hn = hopNode, hn.hasPositions {
870+
if let mostRecent = hn.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
871+
traceRouteHop.altitude = mostRecent.altitude
872+
traceRouteHop.latitudeI = mostRecent.latitudeI
873+
traceRouteHop.longitudeI = mostRecent.longitudeI
874+
traceRoute?.hasPositions = true
885875
}
886-
traceRouteHop.num = hopNode?.num ?? 0
887-
if hopNode != nil {
888-
if decodedInfo.packet.rxTime > 0 {
889-
hopNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
890-
}
876+
}
877+
traceRouteHop.num = hopNode?.num ?? 0
878+
if hopNode != nil {
879+
if decodedInfo.packet.rxTime > 0 {
880+
hopNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
891881
}
892-
hopNodes.append(traceRouteHop)
893-
routeString += "\(hopNode?.user?.longName ?? (node == 4294967295 ? "Repeater" : String(hopNode?.num.toHex() ?? "unknown".localized))) \(hopNode?.viaMqtt ?? false ? "MQTT" : "") (\(traceRouteHop.snr != -32 ? String(traceRouteHop.snr) : "unknown ".localized)dB) --> "
894882
}
895-
let destinationHop = TraceRouteHopEntity(context: context)
896-
destinationHop.name = traceRoute?.node?.user?.longName ?? "unknown".localized
897-
destinationHop.time = Date()
898-
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
899-
destinationHop.snr = Float(routingMessage.snrTowards.last ?? -128) / 4
900-
destinationHop.num = traceRoute?.node?.num ?? 0
901-
if let mostRecent = traceRoute?.node?.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
902-
destinationHop.altitude = mostRecent.altitude
903-
destinationHop.latitudeI = mostRecent.latitudeI
904-
destinationHop.longitudeI = mostRecent.longitudeI
905-
traceRoute?.hasPositions = true
883+
hopNodes.append(traceRouteHop)
884+
routeString += "\(hopNode?.user?.longName ?? (node == 4294967295 ? "Repeater" : String(hopNode?.num.toHex() ?? "unknown".localized))) \(hopNode?.viaMqtt ?? false ? "MQTT" : "") (\(traceRouteHop.snr != -32 ? String(traceRouteHop.snr) : "unknown ".localized)dB) --> "
885+
}
886+
let destinationHop = TraceRouteHopEntity(context: context)
887+
destinationHop.name = traceRoute?.node?.user?.longName ?? "unknown".localized
888+
destinationHop.time = Date()
889+
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
890+
destinationHop.snr = Float(routingMessage.snrTowards.last ?? -128) / 4
891+
destinationHop.num = traceRoute?.node?.num ?? 0
892+
if let mostRecent = traceRoute?.node?.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
893+
destinationHop.altitude = mostRecent.altitude
894+
destinationHop.latitudeI = mostRecent.latitudeI
895+
destinationHop.longitudeI = mostRecent.longitudeI
896+
traceRoute?.hasPositions = true
897+
}
898+
hopNodes.append(destinationHop)
899+
/// Add the destination node to the end of the route towards string and the beginning of teh route back string
900+
routeString += "\(traceRoute?.node?.user?.longName ?? "unknown".localized) \((traceRoute?.node?.num ?? 0).toHex()) (\(destinationHop.snr != -32 ? String(destinationHop.snr) : "unknown ".localized)dB)"
901+
var routeBackString = "\(traceRoute?.node?.user?.longName ?? "unknown".localized) \((traceRoute?.node?.num ?? 0).toHex()) --> "
902+
traceRoute?.hopsBack = Int32(routingMessage.routeBack.count)
903+
for (index, node) in routingMessage.routeBack.enumerated() {
904+
var hopNode = getNodeInfo(id: Int64(node), context: context)
905+
if hopNode == nil && hopNode?.num ?? 0 > 0 && node != 4294967295 {
906+
hopNode = createNodeInfo(num: Int64(node), context: context)
906907
}
907-
hopNodes.append(destinationHop)
908-
/// Add the destination node to the end of the route towards string and the beginning of teh route back string
909-
routeString += "\(traceRoute?.node?.user?.longName ?? "unknown".localized) \((traceRoute?.node?.num ?? 0).toHex()) (\(destinationHop.snr != -32 ? String(destinationHop.snr) : "unknown ".localized)dB)"
910-
var routeBackString = "\(traceRoute?.node?.user?.longName ?? "unknown".localized) \((traceRoute?.node?.num ?? 0).toHex()) --> "
911-
traceRoute?.hopsBack = Int32(routingMessage.routeBack.count)
912-
for (index, node) in routingMessage.routeBack.enumerated() {
913-
var hopNode = getNodeInfo(id: Int64(node), context: context)
914-
if hopNode == nil && hopNode?.num ?? 0 > 0 && node != 4294967295 {
915-
hopNode = createNodeInfo(num: Int64(node), context: context)
916-
}
917-
let traceRouteHop = TraceRouteHopEntity(context: context)
918-
traceRouteHop.time = Date()
919-
traceRouteHop.back = true
920-
if routingMessage.snrBack.count >= index + 1 {
921-
traceRouteHop.snr = Float(routingMessage.snrBack[index]) / 4
922-
} else {
923-
// If no snr in route, set to unknown
924-
traceRouteHop.snr = -32
925-
}
926-
if let hn = hopNode, hn.hasPositions {
927-
if let mostRecent = hn.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
928-
traceRouteHop.altitude = mostRecent.altitude
929-
traceRouteHop.latitudeI = mostRecent.latitudeI
930-
traceRouteHop.longitudeI = mostRecent.longitudeI
931-
traceRoute?.hasPositions = true
932-
}
933-
}
934-
traceRouteHop.num = hopNode?.num ?? 0
935-
if hopNode != nil {
936-
if decodedInfo.packet.rxTime > 0 {
937-
hopNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
938-
}
908+
let traceRouteHop = TraceRouteHopEntity(context: context)
909+
traceRouteHop.time = Date()
910+
traceRouteHop.back = true
911+
if routingMessage.snrBack.count >= index + 1 {
912+
traceRouteHop.snr = Float(routingMessage.snrBack[index]) / 4
913+
} else {
914+
// If no snr in route, set to unknown
915+
traceRouteHop.snr = -32
916+
}
917+
if let hn = hopNode, hn.hasPositions {
918+
if let mostRecent = hn.positions?.lastObject as? PositionEntity, mostRecent.time! >= Calendar.current.date(byAdding: .hour, value: -24, to: Date())! {
919+
traceRouteHop.altitude = mostRecent.altitude
920+
traceRouteHop.latitudeI = mostRecent.latitudeI
921+
traceRouteHop.longitudeI = mostRecent.longitudeI
922+
traceRoute?.hasPositions = true
939923
}
940-
hopNodes.append(traceRouteHop)
941-
routeBackString += "\(hopNode?.user?.longName ?? (node == 4294967295 ? "Repeater" : String(hopNode?.num.toHex() ?? "unknown".localized))) \(hopNode?.viaMqtt ?? false ? "MQTT" : "") (\(traceRouteHop.snr != -32 ? String(traceRouteHop.snr) : "unknown ".localized)dB) --> "
942924
}
943-
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
944-
let snrBackLast = Float(routingMessage.snrBack.last ?? -128) / 4
945-
routeBackString += "\(connectedNode.user?.longName ?? String(connectedNode.num.toHex())) (\(snrBackLast != -32 ? String(snrBackLast) : "unknown ".localized)dB)"
946-
traceRoute?.routeText = routeString
947-
traceRoute?.routeBackText = routeBackString
948-
traceRoute?.hops = NSOrderedSet(array: hopNodes)
949-
traceRoute?.time = Date()
950-
do {
951-
try context.save()
952-
Logger.data.info("💾 Saved Trace Route")
953-
} catch {
954-
context.rollback()
955-
let nsError = error as NSError
956-
Logger.data.error("Error Updating Core Data TraceRouteHop: \(nsError, privacy: .public)")
925+
traceRouteHop.num = hopNode?.num ?? 0
926+
if hopNode != nil {
927+
if decodedInfo.packet.rxTime > 0 {
928+
hopNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(decodedInfo.packet.rxTime)))
929+
}
957930
}
958-
let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.route %@".localized, routeString)
959-
MeshLogger.log("🪧 \(logString)")
931+
hopNodes.append(traceRouteHop)
932+
routeBackString += "\(hopNode?.user?.longName ?? (node == 4294967295 ? "Repeater" : String(hopNode?.num.toHex() ?? "unknown".localized))) \(hopNode?.viaMqtt ?? false ? "MQTT" : "") (\(traceRouteHop.snr != -32 ? String(traceRouteHop.snr) : "unknown ".localized)dB) --> "
933+
}
934+
// If nil, set to unknown, INT8_MIN (-128) then divide by 4
935+
let snrBackLast = Float(routingMessage.snrBack.last ?? -128) / 4
936+
routeBackString += "\(connectedNode.user?.longName ?? String(connectedNode.num.toHex())) (\(snrBackLast != -32 ? String(snrBackLast) : "unknown ".localized)dB)"
937+
traceRoute?.routeText = routeString
938+
traceRoute?.routeBackText = routeBackString
939+
traceRoute?.hops = NSOrderedSet(array: hopNodes)
940+
traceRoute?.time = Date()
941+
do {
942+
try context.save()
943+
Logger.data.info("💾 Saved Trace Route")
944+
} catch {
945+
context.rollback()
946+
let nsError = error as NSError
947+
Logger.data.error("Error Updating Core Data TraceRouteHop: \(nsError, privacy: .public)")
960948
}
949+
let logString = String.localizedStringWithFormat("mesh.log.traceroute.received.route %@".localized, routeString)
950+
MeshLogger.log("🪧 \(logString)")
961951
}
962952
case .neighborinfoApp:
963953
if let neighborInfo = try? NeighborInfo(serializedBytes: decodedInfo.packet.decoded.payload) {

Meshtastic/Views/Nodes/TraceRouteLog.swift

+2-10
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct TraceRouteLog: View {
5454
.font(.caption)
5555
}
5656
} icon: {
57-
Image(systemName: route.response ? (route.hops?.count == 0 && route.response ? "person.line.dotted.person" : "point.3.connected.trianglepath.dotted") : "person.slash")
57+
Image(systemName: route.response ? (route.hopsTowards == 0 && route.response ? "person.line.dotted.person" : "point.3.connected.trianglepath.dotted") : "person.slash")
5858
.symbolRenderingMode(.hierarchical)
5959
}
6060
.swipeActions {
@@ -76,15 +76,7 @@ struct TraceRouteLog: View {
7676
Divider()
7777
ScrollView {
7878
if selectedRoute != nil {
79-
if selectedRoute?.response ?? false && selectedRoute?.hopsTowards ?? 0 == 0 {
80-
Label {
81-
Text("Trace route received directly by \(selectedRoute?.node?.user?.longName ?? "unknown".localized) with a SNR of \(String(format: "%.2f", selectedRoute?.snr ?? 0.0)) dB")
82-
} icon: {
83-
Image(systemName: "signpost.right.and.left")
84-
.symbolRenderingMode(.hierarchical)
85-
}
86-
.font(.title3)
87-
} else if selectedRoute?.response ?? false && selectedRoute?.hopsTowards ?? 0 > 0 {
79+
if selectedRoute?.response ?? false && selectedRoute?.hopsTowards ?? 0 >= 0 {
8880
Label {
8981
Text("Route: \(selectedRoute?.routeText ?? "unknown".localized)")
9082
} icon: {

0 commit comments

Comments
 (0)