3-1
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Byun CAN Logger with Web Interface + RTC Time Synchronization
|
||||
* Version: 2.0
|
||||
* Added: Phone time sync to RTC, File comments, MCP2515 mode control
|
||||
* Version: 3.0
|
||||
* Added: Phone time sync to RTC, File comments, MCP2515 mode control, Serial Terminal
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
@@ -25,10 +25,15 @@
|
||||
#include "graph.h"
|
||||
#include "graph_viewer.h"
|
||||
#include "settings.h"
|
||||
#include "serial_terminal.h"
|
||||
|
||||
// GPIO 핀 정의
|
||||
#define CAN_INT_PIN 27
|
||||
|
||||
// Serial2 핀 정의 (RS232 통신용)
|
||||
#define SERIAL_RX_PIN 16
|
||||
#define SERIAL_TX_PIN 17
|
||||
|
||||
// HSPI 핀 (CAN)
|
||||
#define HSPI_MISO 12
|
||||
#define HSPI_MOSI 13
|
||||
@@ -54,6 +59,11 @@
|
||||
#define MAX_TX_MESSAGES 20
|
||||
#define MAX_COMMENT_LEN 128
|
||||
|
||||
// Serial 버퍼 설정
|
||||
#define SERIAL_RX_BUFFER_SIZE 4096
|
||||
#define SERIAL_TX_QUEUE_SIZE 100
|
||||
#define SERIAL_LOG_BUFFER_SIZE 8192
|
||||
|
||||
// RTC 동기화 설정
|
||||
#define RTC_SYNC_INTERVAL_MS 60000 // 1분마다 RTC와 동기화
|
||||
|
||||
@@ -138,6 +148,40 @@ struct PowerStatus {
|
||||
uint32_t lastMinReset; // 최소값 리셋 시간
|
||||
} powerStatus = {0.0, 999.9, false, 0, 0};
|
||||
|
||||
// ========================================
|
||||
// Serial 통신 관련 구조체
|
||||
// ========================================
|
||||
|
||||
// Serial 설정 구조체
|
||||
struct SerialConfig {
|
||||
uint32_t baudRate;
|
||||
uint8_t dataBits; // 5, 6, 7, 8
|
||||
uint8_t parity; // 0=None, 1=Even, 2=Odd
|
||||
uint8_t stopBits; // 1, 2
|
||||
bool flowControl; // RTS/CTS
|
||||
} serialConfig = {115200, 8, 0, 1, false};
|
||||
|
||||
// Serial 데이터 구조체 (로깅용)
|
||||
struct SerialLogData {
|
||||
uint64_t timestamp_us;
|
||||
bool isTx; // true=송신, false=수신
|
||||
uint16_t length;
|
||||
uint8_t data[256];
|
||||
} __attribute__((packed));
|
||||
|
||||
// Serial 상태
|
||||
struct SerialStatus {
|
||||
bool logging;
|
||||
uint32_t rxCount;
|
||||
uint32_t txCount;
|
||||
uint32_t rxBytesPerSec;
|
||||
uint32_t txBytesPerSec;
|
||||
uint32_t lastRxBytes;
|
||||
uint32_t lastTxBytes;
|
||||
uint32_t lastStatTime;
|
||||
} serialStatus = {false, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
|
||||
// MCP2515 레지스터 주소 정의 (라이브러리에 없는 경우)
|
||||
#ifndef MCP_CANCTRL
|
||||
#define MCP_CANCTRL 0x0F
|
||||
@@ -171,18 +215,27 @@ MCP2515 mcp2515(HSPI_CS, 20000000, &hspi); // 20MHz로 증가 (10MHz → 20MHz)
|
||||
|
||||
WebServer server(80);
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
WebSocketsServer serialWebSocket = WebSocketsServer(82);
|
||||
Preferences preferences;
|
||||
|
||||
// Forward declaration
|
||||
void IRAM_ATTR canISR();
|
||||
void serialWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length);
|
||||
|
||||
QueueHandle_t canQueue;
|
||||
QueueHandle_t serialTxQueue;
|
||||
QueueHandle_t serialLogQueue;
|
||||
SemaphoreHandle_t sdMutex;
|
||||
SemaphoreHandle_t rtcMutex;
|
||||
SemaphoreHandle_t serialMutex;
|
||||
TaskHandle_t canRxTaskHandle = NULL;
|
||||
TaskHandle_t sdWriteTaskHandle = NULL;
|
||||
TaskHandle_t webTaskHandle = NULL;
|
||||
TaskHandle_t rtcTaskHandle = NULL;
|
||||
TaskHandle_t serialRxTaskHandle = NULL;
|
||||
TaskHandle_t serialTxTaskHandle = NULL;
|
||||
TaskHandle_t serialLogTaskHandle = NULL;
|
||||
TaskHandle_t serialWebTaskHandle = NULL;
|
||||
|
||||
volatile bool loggingEnabled = false;
|
||||
volatile bool sdCardReady = false;
|
||||
@@ -231,6 +284,378 @@ SequenceRuntime seqRuntime = {false, 0, 0, 0, -1};
|
||||
FileComment fileComments[MAX_FILE_COMMENTS];
|
||||
int commentCount = 0;
|
||||
|
||||
// Serial 로그 파일
|
||||
File serialLogFile;
|
||||
char currentSerialFilename[MAX_FILENAME_LEN];
|
||||
uint8_t serialLogBuffer[SERIAL_LOG_BUFFER_SIZE];
|
||||
uint16_t serialLogBufferIndex = 0;
|
||||
volatile uint32_t currentSerialFileSize = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
// ========================================
|
||||
// Serial 설정 저장/로드 함수
|
||||
// ========================================
|
||||
|
||||
void saveSerialSettings() {
|
||||
preferences.begin("serial-cfg", false);
|
||||
preferences.putUInt("baudrate", serialConfig.baudRate);
|
||||
preferences.putUChar("databits", serialConfig.dataBits);
|
||||
preferences.putUChar("parity", serialConfig.parity);
|
||||
preferences.putUChar("stopbits", serialConfig.stopBits);
|
||||
preferences.putBool("flowctrl", serialConfig.flowControl);
|
||||
preferences.end();
|
||||
Serial.println("✓ Serial 설정 저장 완료");
|
||||
}
|
||||
|
||||
void loadSerialSettings() {
|
||||
preferences.begin("serial-cfg", true);
|
||||
serialConfig.baudRate = preferences.getUInt("baudrate", 115200);
|
||||
serialConfig.dataBits = preferences.getUChar("databits", 8);
|
||||
serialConfig.parity = preferences.getUChar("parity", 0);
|
||||
serialConfig.stopBits = preferences.getUChar("stopbits", 1);
|
||||
serialConfig.flowControl = preferences.getBool("flowctrl", false);
|
||||
preferences.end();
|
||||
|
||||
Serial.printf("✓ Serial 설정 로드: %u bps, %dN%d\n",
|
||||
serialConfig.baudRate, serialConfig.dataBits, serialConfig.stopBits);
|
||||
}
|
||||
|
||||
void applySerialConfig() {
|
||||
Serial2.end();
|
||||
|
||||
uint32_t config = SERIAL_8N1;
|
||||
|
||||
if (serialConfig.dataBits == 5) config = SERIAL_5N1;
|
||||
else if (serialConfig.dataBits == 6) config = SERIAL_6N1;
|
||||
else if (serialConfig.dataBits == 7) config = SERIAL_7N1;
|
||||
else config = SERIAL_8N1;
|
||||
|
||||
if (serialConfig.parity == 1) {
|
||||
if (serialConfig.dataBits == 5) config = SERIAL_5E1;
|
||||
else if (serialConfig.dataBits == 6) config = SERIAL_6E1;
|
||||
else if (serialConfig.dataBits == 7) config = SERIAL_7E1;
|
||||
else config = SERIAL_8E1;
|
||||
} else if (serialConfig.parity == 2) {
|
||||
if (serialConfig.dataBits == 5) config = SERIAL_5O1;
|
||||
else if (serialConfig.dataBits == 6) config = SERIAL_6O1;
|
||||
else if (serialConfig.dataBits == 7) config = SERIAL_7O1;
|
||||
else config = SERIAL_8O1;
|
||||
}
|
||||
|
||||
if (serialConfig.stopBits == 2) {
|
||||
config |= 0x3000;
|
||||
}
|
||||
|
||||
Serial2.begin(serialConfig.baudRate, config, SERIAL_RX_PIN, SERIAL_TX_PIN);
|
||||
Serial2.setRxBufferSize(SERIAL_RX_BUFFER_SIZE);
|
||||
|
||||
Serial.printf("✓ Serial2 재구성: %u bps\n", serialConfig.baudRate);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Serial 로깅 함수
|
||||
// ========================================
|
||||
|
||||
void flushSerialLogBuffer() {
|
||||
if (serialLogBufferIndex > 0 && serialLogFile) {
|
||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||
serialLogFile.write(serialLogBuffer, serialLogBufferIndex);
|
||||
currentSerialFileSize += serialLogBufferIndex;
|
||||
serialLogBufferIndex = 0;
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startSerialLogging() {
|
||||
if (!sdCardReady) {
|
||||
Serial.println("✗ SD 카드 없음 - Serial 로깅 불가");
|
||||
return;
|
||||
}
|
||||
|
||||
if (serialStatus.logging) {
|
||||
Serial.println("⚠ Serial 로깅이 이미 실행 중입니다");
|
||||
return;
|
||||
}
|
||||
|
||||
struct tm timeinfo;
|
||||
if (!getLocalTime(&timeinfo)) {
|
||||
sprintf(currentSerialFilename, "/SERIAL_%lu.log", millis());
|
||||
} else {
|
||||
sprintf(currentSerialFilename, "/SERIAL_%04d%02d%02d_%02d%02d%02d.log",
|
||||
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
}
|
||||
|
||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
serialLogFile = SD.open(currentSerialFilename, FILE_WRITE);
|
||||
if (serialLogFile) {
|
||||
serialStatus.logging = true;
|
||||
currentSerialFileSize = 0;
|
||||
serialLogBufferIndex = 0;
|
||||
|
||||
char header[256];
|
||||
snprintf(header, sizeof(header),
|
||||
"Serial Log - BaudRate: %u, DataBits: %d, Parity: %d, StopBits: %d\n",
|
||||
serialConfig.baudRate, serialConfig.dataBits,
|
||||
serialConfig.parity, serialConfig.stopBits);
|
||||
serialLogFile.print(header);
|
||||
|
||||
Serial.printf("✓ Serial 로깅 시작: %s\n", currentSerialFilename);
|
||||
} else {
|
||||
Serial.println("✗ Serial 로그 파일 생성 실패");
|
||||
}
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void stopSerialLogging() {
|
||||
if (!serialStatus.logging) return;
|
||||
|
||||
serialStatus.logging = false;
|
||||
flushSerialLogBuffer();
|
||||
|
||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||
if (serialLogFile) {
|
||||
serialLogFile.close();
|
||||
Serial.printf("✓ Serial 로깅 종료: %s (크기: %u bytes)\n",
|
||||
currentSerialFilename, currentSerialFileSize);
|
||||
}
|
||||
xSemaphoreGive(sdMutex);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Serial Task 함수들
|
||||
// ========================================
|
||||
|
||||
void serialRxTask(void* parameter) {
|
||||
SerialLogData logData;
|
||||
uint8_t rxBuffer[256];
|
||||
|
||||
Serial.println("✓ Serial RX Task 시작");
|
||||
|
||||
while (true) {
|
||||
if (Serial2.available()) {
|
||||
int len = Serial2.readBytes(rxBuffer, sizeof(rxBuffer));
|
||||
|
||||
if (len > 0) {
|
||||
serialStatus.rxCount += len;
|
||||
|
||||
String hexStr = "";
|
||||
String asciiStr = "";
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char hexBuf[4];
|
||||
sprintf(hexBuf, "%02X ", rxBuffer[i]);
|
||||
hexStr += hexBuf;
|
||||
|
||||
if (rxBuffer[i] >= 32 && rxBuffer[i] < 127) {
|
||||
asciiStr += (char)rxBuffer[i];
|
||||
} else {
|
||||
asciiStr += '.';
|
||||
}
|
||||
}
|
||||
|
||||
String wsData = "RX:" + hexStr + "|" + asciiStr;
|
||||
serialWebSocket.broadcastTXT(wsData);
|
||||
|
||||
if (serialStatus.logging) {
|
||||
logData.timestamp_us = esp_timer_get_time();
|
||||
logData.isTx = false;
|
||||
logData.length = len;
|
||||
memcpy(logData.data, rxBuffer, len);
|
||||
|
||||
xQueueSend(serialLogQueue, &logData, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
}
|
||||
}
|
||||
|
||||
void serialTxTask(void* parameter) {
|
||||
uint8_t txData[256];
|
||||
int txLen;
|
||||
|
||||
Serial.println("✓ Serial TX Task 시작");
|
||||
|
||||
while (true) {
|
||||
if (xQueueReceive(serialTxQueue, txData, pdMS_TO_TICKS(100))) {
|
||||
txLen = txData[0];
|
||||
|
||||
if (txLen > 0 && txLen < 256) {
|
||||
Serial2.write(&txData[1], txLen);
|
||||
serialStatus.txCount += txLen;
|
||||
|
||||
if (serialStatus.logging) {
|
||||
SerialLogData logData;
|
||||
logData.timestamp_us = esp_timer_get_time();
|
||||
logData.isTx = true;
|
||||
logData.length = txLen;
|
||||
memcpy(logData.data, &txData[1], txLen);
|
||||
|
||||
xQueueSend(serialLogQueue, &logData, 0);
|
||||
}
|
||||
|
||||
String hexStr = "TX:";
|
||||
for (int i = 0; i < txLen; i++) {
|
||||
char hexBuf[4];
|
||||
sprintf(hexBuf, "%02X ", txData[i + 1]);
|
||||
hexStr += hexBuf;
|
||||
}
|
||||
serialWebSocket.broadcastTXT(hexStr);
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
|
||||
void serialLogTask(void* parameter) {
|
||||
SerialLogData logData;
|
||||
char logLine[512];
|
||||
|
||||
Serial.println("✓ Serial Log Task 시작");
|
||||
|
||||
while (true) {
|
||||
if (xQueueReceive(serialLogQueue, &logData, pdMS_TO_TICKS(100))) {
|
||||
if (serialStatus.logging && serialLogFile) {
|
||||
int offset = snprintf(logLine, sizeof(logLine),
|
||||
"[%llu] %s: ", logData.timestamp_us, logData.isTx ? "TX" : "RX");
|
||||
|
||||
for (int i = 0; i < logData.length && offset < sizeof(logLine) - 10; i++) {
|
||||
offset += snprintf(logLine + offset, sizeof(logLine) - offset,
|
||||
"%02X ", logData.data[i]);
|
||||
}
|
||||
|
||||
offset += snprintf(logLine + offset, sizeof(logLine) - offset, " | ");
|
||||
for (int i = 0; i < logData.length && offset < sizeof(logLine) - 5; i++) {
|
||||
if (logData.data[i] >= 32 && logData.data[i] < 127) {
|
||||
logLine[offset++] = logData.data[i];
|
||||
} else {
|
||||
logLine[offset++] = '.';
|
||||
}
|
||||
}
|
||||
logLine[offset++] = '\n';
|
||||
logLine[offset] = '\0';
|
||||
|
||||
int lineLen = strlen(logLine);
|
||||
if (serialLogBufferIndex + lineLen >= SERIAL_LOG_BUFFER_SIZE) {
|
||||
flushSerialLogBuffer();
|
||||
}
|
||||
|
||||
memcpy(&serialLogBuffer[serialLogBufferIndex], logLine, lineLen);
|
||||
serialLogBufferIndex += lineLen;
|
||||
}
|
||||
} else {
|
||||
if (serialLogBufferIndex > 0) {
|
||||
flushSerialLogBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
void serialWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
|
||||
if (type == WStype_TEXT) {
|
||||
String msg = String((char*)payload);
|
||||
|
||||
if (msg.startsWith("CONFIG:")) {
|
||||
int idx2 = msg.indexOf(',');
|
||||
int idx3 = msg.indexOf(',', idx2 + 1);
|
||||
int idx4 = msg.indexOf(',', idx3 + 1);
|
||||
|
||||
serialConfig.baudRate = msg.substring(7, idx2).toInt();
|
||||
serialConfig.dataBits = msg.substring(idx2 + 1, idx3).toInt();
|
||||
serialConfig.parity = msg.substring(idx3 + 1, idx4).toInt();
|
||||
serialConfig.stopBits = msg.substring(idx4 + 1).toInt();
|
||||
|
||||
applySerialConfig();
|
||||
saveSerialSettings();
|
||||
|
||||
serialWebSocket.sendTXT(num, "CONFIG_OK");
|
||||
|
||||
} else if (msg == "START_LOG") {
|
||||
startSerialLogging();
|
||||
serialWebSocket.sendTXT(num, serialStatus.logging ? "LOG_STARTED" : "LOG_FAILED");
|
||||
|
||||
} else if (msg == "STOP_LOG") {
|
||||
stopSerialLogging();
|
||||
serialWebSocket.sendTXT(num, "LOG_STOPPED");
|
||||
|
||||
} else if (msg == "GET_CONFIG") {
|
||||
char cfgStr[128];
|
||||
snprintf(cfgStr, sizeof(cfgStr), "CFG:%u,%d,%d,%d,%d",
|
||||
serialConfig.baudRate, serialConfig.dataBits, serialConfig.parity,
|
||||
serialConfig.stopBits, serialConfig.flowControl ? 1 : 0);
|
||||
serialWebSocket.sendTXT(num, cfgStr);
|
||||
|
||||
} else if (msg == "GET_STATUS") {
|
||||
char statStr[256];
|
||||
snprintf(statStr, sizeof(statStr), "STAT:%d,%u,%u,%u,%u,%s",
|
||||
serialStatus.logging ? 1 : 0,
|
||||
serialStatus.rxCount, serialStatus.txCount,
|
||||
serialStatus.rxBytesPerSec, serialStatus.txBytesPerSec,
|
||||
currentSerialFilename);
|
||||
serialWebSocket.sendTXT(num, statStr);
|
||||
|
||||
} else if (msg.startsWith("TX:")) {
|
||||
String hexData = msg.substring(3);
|
||||
hexData.trim();
|
||||
|
||||
uint8_t txBuffer[256];
|
||||
int txLen = 0;
|
||||
|
||||
for (int i = 0; i < hexData.length() && txLen < 255; i += 2) {
|
||||
if (i + 1 < hexData.length()) {
|
||||
String hexByte = hexData.substring(i, i + 2);
|
||||
txBuffer[txLen + 1] = (uint8_t)strtol(hexByte.c_str(), NULL, 16);
|
||||
txLen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (txLen > 0) {
|
||||
txBuffer[0] = txLen;
|
||||
xQueueSend(serialTxQueue, txBuffer, 0);
|
||||
}
|
||||
} else if (msg.startsWith("TXT:")) {
|
||||
String text = msg.substring(4);
|
||||
uint8_t txBuffer[256];
|
||||
int txLen = text.length();
|
||||
|
||||
if (txLen > 0 && txLen < 255) {
|
||||
txBuffer[0] = txLen;
|
||||
memcpy(&txBuffer[1], text.c_str(), txLen);
|
||||
xQueueSend(serialTxQueue, txBuffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serialWebUpdateTask(void* parameter) {
|
||||
Serial.println("✓ Serial Web Update Task 시작");
|
||||
|
||||
while (true) {
|
||||
serialWebSocket.loop();
|
||||
|
||||
uint32_t now = millis();
|
||||
if (now - serialStatus.lastStatTime >= 1000) {
|
||||
serialStatus.rxBytesPerSec = serialStatus.rxCount - serialStatus.lastRxBytes;
|
||||
serialStatus.txBytesPerSec = serialStatus.txCount - serialStatus.lastTxBytes;
|
||||
serialStatus.lastRxBytes = serialStatus.rxCount;
|
||||
serialStatus.lastTxBytes = serialStatus.txCount;
|
||||
serialStatus.lastStatTime = now;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 설정 저장/로드 함수
|
||||
// ========================================
|
||||
@@ -1633,6 +2058,7 @@ void setup() {
|
||||
|
||||
// 설정 로드
|
||||
loadSettings();
|
||||
loadSerialSettings();
|
||||
|
||||
// 설정값 표시
|
||||
Serial.println("\n📋 현재 설정값:");
|
||||
@@ -1648,6 +2074,10 @@ void setup() {
|
||||
|
||||
pinMode(CAN_INT_PIN, INPUT_PULLUP);
|
||||
|
||||
// Serial2 초기화
|
||||
applySerialConfig();
|
||||
Serial.println("✓ Serial2 초기화 완료");
|
||||
|
||||
// ADC 설정 (전압 모니터링용)
|
||||
analogSetAttenuation(ADC_11db); // 0-3.3V 범위
|
||||
|
||||
@@ -1669,8 +2099,9 @@ void setup() {
|
||||
// Mutex 생성 (다른 초기화보다 먼저!)
|
||||
sdMutex = xSemaphoreCreateMutex();
|
||||
rtcMutex = xSemaphoreCreateMutex();
|
||||
serialMutex = xSemaphoreCreateMutex();
|
||||
|
||||
if (sdMutex == NULL || rtcMutex == NULL) {
|
||||
if (sdMutex == NULL || rtcMutex == NULL || serialMutex == NULL) {
|
||||
Serial.println("✗ Mutex 생성 실패!");
|
||||
while (1) delay(1000);
|
||||
}
|
||||
@@ -1747,6 +2178,11 @@ void setup() {
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
// Serial WebSocket 시작
|
||||
serialWebSocket.begin();
|
||||
serialWebSocket.onEvent(serialWebSocketEvent);
|
||||
Serial.println("✓ Serial WebSocket 시작 (포트 82)");
|
||||
|
||||
// 웹 서버 라우팅
|
||||
server.on("/", HTTP_GET, []() {
|
||||
server.send_P(200, "text/html", index_html);
|
||||
@@ -1768,6 +2204,10 @@ void setup() {
|
||||
server.send_P(200, "text/html", settings_html);
|
||||
});
|
||||
|
||||
server.on("/serial", HTTP_GET, []() {
|
||||
server.send_P(200, "text/html", serial_terminal_html);
|
||||
});
|
||||
|
||||
server.on("/download", HTTP_GET, []() {
|
||||
if (server.hasArg("file")) {
|
||||
String filename = "/" + server.arg("file");
|
||||
@@ -1838,11 +2278,14 @@ void setup() {
|
||||
|
||||
// Queue 생성
|
||||
canQueue = xQueueCreate(CAN_QUEUE_SIZE, sizeof(CANMessage));
|
||||
serialTxQueue = xQueueCreate(SERIAL_TX_QUEUE_SIZE, 256);
|
||||
serialLogQueue = xQueueCreate(200, sizeof(SerialLogData));
|
||||
|
||||
if (canQueue == NULL) {
|
||||
if (canQueue == NULL || serialTxQueue == NULL || serialLogQueue == NULL) {
|
||||
Serial.println("✗ Queue 생성 실패!");
|
||||
while (1) delay(1000);
|
||||
}
|
||||
Serial.println("✓ Serial Queue 생성 완료");
|
||||
|
||||
// CAN 인터럽트 활성화
|
||||
attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING);
|
||||
@@ -1855,6 +2298,13 @@ void setup() {
|
||||
xTaskCreatePinnedToCore(txTask, "TX_TASK", 4096, NULL, 2, NULL, 1);
|
||||
xTaskCreatePinnedToCore(sequenceTask, "SEQ_TASK", 4096, NULL, 2, NULL, 1); // 시퀀스 Task 추가
|
||||
|
||||
// Serial Task 생성
|
||||
xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 4096, NULL, 4, &serialRxTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(serialTxTask, "SERIAL_TX", 4096, NULL, 3, &serialTxTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(serialLogTask, "SERIAL_LOG", 8192, NULL, 2, &serialLogTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(serialWebUpdateTask, "SERIAL_WEB", 4096, NULL, 2, &serialWebTaskHandle, 0);
|
||||
Serial.println("✓ Serial Task 시작 완료");
|
||||
|
||||
// RTC 동기화 Task
|
||||
if (timeSyncStatus.rtcAvailable) {
|
||||
xTaskCreatePinnedToCore(rtcSyncTask, "RTC_SYNC", 4096, NULL, 0, &rtcTaskHandle, 0);
|
||||
@@ -1879,6 +2329,7 @@ void setup() {
|
||||
Serial.println(" - Transmit : /transmit");
|
||||
Serial.println(" - Graph : /graph");
|
||||
Serial.println(" - Settings : /settings");
|
||||
Serial.println(" - Serial : /serial");
|
||||
Serial.println("========================================\n");
|
||||
}
|
||||
|
||||
@@ -1888,18 +2339,15 @@ void loop() {
|
||||
|
||||
static uint32_t lastPrint = 0;
|
||||
if (millis() - lastPrint > 10000) {
|
||||
Serial.printf("[상태] 큐: %d/%d | 로깅: %s | SD: %s | RX: %lu | TX: %lu | 파일크기: %u | 시간: %s | RTC: %s(%u) | 전압: %.2fV%s | 모드: %d\n",
|
||||
Serial.printf("[상태] CAN큐: %d/%d | CAN: %s | Serial: RX=%u TX=%u LOG=%s | SD: %s | 시간: %s | 전압: %.2fV%s\n",
|
||||
uxQueueMessagesWaiting(canQueue), CAN_QUEUE_SIZE,
|
||||
loggingEnabled ? "ON " : "OFF",
|
||||
serialStatus.rxCount, serialStatus.txCount,
|
||||
serialStatus.logging ? "ON" : "OFF",
|
||||
sdCardReady ? "OK" : "NO",
|
||||
totalMsgCount, totalTxCount,
|
||||
currentFileSize,
|
||||
timeSyncStatus.synchronized ? "OK" : "NO",
|
||||
timeSyncStatus.rtcAvailable ? "OK" : "NO",
|
||||
timeSyncStatus.rtcSyncCount,
|
||||
powerStatus.voltage,
|
||||
powerStatus.lowVoltage ? " ⚠️" : "",
|
||||
currentMcpMode);
|
||||
powerStatus.lowVoltage ? " ⚠️" : "");
|
||||
lastPrint = millis();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user