mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-13 22:32:27 +00:00
Try-fix traceroute panic (#8568)
This commit is contained in:
@@ -11,6 +11,113 @@ extern graphics::Screen *screen;
|
||||
|
||||
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)
|
||||
{
|
||||
// We only alter the packet in alterReceivedProtobuf()
|
||||
@@ -406,7 +513,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
||||
if (node == 0 || node == NODENUM_BROADCAST) {
|
||||
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Invalid node";
|
||||
setResultText("Invalid node");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -420,7 +527,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
||||
if (node == nodeDB->getNodeNum()) {
|
||||
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Cannot trace self";
|
||||
setResultText("Cannot trace self");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -447,6 +554,8 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
||||
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
||||
bannerText = String("Wait for ") + String(wait) + String("s");
|
||||
runState = TRACEROUTE_STATE_COOLDOWN;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
|
||||
requestFocus();
|
||||
UIFrameEvent e;
|
||||
@@ -459,6 +568,8 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
||||
tracingNode = node;
|
||||
lastTraceRouteTime = now;
|
||||
runState = TRACEROUTE_STATE_TRACKING;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
bannerText = String("Tracing ") + getNodeName(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 {
|
||||
LOG_ERROR("MeshService is NULL!");
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Service unavailable";
|
||||
setResultText("Service unavailable");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -514,7 +625,7 @@ bool TraceRouteModule::startTraceRoute(NodeNum node)
|
||||
} else {
|
||||
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Failed to send";
|
||||
setResultText("Failed to send");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -532,7 +643,7 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
if (node == 0 || node == NODENUM_BROADCAST) {
|
||||
LOG_ERROR("Invalid node number for trace route: 0x%08x", node);
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Invalid node";
|
||||
setResultText("Invalid node");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -546,7 +657,7 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
if (node == nodeDB->getNodeNum()) {
|
||||
LOG_ERROR("Cannot trace route to self: 0x%08x", node);
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Cannot trace self";
|
||||
setResultText("Cannot trace self");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -568,6 +679,8 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
unsigned long wait = (cooldownMs - (now - lastTraceRouteTime)) / 1000;
|
||||
bannerText = String("Wait for ") + String(wait) + String("s");
|
||||
runState = TRACEROUTE_STATE_COOLDOWN;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
|
||||
requestFocus();
|
||||
UIFrameEvent e;
|
||||
@@ -580,6 +693,8 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
runState = TRACEROUTE_STATE_TRACKING;
|
||||
tracingNode = node;
|
||||
lastTraceRouteTime = now;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
bannerText = String("Tracing ") + getNodeName(node);
|
||||
|
||||
requestFocus();
|
||||
@@ -614,14 +729,14 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
} else {
|
||||
LOG_ERROR("MeshService is NULL!");
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Service unavailable";
|
||||
setResultText("Service unavailable");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Failed to allocate TraceRoute packet from router");
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "Failed to send";
|
||||
setResultText("Failed to send");
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
}
|
||||
@@ -629,7 +744,7 @@ void TraceRouteModule::launch(NodeNum node)
|
||||
|
||||
void TraceRouteModule::handleTraceRouteResult(const String &result)
|
||||
{
|
||||
resultText = result;
|
||||
setResultText(result);
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultShowTime = millis();
|
||||
tracingNode = 0;
|
||||
@@ -679,83 +794,15 @@ void TraceRouteModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
if (resultText.length() > 0) {
|
||||
std::vector<String> lines;
|
||||
String currentLine = "";
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resultLinesDirty) {
|
||||
rebuildResultLines(display);
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
LOG_INFO("TraceRoute timeout, no response received");
|
||||
runState = TRACEROUTE_STATE_RESULT;
|
||||
resultText = "No response received";
|
||||
setResultText("No response received");
|
||||
resultShowTime = now;
|
||||
tracingNode = 0;
|
||||
|
||||
@@ -815,6 +862,8 @@ int32_t TraceRouteModule::runOnce()
|
||||
// Cooldown finished
|
||||
LOG_INFO("TraceRoute cooldown finished, returning to IDLE");
|
||||
runState = TRACEROUTE_STATE_IDLE;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
bannerText = "";
|
||||
UIFrameEvent e;
|
||||
e.action = UIFrameEvent::Action::REGENERATE_FRAMESET;
|
||||
@@ -828,6 +877,7 @@ int32_t TraceRouteModule::runOnce()
|
||||
LOG_INFO("TraceRoute result display timeout, returning to IDLE");
|
||||
runState = TRACEROUTE_STATE_IDLE;
|
||||
resultText = "";
|
||||
clearResultLines();
|
||||
bannerText = "";
|
||||
tracingNode = 0;
|
||||
UIFrameEvent e;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#if HAS_SCREEN
|
||||
#include "OLEDDisplayUi.h"
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
#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;
|
||||
|
||||
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
|
||||
void insertUnknownHops(meshtastic_MeshPacket &p, meshtastic_RouteDiscovery *r, bool isTowardsDestination);
|
||||
|
||||
@@ -74,6 +80,8 @@ class TraceRouteModule : public ProtobufModule<meshtastic_RouteDiscovery>,
|
||||
unsigned long trackingTimeoutMs = 10000;
|
||||
String bannerText;
|
||||
String resultText;
|
||||
std::vector<String> resultLines;
|
||||
bool resultLinesDirty = false;
|
||||
NodeNum tracingNode = 0;
|
||||
bool initialized = false;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user