CAN 은 이미 15비트 CRC 를 갖고 있다. 그런데 왜 또 하나?
CAN CRC 는 버스 구간만 보호한다
[송신 앱] → [송신 버퍼] → [컨트롤러] ══CRC══ [컨트롤러] → [수신 버퍼] → [수신 앱]
↑ ↑ ↑ ↑
여기서 깨지면 CAN CRC 가 못 잡는다 ─────────────────────────────────┘
메모리 손상, DMA 오설정, 버퍼 인덱스 버그, 신호 인코딩 실수 — 전부 CAN CRC 범위 밖이다. E2E 는 앱에서 앱까지를 보호한다.
네 필드가 각각 다른 고장을 잡는다
| 필드 | 잡는 것 |
|---|---|
crc | 데이터 손상 (버스 밖 구간 포함) |
seq_counter | 중복 · 역순 · 유실 |
| alive counter | 송신 태스크 정지 |
data_id | CAN ID 오배선 · 설정 실수 |
검사 결과는 bool 이 아니라 열거형이어야
typedef enum { E2E_OK, E2E_CRC_ERR, E2E_REPEATED, E2E_LOST,
E2E_STALE_ALIVE, E2E_WRONG_ID } e2e_result_t;
§6.5.3 이 오류 종류 구분을 요구하기 때문이다. E2E_CRC_ERR(전기적 문제)와 E2E_STALE_ALIVE(송신 노드 hang)는 사용자에게 다른 오류로 보여야 한다.
§6.2.5 를 진지하게 구현하려면 필요하다
"의도하지 않은 윈도우 구동이 발생하지 않아야 한다"를 만족시키려면 유령 명령을 걸러야 하고, 그 방어가 CRC · seq · age · heartbeat 네 겹이다. 하나만 빠져도 통과한다.