diff --git a/ESP32_CAN_Logger.ino b/ESP32_CAN_Logger.ino index ac6740a..9da4005 100644 --- a/ESP32_CAN_Logger.ino +++ b/ESP32_CAN_Logger.ino @@ -168,6 +168,9 @@ WebServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); Preferences preferences; +// Forward declaration +void IRAM_ATTR canISR(); + QueueHandle_t canQueue; SemaphoreHandle_t sdMutex; SemaphoreHandle_t rtcMutex; @@ -617,8 +620,11 @@ bool setMCP2515Mode(MCP2515Mode mode) { case MCP_MODE_NORMAL: result = mcp2515.setNormalMode(); if (result == MCP2515::ERROR_OK) { + // 인터럽트 재활성화 + attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING); currentMcpMode = MCP_MODE_NORMAL; Serial.println("✓ MCP2515 모드: NORMAL"); + Serial.println(" 송수신 모두 가능, ACK 전송"); return true; } break; @@ -626,8 +632,11 @@ bool setMCP2515Mode(MCP2515Mode mode) { case MCP_MODE_LISTEN_ONLY: result = mcp2515.setListenOnlyMode(); if (result == MCP2515::ERROR_OK) { + // 인터럽트 재활성화 + attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING); currentMcpMode = MCP_MODE_LISTEN_ONLY; Serial.println("✓ MCP2515 모드: LISTEN-ONLY"); + Serial.println(" 수신만 가능, ACK 전송 안 함"); return true; } break; @@ -635,21 +644,35 @@ bool setMCP2515Mode(MCP2515Mode mode) { case MCP_MODE_LOOPBACK: result = mcp2515.setLoopbackMode(); if (result == MCP2515::ERROR_OK) { + // 인터럽트 재활성화 + attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING); currentMcpMode = MCP_MODE_LOOPBACK; Serial.println("✓ MCP2515 모드: LOOPBACK"); + Serial.println(" 자가 테스트 모드"); return true; } break; case MCP_MODE_TRANSMIT: - // Transmit mode: Normal 모드와 동일하게 동작 - // (라이브러리 제약으로 인해 레지스터 직접 접근 불가) - // 송신 위주로 사용하되, 수신도 가능한 모드 - result = mcp2515.setNormalMode(); + // TRANSMIT 모드: Listen-Only 기반 + // 평상시에는 Listen-Only로 동작하여 ACK를 보내지 않음 + // 송신이 필요할 때만 일시적으로 Normal 모드로 전환 + result = mcp2515.setListenOnlyMode(); if (result == MCP2515::ERROR_OK) { + // 인터럽트는 비활성화 (수신 처리하지 않음) + detachInterrupt(digitalPinToInterrupt(CAN_INT_PIN)); + + // 수신 버퍼를 비움 + struct can_frame frame; + while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) { + // 버퍼만 비움 + } + currentMcpMode = MCP_MODE_TRANSMIT; - Serial.println("✓ MCP2515 모드: TRANSMIT (Normal mode base)"); - Serial.println(" ※ 송신 위주 사용, 수신 데이터는 로깅하지 않음"); + Serial.println("✓ MCP2515 모드: TRANSMIT-ONLY"); + Serial.println(" 기본: Listen-Only (ACK 안 함)"); + Serial.println(" 송신 시: 일시적으로 Normal 전환"); + Serial.println(" 수신 인터럽트: 비활성화"); return true; } break; @@ -659,6 +682,41 @@ bool setMCP2515Mode(MCP2515Mode mode) { return false; } +// ======================================== +// CAN 송신 헬퍼 함수 (TRANSMIT 모드 자동 처리) +// ======================================== + +MCP2515::ERROR sendCANMessage(struct can_frame* frame) { + MCP2515::ERROR result; + + // TRANSMIT 모드일 때만 특별 처리 + if (currentMcpMode == MCP_MODE_TRANSMIT) { + // 1. 일시적으로 Normal 모드로 전환 + result = mcp2515.setNormalMode(); + if (result != MCP2515::ERROR_OK) { + Serial.println("✗ TRANSMIT 모드: Normal 전환 실패"); + return result; + } + + // 2. 메시지 송신 + result = mcp2515.sendMessage(frame); + + // 3. 즉시 Listen-Only 모드로 복귀 + mcp2515.setListenOnlyMode(); + + // 4. 수신 버퍼 비우기 (전환 중 수신된 데이터) + struct can_frame dummy; + while (mcp2515.readMessage(&dummy) == MCP2515::ERROR_OK) { + // 버퍼만 비움 + } + + return result; + } else { + // 다른 모드에서는 바로 송신 + return mcp2515.sendMessage(frame); + } +} + // ======================================== // CAN 인터럽트 및 수신 함수 // ======================================== @@ -678,15 +736,6 @@ void canRxTask(void* parameter) { for (;;) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - // Transmit 모드일 때는 수신 데이터를 처리하지 않음 - if (currentMcpMode == MCP_MODE_TRANSMIT) { - // MCP2515 버퍼만 비우고 처리는 건너뜀 - while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) { - // 버퍼만 비움 - } - continue; - } - // 한 번에 여러 메시지를 읽어서 처리 속도 향상 int readCount = 0; while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK && readCount < 20) { @@ -897,7 +946,7 @@ void txTask(void* parameter) { frame.can_dlc = txMessages[i].dlc; memcpy(frame.data, txMessages[i].data, 8); - if (mcp2515.sendMessage(&frame) == MCP2515::ERROR_OK) { + if (sendCANMessage(&frame) == MCP2515::ERROR_OK) { txMessages[i].lastSent = now; totalTxCount++; } @@ -934,7 +983,7 @@ void sequenceTask(void* parameter) { frame.can_dlc = step->dlc; memcpy(frame.data, step->data, 8); - MCP2515::ERROR result = mcp2515.sendMessage(&frame); + MCP2515::ERROR result = sendCANMessage(&frame); if (result == MCP2515::ERROR_OK) { totalTxCount++; Serial.printf(" [Seq] Step %d/%d: ID=0x%X, DLC=%d, Delay=%dms - OK\n", @@ -1118,7 +1167,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) int mode = message.substring(modeStart, modeEnd).toInt(); - if (mode >= 0 && mode <= 2) { + if (mode >= 0 && mode <= 3) { // 0~3으로 확장 (TRANSMIT 모드 포함) setMCP2515Mode((MCP2515Mode)mode); } diff --git a/index.h b/index.h index 05d27f6..7da59dd 100644 --- a/index.h +++ b/index.h @@ -701,10 +701,10 @@ const char index_html[] PROGMEM = R"rawliteral(