From 5e2da1907514e5bc1f7bf3806dc01929763bf052 Mon Sep 17 00:00:00 2001 From: byun Date: Wed, 8 Oct 2025 20:44:38 +0000 Subject: [PATCH] =?UTF-8?q?=EB=AC=BC=EB=A6=AC=EC=A0=81=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=83=81=ED=83=9CLED=EC=A0=9C=EA=B1=B0=20=EC=9B=B9?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=20=EC=A1=B0=EC=9E=91=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ESP32_CAN_Logger.ino | 124 +++++++++++++++++++------------------------ index.h | 16 ++++++ 2 files changed, 71 insertions(+), 69 deletions(-) diff --git a/ESP32_CAN_Logger.ino b/ESP32_CAN_Logger.ino index a930a74..a7c0c01 100644 --- a/ESP32_CAN_Logger.ino +++ b/ESP32_CAN_Logger.ino @@ -1,6 +1,6 @@ /* * Byun CAN Logger with Web Interface - * Version: 1.0 + * Version: 1.1 */ #include @@ -16,14 +16,11 @@ #include #include "index.h" #include "transmit.h" -#include "graph.h" // 그래프 페이지 추가 -#include "graph_viewer.h" // 새로 추가 +#include "graph.h" +#include "graph_viewer.h" // GPIO 핀 정의 #define CAN_INT_PIN 27 -#define LOGGING_CONTROL_PIN 17 -#define LOGGING_STATUS_LED 16 -#define SD_READY_LED 26 // HSPI 핀 (CAN) #define HSPI_MISO 12 @@ -85,7 +82,6 @@ QueueHandle_t canQueue; SemaphoreHandle_t sdMutex; TaskHandle_t canRxTaskHandle = NULL; TaskHandle_t sdWriteTaskHandle = NULL; -TaskHandle_t controlTaskHandle = NULL; TaskHandle_t webTaskHandle = NULL; volatile bool loggingEnabled = false; @@ -117,9 +113,10 @@ void changeCanSpeed(CAN_SPEED newSpeed); void scanExistingFiles(); bool createNewLogFile(); bool flushBuffer(); +void startLogging(); +void stopLogging(); void canRxTask(void *pvParameters); void sdWriteTask(void *pvParameters); -void controlTask(void *pvParameters); void sdMonitorTask(void *pvParameters); void sendFileList(uint8_t clientNum); void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length); @@ -246,6 +243,49 @@ bool flushBuffer() { return false; } +// 로깅 시작 +void startLogging() { + if (loggingEnabled) { + Serial.println("이미 로깅 중"); + return; + } + + if (!sdCardReady) { + Serial.println("SD 카드가 준비되지 않음"); + return; + } + + Serial.println("로깅 시작"); + + if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { + if (createNewLogFile()) { + loggingEnabled = true; + bufferIndex = 0; + } + xSemaphoreGive(sdMutex); + } +} + +// 로깅 중지 +void stopLogging() { + if (!loggingEnabled) { + Serial.println("로깅이 실행 중이 아님"); + return; + } + + Serial.println("로깅 정지"); + loggingEnabled = false; + + flushBuffer(); + + if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { + if (logFile) { + logFile.close(); + } + xSemaphoreGive(sdMutex); + } +} + // CAN 수신 태스크 void canRxTask(void *pvParameters) { struct can_frame frame; @@ -316,15 +356,12 @@ void sdWriteTask(void *pvParameters) { if (loggingEnabled && sdCardReady) { if (bufferIndex + sizeof(CANMessage) > FILE_BUFFER_SIZE) { if (!flushBuffer()) { - digitalWrite(LOGGING_STATUS_LED, LOW); continue; } } memcpy(&fileBuffer[bufferIndex], &msg, sizeof(CANMessage)); bufferIndex += sizeof(CANMessage); - - digitalWrite(LOGGING_STATUS_LED, HIGH); } } else { if (loggingEnabled && bufferIndex > 0) { @@ -334,49 +371,6 @@ void sdWriteTask(void *pvParameters) { } } -// 제어 태스크 -void controlTask(void *pvParameters) { - bool lastLoggingState = false; - - Serial.println("제어 태스크 시작"); - - while (1) { - bool currentState = digitalRead(LOGGING_CONTROL_PIN); - - if (currentState != lastLoggingState) { - if (currentState == HIGH && sdCardReady) { - Serial.println("로깅 시작"); - - if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - if (createNewLogFile()) { - loggingEnabled = true; - bufferIndex = 0; - } - xSemaphoreGive(sdMutex); - } - } else if (currentState == LOW && loggingEnabled) { - Serial.println("로깅 정지"); - loggingEnabled = false; - - flushBuffer(); - - if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - if (logFile) { - logFile.close(); - } - xSemaphoreGive(sdMutex); - } - - digitalWrite(LOGGING_STATUS_LED, LOW); - } - - lastLoggingState = currentState; - } - - vTaskDelay(pdMS_TO_TICKS(50)); - } -} - // SD 모니터 태스크 void sdMonitorTask(void *pvParameters) { Serial.println("SD 모니터 태스크 시작"); @@ -386,7 +380,6 @@ void sdMonitorTask(void *pvParameters) { if (cardPresent != sdCardReady) { sdCardReady = cardPresent; - digitalWrite(SD_READY_LED, sdCardReady ? HIGH : LOW); if (sdCardReady) { Serial.println("SD 카드 준비됨"); @@ -394,8 +387,7 @@ void sdMonitorTask(void *pvParameters) { } else { Serial.println("SD 카드 없음"); if (loggingEnabled) { - loggingEnabled = false; - digitalWrite(LOGGING_STATUS_LED, LOW); + stopLogging(); } } } @@ -565,6 +557,12 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length else if (msg.indexOf("\"cmd\":\"getFiles\"") >= 0) { sendFileList(num); } + else if (msg.indexOf("\"cmd\":\"startLogging\"") >= 0) { + startLogging(); + } + else if (msg.indexOf("\"cmd\":\"stopLogging\"") >= 0) { + stopLogging(); + } else if (msg.indexOf("\"cmd\":\"sendCan\"") >= 0) { handleCanTransmit(msg); } @@ -700,14 +698,8 @@ void setup() { memset(recentData, 0, sizeof(recentData)); memset(txMessages, 0, sizeof(txMessages)); - pinMode(LOGGING_CONTROL_PIN, INPUT); - pinMode(LOGGING_STATUS_LED, OUTPUT); - pinMode(SD_READY_LED, OUTPUT); pinMode(CAN_INT_PIN, INPUT_PULLUP); - digitalWrite(LOGGING_STATUS_LED, LOW); - digitalWrite(SD_READY_LED, LOW); - hspi.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS); vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_CS); @@ -718,7 +710,6 @@ void setup() { if (SD.begin(VSPI_CS, vspi)) { sdCardReady = true; - digitalWrite(SD_READY_LED, HIGH); Serial.println("✓ SD 카드 초기화 완료"); scanExistingFiles(); } else { @@ -744,7 +735,6 @@ void setup() { server.send_P(200, "text/html", graph_html); }); - // ⭐ 새로 추가: 그래프 뷰어 페이지 server.on("/graph-view", HTTP_GET, []() { server.send_P(200, "text/html", graph_viewer_html); }); @@ -756,15 +746,12 @@ void setup() { if (SD.exists(filename)) { File file = SD.open(filename, FILE_READ); if (file) { - // 파일명만 추출 (경로 제거) String displayName = server.arg("file"); - // Content-Disposition 헤더 추가 (원본 파일명 지정) server.sendHeader("Content-Disposition", "attachment; filename=\"" + displayName + "\""); server.sendHeader("Content-Type", "application/octet-stream"); - // 파일 전송 server.streamFile(file, "application/octet-stream"); file.close(); } else { @@ -791,7 +778,6 @@ void setup() { xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 4096, NULL, 4, &canRxTaskHandle, 1); xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 12288, NULL, 3, &sdWriteTaskHandle, 1); - xTaskCreatePinnedToCore(controlTask, "CONTROL", 8192, NULL, 2, &controlTaskHandle, 0); xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 4096, NULL, 1, NULL, 0); xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 8192, NULL, 2, &webTaskHandle, 0); diff --git a/index.h b/index.h index 8216b6d..7bb598b 100644 --- a/index.h +++ b/index.h @@ -241,6 +241,8 @@ const char index_html[] PROGMEM = R"rawliteral(
+ +
@@ -518,6 +520,20 @@ const char index_html[] PROGMEM = R"rawliteral( console.log('CAN speed set to:', speedName); } + function startLogging() { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({cmd: 'startLogging'})); + console.log('Start logging command sent'); + } + } + + function stopLogging() { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({cmd: 'stopLogging'})); + console.log('Stop logging command sent'); + } + } + function refreshFiles() { if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({cmd: 'getFiles'}));