diff --git a/ESP32_CAN_Logger-a.ino b/ESP32_CAN_Logger-a.ino index 4c5ad73..43efb6f 100644 --- a/ESP32_CAN_Logger-a.ino +++ b/ESP32_CAN_Logger-a.ino @@ -688,8 +688,8 @@ void applySerialSettings() { else config = SERIAL_8O1; } if (serialSettings.stopBits == 2) config |= 0x3000; + SerialComm.setRxBufferSize(2048); // ★ begin() 전에 호출 필수 (ESP32) SerialComm.begin(serialSettings.baudRate, config, SERIAL_RX_PIN, SERIAL_TX_PIN); - SerialComm.setRxBufferSize(2048); uint32_t config2 = SERIAL_8N1; if (serial2Settings.dataBits == 5) { @@ -710,8 +710,8 @@ void applySerialSettings() { else config2 = SERIAL_8O1; } if (serial2Settings.stopBits == 2) config2 |= 0x3000; + Serial2Comm.setRxBufferSize(2048); // ★ begin() 전에 호출 필수 (ESP32) Serial2Comm.begin(serial2Settings.baudRate, config2, SERIAL2_RX_PIN, SERIAL2_TX_PIN); - Serial2Comm.setRxBufferSize(2048); } // ======================================== @@ -1142,8 +1142,9 @@ void canRxTask(void *parameter) { // 읽기 완료 후 즉시 다음 폴링 (loop 재진입) } else { // INT HIGH, 플래그도 없음 → 타 태스크에 CPU 양보 - // ★ vTaskDelay 사용 금지: delay 중 HW 오버플로우 가능 - taskYIELD(); + // ★ vTaskDelay(1) 사용: taskYIELD()는 동일 우선순위에만 양보하므로 + // 하위 우선순위 태스크(Serial RX 등)가 CPU를 받을 수 없음 + vTaskDelay(pdMS_TO_TICKS(1)); } } } @@ -1618,6 +1619,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) DynamicJsonDocument doc(44384); if (deserializeJson(doc, payload)) return; const char* cmd = doc["cmd"]; + if (!cmd) return; // ★ cmd 없는 메시지 무시 (NULL strcmp 크래시 방지) if (strcmp(cmd, "getSettings") == 0) { DynamicJsonDocument r(1024); @@ -1765,6 +1767,14 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) serialSettings.stopBits = doc["stopBits"] | 1; saveSerialSettings(); applySerialSettings(); } + else if (strcmp(cmd, "setSerialBaud") == 0) { + // ★ JS applySettings()에서 전송하는 커맨드 지원 + serialSettings.baudRate = doc["baud"] | 115200; + saveSerialSettings(); applySerialSettings(); + char resp[128]; + snprintf(resp, sizeof(resp), "{\"type\":\"serialConfig\",\"baudRate\":%u}", serialSettings.baudRate); + webSocket.sendTXT(num, resp); + } else if (strcmp(cmd, "getSerialConfig") == 0) { DynamicJsonDocument r(512); r["type"]="serialConfig"; r["baudRate"]=serialSettings.baudRate; @@ -1836,6 +1846,14 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) serial2Settings.stopBits = doc["stopBits"] | 1; saveSerialSettings(); applySerialSettings(); } + else if (strcmp(cmd, "setSerial2Baud") == 0) { + // ★ JS applySettings()에서 전송하는 커맨드 지원 + serial2Settings.baudRate = doc["baud"] | 115200; + saveSerialSettings(); applySerialSettings(); + char resp[128]; + snprintf(resp, sizeof(resp), "{\"type\":\"serial2Config\",\"baudRate\":%u}", serial2Settings.baudRate); + webSocket.sendTXT(num, resp); + } else if (strcmp(cmd, "getSerial2Config") == 0) { DynamicJsonDocument r(512); r["type"]="serial2Config"; r["baudRate"]=serial2Settings.baudRate; @@ -2675,8 +2693,8 @@ void setup() { xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 4096, NULL, 1, NULL, 1); xTaskCreatePinnedToCore(sdFlushTask, "SD_FLUSH", 4096, NULL, 9, &sdFlushTaskHandle, 0); xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 18576, NULL, 8, &sdWriteTaskHandle, 0); - xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 6144, NULL, 6, &serialRxTaskHandle, 1); - xTaskCreatePinnedToCore(serial2RxTask, "SERIAL2_RX", 6144, NULL, 6, &serial2RxTaskHandle, 1); + xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 6144, NULL, 6, &serialRxTaskHandle, 0); + xTaskCreatePinnedToCore(serial2RxTask, "SERIAL2_RX", 6144, NULL, 6, &serial2RxTaskHandle, 0); if (timeSyncStatus.rtcAvailable) xTaskCreatePinnedToCore(rtcSyncTask,"RTC_SYNC", 3072, NULL, 0, &rtcTaskHandle, 0); // ★ canRxTask 마지막 생성 (Core 1 Pri 24 → 이 시점엔 setup() 완료 직전) @@ -2687,10 +2705,10 @@ void setup() { Serial.println("========================================"); Serial.println("Core 1:"); Serial.printf(" CAN_RX Pri 24 → canRing (SPSC push, no mutex)\n"); - Serial.printf(" WEB_UPDATE Pri 8 ← serialRing (SPSC pop, no mutex)\n"); Serial.printf(" TX/SEQ/MON Pri 3/2/1\n"); Serial.println("Core 0:"); Serial.printf(" SD_FLUSH Pri 9 (Double Buffer 비동기 flush)\n"); + Serial.printf(" WEB_UPDATE Pri 8 ← serialRing (SPSC pop, no mutex)\n"); Serial.printf(" SD_WRITE Pri 8 ← canRing (SPSC pop, BIN no mutex)\n"); Serial.printf(" SERIAL_RX Pri 6 → serialRing (SPSC push)\n"); Serial.printf(" SERIAL2_RX Pri 6 → serial2Ring(SPSC push)\n"); diff --git a/serial_terminal.h b/serial_terminal.h index c1bccdf..b17a83d 100644 --- a/serial_terminal.h +++ b/serial_terminal.h @@ -549,9 +549,12 @@ const char serial_terminal_html[] PROGMEM = R"rawliteral( } else if (data.type === 'serialStatus' || data.type === 'update') { updateStatus(data); } else if (data.type === 'pong') { - // keepalive } else if (data.type === 'usbMirrorState') { + // keepalive + } else if (data.type === 'usbMirrorState') { usbMirrorEnabled = data.enabled; updateToggle('btn-usbmirror', usbMirrorEnabled, '🔌 USB Mirror'); + } else if (data.type === 'webLog') { + showWebLog(data.msg); } } catch (e) { console.error('Parse error:', e);