STM32 · Classic CAN 2.0B · HAL

SETCAN
руководство разработчика

Карта библиотеки ProtoCAN, формат кадров и практический маршрут переноса в существующую прошивку STM32.

29 бит Extended ID0…8 байт payload128 адресов устройств127 кадров в RX-очереди

Что находится в проекте

SETCAN — не готовый CubeIDE-проект, а подключаемый C-модуль поверх STM32 HAL. Его задача — фильтровать, принимать, разбирать и отправлять прикладные сообщения ProtoCAN.

Структура

Минимальное ядро + нормативные документы

SETCAN/ ├── Inc/protocan.h публичные типы, настройки и API ├── Src/protocan.c фильтры, RX-очередь, разбор и отправка ├── doc/setcan/protocan/ спецификация протокола │ ├── PROTOCOL.md 29-битный ID и типы сообщений │ ├── OAP.md общее адресное пространство │ ├── BOOTLOADER.md обновление прошивки по CAN (draft) │ └── examples/ эталонные кадры JSON ├── Протокол CAN и ОАП.xlsx редактируемый реестр ОАП └── doc/index.html эта страница
Зависимости

Что ожидает модуль

  • 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 не входят в ядро.

01 · FIFO0 IRQHAL сообщает о новом кадре
02 · RX bufferExtended ID помещается в очередь
03 · DispatcherРазбор по MsgType
04 · Weak handlerЛогика приложения

Состав библиотеки

Два файла образуют один модуль. Заголовок — контракт интеграции; C-файл — транспортная реализация и демонстрационные слабые обработчики.

Inc

protocan.h

Конфигурация текущего устройства, размеры буфера, enum типов сообщений, битовые представления ID/Body, структуры TX/RX и публичные функции.

Меняют при переносе: CURRENT_TYPE_DEVICE, CURRENT_ID_DEVICE, иногда PROTOCAN_RX_BUFFER_SIZE.

Src

protocan.c

Инициализация, фильтры, кольцевой буфер, диспетчеризация, RTC sync, pulse и упаковка кадров.

Обычно не правят: прикладную логику лучше добавлять переопределением __weak-функций.

HAL

Внешний слой

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 бит
Многобайтовые значения payload передаются little-endian. Разметка ID через C bit-fields требует проверки при смене компилятора или ABI.

Реестр MsgType

КодТипНазначениеСтатус
0x0BROADCASTОбщие команды всем устройствамstable
0x1DISCRETEСостояния, команды, флагиstable
0x2ANALOGДатчики U / I / T и универсальные данныеstable
0x3GASОбщее 16-битное адресное пространствоstable
0x4…0x7MODBUSCoil, Discrete, Holding, Inputstable
0x8ERRORКод ошибки и дополнительная информацияstable
0x9…0xDBOOTУправление, блоки A/B, статус, discoverydraft
0xESETTINGSПривязка 1-Wire ROM к локации Z/Ystable
0xFPULSEПрисутствие устройстваstable

Как портировать в свой STM32-проект

Рабочая последовательность для CubeMX/CubeIDE. Имена hcan, hrtc и htim2 замените на handles своего проекта.

Шаг 1

Добавьте исходники

  • Inc/protocan.h в include path
  • Src/protocan.c в сборку
  • Проверьте доступность main.h и can.h
Шаг 2

Настройте адрес

В protocan.h задайте тип 0…7 и ID 0…15. Пара должна быть уникальной на шине.

#define CURRENT_TYPE_DEVICE 0b011
#define CURRENT_ID_DEVICE   0b0101
Шаг 3

Настройте CubeMX

  • CAN: Extended ID, FIFO0
  • RTC: если нужна синхронизация времени
  • TIM: период pulse
  • Проверьте filter banks 0, 1, 2 и границу 14
Шаг 4

Инициализация и основной цикл

#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();
    }
}
Шаг 5

Свяжите 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’ов.

Шаг 6

Перенесите прикладную логику

Создайте, например, 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 история версий документа нормативный

Приоритет источников

При расхождении данных действует следующий порядок:

  1. PROTOCOL.md — структура ProtoCAN и реестр типов сообщений.
  2. BOOTLOADER.md — загрузочный сервис 0x9…0xD.
  3. XLSX — адреса и свойства регистров ОАП.
  4. Сгенерированный ../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 за установленное число запусков, загрузчик возвращается к предыдущему подтверждённому слоту.

Эталонный сценарий

  1. ПМ адресно отправляет IDENTIFY.
  2. ПМ открывает ненулевой SessionID командой ENTER_BOOT.
  3. ПМ отправляет BEGIN_IMAGE и BEGIN_COMPAT.
  4. Прибор сообщает выбранный неактивный слот.
  5. ПМ выполняет ERASE и передаёт BOOT_DATA_A либо BOOT_DATA_B.
  6. ПМ выполняет VERIFY, затем COMMIT и REBOOT.
  7. Новое приложение после самопроверки выполняет 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"
    }
  ]
}