SETCAN
руководство разработчика
Карта библиотеки ProtoCAN, формат кадров и практический маршрут переноса в существующую прошивку STM32.
Что находится в проекте
SETCAN — не готовый CubeIDE-проект, а подключаемый C-модуль поверх STM32 HAL. Его задача — фильтровать, принимать, разбирать и отправлять прикладные сообщения ProtoCAN.
Что ожидает модуль
main.hиcan.hиз CubeMX- STM32 HAL CAN, RTC и TIM
- CAN FIFO0 и Extended ID
- STM32 GCC ABI для C bit-fields
Путь кадра
IRQ вычитывает FIFO0. Pulse обрабатывается сразу, остальные Extended-кадры попадают в кольцевой буфер и разбираются в основном цикле.
Единая точка отправки
PROTOCAN_SEND() выбирает упаковщик по MsgType. GAS и Modbus автоматически разбиваются на кадры до 8 байт.
Что приложение реализует само
Прикладные действия, хранение SETTINGS, EEPROM, DS18B20, таймаут online/offline и полноценный bootloader не входят в ядро.
Состав библиотеки
Два файла образуют один модуль. Заголовок — контракт интеграции; C-файл — транспортная реализация и демонстрационные слабые обработчики.
protocan.h
Конфигурация текущего устройства, размеры буфера, enum типов сообщений, битовые представления ID/Body, структуры TX/RX и публичные функции.
Меняют при переносе: CURRENT_TYPE_DEVICE, CURRENT_ID_DEVICE, иногда PROTOCAN_RX_BUFFER_SIZE.
protocan.c
Инициализация, фильтры, кольцевой буфер, диспетчеризация, RTC sync, pulse и упаковка кадров.
Обычно не правят: прикладную логику лучше добавлять переопределением __weak-функций.
Внешний слой
CAN_HandleTypeDef, RTC_HandleTypeDef и TIM_HandleTypeDef передаются в PROTOCAN_INIT(). Запуск периферии выполняет приложение.
Основной API
| Функция | Назначение | Где вызывать |
|---|---|---|
| PROTOCAN_INIT | Сохраняет HAL handles, настраивает фильтры и callback’и при доступной регистрации. | После MX_*_Init(), до HAL_CAN_Start(). |
| PROTOCAN_ProcessAllRxMsgs | Обрабатывает всю накопленную RX-очередь и возвращает первую ошибку. | В основном цикле. |
| PROTOCAN_ProcessSingleRxMsg | Обрабатывает максимум один кадр. | В планировщике или ограниченном временном слоте. |
| PROTOCAN_SEND | Упаковывает и отправляет сообщение выбранного типа. | Из логики приложения, не удерживая изменяемые данные. |
| ProtoCanRxFifo0MsgPendingCallback | Забирает кадры из CAN FIFO0. | Из HAL callback, если авто-регистрация выключена. |
| ProtoCanPulseCallback | Отправляет периодический pulse со счётчиком. | Из callback нужного базового таймера. |
| PROTOCAN_SEND_SETTINGS_RESPONSE / ERROR | Формирует успешный либо ошибочный ответ привязки ROM. | Из пользовательского обработчика SETTINGS. |
Точки расширения
Переопределите нужную __weak-функцию в собственном C-файле: семейства ProtoCanMsgToBroadcast…, …Discrete…, …Analog…, ProtoCanMsgToSettings, ProtoCanMsgToGeneralAddressSpace и …Modbus…. Не редактируйте демонстрационную реализацию в ядре — так обновлять библиотеку проще.
Формат ProtoCAN
Протокол использует только CAN 2.0B Extended ID. Адрес устройства — пара DeviceType/DeviceID; назначение младших 16 бит зависит от типа сообщения.
29-битный идентификатор
28 27 26··24 23··20 19··16 15········0
Priority Route DeviceType DeviceID MsgType MsgBody
1 бит 1 бит 3 бита 4 бита 4 бита 16 битРеестр MsgType
| Код | Тип | Назначение | Статус |
|---|---|---|---|
| 0x0 | BROADCAST | Общие команды всем устройствам | stable |
| 0x1 | DISCRETE | Состояния, команды, флаги | stable |
| 0x2 | ANALOG | Датчики U / I / T и универсальные данные | stable |
| 0x3 | GAS | Общее 16-битное адресное пространство | stable |
| 0x4…0x7 | MODBUS | Coil, Discrete, Holding, Input | stable |
| 0x8 | ERROR | Код ошибки и дополнительная информация | stable |
| 0x9…0xD | BOOT | Управление, блоки A/B, статус, discovery | draft |
| 0xE | SETTINGS | Привязка 1-Wire ROM к локации Z/Y | stable |
| 0xF | PULSE | Присутствие устройства | stable |
Как портировать в свой STM32-проект
Рабочая последовательность для CubeMX/CubeIDE. Имена hcan, hrtc и htim2 замените на handles своего проекта.
Добавьте исходники
Inc/protocan.hв include pathSrc/protocan.cв сборку- Проверьте доступность
main.hиcan.h
Настройте адрес
В protocan.h задайте тип 0…7 и ID 0…15. Пара должна быть уникальной на шине.
#define CURRENT_TYPE_DEVICE 0b011
#define CURRENT_ID_DEVICE 0b0101Настройте CubeMX
- CAN: Extended ID, FIFO0
- RTC: если нужна синхронизация времени
- TIM: период pulse
- Проверьте filter banks 0, 1, 2 и границу 14
Инициализация и основной цикл
#include "protocan.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_CAN_Init();
MX_RTC_Init();
MX_TIM2_Init();
if (PROTOCAN_INIT(&hcan, &hrtc, &htim2) != PROTOCAN_INIT_OK) {
Error_Handler();
}
if (HAL_CAN_Start(&hcan) != HAL_OK) {
Error_Handler();
}
if (HAL_CAN_ActivateNotification(
&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK) {
Error_Handler();
}
while (1) {
(void)PROTOCAN_ProcessAllRxMsgs();
}
}Свяжите callback’и при отключённой регистрации HAL
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan_ptr)
{
if (hcan_ptr == &hcan) {
ProtoCanRxFifo0MsgPendingCallback(hcan_ptr);
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim_ptr)
{
if (htim_ptr == &htim2) {
ProtoCanPulseCallback(htim_ptr);
}
}Не дублируйте события
Если USE_HAL_*_REGISTER_CALLBACKS == 1, библиотека регистрирует callback’и сама. Не вызывайте те же функции ещё раз из стандартных callback’ов.
Перенесите прикладную логику
Создайте, например, protocan_app.c и определите там только нужные weak handlers. Так ядро остаётся обновляемым.
#include "protocan.h"
PROTOCAN_StatusTypeDef ProtoCanMsgToAnalogTSens(struct RXMsg msg)
{
msgBodyAnalogType body = {0};
body.Body = msg.eID.Fields.MsgBody;
uint16_t sensor_id = body.Fields.SensorID;
/* Получить температуру sensor_id и сформировать ответ. */
return PROTOCAN_OK;
}Проверка после переноса
- Проект собирается без повторных определений HAL callback’ов.
- CAN стартует и принимает только Extended ID.
- Pulse появляется с периодом выбранного таймера.
- Эталонный ID
0x13590702декодируется как DeviceType=3, DeviceID=5, MsgType=9, Body=0x0702. - При нагрузке учтено, что буфер размера 128 хранит максимум 127 кадров.
Готовые шаблоны
Минимальные примеры формирования исходящего кадра и обработчика SETTINGS. Их можно вынести в прикладной слой проекта.
Отправка трёх регистров GAS
uint16_t registers[] = { 0x1234, 0x5678, 0x9ABC };
ProtoCanId_t id = {0};
id.Fields.Priority = PROTOCAN_PRIORITY_STANDARD;
id.Fields.Route = PROTOCAN_ROUTE_FROM_DEVICE;
id.Fields.DeviceType = CURRENT_TYPE_DEVICE;
id.Fields.DeviceID = CURRENT_ID_DEVICE;
id.Fields.MsgType = PROTOCAN_MSGTYPE_GENERAL_ADDRESS_SPACE;
ProtoCanData_t tx = {0};
tx.GeneralAddressSpaceData.RegStartAdr = 100;
tx.GeneralAddressSpaceData.Data = registers;
tx.GeneralAddressSpaceData.RegCount = 3;
if (PROTOCAN_SEND(id, tx) != PROTOCAN_OK) {
/* CAN занят или HAL вернул ошибку. */
}SETTINGS: прикладное хранение ROM
PROTOCAN_StatusTypeDef ProtoCanMsgToSettings(
const ProtoCanSettingsMsg_t *message)
{
uint8_t current_rom[PROTOCAN_SETTINGS_ROM_SIZE] = {0};
switch (message->Operation) {
case PROTOCAN_SETTINGS_GET:
/* Загрузить ROM из EEPROM в current_rom. */
return PROTOCAN_SEND_SETTINGS_RESPONSE(
message->AssemblySerial, message->Position, current_rom);
case PROTOCAN_SETTINGS_WRITE:
/* Проверить CRC/наличие и атомарно записать message->Rom. */
return PROTOCAN_SEND_SETTINGS_RESPONSE(
message->AssemblySerial, message->Position, message->Rom);
case PROTOCAN_SETTINGS_CLEAR:
/* Очистить запись; current_rom должен содержать нули. */
return PROTOCAN_SEND_SETTINGS_RESPONSE(
message->AssemblySerial, message->Position, current_rom);
default:
return PROTOCAN_SEND_SETTINGS_ERROR(
message->AssemblySerial, message->Position,
PROTOCAN_SETTINGS_RESULT_INVALID_DLC);
}
}Полная документация ProtoCAN
Нормативные документы и тестовые векторы собраны в эту страницу из исходников doc/setcan/protocan.
Документация ProtoCAN
Статус комплекта: 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.- XLSX — адреса и свойства регистров ОАП.
- Сгенерированный
../index.html— только представление, не самостоятельный источник.
Сборка HTML
Из корня проекта:
./doc/setcan/build-html.bat
Все документы и тестовые векторы включаются в единый файл
doc/setcan/index.html.
Скрипт не изменяет исходные Markdown/XLSX и пригоден для запуска в CI.
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
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.
Разметки 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
Priority = 1
Route = 0
DeviceType = 3
DeviceID = 5
MsgType = 0x9
MsgBody = 0x0702
CAN ID = 0x13590702
Этот пример соответствует ENTER_BOOT, SessionID=7. Машинные варианты
находятся в examples/test-vectors.json.
ProtoCAN Boot Protocol
Статус: 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_IMAGE
DATA[0..3] ImageSize, uint32 little-endian
DATA[4..7] ImageCRC32, uint32 little-endian
BEGIN_COMPAT
DATA[0..1] ProductType, uint16 little-endian
DATA[2] HardwareRevisionMin
DATA[3] HardwareRevisionMax
DATA[4..7] FirmwareVersion, uint32 little-endian
До ERASE прибор обязан получить обе части метаданных и проверить размер,
тип изделия, аппаратную ревизию, версию и политику anti-rollback.
BOOT_STATUS
MsgBody[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 |
выполнить правильный переход |
State machine
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. - Базовый режим подтверждает каждый блок.
- Рабочий режим может подтверждать окно из 16 блоков.
- После потери связи
QUERY_PROGRESSвозвращает следующий ожидаемый блок, пока состояние загрузчика сохранено. - Для продолжения после перезагрузки порт должен сохранять session metadata и восстановить её при инициализации; ядро версии 1.0 само это не делает.
Безопасность и A/B-обновление
active=A -> target=B -> verify -> pending=B
active=B -> target=A -> verify -> pending=A
CRC32 защищает только от случайного повреждения. Серийный загрузчик должен
дополнительно проверить подпись контейнера, границы вектора, совместимость и
anti-rollback. Bootloader не обновляется командами BOOT_DATA_A/B.
Boot metadata должна атомарно хранить:
- активный слот;
- pending-слот;
- подтверждение запуска;
- число неудачных попыток;
- версию и CRC32 образа.
Если приложение не выполняет 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 | семантика, диапазон и особые значения |
Правила ведения
- Адрес не переиспользуется с другим смыслом после выпуска стабильной версии.
- Многорегистровое значение занимает непрерывный диапазон.
- Порядок 16-битных слов для 32-битного значения фиксируется в строке типа.
- Резервные диапазоны явно отмечаются и не используются без изменения версии.
- Удалённый параметр помечается deprecated, а не исчезает молча.
- Изменение адреса, типа или масштаба отражается в
CHANGELOG.md.
Экспорт
Для программной генерации каталог следует экспортировать из XLSX в CSV с UTF-8 и фиксированными английскими именами колонок. CSV должен проверяться на:
- уникальность адресов;
- пересечение многорегистровых значений;
- допустимые типы и права доступа;
- равенство шестнадцатеричного и десятичного адреса;
- попадание адреса в диапазон
0x0000…0xFFFF.
До появления автоматического экспортёра нормативным источником адресов остаётся XLSX, а HTML/Markdown считаются представлением.
История изменений ProtoCAN
Формат основан на Keep a Changelog. Версия относится к спецификации, а не к версии прошивки отдельного прибора.
[Unreleased]
Added
- Структурированный комплект документации
doc/setcan/protocan. - Загрузочный сервис
MsgType=0x9…0xD. - Два логических слота по 512 КиБ, 65 536 блоков по 8 байт каждый.
- Машинные эталоны CAN ID в
examples/test-vectors.json.
[1.0] — 2026-08-29
Added
- Зафиксирована 29-битная структура ProtoCAN ID.
- Зафиксирована адресация 8 типов по 16 экземпляров.
- Существующие сообщения
0x0…0x8,0xE,0xFсохранены.
Тестовые векторы
Машинные эталоны из examples/test-vectors.json.
{
"schema_version": 1,
"byte_order": "little-endian",
"frames": [
{
"name": "enter_boot_session_7",
"direction": "pm_to_device",
"priority": 1,
"route": 0,
"device_type": 3,
"device_id": 5,
"msg_type": 9,
"msg_body": 1794,
"can_id_hex": "0x13590702",
"dlc": 0,
"data_hex": ""
},
{
"name": "slot_b_block_1",
"direction": "pm_to_device",
"priority": 1,
"route": 0,
"device_type": 3,
"device_id": 5,
"msg_type": 11,
"msg_body": 1,
"can_id_hex": "0x135B0001",
"dlc": 8,
"data_hex": "1011121314151617"
},
{
"name": "enter_boot_ok",
"direction": "device_to_pm",
"priority": 1,
"route": 1,
"device_type": 3,
"device_id": 5,
"msg_type": 12,
"msg_body": 1794,
"can_id_hex": "0x1B5C0702",
"dlc": 8,
"data_hex": "00FF000000000000"
}
]
}