# ProtoCAN — базовый протокол Статус: **Stable с зарезервированным загрузочным расширением**
Версия: **1.0**
Порядок байтов 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).