big refactoring: J1939, log output, state machine bug fixes

This commit is contained in:
2026-05-07 22:12:13 +03:00
parent 137c9d3c8d
commit 7a74ef1367
49 changed files with 2574 additions and 684 deletions
+180
View File
@@ -0,0 +1,180 @@
# GB/T + J1939 Debug Flow (CAN ExtId)
Документ для ручного дебага обмена EV <-> EVSE по CAN (J1939 TP + short PGN).
## 1) Базовая структура CAN Extended ID (29-bit)
В проекте используется формула:
- `ExtId = (priority << 26) | (PGN << 8) | (SA << 8) | DA`
Где:
- `priority` — обычно `6` или `7`
- `PGN` — Parameter Group Number
- `SA` — Source Address
- `DA` — Destination Address
Адреса в ваших прошивках:
- `EVSE (SE)` = `0x56`
- `EV` = `0xF4`
Примеры:
- `0x181056F4` -> short PGN `0x1000` (BCL), `SA=0x56`, `DA=0xF4`
- `0x1CEC56F4` -> TP.CM от `0x56` к `0xF4`
- `0x1CECF456` -> TP.CM от `0xF4` к `0x56`
- `0x1CEB56F4` -> TP.DT от `0x56` к `0xF4`
## 2) Какие PGN short, какие TP
Short (<=8 байт, один CAN кадр):
- `0x0900` BRO
- `0x0A00` CRO
- `0x1000` BCL (5 байт)
- `0x1200` CCS
- `0x1300` BSM (7 байт)
- `0x1A00` CST
Через TP (>8 байт):
- `0x0200` BRM (49 байт)
- `0x0600` BCP (13 байт)
- `0x1100` BCS (9 байт)
## 3) Нормальная последовательность (высокоуровнево)
1. Handshake/recognition:
- CHM/CRM/BRM/BCP/CML/BRO/CRO
2. Переход в заряд:
- EVSE `S8 -> S9`
- EV начинает слать BCL/BSM/BCS
- EVSE принимает BCL и переходит `S9 -> S10`
3. Во время зарядки:
- EV регулярно шлет:
- BCL (short)
- BSM (short)
- BCS (TP, `PGN=0x1100`)
- EVSE регулярно шлет CCS
## 4) Нормальная TP-сессия для BCS (`PGN=0x1100`, size=9, packets=2)
### Шаг 1: RTS (originator -> responder)
ID:
- от EV к EVSE: `1CEC F4 56` (`0x1CECF456`)
Data (TP.CM_RTS):
- `byte0 = 0x10` (RTS)
- `byte1..2 = total_size` (LSB/MSB), для BCS: `0x09 0x00`
- `byte3 = total_packets`, для BCS: `0x02`
- `byte4 = max_packets_per_CTS` (часто `0x02`)
- `byte5..7 = PGN` в little-endian (`00 11 00` для `0x1100`)
### Шаг 2: CTS (responder -> originator)
ID:
- от EVSE к EV: `1CEC 56 F4` (`0x1CEC56F4`)
Data (TP.CM_CTS):
- `byte0 = 0x11` (CTS)
- `byte1 = allowed_packet_count`
- `byte2 = next_packet_number` (обычно `1` для новой сессии)
- `byte3..4 = 0xFF`
- `byte5..7 = PGN` (`00 11 00`)
### Шаг 3: DT (originator -> responder)
ID:
- `1CEB F4 56` (EV -> EVSE)
Data (TP.DT):
- `byte0 = seq` (`1`, потом `2`)
- `byte1..7 = payload chunk`
Для 9 байт:
- DT#1 несет первые 7 байт
- DT#2 несет оставшиеся 2 байта + заполнение `0xFF`
### Шаг 4: ACK (responder -> originator)
ID:
- `1CEC 56 F4` (EVSE -> EV)
Data (TP.CM_EndOfMsgACK):
- `byte0 = 0x13` (ACK)
- `byte1..2 = total_size` (`09 00`)
- `byte3 = total_packets` (`02`)
- `byte4 = 0xFF`
- `byte5..7 = PGN` (`00 11 00`)
## 5) Как понять по логу, что сессия "правильная"
Для каждого `RTS(0x1100)` должен быть полный шаблон:
- `RTS` -> `CTS` -> `DT #1` -> `DT #2` -> `ACK`
Если есть `RTS`, но нет `CTS`:
- проблема на стороне responder (EVSE) TX/фильтр/перегрузка
Если есть `CTS`, но нет `DT`:
- проблема на стороне originator (EV) RX/парсинг/состояние
Если есть `DT`, но нет `ACK`:
- проблема на стороне responder reassembly/timeout
## 6) Поля основных GB/T пакетов (payload)
### BCL (`PGN 0x1000`, short, 5 bytes)
Структура:
- `requestedVoltage` (`uint16`, 0.1V/bit)
- `requestedCurrent` (`uint16`, 0.1A/bit, в вашем коде может интерпретироваться как `4000 - value`)
- `chargingMode` (`uint8`, `0x01` CV, `0x02` CC)
### BCS (`PGN 0x1100`, TP, 9 bytes)
Структура:
- `measuredChargingVoltage` (`uint16`)
- `measuredChargingCurrent` (`uint16`)
- `highestVoltageOfBatteryCell` (`uint16`)
- `currentChargeState` (`uint8`)
- `estimatedRemainingChargingTime` (`uint16`)
### BSM (`PGN 0x1300`, short, 7 bytes)
Структура:
- max/temperature индексы и статусы:
- `singleBatteryHighestVoltageSerNo`
- `batteryHighestTemp`
- `batteryHighestTempSerNo`
- `batteryLowestTemp`
- `batteryLowestTempSerNo`
- `batteryCellVoltageState`
- `batteryStatus`
## 7) Тайминги TP из J1939 (важное для дебага)
Ключевые reference значения:
- `Tr = 200 ms`
- `Th = 500 ms`
- `T1 = 750 ms`
- `T2 = 1250 ms`
- `T3 = 1250 ms`
- `T4 = 1050 ms`
Практически:
- если responder выдал CTS, originator не должен задерживать DT дольше допусков
- если originator отправил RTS/DT, responder должен ответить CTS/ACK в окне таймаутов
## 8) Мини-чеклист при "вдруг стопнулось"
1. Найти последний `RTS` по `PGN=0x1100`.
2. Проверить, был ли `CTS` на шине с тем же `PGN`.
3. Проверить наличие `DT#1/#2`.
4. Проверить `ACK`.
5. Если цепочка оборвалась:
- зафиксировать на каком шаге;
- сопоставить с UART логом state machine (`S9/S10`, `TP timeout`, `BCS timeout`).