Add initial skeleton for replay

This commit is contained in:
Daniel Öster 2025-02-26 23:31:16 +02:00
parent 827e7eae70
commit 26baf25c97
4 changed files with 129 additions and 2 deletions

View file

@ -41,7 +41,7 @@
//#define TESLA_MODEL_SX_BATTERY //#define TESLA_MODEL_SX_BATTERY
//#define VOLVO_SPA_BATTERY //#define VOLVO_SPA_BATTERY
//#define VOLVO_SPA_HYBRID_BATTERY //#define VOLVO_SPA_HYBRID_BATTERY
//#define TEST_FAKE_BATTERY #define TEST_FAKE_BATTERY
//#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup) //#define DOUBLE_BATTERY //Enable this line if you use two identical batteries at the same time (requires CAN_ADDON setup)
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
@ -67,7 +67,7 @@
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
/* Select hardware used for Battery-Emulator */ /* Select hardware used for Battery-Emulator */
//#define HW_LILYGO #define HW_LILYGO
//#define HW_STARK //#define HW_STARK
//#define HW_3LB //#define HW_3LB
//#define HW_DEVKIT //#define HW_DEVKIT

View file

@ -0,0 +1,75 @@
#include "can_replay_html.h"
#include <Arduino.h>
#include "../../datalayer/datalayer.h"
#include "index_html.h"
String can_replay_processor(void) {
if (!datalayer.system.info.can_logging_active) {
datalayer.system.info.logged_can_messages_offset = 0;
datalayer.system.info.logged_can_messages[0] = '\0';
}
datalayer.system.info.can_logging_active =
true; // Signal to main loop that we should log messages. Disabled by default for performance reasons
String content = index_html_header;
// Page format
content += "<style>";
content += "body { background-color: black; color: white; font-family: Arial, sans-serif; }";
content +=
"button { background-color: #505E67; color: white; border: none; padding: 10px 20px; margin-bottom: 20px; "
"cursor: pointer; border-radius: 10px; }";
content += "button:hover { background-color: #3A4A52; }";
content +=
".can-message { background-color: #404E57; margin-bottom: 5px; padding: 10px; border-radius: 5px; font-family: "
"monospace; }";
content += "</style>";
content += "<button onclick='importLog()'>Import .txt</button> ";
content += "<button onclick='stopPlaybackAndGoToMainPage()'>Stop &amp; Back to main page</button>";
// Start a new block for the CAN messages
content += "<div style='background-color: #303E47; padding: 20px; border-radius: 15px'>";
// Ask user to select which CAN interface log should be sent to
content += "<h4>Select CAN Interface for Playback</h4>";
// Dropdown with choices
content += "<label for='canInterface'>CAN Interface:</label>";
content += "<select id='canInterface' name='canInterface'>";
content += "<option value='" + String(CAN_NATIVE) + "'>CAN Native</option>";
content += "<option value='" + String(CANFD_NATIVE) + "'>CANFD Native</option>";
content += "<option value='" + String(CAN_ADDON_MCP2515) + "'>CAN Addon MCP2515</option>";
content += "<option value='" + String(CANFD_ADDON_MCP2518) + "'>CANFD Addon MCP2518</option>";
content += "</select>";
// Add a button to submit the selected CAN interface
content += "<button onclick='sendCANSelection()'>Apply</button>";
// Show text that log file is not loaded yet
content += "<h4>Log file not loaded yet. Import log before starting replay!</h4>";
// Add a button to start playing the log
content += "<button onclick='startReplay()'>Start</button> ";
// Add a button to stop playing the log
content += "<button onclick='startReplay()'>Stop</button> ";
// Add a checkbox to loop the log
//content += "<input type="checkbox" id="myCheck" onclick="myFunction()">";
content += "</div>";
// Add JavaScript for navigation
content += "<script>";
content += "function sendCANSelection() {";
content += " var selectedInterface = document.getElementById('canInterface').value;";
content += " var xhr = new XMLHttpRequest();";
content += " xhr.open('GET', '/setCANInterface?interface=' + selectedInterface, true);";
content += " xhr.send();";
content += "}";
content += "function importLog() { window.location.href = '/import_can_log'; }";
content += "function stopPlaybackAndGoToMainPage() {";
content += " fetch('/stop_can_logging').then(() => window.location.href = '/');";
content += "}";
content += "</script>";
content += index_html_footer;
return content;
}

