mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-21 02:02:23 +00:00
Try-fix traceroute panic (#8568)
This commit is contained in:
@@ -11,6 +11,113 @@ extern graphics::Screen *screen;
|
|||||||
|
|
||||||
TraceRouteModule *traceRouteModule;
|
TraceRouteModule *traceRouteModule;
|
||||||
|
|
||||||
|
void TraceRouteModule::setResultText(const String &text)
|
||||||
|
{
|
||||||
|
resultText = text;
|
||||||
|
resultLines.clear();
|
||||||
|
resultLinesDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceRouteModule::clearResultLines()
|
||||||
|
{
|
||||||
|
resultLines.clear();
|
||||||
|
resultLinesDirty = false;
|
||||||
|
}
|
||||||
|
#if HAS_SCREEN
|
||||||
|
void TraceRouteModule::rebuildResultLines(OLEDDisplay *display)
|
||||||
|
{
|
||||||
|
if (!display) {
|
||||||
|
resultLinesDirty = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLines.clear();
|
||||||
|
|
||||||
|
if (resultText.length() == 0) {
|
||||||
|
resultLinesDirty = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxWidth = display->getWidth() - 4;
|
||||||
|
if (maxWidth <= 0) {
|
||||||
|
resultLinesDirty = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
int textLength = resultText.length();
|
||||||
|
|
||||||
|
while (start <= textLength) {
|
||||||
|
int newlinePos = resultText.indexOf('\n', start);
|
||||||
|
String segment;
|
||||||
|
|
||||||
|
if (newlinePos != -1) {
|
||||||
|
segment = resultText.substring(start, newlinePos);
|
||||||
|
start = newlinePos + 1;
|
||||||
|
} else {
|
||||||
|
segment = resultText.substring(start);
|
||||||
|
start = textLength + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segment.length() == 0) {
|
||||||
|
resultLines.push_back("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (display->getStringWidth(segment) <= maxWidth) {
|
||||||
|
resultLines.push_back(segment);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String remaining = segment;
|
||||||
|
|
||||||
|
while (remaining.length() > 0) {
|
||||||
|
String tempLine = "";
|
||||||
|
int lastGoodBreak = -1;
|
||||||
|
bool lineComplete = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < static_cast<int>(remaining.length()); i++) {
|
||||||
|
char ch = remaining.charAt(i);
|
||||||
|
String testLine = tempLine + ch;
|
||||||
|
|
||||||
|
if (display->getStringWidth(testLine) > maxWidth) {
|
||||||
|
if (lastGoodBreak >= 0) {
|
||||||
|
resultLines.push_back(remaining.substring(0, lastGoodBreak + 1));
|
||||||
|
remaining = remaining.substring(lastGoodBreak + 1);
|
||||||
|
lineComplete = true;
|
||||||
|
break;
|
||||||
|
} else if (tempLine.length() > 0) {
|
||||||
|
resultLines.push_back(tempLine);
|
||||||
|
remaining = remaining.substring(i);
|
||||||
|
lineComplete = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
resultLines.push_back(String(ch));
|
||||||
|
remaining = remaining.substring(i + 1);
|
||||||
|
lineComplete = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tempLine = testLine;
|
||||||
|
if (ch == ' ' || ch == '>' || ch == '<' || ch == '-' || ch == '(' || ch == ')' || ch == ',') {
|
||||||
|
lastGoodBreak = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lineComplete) {
|
||||||
|
if (tempLine.length() > 0) {
|
||||||
|
resultLines.push_back(tempLine);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultLinesDirty = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool TraceRouteModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_RouteDiscovery *r)
|
bool TraceRouteModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_RouteDiscovery *r)
|
||||||
{
|
{
|
||||||
// We only alter the packet in alterReceivedProtobuf()
|
// We only alter the packet in alterReceivedProtobuf()
|
||||||
@@ -406,7 +513,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
if (node == 0 || node == NODENUM_BROADCAST) {
|
if (node == 0 || node == NODENUM_BROADCAST) {
|
||||||
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Invalid node";
|
setResultText("Invalid node");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -420,7 +527,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
if (node == nodeDB->getNodeNum()) {
|
if (node == nodeDB->getNodeNum()) {
|
||||||
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Cannot trace self";
|
setResultText("Cannot trace self");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -447,6 +554,8 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
||||||
bannerText = String("Wait for ") + String(wait) + String("s");
|
bannerText = String("Wait for ") + String(wait) + String("s");
|
||||||
runState = TRACEROUTE_STATE_COOLDOWN;
|
runState = TRACEROUTE_STATE_COOLDOWN;
|
||||||
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
|
|
||||||
requestFocus();
|
requestFocus();
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
@@ -459,6 +568,8 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
tracingNode = node;
|
tracingNode = node;
|
||||||
lastTraceRouteTime = now;
|
lastTraceRouteTime = now;
|
||||||
runState = TRACEROUTE_STATE_TRACKING;
|
runState = TRACEROUTE_STATE_TRACKING;
|
||||||
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
bannerText = String("Tracing ") + getNodeName(node);
|
bannerText = String("Tracing ") + getNodeName(node);
|
||||||
|
|
||||||
LOG_INFO("TraceRoute UI: Starting trace route to node 0x%08x, requesting focus", node);
|
LOG_INFO("TraceRoute UI: Starting trace route to node 0x%08x, requesting focus", node);
|
||||||
@@ -501,7 +612,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
} else {
|
} else {
|
||||||
LOG_ERROR("MeshService is NULL!");
|
LOG_ERROR("MeshService is NULL!");
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Service unavailable";
|
setResultText("Service unavailable");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -514,7 +625,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
|||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Failed to send";
|
setResultText("Failed to send");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -532,7 +643,7 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
if (node == 0 || node == NODENUM_BROADCAST) {
|
if (node == 0 || node == NODENUM_BROADCAST) {
|
||||||
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Invalid node";
|
setResultText("Invalid node");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -546,7 +657,7 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
if (node == nodeDB->getNodeNum()) {
|
if (node == nodeDB->getNodeNum()) {
|
||||||
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Cannot trace self";
|
setResultText("Cannot trace self");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -568,6 +679,8 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
||||||
bannerText = String("Wait for ") + String(wait) + String("s");
|
bannerText = String("Wait for ") + String(wait) + String("s");
|
||||||
runState = TRACEROUTE_STATE_COOLDOWN;
|
runState = TRACEROUTE_STATE_COOLDOWN;
|
||||||
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
|
|
||||||
requestFocus();
|
requestFocus();
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
@@ -580,6 +693,8 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
runState = TRACEROUTE_STATE_TRACKING;
|
runState = TRACEROUTE_STATE_TRACKING;
|
||||||
tracingNode = node;
|
tracingNode = node;
|
||||||
lastTraceRouteTime = now;
|
lastTraceRouteTime = now;
|
||||||
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
bannerText = String("Tracing ") + getNodeName(node);
|
bannerText = String("Tracing ") + getNodeName(node);
|
||||||
|
|
||||||
requestFocus();
|
requestFocus();
|
||||||
@@ -614,14 +729,14 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
} else {
|
} else {
|
||||||
LOG_ERROR("MeshService is NULL!");
|
LOG_ERROR("MeshService is NULL!");
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Service unavailable";
|
setResultText("Service unavailable");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "Failed to send";
|
setResultText("Failed to send");
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
}
|
}
|
||||||
@@ -629,7 +744,7 @@ void TraceRouteModule::launch(NodeNum node)
|
|||||||
|
|
||||||
void TraceRouteModule::handleTraceRouteResult(const String &result)
|
void TraceRouteModule::handleTraceRouteResult(const String &result)
|
||||||
{
|
{
|
||||||
resultText = result;
|
setResultText(result);
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultShowTime = millis();
|
resultShowTime = millis();
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
@@ -679,83 +794,15 @@ void TraceRouteModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
if (resultText.length() > 0) {
|
if (resultText.length() > 0) {
|
||||||
std::vector<String> lines;
|
if (resultLinesDirty) {
|
||||||
String currentLine = "";
|
rebuildResultLines(display);
|
||||||
int maxWidth = display->getWidth() - 4;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
int newlinePos = resultText.indexOf('\n', start);
|
|
||||||
|
|
||||||
while (newlinePos != -1 || start < static_cast<int>(resultText.length())) {
|
|
||||||
String segment;
|
|
||||||
if (newlinePos != -1) {
|
|
||||||
segment = resultText.substring(start, newlinePos);
|
|
||||||
start = newlinePos + 1;
|
|
||||||
newlinePos = resultText.indexOf('\n', start);
|
|
||||||
} else {
|
|
||||||
segment = resultText.substring(start);
|
|
||||||
start = resultText.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display->getStringWidth(segment) <= maxWidth) {
|
|
||||||
lines.push_back(segment);
|
|
||||||
} else {
|
|
||||||
// Try to break at better positions (space, >, <, -)
|
|
||||||
String remaining = segment;
|
|
||||||
|
|
||||||
while (remaining.length() > 0) {
|
|
||||||
String tempLine = "";
|
|
||||||
int lastGoodBreak = -1;
|
|
||||||
bool lineComplete = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < static_cast<int>(remaining.length()); i++) {
|
|
||||||
char ch = remaining.charAt(i);
|
|
||||||
String testLine = tempLine + ch;
|
|
||||||
|
|
||||||
if (display->getStringWidth(testLine) > maxWidth) {
|
|
||||||
if (lastGoodBreak >= 0) {
|
|
||||||
// Break at the last good position
|
|
||||||
lines.push_back(remaining.substring(0, lastGoodBreak + 1));
|
|
||||||
remaining = remaining.substring(lastGoodBreak + 1);
|
|
||||||
lineComplete = true;
|
|
||||||
break;
|
|
||||||
} else if (tempLine.length() > 0) {
|
|
||||||
lines.push_back(tempLine);
|
|
||||||
remaining = remaining.substring(i);
|
|
||||||
lineComplete = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Single character exceeds width
|
|
||||||
lines.push_back(String(ch));
|
|
||||||
remaining = remaining.substring(i + 1);
|
|
||||||
lineComplete = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tempLine = testLine;
|
|
||||||
// Mark good break positions
|
|
||||||
if (ch == ' ' || ch == '>' || ch == '<' || ch == '-' || ch == '(' || ch == ')') {
|
|
||||||
lastGoodBreak = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lineComplete) {
|
|
||||||
// Reached end of remaining text
|
|
||||||
if (tempLine.length() > 0) {
|
|
||||||
lines.push_back(tempLine);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineHeight = FONT_HEIGHT_SMALL + 1; // Use proper font height with 1px spacing
|
int lineHeight = FONT_HEIGHT_SMALL + 1; // Use proper font height with 1px spacing
|
||||||
for (size_t i = 0; i < lines.size(); i++) {
|
for (size_t i = 0; i < resultLines.size(); i++) {
|
||||||
int lineY = contentStartY + (i * lineHeight);
|
int lineY = contentStartY + (i * lineHeight);
|
||||||
if (lineY + FONT_HEIGHT_SMALL <= display->getHeight()) {
|
if (lineY + FONT_HEIGHT_SMALL <= display->getHeight()) {
|
||||||
display->drawString(x + 2, lineY, lines[i]);
|
display->drawString(x + 2, lineY, resultLines[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,7 +826,7 @@ int32_t TraceRouteModule::runOnce()
|
|||||||
if (runState == TRACEROUTE_STATE_TRACKING && now - lastTraceRouteTime > trackingTimeoutMs) {
|
if (runState == TRACEROUTE_STATE_TRACKING && now - lastTraceRouteTime > trackingTimeoutMs) {
|
||||||
LOG_INFO("TraceRoute timeout, no response received");
|
LOG_INFO("TraceRoute timeout, no response received");
|
||||||
runState = TRACEROUTE_STATE_RESULT;
|
runState = TRACEROUTE_STATE_RESULT;
|
||||||
resultText = "No response received";
|
setResultText("No response received");
|
||||||
resultShowTime = now;
|
resultShowTime = now;
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
|
|
||||||
@@ -815,6 +862,8 @@ int32_t TraceRouteModule::runOnce()
|
|||||||
// Cooldown finished
|
// Cooldown finished
|
||||||
LOG_INFO("TraceRoute cooldown finished, returning to IDLE");
|
LOG_INFO("TraceRoute cooldown finished, returning to IDLE");
|
||||||
runState = TRACEROUTE_STATE_IDLE;
|
runState = TRACEROUTE_STATE_IDLE;
|
||||||
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
bannerText = "";
|
bannerText = "";
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||||
@@ -828,6 +877,7 @@ int32_t TraceRouteModule::runOnce()
|
|||||||
LOG_INFO("TraceRoute result display timeout, returning to IDLE");
|
LOG_INFO("TraceRoute result display timeout, returning to IDLE");
|
||||||
runState = TRACEROUTE_STATE_IDLE;
|
runState = TRACEROUTE_STATE_IDLE;
|
||||||
resultText = "";
|
resultText = "";
|
||||||
|
clearResultLines();
|
||||||
bannerText = "";
|
bannerText = "";
|
||||||
tracingNode = 0;
|
tracingNode = 0;
|
||||||
UIFrameEvent e;
|
UIFrameEvent e;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
#include "OLEDDisplayUi.h"
|
#include "OLEDDisplayUi.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#define ROUTE_SIZE sizeof(((meshtastic_RouteDiscovery *)0)->route) / sizeof(((meshtastic_RouteDiscovery *)0)->route[0])
|
#define ROUTE_SIZE sizeof(((meshtastic_RouteDiscovery *)0)->route) / sizeof(((meshtastic_RouteDiscovery *)0)->route[0])
|
||||||
|
|
||||||
@@ -49,6 +50,11 @@ class TraceRouteModule : public ProtobufModule<meshtastic_RouteDiscovery>,
|
|||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setResultText(const String &text);
|
||||||
|
void clearResultLines();
|
||||||
|
#if HAS_SCREEN
|
||||||
|
void rebuildResultLines(OLEDDisplay *display);
|
||||||
|
#endif
|
||||||
// Call to add unknown hops (e.g. when a node couldn't decrypt it) to the route based on hopStart and current hopLimit
|
// Call to add unknown hops (e.g. when a node couldn't decrypt it) to the route based on hopStart and current hopLimit
|
||||||
void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r, bool isTowardsDestination);
|
void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r, bool isTowardsDestination);
|
||||||
|
|
||||||
@@ -74,6 +80,8 @@ class TraceRouteModule : public ProtobufModule<meshtastic_RouteDiscovery>,
|
|||||||
unsigned long trackingTimeoutMs = 10000;
|
unsigned long trackingTimeoutMs = 10000;
|
||||||
String bannerText;
|
String bannerText;
|
||||||
String resultText;
|
String resultText;
|
||||||
|
std::vector<String> resultLines;
|
||||||
|
bool resultLinesDirty = false;
|
||||||
NodeNum tracingNode = 0;
|
NodeNum tracingNode = 0;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user