mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 10:19:29 +02:00
Make playback work if order is wrong
This commit is contained in:
parent
e057df3345
commit
8c44da7070
3 changed files with 148 additions and 139 deletions
|
@ -41,7 +41,7 @@
|
|||
//#define TESLA_MODEL_SX_BATTERY
|
||||
//#define VOLVO_SPA_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 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)
|
||||
|
||||
/* Select hardware used for Battery-Emulator */
|
||||
#define HW_LILYGO
|
||||
//#define HW_LILYGO
|
||||
//#define HW_STARK
|
||||
//#define HW_3LB
|
||||
//#define HW_DEVKIT
|
||||
|
@ -81,7 +81,7 @@
|
|||
//#define PERIODIC_BMS_RESET //Enable to have the emulator powercycle the connected battery every 24hours via GPIO. Useful for some batteries like Nissan LEAF
|
||||
//#define REMOTE_BMS_RESET //Enable to allow the emulator to remotely trigger a powercycle of the battery via MQTT. Useful for some batteries like Nissan LEAF
|
||||
// PERIODIC_BMS_RESET_AT Uses NTP server, internet required. In 24 Hour format WITHOUT leading 0. e.g 0230 should be 230. Time Zone is set in USER_SETTINGS.cpp
|
||||
#define PERIODIC_BMS_RESET_AT 525
|
||||
//#define PERIODIC_BMS_RESET_AT 525
|
||||
|
||||
/* Shunt/Contactor settings (Optional) */
|
||||
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement
|
||||
|
|
|
@ -34,11 +34,9 @@ String can_replay_processor(void) {
|
|||
content += "<label for='canInterface'>CAN Interface:</label>";
|
||||
content += "<select id='canInterface' name='canInterface'>";
|
||||
content += "<option value='" + String(CAN_NATIVE) + "' " +
|
||||
(datalayer.system.info.can_replay_interface == CAN_NATIVE ? "selected" : "") +
|
||||
">CAN Native</option>";
|
||||
(datalayer.system.info.can_replay_interface == CAN_NATIVE ? "selected" : "") + ">CAN Native</option>";
|
||||
content += "<option value='" + String(CANFD_NATIVE) + "' " +
|
||||
(datalayer.system.info.can_replay_interface == CANFD_NATIVE ? "selected" : "") +
|
||||
">CANFD Native</option>";
|
||||
(datalayer.system.info.can_replay_interface == CANFD_NATIVE ? "selected" : "") + ">CANFD Native</option>";
|
||||
content += "<option value='" + String(CAN_ADDON_MCP2515) + "' " +
|
||||
(datalayer.system.info.can_replay_interface == CAN_ADDON_MCP2515 ? "selected" : "") +
|
||||
">CAN Addon MCP2515</option>";
|
||||
|
@ -83,9 +81,13 @@ content += "const progressBar = document.getElementById('progress-bar');";
|
|||
content += "const progressContainer = document.getElementById('progress');";
|
||||
content += "let selectedFile = null;";
|
||||
|
||||
content += "dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.style.background = '#f0f0f0'; });";
|
||||
content +=
|
||||
"dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.style.background = '#f0f0f0'; });";
|
||||
content += "dropArea.addEventListener('dragleave', () => { dropArea.style.background = 'white'; });";
|
||||
content += "dropArea.addEventListener('drop', (e) => { e.preventDefault(); dropArea.style.background = 'white'; if (e.dataTransfer.files.length > 0) { fileInput.files = e.dataTransfer.files; selectedFile = fileInput.files[0]; }});";
|
||||
content +=
|
||||
"dropArea.addEventListener('drop', (e) => { e.preventDefault(); dropArea.style.background = 'white'; if "
|
||||
"(e.dataTransfer.files.length > 0) { fileInput.files = e.dataTransfer.files; selectedFile = fileInput.files[0]; "
|
||||
"}});";
|
||||
|
||||
content += "fileInput.addEventListener('change', () => { selectedFile = fileInput.files[0]; });";
|
||||
|
||||
|
@ -95,8 +97,13 @@ content += "const formData = new FormData();";
|
|||
content += "formData.append('file', selectedFile);";
|
||||
content += "const xhr = new XMLHttpRequest();";
|
||||
content += "xhr.open('POST', '/import_can_log', true);";
|
||||
content += "xhr.upload.onprogress = (event) => { if (event.lengthComputable) { const percent = (event.loaded / event.total) * 100; progressContainer.style.display = 'block'; progressBar.style.width = percent + '%'; }};";
|
||||
content += "xhr.onload = () => { if (xhr.status === 200) { alert('File uploaded successfully!'); progressBar.style.width = '100%'; const reader = new FileReader(); reader.onload = function (e) { fileContent.textContent = e.target.result; }; reader.readAsText(selectedFile); } else { alert('Upload failed! Server error.'); }};";
|
||||
content +=
|
||||
"xhr.upload.onprogress = (event) => { if (event.lengthComputable) { const percent = (event.loaded / event.total) "
|
||||
"* 100; progressContainer.style.display = 'block'; progressBar.style.width = percent + '%'; }};";
|
||||
content +=
|
||||
"xhr.onload = () => { if (xhr.status === 200) { alert('File uploaded successfully!'); progressBar.style.width = "
|
||||
"'100%'; const reader = new FileReader(); reader.onload = function (e) { fileContent.textContent = "
|
||||
"e.target.result; }; reader.readAsText(selectedFile); } else { alert('Upload failed! Server error.'); }};";
|
||||
content += "xhr.send(formData);";
|
||||
content += "});";
|
||||
content += "</script>";
|
||||
|
|
|
@ -38,20 +38,18 @@ CAN_frame currentFrame = {.FD = false,
|
|||
.ID = 0x12F,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
void handleFileUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
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());
|
||||
logging.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 (TODO: Remove these prints when feature works)
|
||||
//datalayer.system.info.logged_can_messages = importedLogs;
|
||||
logging.println("Upload Complete!");
|
||||
request->send(200, "text/plain", "File uploaded successfully");
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +124,14 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|||
String line = messages[i];
|
||||
line.trim(); // Remove leading/trailing spaces
|
||||
|
||||
if (line.length() == 0) continue; // Skip empty lines
|
||||
if (line.length() == 0)
|
||||
continue; // Skip empty lines
|
||||
|
||||
// Extract timestamp
|
||||
int timeStart = line.indexOf("(") + 1;
|
||||
int timeEnd = line.indexOf(")");
|
||||
if (timeStart == 0 || timeEnd == -1) continue;
|
||||
if (timeStart == 0 || timeEnd == -1)
|
||||
continue;
|
||||
|
||||
float currentTimestamp = line.substring(timeStart, timeEnd).toFloat();
|
||||
|
||||
|
@ -139,9 +139,10 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|||
firstTimestamp = currentTimestamp; // Store first message timestamp
|
||||
}
|
||||
|
||||
// Calculate delay (skip for the first message)
|
||||
if (i > 0) {
|
||||
// Calculate delay (skip for the first message, and incase the log is out of order)
|
||||
if ((i > 0) && (currentTimestamp > lastTimestamp)) {
|
||||
float deltaT = (currentTimestamp - lastTimestamp) * 1000; // Convert seconds to milliseconds
|
||||
|
||||
delay((int)deltaT); // Delay before sending this message
|
||||
}
|
||||
|
||||
|
@ -150,21 +151,24 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|||
// Find the first space after the timestamp to locate the interface (TX# or RX#)
|
||||
int interfaceStart = timeEnd + 2; // Start after ") "
|
||||
int interfaceEnd = line.indexOf(" ", interfaceStart);
|
||||
if (interfaceEnd == -1) continue;
|
||||
if (interfaceEnd == -1)
|
||||
continue;
|
||||
|
||||
String canInterface = line.substring(interfaceStart, interfaceEnd); // Extract TX# or RX#
|
||||
|
||||
// Extract CAN ID
|
||||
int idStart = interfaceEnd + 1;
|
||||
int idEnd = line.indexOf(" [", idStart);
|
||||
if (idStart == -1 || idEnd == -1) continue;
|
||||
if (idStart == -1 || idEnd == -1)
|
||||
continue;
|
||||
|
||||
String messageID = line.substring(idStart, idEnd);
|
||||
|
||||
// Extract DLC
|
||||
int dlcStart = idEnd + 2;
|
||||
int dlcEnd = line.indexOf("]", dlcStart);
|
||||
if (dlcEnd == -1) continue;
|
||||
if (dlcEnd == -1)
|
||||
continue;
|
||||
|
||||
String dlc = line.substring(dlcStart, dlcEnd);
|
||||
|
||||
|
@ -191,8 +195,6 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|||
request->send(200, "text/plain", "All CAN messages sent with correct interfaces!");
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Route to handle setting the CAN interface for CAN replay
|
||||
server.on("/setCANInterface", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("interface")) {
|
||||
|
@ -226,12 +228,12 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|||
});
|
||||
|
||||
// Define the handler to import can log
|
||||
server.on("/import_can_log", HTTP_POST,[](AsyncWebServerRequest *request) {
|
||||
server.on(
|
||||
"/import_can_log", HTTP_POST,
|
||||
[](AsyncWebServerRequest* request) {
|
||||
request->send(200, "text/plain", "Ready to receive file."); // Response when request is made
|
||||
},
|
||||
handleFileUpload
|
||||
);
|
||||
|
||||
handleFileUpload);
|
||||
|
||||
#ifndef LOG_CAN_TO_SD
|
||||
// Define the handler to export can log
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue