115 lines
5.0 KiB
Markdown
115 lines
5.0 KiB
Markdown
# ProtoCAN — базовый протокол
|
||
|
||
Статус: **Stable с зарезервированным загрузочным расширением**<br>
|
||
Версия: **1.0**<br>
|
||
Порядок байтов payload: **little-endian**, если явно не указано иное
|
||
|
||
## Назначение
|
||
|
||
ProtoCAN — прикладной протокол поверх classic CAN 2.0B. Используются только
|
||
расширенные 29-битные идентификаторы (`IDE=1`) и payload длиной 0…8 байт.
|
||
|
||
## Термины
|
||
|
||
| Термин | Значение |
|
||
|---|---|
|
||
| ПМ | управляющий модуль |
|
||
| прибор | адресуемый узел на шине |
|
||
| `DeviceType` | тип прибора, 0…7 |
|
||
| `DeviceID` | экземпляр прибора данного типа, 0…15 |
|
||
| `MsgType` | класс сообщения или сервис |
|
||
| `MsgBody` | 16-битное поле, формат которого зависит от `MsgType` |
|
||
|
||
Пара `DeviceType/DeviceID` задаёт до `8 × 16 = 128` уникальных адресов.
|
||
|
||
## Расширенный CAN ID
|
||
|
||
```text
|
||
28 27 26...24 23...20 19...16 15........0
|
||
Priority Route DeviceType DeviceID MsgType MsgBody
|
||
1 бит 1 бит 3 бита 4 бита 4 бита 16 бит
|
||
```
|
||
|
||
```c
|
||
can_id =
|
||
((uint32_t)priority << 28) |
|
||
((uint32_t)route << 27) |
|
||
((uint32_t)device_type << 24) |
|
||
((uint32_t)device_id << 20) |
|
||
((uint32_t)msg_type << 16) |
|
||
msg_body;
|
||
```
|
||
|
||
| Поле | Значения | Назначение |
|
||
|---|---|---|
|
||
| `Priority` | `0` critical, `1` standard | CAN-арбитраж |
|
||
| `Route` | `0` от ПМ, `1` от прибора | логическое направление |
|
||
| `DeviceType` | `0…7` | тип прибора |
|
||
| `DeviceID` | `0…15` | номер экземпляра |
|
||
| `MsgType` | `0…15` | тип сообщения |
|
||
| `MsgBody` | `0…65535` | команда, адрес или номер блока |
|
||
|
||
`Route` не является направлением физического трансивера. Ответ прибора
|
||
сохраняет адрес `DeviceType/DeviceID` и устанавливает `Route=1`.
|
||
|
||
## Реестр `MsgType`
|
||
|
||
| Код | Имя | Основное направление | DLC | Статус |
|
||
|---:|---|---|---:|---|
|
||
| `0x0` | `BROADCAST` | ПМ → все | зависит от команды | stable |
|
||
| `0x1` | `DISCRETE` | оба | 0…8 | stable |
|
||
| `0x2` | `ANALOG` | оба | 0…8 | stable |
|
||
| `0x3` | `GAS` | оба | 0/2/4/6/8 | stable |
|
||
| `0x4` | `MODBUS_COIL` | оба | 0…8 | stable |
|
||
| `0x5` | `MODBUS_DISCRETE` | оба | 0…8 | stable |
|
||
| `0x6` | `MODBUS_HOLDING` | оба | 0…8 | stable |
|
||
| `0x7` | `MODBUS_INPUT` | оба | 0…8 | stable |
|
||
| `0x8` | `ERROR` | прибор → ПМ | 0 | stable |
|
||
| `0x9` | `BOOT_CONTROL` | ПМ → прибор | 0/8 | draft |
|
||
| `0xA` | `BOOT_DATA_A` | ПМ → прибор | 8 | draft |
|
||
| `0xB` | `BOOT_DATA_B` | ПМ → прибор | 8 | draft |
|
||
| `0xC` | `BOOT_STATUS` | прибор → ПМ | 8 | draft |
|
||
| `0xD` | `BOOT_DISCOVERY` | прибор → ПМ | 8 | draft |
|
||
| `0xE` | `SETTINGS` | оба | 0/1/8 | stable |
|
||
| `0xF` | `PULSE` | прибор → сеть | 1 | stable |
|
||
|
||
Подробный формат `0x9…0xD` находится в [BOOTLOADER.md](BOOTLOADER.md).
|
||
|
||
## Разметки `MsgBody`
|
||
|
||
| `MsgType` | Биты `MsgBody` |
|
||
|---|---|
|
||
| broadcast | команда `[15:4]`, параметр `[3:0]` |
|
||
| discrete/analog | подтип `[15:12]`, значение/адрес `[11:0]` |
|
||
| Modbus | начальный адрес `[15:4]`, количество `[3:0]` |
|
||
| GAS | адрес первого 16-битного регистра `[15:0]` |
|
||
| error | дополнительная информация `[15:8]`, код `[7:0]` |
|
||
| settings | номер сборки `[15:8]`, позиция `[7:0]` |
|
||
| boot control/status | `SessionID[15:8]`, команда `[7:0]` |
|
||
| boot data | `BlockIndex[15:0]` |
|
||
|
||
## Общие правила обмена
|
||
|
||
- Многобайтовые значения в `DATA` передаются little-endian.
|
||
- Узел игнорирует адресованные кадры с чужим `DeviceType/DeviceID`.
|
||
- Прибор принимает команды ПМ с `Route=0`; ПМ принимает ответы с `Route=1`.
|
||
- Стандартные 11-битные CAN ID не являются кадрами ProtoCAN.
|
||
- RTR для загрузочного сервиса запрещён.
|
||
- Неописанные комбинации `MsgType/MsgBody/DLC` должны отвергаться.
|
||
|
||
## Эталон упаковки ID
|
||
|
||
```text
|
||
Priority = 1
|
||
Route = 0
|
||
DeviceType = 3
|
||
DeviceID = 5
|
||
MsgType = 0x9
|
||
MsgBody = 0x0702
|
||
|
||
CAN ID = 0x13590702
|
||
```
|
||
|
||
Этот пример соответствует `ENTER_BOOT`, `SessionID=7`. Машинные варианты
|
||
находятся в [examples/test-vectors.json](examples/test-vectors.json).
|