Adding ability to log CAN frames to SD card

This commit is contained in:
No-Signal 2024-12-29 13:42:14 +00:00
parent 47c99f9c3a
commit 40399b446e
9 changed files with 237 additions and 2 deletions

View file

@ -18,6 +18,7 @@
#include "src/communication/rs485/comm_rs485.h"
#include "src/communication/seriallink/comm_seriallink.h"
#include "src/datalayer/datalayer.h"
#include "src/devboard/sdcard/sdcard.h"
#include "src/devboard/utils/events.h"
#include "src/devboard/utils/led_handler.h"
#include "src/devboard/utils/logging.h"
@ -78,12 +79,16 @@ MyTimer core_task_timer_10s(INTERVAL_10_S);
int64_t connectivity_task_time_us;
MyTimer connectivity_task_timer_10s(INTERVAL_10_S);
int64_t logging_task_time_us;
MyTimer logging_task_timer_10s(INTERVAL_10_S);
MyTimer loop_task_timer_10s(INTERVAL_10_S);
MyTimer check_pause_2s(INTERVAL_2_S);
TaskHandle_t main_loop_task;
TaskHandle_t connectivity_loop_task;
TaskHandle_t logging_loop_task;
Logging logging;
@ -98,6 +103,11 @@ void setup() {
TASK_CONNECTIVITY_PRIO, &connectivity_loop_task, WIFI_CORE);
#endif
#ifdef LOG_CAN_TO_SD
xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, &logging_task_time_us,
TASK_CONNECTIVITY_PRIO, &logging_loop_task, WIFI_CORE);
#endif
init_events();
init_CAN();
@ -137,6 +147,18 @@ void loop() {
#endif
}
#ifdef LOG_CAN_TO_SD
void logging_loop(void* task_time_us) {
init_logging_buffer();
init_sdcard();
while (true) {
write_can_frame_to_sdcard();
}
}
#endif
#ifdef WIFI
void connectivity_loop(void* task_time_us) {

View file

@ -73,6 +73,7 @@
#endif
//#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 LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card
//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting
//#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 CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency?

View file

@ -1,5 +1,6 @@
#include "comm_can.h"
#include "../../include.h"
#include "src/devboard/sdcard/sdcard.h"
// Parameters
@ -107,6 +108,10 @@ void transmit_can(CAN_frame* tx_frame, int interface) {
}
print_can_frame(*tx_frame, frameDirection(MSG_TX));
#ifdef LOG_CAN_TO_SD
add_can_frame_to_buffer(*tx_frame, frameDirection(MSG_TX));
#endif
switch (interface) {
case CAN_NATIVE:
CAN_frame_t frame;
@ -186,6 +191,10 @@ void send_can() {
void receive_can(CAN_frame* rx_frame, int interface) {
print_can_frame(*rx_frame, frameDirection(MSG_RX));
#ifdef LOG_CAN_TO_SD
add_can_frame_to_buffer(*rx_frame, frameDirection(MSG_RX));
#endif
if (interface == can_config.battery) {
receive_can_battery(*rx_frame);
#ifdef CHADEMO_BATTERY

View file

@ -15,8 +15,6 @@
#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
#endif //CANFD_ADDON
enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1
/**
* @brief Initialization function for CAN.
*

View file

@ -0,0 +1,151 @@
#include "sdcard.h"
#include "freertos/ringbuf.h"
File can_log_file;
RingbufHandle_t can_bufferHandle;
bool can_logging_paused = false;
bool can_file_open = false;
bool delete_can_file = false;
bool sd_card_active = false;
void delete_can_log() {
can_logging_paused = true;
delete_can_file = true;
}
void resume_can_writing() {
can_logging_paused = false;
can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND);
can_file_open = true;
}
void pause_can_writing() {
can_logging_paused = true;
}
void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) {
if (!sd_card_active)
return;
CAN_log_frame log_frame = {frame, msgDir};
if (xRingbufferSend(can_bufferHandle, &log_frame, sizeof(log_frame), 0) != pdTRUE) {
Serial.println("Failed to send CAN frame to ring buffer!");
return;
}
}
void write_can_frame_to_sdcard() {
if (!sd_card_active)
return;
size_t receivedMessageSize;
CAN_log_frame* log_frame =
(CAN_log_frame*)xRingbufferReceive(can_bufferHandle, &receivedMessageSize, pdMS_TO_TICKS(10));
if (log_frame != NULL) {
if (can_logging_paused) {
if (can_file_open) {
can_log_file.close();
can_file_open = false;
}
if (delete_can_file) {
SD.remove(CAN_LOG_FILE);
delete_can_file = false;
can_logging_paused = false;
}
vRingbufferReturnItem(can_bufferHandle, (void*)log_frame);
return;
}
if (can_file_open == false) {
can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND);
can_file_open = true;
}
uint8_t i = 0;
can_log_file.print("(");
can_log_file.print(millis() / 1000.0);
(log_frame->direction == MSG_RX) ? can_log_file.print(") RX0 ") : can_log_file.print(") TX1 ");
can_log_file.print(log_frame->frame.ID, HEX);
can_log_file.print(" [");
can_log_file.print(log_frame->frame.DLC);
can_log_file.print("] ");
for (i = 0; i < log_frame->frame.DLC; i++) {
can_log_file.print(log_frame->frame.data.u8[i] < 16 ? "0" : "");
can_log_file.print(log_frame->frame.data.u8[i], HEX);
if (i < log_frame->frame.DLC - 1)
can_log_file.print(" ");
}
can_log_file.println("");
vRingbufferReturnItem(can_bufferHandle, (void*)log_frame);
}
}
void init_logging_buffer() {
can_bufferHandle = xRingbufferCreate(64 * 1024, RINGBUF_TYPE_BYTEBUF);
if (can_bufferHandle == NULL) {
Serial.println("Failed to create CAN ring buffer!");
return;
}
}
void init_sdcard() {
pinMode(SD_CS_PIN, OUTPUT);
digitalWrite(SD_CS_PIN, HIGH);
pinMode(SD_SCLK_PIN, OUTPUT);
pinMode(SD_MOSI_PIN, OUTPUT);
pinMode(SD_MISO_PIN, INPUT);
SPI.begin(SD_SCLK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN);
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD Card initialization failed!");
return;
}
Serial.println("SD Card initialization successful.");
sd_card_active = true;
print_sdcard_details();
}
void print_sdcard_details() {
Serial.print("SD Card Type: ");
switch (SD.cardType()) {
case CARD_MMC:
Serial.println("MMC");
break;
case CARD_SD:
Serial.println("SD");
break;
case CARD_SDHC:
Serial.println("SDHC");
break;
case CARD_UNKNOWN:
Serial.println("UNKNOWN");
break;
case CARD_NONE:
Serial.println("No SD Card found");
break;
}
if (SD.cardType() != CARD_NONE) {
Serial.print("SD Card Size: ");
Serial.print(SD.cardSize() / 1024 / 1024);
Serial.println(" MB");
Serial.print("Total space: ");
Serial.print(SD.totalBytes() / 1024 / 1024);
Serial.println(" MB");
Serial.print("Used space: ");
Serial.print(SD.usedBytes() / 1024 / 1024);
Serial.println(" MB");
}
}

View file

@ -0,0 +1,23 @@
#ifndef SDCARD_H
#define SDCARD_H
#include <SD.h>
#include <SPI.h>
#include "../../communication/can/comm_can.h"
#include "../hal/hal.h"
#define CAN_LOG_FILE "/canlog.txt"
void init_logging_buffer();
void init_sdcard();
void print_sdcard_details();
void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir);
void write_can_frame_to_sdcard();
void pause_can_writing();
void resume_can_writing();
void delete_can_log();
#endif

View file

@ -51,6 +51,13 @@ typedef struct {
} data;
} CAN_frame;
enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1
typedef struct {
CAN_frame frame;
frameDirection direction;
} CAN_log_frame;
std::string getBMSStatus(bms_status_enum status);
#endif

View file

@ -24,6 +24,9 @@ String can_logger_processor(const String& var) {
content += "</style>";
content += "<button onclick='refreshPage()'>Refresh data</button> ";
content += "<button onclick='exportLog()'>Export to .txt</button> ";
#ifdef LOG_CAN_TO_SD
content += "<button onclick='deleteLogFile()'>Delete log file</button> ";
#endif
content += "<button onclick='stopLoggingAndGoToMainPage()'>Back to main page</button>";
// Start a new block for the CAN messages
@ -52,6 +55,9 @@ String can_logger_processor(const String& var) {
content += "<script>";
content += "function refreshPage(){ location.reload(true); }";
content += "function exportLog() { window.location.href = '/export_can_log'; }";
#ifdef LOG_CAN_TO_SD
content += "function deleteLogFile() { window.location.href = '/delete_can_log'; }";
#endif
content += "function stopLoggingAndGoToMainPage() {";
content += " fetch('/stop_can_logging').then(() => window.location.href = '/');";
content += "}";

View file

@ -5,6 +5,7 @@
#include "../../datalayer/datalayer.h"
#include "../../datalayer/datalayer_extended.h"
#include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h"
#include "../sdcard/sdcard.h"
#include "../utils/events.h"
#include "../utils/led_handler.h"
#include "../utils/timer.h"
@ -78,6 +79,7 @@ void init_webserver() {
request->send_P(200, "text/plain", "Logging stopped");
});
#ifndef LOG_CAN_TO_SD
// Define the handler to export can log
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
String logs = String(datalayer.system.info.logged_can_messages);
@ -104,6 +106,22 @@ void init_webserver() {
response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\"");
request->send(response);
});
#endif
#ifdef LOG_CAN_TO_SD
// Define the handler to export can log
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
pause_can_writing();
request->send(SD, CAN_LOG_FILE, String(), true);
resume_can_writing();
});
// Define the handler to delete can log
server.on("/delete_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
delete_can_log();
request->send_P(200, "text/plain", "Log file deleted");
});
#endif
// Define the handler to export debug log
server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) {