Статус комплекта: Draft
Версия комплекта: 1.0
Дата редакции: 2026-08-29
Транспорт: Classic CAN 2.0B, Extended ID, DLC 0…8
Этот каталог разделяет нормативное описание протокола, загрузчик и реестр
общего адресного пространства. Большой исходный документ
Протокол CAN и ОАП.md сохранён как
совместимое представление таблиц из Excel.
| Документ | Назначение | Статус источника |
|---|---|---|
| PROTOCOL.md | 29-битный CAN ID, адресация, реестр MsgType, порядок байтов |
нормативный |
| BOOTLOADER.md | обновление прошивки, кадры, состояния, ошибки и A/B-слоты | нормативный draft |
| OAP.md | правила ведения общего адресного пространства | нормативный индекс |
| ../../Протокол CAN и ОАП.xlsx | редактируемый реестр ОАП | источник таблиц |
| examples/test-vectors.json | машинные эталоны CAN ID и payload | нормативные примеры |
| CHANGELOG.md | история версий документа | нормативный |
При расхождении данных действует следующий порядок:
PROTOCOL.md — структура ProtoCAN и реестр типов сообщений.BOOTLOADER.md — загрузочный сервис 0x9…0xD.В PowerShell 7:
./build-html.ps1
Результат создаётся в build/protocol.html. Скрипт не изменяет исходные
Markdown/XLSX и пригоден для запуска в CI.
Статус: 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 уникальных адресов.
28 27 26...24 23...20 19...16 15........0
Priority Route DeviceType DeviceID MsgType MsgBody
1 бит 1 бит 3 бита 4 бита 4 бита 16 бит
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.
MsgBodyMsgType |
Биты 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.MsgType/MsgBody/DLC должны отвергаться.Priority = 1
Route = 0
DeviceType = 3
DeviceID = 5
MsgType = 0x9
MsgBody = 0x0702
CAN ID = 0x13590702
Этот пример соответствует ENTER_BOOT, SessionID=7. Машинные варианты
находятся в examples/test-vectors.json.
Статус: Draft
Версия протокола: 1.0
Совместимость: classic CAN 2.0B, Extended ID, DLC 0…8
Реализация: templates/c/protocan-boot
Сервис обновляет адресованный прибор по CAN и поддерживает два логических слота A/B. Активный слот не стирается: новый образ записывается в неактивный, проверяется и атомарно назначается кандидатом на запуск.
MsgType |
Имя | MsgBody |
Payload |
|---|---|---|---|
0x9 |
BOOT_CONTROL |
SessionID[15:8] \| Command[7:0] |
параметры команды |
0xA |
BOOT_DATA_A |
BlockIndex[15:0] |
8 байт слота A |
0xB |
BOOT_DATA_B |
BlockIndex[15:0] |
8 байт слота B |
0xC |
BOOT_STATUS |
SessionID[15:8] \| Command[7:0] |
статус и прогресс |
0xD |
BOOT_DISCOVERY |
подтип ответа | идентификация |
Все команды записи адресуются конкретному DeviceType/DeviceID и имеют
Route=0. Ответы сохраняют адрес прибора и имеют Route=1.
MsgBody кадра данных — номер 8-байтового блока:
offset = (uint32_t)BlockIndex * 8U;
address = SLOT_X_BASE + offset;
512 КиБ = 524 288 байт
524 288 / 8 = 65 536 блоков
BlockIndex = 0x0000…0xFFFF
BlockIndex |
Смещение | Диапазон байтов |
|---|---|---|
0x0000 |
0x00000 |
0x00000…0x00007 |
0x0001 |
0x00008 |
0x00008…0x0000F |
0xFFFF |
0x7FFF8 |
0x7FFF8…0x7FFFF |
0x80000 является первой позицией за границей слота. Последний кадр
дополняется 0xFF, но CRC32 вычисляется только по ImageSize байтам.
BOOT_CONTROL| Код | Команда | DLC | Payload | Допустимое состояние |
|---|---|---|---|---|
0x01 |
IDENTIFY |
0 | отсутствует | любое |
0x02 |
ENTER_BOOT |
0 | отсутствует | любое; SessionID != 0 |
0x03 |
BEGIN_IMAGE |
8 | размер и CRC32 | metadata |
0x04 |
BEGIN_COMPAT |
8 | совместимость и версия | metadata |
0x05 |
ERASE |
0 | отсутствует | ready-to-erase |
0x06 |
VERIFY |
0 | отсутствует | образ получен |
0x07 |
COMMIT |
0 | отсутствует | verified |
0x08 |
CONFIRM |
0 | отсутствует | запущенное приложение |
0x09 |
REBOOT |
0 | отсутствует | активная сессия |
0x0A |
ABORT |
0 | отсутствует | активная сессия |
0x0B |
QUERY_PROGRESS |
0 | отсутствует | активная сессия |
BEGIN_IMAGEDATA[0..3] ImageSize, uint32 little-endian
DATA[4..7] ImageCRC32, uint32 little-endian
BEGIN_COMPATDATA[0..1] ProductType, uint16 little-endian
DATA[2] HardwareRevisionMin
DATA[3] HardwareRevisionMax
DATA[4..7] FirmwareVersion, uint32 little-endian
До ERASE прибор обязан получить обе части метаданных и проверить размер,
тип изделия, аппаратную ревизию, версию и политику anti-rollback.
BOOT_STATUSMsgBody[15..8] SessionID
MsgBody[7..0] команда, на которую дан ответ
DATA[0] Status
DATA[1] TargetSlot: 0=A, 1=B, 0xFF=не выбран
DATA[2..3] NextBlock, uint16 little-endian
DATA[4..7] RunningCRC32, uint32 little-endian
| Код | Статус | Повтор допустим |
|---|---|---|
0x00 |
OK |
— |
0x01 |
BUSY |
да, после задержки |
0x02 |
INVALID_COMMAND |
после исправления |
0x03 |
WRONG_DEVICE |
нет для этого образа |
0x04 |
WRONG_HARDWARE |
нет для этого образа |
0x05 |
INVALID_SIZE |
нет для этого образа |
0x06 |
CRC_ERROR |
новая передача |
0x07 |
FLASH_ERROR |
зависит от платформы |
0x08 |
SEQUENCE_ERROR |
да, с NextBlock |
0x09 |
SIGNATURE_ERROR |
нет |
0x0A |
SESSION_ERROR |
открыть новую сессию |
0x0B |
VOLTAGE_ERROR |
да после нормализации питания |
0x0C |
INVALID_STATE |
выполнить правильный переход |
IDLE
└─ ENTER_BOOT ─> METADATA
├─ BEGIN_IMAGE
└─ BEGIN_COMPAT
│
v
READY_TO_ERASE
│ ERASE
v
RECEIVING
│ VERIFY
v
VERIFIED
│ COMMIT
v
PENDING + REBOOT
│ CONFIRM
v
CONFIRMED
Ошибка Flash, CRC, совместимости или подписи переводит сессию в FAILED.
Новая ENTER_BOOT создаёт чистую сессию. ABORT прекращает текущую передачу,
не активируя частично записанный слот.
BlockIndex.SEQUENCE_ERROR и ожидаемый NextBlock.QUERY_PROGRESS возвращает следующий ожидаемый блок,
пока состояние загрузчика сохранено.active=A -> target=B -> verify -> pending=B
active=B -> target=A -> verify -> pending=A
CRC32 защищает только от случайного повреждения. Серийный загрузчик должен
дополнительно проверить подпись контейнера, границы вектора, совместимость и
anti-rollback. Bootloader не обновляется командами BOOT_DATA_A/B.
Boot metadata должна атомарно хранить:
Если приложение не выполняет CONFIRM за установленное число запусков,
загрузчик возвращается к предыдущему подтверждённому слоту.
IDENTIFY.SessionID командой ENTER_BOOT.BEGIN_IMAGE и BEGIN_COMPAT.ERASE и передаёт BOOT_DATA_A либо BOOT_DATA_B.VERIFY, затем COMMIT и REBOOT.CONFIRM.Статус: Stable, данные ведутся в XLSX
Порядок значений: 16-битные регистры, little-endian в CAN payload
Редактируемый источник реестра:
Протокол CAN и ОАП.xlsx.
Просматриваемая большая таблица находится в
Протокол CAN и ОАП.html и
Протокол CAN и ОАП.md.
ОАП связывает 16-битный адрес регистра с его типом, назначением, доступом и
масштабом. В ProtoCAN используется MsgType=0x3, а MsgBody содержит адрес
первого регистра.
| Поле | Требование |
|---|---|
| AddressHex | 0x0000…0xFFFF, уникальное значение |
| AddressDec | десятичный эквивалент AddressHex |
| Group | функциональная группа |
| Name | однозначное имя параметра |
| Type | u16, i16, u32, i32, float32, bitmap или массив |
| Registers | число занятых 16-битных регистров |
| Access | R, W или RW |
| Unit | физическая единица либо — |
| Scale | множитель/делитель представления |
| Default | значение после сброса, если применимо |
| Description | семантика, диапазон и особые значения |
CHANGELOG.md.Для программной генерации каталог следует экспортировать из XLSX в CSV с UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:
0x0000…0xFFFF.До появления автоматического экспортёра нормативным источником адресов остаётся XLSX, а HTML/Markdown считаются представлением.
Формат основан на Keep a Changelog. Версия относится к спецификации, а не к версии прошивки отдельного прибора.
docs/protocan.MsgType=0x9…0xD.examples/test-vectors.json.0x0…0x8, 0xE, 0xF сохранены.