transmit 모드 변경

listen-only모드에서 송신 시에만 normal 모드
This commit is contained in:
2025-11-09 11:55:07 +00:00
parent 94e5817678
commit 01810e0ff4
2 changed files with 72 additions and 23 deletions

View File

@@ -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);
}

10
index.h
View File

@@ -701,10 +701,10 @@ const char index_html[] PROGMEM = R"rawliteral(
<div class="control-row">
<label for="mcp-mode">MCP2515 Mode:</label>
<select id="mcp-mode">
<option value="0" selected>Normal</option>
<option value="1">Listen-Only</option>
<option value="2">Loopback</option>
<option value="3">Transmit (TX Focus)</option>
<option value="0" selected>Normal (TX/RX + ACK)</option>
<option value="1">Listen-Only (RX only, no ACK)</option>
<option value="2">Loopback (Self-test)</option>
<option value="3">Transmit Only (no ACK, auto mode switch)</option>
</select>
<button onclick="setMcpMode()">Apply</button>
<span id="mode-status" style="color: #11998e; font-size: 0.85em; font-weight: 600;"></span>
@@ -768,7 +768,7 @@ const char index_html[] PROGMEM = R"rawliteral(
let messageOrder = [];
let lastMessageData = {};
const speedNames = {0: '125K', 1: '250K', 2: '500K', 3: '1M'};
const modeNames = {0: 'NORMAL', 1: 'LISTEN-ONLY', 2: 'LOOPBACK', 3: 'TRANSMIT'};
const modeNames = {0: 'NORMAL (TX/RX+ACK)', 1: 'LISTEN-ONLY (RX)', 2: 'LOOPBACK', 3: 'TRANSMIT-ONLY (TX)'};
let currentLoggingFile = '';
let commentingFile = '';
let hasInitialSync = false; // 초기 동기화 완료 여부