View file

@ -0,0 +1,16 @@
#ifndef CANREPLAY_H
#define CANREPLAY_H
#include <Arduino.h>
#include <string>
/**
* @brief Replaces placeholder with content section in web page
*
* @param[in] var
*
* @return String
*/
String can_replay_processor(void);
#endif

View file

@ -18,6 +18,7 @@ unsigned long ota_progress_millis = 0;
#include "advanced_battery_html.h" #include "advanced_battery_html.h"
#include "can_logging_html.h" #include "can_logging_html.h"
#include "can_replay_html.h"
#include "cellmonitor_html.h" #include "cellmonitor_html.h"
#include "debug_logging_html.h" #include "debug_logging_html.h"
#include "events_html.h" #include "events_html.h"
@ -29,6 +30,25 @@ 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 /WARNING THIS MIGHT GO BOOM
void handleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!index) {
importedLogs = ""; // Clear previous logs
Serial.printf("Receiving file: %s\n", filename.c_str());
}
// Append received data to the string (RAM storage)
importedLogs += String((char*)data).substring(0, len);
if (final) {
Serial.println("Upload Complete!");
Serial.println("Imported Log Data:");
Serial.println(importedLogs); // Display contents for debugging
request->send(200, "text/plain", "File uploaded successfully");
}
}
void init_webserver() { void init_webserver() {
server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); }); server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); });
@ -65,6 +85,12 @@ void init_webserver() {
request->send(response); request->send(response);
}); });
// Route for going to CAN replay web page
server.on("/canreplay", HTTP_GET, [](AsyncWebServerRequest* request) {
AsyncWebServerResponse* response = request->beginResponse(200, "text/html", can_replay_processor());
request->send(response);
});
#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) #if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD)
// Route for going to debug logging web page // Route for going to debug logging web page
server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) { server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) {
@ -79,6 +105,14 @@ void init_webserver() {
request->send(200, "text/plain", "Logging stopped"); request->send(200, "text/plain", "Logging stopped");
}); });
// Define the handler to import can log
server.on("/import_can_log", HTTP_POST,[](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Ready to receive file."); // Response when request is made
},
handleFileUpload
);
#ifndef LOG_CAN_TO_SD #ifndef LOG_CAN_TO_SD
// Define the handler to export can log // Define the handler to export can log
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) { server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
@ -1280,6 +1314,7 @@ String processor(const String& var) {
content += "<button onclick='Settings()'>Change Settings</button> "; content += "<button onclick='Settings()'>Change Settings</button> ";
content += "<button onclick='Advanced()'>More Battery Info</button> "; content += "<button onclick='Advanced()'>More Battery Info</button> ";
content += "<button onclick='CANlog()'>CAN logger</button> "; content += "<button onclick='CANlog()'>CAN logger</button> ";
content += "<button onclick='CANreplay()'>CAN replay</button> ";
#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) #if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD)
content += "<button onclick='Log()'>Log</button> "; content += "<button onclick='Log()'>Log</button> ";
#endif // DEBUG_VIA_WEB #endif // DEBUG_VIA_WEB
@ -1308,6 +1343,7 @@ String processor(const String& var) {
content += "function Settings() { window.location.href = '/settings'; }"; content += "function Settings() { window.location.href = '/settings'; }";
content += "function Advanced() { window.location.href = '/advanced'; }"; content += "function Advanced() { window.location.href = '/advanced'; }";
content += "function CANlog() { window.location.href = '/canlog'; }"; content += "function CANlog() { window.location.href = '/canlog'; }";
content += "function CANreplay() { window.location.href = '/canreplay'; }";
content += "function Log() { window.location.href = '/log'; }"; content += "function Log() { window.location.href = '/log'; }";
content += "function Events() { window.location.href = '/events'; }"; content += "function Events() { window.location.href = '/events'; }";
content += content +=