Make replay more robust and less likely to crash

This commit is contained in:
Daniel Öster 2025-03-04 19:55:49 +02:00
parent dfff57d520
commit effd80cc58

View file

@ -31,7 +31,8 @@ bool ota_active = false;
const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral"; const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral";
String importedLogs = ""; // Store the uploaded file contents in RAM String importedLogs = ""; // Store the uploaded logfile contents in RAM
bool isReplayRunning = false; // Global flag to track replay state
CAN_frame currentFrame = {.FD = true, .ext_ID = false, .DLC = 64, .ID = 0x12F, .data = {0}}; CAN_frame currentFrame = {.FD = true, .ext_ID = false, .DLC = 64, .ID = 0x12F, .data = {0}};
@ -52,16 +53,16 @@ void handleFileUpload(AsyncWebServerRequest* request, String filename, size_t in
} }
void canReplayTask(void* param) { void canReplayTask(void* param) {
std::vector<String> messages; std::vector<String> messages;
int lastIndex = 0; messages.reserve(1000); // Pre-allocate memory to reduce fragmentation
if (!importedLogs.isEmpty()) {
int lastIndex = 0;
if (!(importedLogs.length() == 0)) {
// Split importedLogs into individual messages
while (true) { while (true) {
int nextIndex = importedLogs.indexOf("\n", lastIndex); int nextIndex = importedLogs.indexOf("\n", lastIndex);
if (nextIndex == -1) { if (nextIndex == -1) {
messages.push_back(importedLogs.substring(lastIndex)); // Add last message messages.push_back(importedLogs.substring(lastIndex));
break; break;
} }
messages.push_back(importedLogs.substring(lastIndex, nextIndex)); messages.push_back(importedLogs.substring(lastIndex, nextIndex));
@ -71,6 +72,7 @@ void canReplayTask(void* param) {
do { do {
float firstTimestamp = -1.0; float firstTimestamp = -1.0;
float lastTimestamp = 0.0; float lastTimestamp = 0.0;
bool firstMessageSent = false; // Track first message
for (size_t i = 0; i < messages.size(); i++) { for (size_t i = 0; i < messages.size(); i++) {
String line = messages[i]; String line = messages[i];
@ -84,10 +86,17 @@ void canReplayTask(void* param) {
continue; continue;
float currentTimestamp = line.substring(timeStart, timeEnd).toFloat(); float currentTimestamp = line.substring(timeStart, timeEnd).toFloat();
if (firstTimestamp < 0)
firstTimestamp = currentTimestamp;
if ((i > 0) && (currentTimestamp > lastTimestamp)) { if (firstTimestamp < 0) {
firstTimestamp = currentTimestamp;
}
// Send first message immediately
if (!firstMessageSent) {
firstMessageSent = true;
firstTimestamp = currentTimestamp; // Adjust reference time
} else {
// Delay only if this isn't the first message
float deltaT = (currentTimestamp - lastTimestamp) * 1000; float deltaT = (currentTimestamp - lastTimestamp) * 1000;
vTaskDelay((int)deltaT / portTICK_PERIOD_MS); vTaskDelay((int)deltaT / portTICK_PERIOD_MS);
} }
@ -124,19 +133,20 @@ void canReplayTask(void* param) {
token = strtok(NULL, " "); token = strtok(NULL, " ");
} }
// Apply FD in case interface is set to FD
currentFrame.FD = (datalayer.system.info.can_replay_interface == CANFD_NATIVE) || currentFrame.FD = (datalayer.system.info.can_replay_interface == CANFD_NATIVE) ||
(datalayer.system.info.can_replay_interface == CANFD_ADDON_MCP2518); (datalayer.system.info.can_replay_interface == CANFD_ADDON_MCP2518);
// Apply extended ID in case ID is longer than 0x7F0
currentFrame.ext_ID = (currentFrame.ID > 0x7F0); currentFrame.ext_ID = (currentFrame.ID > 0x7F0);
transmit_can_frame(&currentFrame, datalayer.system.info.can_replay_interface); transmit_can_frame(&currentFrame, datalayer.system.info.can_replay_interface);
} }
} while (datalayer.system.info.loop_playback); } while (datalayer.system.info.loop_playback);
messages.clear(); // Free vector memory
messages.shrink_to_fit(); // Release excess memory
} }
vTaskDelete(NULL); // Delete task when done isReplayRunning = false; // Mark replay as stopped
vTaskDelete(NULL);
} }
void init_webserver() { void init_webserver() {
@ -184,17 +194,20 @@ void init_webserver() {
request->send(response); request->send(response);
}); });
// Route for starting the CAN replay
server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) { server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) { if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password)) {
return request->requestAuthentication(); return request->requestAuthentication();
} }
if (request->hasParam("loop")) { // Prevent multiple replay tasks from being created
datalayer.system.info.loop_playback = request->getParam("loop")->value().toInt() == 1; if (isReplayRunning) {
request->send(400, "text/plain", "Replay already running!");
return;
} }
// Start the replay task on Core 1 datalayer.system.info.loop_playback = request->hasParam("loop") && request->getParam("loop")->value().toInt() == 1;
isReplayRunning = true; // Set flag before starting task
xTaskCreatePinnedToCore(canReplayTask, "CAN_Replay", 8192, NULL, 1, NULL, 1); xTaskCreatePinnedToCore(canReplayTask, "CAN_Replay", 8192, NULL, 1, NULL, 1);
request->send(200, "text/plain", "CAN replay started!"); request->send(200, "text/plain", "CAN replay started!");