mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +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 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
|
||||||
|
@ -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 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
|
//#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
|
// 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) */
|
/* Shunt/Contactor settings (Optional) */
|
||||||
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement
|
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement
|
||||||
|
@ -101,7 +101,7 @@
|
||||||
//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card (WARNING, raises CPU load, do not use for production)
|
//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card (WARNING, raises CPU load, do not use for production)
|
||||||
//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production)
|
//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production)
|
||||||
//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production)
|
//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production)
|
||||||
#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production)
|
#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production)
|
||||||
|
|
||||||
/* CAN options */
|
/* CAN options */
|
||||||
//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
||||||
|
|
|
@ -34,17 +34,15 @@ String can_replay_processor(void) {
|
||||||
content += "<label for='canInterface'>CAN Interface:</label>";
|
content += "<label for='canInterface'>CAN Interface:</label>";
|
||||||
content += "<select id='canInterface' name='canInterface'>";
|
content += "<select id='canInterface' name='canInterface'>";
|
||||||
content += "<option value='" + String(CAN_NATIVE) + "' " +
|
content += "<option value='" + String(CAN_NATIVE) + "' " +
|
||||||
(datalayer.system.info.can_replay_interface == CAN_NATIVE ? "selected" : "") +
|
(datalayer.system.info.can_replay_interface == CAN_NATIVE ? "selected" : "") + ">CAN Native</option>";
|
||||||
">CAN Native</option>";
|
|
||||||
content += "<option value='" + String(CANFD_NATIVE) + "' " +
|
content += "<option value='" + String(CANFD_NATIVE) + "' " +
|
||||||
(datalayer.system.info.can_replay_interface == CANFD_NATIVE ? "selected" : "") +
|
(datalayer.system.info.can_replay_interface == CANFD_NATIVE ? "selected" : "") + ">CANFD Native</option>";
|
||||||
">CANFD Native</option>";
|
|
||||||
content += "<option value='" + String(CAN_ADDON_MCP2515) + "' " +
|
content += "<option value='" + String(CAN_ADDON_MCP2515) + "' " +
|
||||||
(datalayer.system.info.can_replay_interface == CAN_ADDON_MCP2515 ? "selected" : "") +
|
(datalayer.system.info.can_replay_interface == CAN_ADDON_MCP2515 ? "selected" : "") +
|
||||||
">CAN Addon MCP2515</option>";
|
">CAN Addon MCP2515</option>";
|
||||||
content += "<option value='" + String(CANFD_ADDON_MCP2518) + "' " +
|
content += "<option value='" + String(CANFD_ADDON_MCP2518) + "' " +
|
||||||
(datalayer.system.info.can_replay_interface == CANFD_ADDON_MCP2518 ? "selected" : "") +
|
(datalayer.system.info.can_replay_interface == CANFD_ADDON_MCP2518 ? "selected" : "") +
|
||||||
">CANFD Addon MCP2518</option>";
|
">CANFD Addon MCP2518</option>";
|
||||||
|
|
||||||
content += "</select>";
|
content += "</select>";
|
||||||
|
|
||||||
|
@ -54,14 +52,14 @@ String can_replay_processor(void) {
|
||||||
|
|
||||||
content += "<h3>Step 2: Upload CAN Log File</h3>";
|
content += "<h3>Step 2: Upload CAN Log File</h3>";
|
||||||
|
|
||||||
content += "<div id='drop-area' onclick=\"document.getElementById('file-input').click()\">";
|
content += "<div id='drop-area' onclick=\"document.getElementById('file-input').click()\">";
|
||||||
content += "<p>Drag & drop a .txt file here, or click Browse to select one.</p>";
|
content += "<p>Drag & drop a .txt file here, or click Browse to select one.</p>";
|
||||||
content += "<input type='file' id='file-input' accept='.txt'>";
|
content += "<input type='file' id='file-input' accept='.txt'>";
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
|
||||||
content += "<div id='progress'><div id='progress-bar'></div></div>";
|
content += "<div id='progress'><div id='progress-bar'></div></div>";
|
||||||
|
|
||||||
content += "<button id='upload-btn'>Upload</button>";
|
content += "<button id='upload-btn'>Upload</button>";
|
||||||
|
|
||||||
content += "<h3>Step 3: Playback control</h3>";
|
content += "<h3>Step 3: Playback control</h3>";
|
||||||
|
|
||||||
|
@ -71,41 +69,50 @@ content += "<button id='upload-btn'>Upload</button>";
|
||||||
// Add a button to stop playing the log
|
// Add a button to stop playing the log
|
||||||
content += "<button onclick='startReplay()'>Stop</button> ";
|
content += "<button onclick='startReplay()'>Stop</button> ";
|
||||||
|
|
||||||
content += "<h3>Uploaded Log Preview:</h3>";
|
content += "<h3>Uploaded Log Preview:</h3>";
|
||||||
content += "<pre id='file-content'></pre>";
|
content += "<pre id='file-content'></pre>";
|
||||||
|
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "const fileInput = document.getElementById('file-input');";
|
content += "const fileInput = document.getElementById('file-input');";
|
||||||
content += "const uploadBtn = document.getElementById('upload-btn');";
|
content += "const uploadBtn = document.getElementById('upload-btn');";
|
||||||
content += "const fileContent = document.getElementById('file-content');";
|
content += "const fileContent = document.getElementById('file-content');";
|
||||||
content += "const dropArea = document.getElementById('drop-area');";
|
content += "const dropArea = document.getElementById('drop-area');";
|
||||||
content += "const progressBar = document.getElementById('progress-bar');";
|
content += "const progressBar = document.getElementById('progress-bar');";
|
||||||
content += "const progressContainer = document.getElementById('progress');";
|
content += "const progressContainer = document.getElementById('progress');";
|
||||||
content += "let selectedFile = null;";
|
content += "let selectedFile = null;";
|
||||||
|
|
||||||
content += "dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.style.background = '#f0f0f0'; });";
|
content +=
|
||||||
content += "dropArea.addEventListener('dragleave', () => { dropArea.style.background = 'white'; });";
|
"dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.style.background = '#f0f0f0'; });";
|
||||||
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('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 += "fileInput.addEventListener('change', () => { selectedFile = fileInput.files[0]; });";
|
content += "fileInput.addEventListener('change', () => { selectedFile = fileInput.files[0]; });";
|
||||||
|
|
||||||
content += "uploadBtn.addEventListener('click', () => {";
|
content += "uploadBtn.addEventListener('click', () => {";
|
||||||
content += "if (!selectedFile) { alert('Please select a file first!'); return; }";
|
content += "if (!selectedFile) { alert('Please select a file first!'); return; }";
|
||||||
content += "const formData = new FormData();";
|
content += "const formData = new FormData();";
|
||||||
content += "formData.append('file', selectedFile);";
|
content += "formData.append('file', selectedFile);";
|
||||||
content += "const xhr = new XMLHttpRequest();";
|
content += "const xhr = new XMLHttpRequest();";
|
||||||
content += "xhr.open('POST', '/import_can_log', true);";
|
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 +=
|
||||||
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.'); }};";
|
"xhr.upload.onprogress = (event) => { if (event.lengthComputable) { const percent = (event.loaded / event.total) "
|
||||||
content += "xhr.send(formData);";
|
"* 100; progressContainer.style.display = 'block'; progressBar.style.width = percent + '%'; }};";
|
||||||
content += "});";
|
content +=
|
||||||
content += "</script>";
|
"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>";
|
||||||
|
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
|
||||||
// Add JavaScript for navigation
|
// Add JavaScript for navigation
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "function startReplay() {";
|
content += "function startReplay() {";
|
||||||
content += " var xhr = new XMLHttpRequest();";
|
content += " var xhr = new XMLHttpRequest();";
|
||||||
content += " xhr.open('GET', '/startReplay', true);";
|
content += " xhr.open('GET', '/startReplay', true);";
|
||||||
content += " xhr.send();";
|
content += " xhr.send();";
|
||||||
|
|
|
@ -33,27 +33,25 @@ const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral";
|
||||||
String importedLogs = ""; // Store the uploaded file contents in RAM /WARNING THIS MIGHT GO BOOM
|
String importedLogs = ""; // Store the uploaded file contents in RAM /WARNING THIS MIGHT GO BOOM
|
||||||
|
|
||||||
CAN_frame currentFrame = {.FD = false,
|
CAN_frame currentFrame = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
.DLC = 8,
|
.DLC = 8,
|
||||||
.ID = 0x12F,
|
.ID = 0x12F,
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
.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,
|
||||||
if (!index) {
|
bool final) {
|
||||||
importedLogs = ""; // Clear previous logs
|
if (!index) {
|
||||||
Serial.printf("Receiving file: %s\n", filename.c_str());
|
importedLogs = ""; // Clear previous logs
|
||||||
}
|
logging.printf("Receiving file: %s\n", filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// Append received data to the string (RAM storage)
|
// Append received data to the string (RAM storage)
|
||||||
importedLogs += String((char*)data).substring(0, len);
|
importedLogs += String((char*)data).substring(0, len);
|
||||||
|
|
||||||
if (final) {
|
if (final) {
|
||||||
Serial.println("Upload Complete!");
|
logging.println("Upload Complete!");
|
||||||
Serial.println("Imported Log Data:");
|
request->send(200, "text/plain", "File uploaded successfully");
|
||||||
Serial.println(importedLogs); // Display contents for debugging (TODO: Remove these prints when feature works)
|
}
|
||||||
//datalayer.system.info.logged_can_messages = importedLogs;
|
|
||||||
request->send(200, "text/plain", "File uploaded successfully");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_webserver() {
|
void init_webserver() {
|
||||||
|
@ -101,113 +99,117 @@ void init_webserver() {
|
||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route for starting the CAN replay
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<String> messages;
|
std::vector<String> messages;
|
||||||
int lastIndex = 0;
|
int lastIndex = 0;
|
||||||
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)); // Add last message
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
messages.push_back(importedLogs.substring(lastIndex, nextIndex));
|
messages.push_back(importedLogs.substring(lastIndex, nextIndex));
|
||||||
lastIndex = nextIndex + 1;
|
lastIndex = nextIndex + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
float firstTimestamp = -1.0;
|
float firstTimestamp = -1.0;
|
||||||
float lastTimestamp = 0.0;
|
float lastTimestamp = 0.0;
|
||||||
|
|
||||||
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];
|
||||||
line.trim(); // Remove leading/trailing spaces
|
line.trim(); // Remove leading/trailing spaces
|
||||||
|
|
||||||
if (line.length() == 0) continue; // Skip empty lines
|
if (line.length() == 0)
|
||||||
|
continue; // Skip empty lines
|
||||||
|
|
||||||
// Extract timestamp
|
// Extract timestamp
|
||||||
int timeStart = line.indexOf("(") + 1;
|
int timeStart = line.indexOf("(") + 1;
|
||||||
int timeEnd = line.indexOf(")");
|
int timeEnd = line.indexOf(")");
|
||||||
if (timeStart == 0 || timeEnd == -1) continue;
|
if (timeStart == 0 || timeEnd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
float currentTimestamp = line.substring(timeStart, timeEnd).toFloat();
|
float currentTimestamp = line.substring(timeStart, timeEnd).toFloat();
|
||||||
|
|
||||||
if (firstTimestamp < 0) {
|
if (firstTimestamp < 0) {
|
||||||
firstTimestamp = currentTimestamp; // Store first message timestamp
|
firstTimestamp = currentTimestamp; // Store first message timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate delay (skip for the first message)
|
// Calculate delay (skip for the first message, and incase the log is out of order)
|
||||||
if (i > 0) {
|
if ((i > 0) && (currentTimestamp > lastTimestamp)) {
|
||||||
float deltaT = (currentTimestamp - lastTimestamp) * 1000; // Convert seconds to milliseconds
|
float deltaT = (currentTimestamp - lastTimestamp) * 1000; // Convert seconds to milliseconds
|
||||||
delay((int)deltaT); // Delay before sending this message
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTimestamp = currentTimestamp;
|
delay((int)deltaT); // Delay before sending this message
|
||||||
|
}
|
||||||
|
|
||||||
// Find the first space after the timestamp to locate the interface (TX# or RX#)
|
lastTimestamp = currentTimestamp;
|
||||||
int interfaceStart = timeEnd + 2; // Start after ") "
|
|
||||||
int interfaceEnd = line.indexOf(" ", interfaceStart);
|
|
||||||
if (interfaceEnd == -1) continue;
|
|
||||||
|
|
||||||
String canInterface = line.substring(interfaceStart, interfaceEnd); // Extract TX# or RX#
|
// 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;
|
||||||
|
|
||||||
// Extract CAN ID
|
String canInterface = line.substring(interfaceStart, interfaceEnd); // Extract TX# or RX#
|
||||||
int idStart = interfaceEnd + 1;
|
|
||||||
int idEnd = line.indexOf(" [", idStart);
|
|
||||||
if (idStart == -1 || idEnd == -1) continue;
|
|
||||||
|
|
||||||
String messageID = line.substring(idStart, idEnd);
|
// Extract CAN ID
|
||||||
|
int idStart = interfaceEnd + 1;
|
||||||
|
int idEnd = line.indexOf(" [", idStart);
|
||||||
|
if (idStart == -1 || idEnd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Extract DLC
|
String messageID = line.substring(idStart, idEnd);
|
||||||
int dlcStart = idEnd + 2;
|
|
||||||
int dlcEnd = line.indexOf("]", dlcStart);
|
|
||||||
if (dlcEnd == -1) continue;
|
|
||||||
|
|
||||||
String dlc = line.substring(dlcStart, dlcEnd);
|
// Extract DLC
|
||||||
|
int dlcStart = idEnd + 2;
|
||||||
|
int dlcEnd = line.indexOf("]", dlcStart);
|
||||||
|
if (dlcEnd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Extract data bytes
|
String dlc = line.substring(dlcStart, dlcEnd);
|
||||||
int dataStart = dlcEnd + 2;
|
|
||||||
String dataBytes = line.substring(dataStart);
|
|
||||||
|
|
||||||
// Assign values to the CAN frame
|
// Extract data bytes
|
||||||
currentFrame.ID = strtol(messageID.c_str(), NULL, 16);
|
int dataStart = dlcEnd + 2;
|
||||||
currentFrame.DLC = dlc.toInt();
|
String dataBytes = line.substring(dataStart);
|
||||||
|
|
||||||
// Parse and store data bytes
|
// Assign values to the CAN frame
|
||||||
int byteIndex = 0;
|
currentFrame.ID = strtol(messageID.c_str(), NULL, 16);
|
||||||
char* token = strtok((char*)dataBytes.c_str(), " ");
|
currentFrame.DLC = dlc.toInt();
|
||||||
while (token != NULL && byteIndex < 8) {
|
|
||||||
currentFrame.data.u8[byteIndex++] = strtol(token, NULL, 16);
|
|
||||||
token = strtok(NULL, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transmit the CAN frame
|
// Parse and store data bytes
|
||||||
transmit_can_frame(¤tFrame, datalayer.system.info.can_replay_interface);
|
int byteIndex = 0;
|
||||||
|
char* token = strtok((char*)dataBytes.c_str(), " ");
|
||||||
|
while (token != NULL && byteIndex < 8) {
|
||||||
|
currentFrame.data.u8[byteIndex++] = strtol(token, NULL, 16);
|
||||||
|
token = strtok(NULL, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit the CAN frame
|
||||||
|
transmit_can_frame(¤tFrame, datalayer.system.info.can_replay_interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
request->send(200, "text/plain", "All CAN messages sent with correct interfaces!");
|
request->send(200, "text/plain", "All CAN messages sent with correct interfaces!");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Route to handle setting the CAN interface for CAN replay
|
// Route to handle setting the CAN interface for CAN replay
|
||||||
server.on("/setCANInterface", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/setCANInterface", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
if (request->hasParam("interface")) {
|
if (request->hasParam("interface")) {
|
||||||
String canInterface = request->getParam("interface")->value();
|
String canInterface = request->getParam("interface")->value();
|
||||||
|
|
||||||
// Convert the received value to an integer
|
// Convert the received value to an integer
|
||||||
int interfaceValue = canInterface.toInt();
|
int interfaceValue = canInterface.toInt();
|
||||||
|
|
||||||
// Update the datalayer with the selected interface
|
// Update the datalayer with the selected interface
|
||||||
datalayer.system.info.can_replay_interface = interfaceValue;
|
datalayer.system.info.can_replay_interface = interfaceValue;
|
||||||
|
|
||||||
// Respond with success message
|
// Respond with success message
|
||||||
request->send(200, "text/plain", "CAN Interface Updated to " + canInterface);
|
request->send(200, "text/plain", "CAN Interface Updated to " + canInterface);
|
||||||
} else {
|
} else {
|
||||||
request->send(400, "text/plain", "Error: Missing parameter 'interface'");
|
request->send(400, "text/plain", "Error: Missing parameter 'interface'");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,12 +228,12 @@ server.on("/startReplay", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define the handler to import can log
|
// 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
|
request->send(200, "text/plain", "Ready to receive file."); // Response when request is made
|
||||||
},
|
},
|
||||||
handleFileUpload
|
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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue