181 lines
5.3 KiB
Markdown
181 lines
5.3 KiB
Markdown
# 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`).
|