big refactoring: J1939, log output, state machine bug fixes
This commit is contained in:
@@ -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`).
|
||||
Reference in New Issue
Block a user