# 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). ## GAS: сквозная карта УКСС и профиль 167/v1 УКСС назначены десятичные ID **0…11999**, блоки по 1000 слов: `GAS_ID = номер_узла × 1000 + смещение`. Блок 0 — общий резерв; узлы 1…11 и все границы описаны в [GAS_ADDRESS_ALLOCATION_167.md](GAS_ADDRESS_ALLOCATION_167.md). Диапазон 12000…65535 свободен для последующего распределения. УМП 1 (узел 5) назначены ID 5000…5127, УМП 2 (узел 6) — 6000…6127. Смещения 128…999 зарезервированы. Полный словарь 128 слов, ограничения LOAD, биты Commands/LOAD_STATUS и соответствие Modbus приведены в [GAS_MODBUS_MAP_167.md](GAS_MODBUS_MAP_167.md). Новые ID пока назначены только в документации. Действующий профиль 167/v1 использует Modbus 0x0000…0x007F и окно GAS 0x5000…0x507F; например, LOAD_CAN_TIMEOUT: Modbus 0x0052, GAS 0x5052, новые ID 5082/6082. Десятичный ID 5000 не равен hex-адресу 0x5000. Служебный CAN УМП с маркером 0x1F00 — отдельный транспорт; его пакет нельзя интерпретировать как обычный payload ProtoCAN GAS. Словарь и lookup находятся в `python/protocan/gas_167.py` и `gas_167_registers.json` проекта templates. Парсер обычных кадров GAS показывает назначенные имена, узел, старые адреса и статус для запросов и каждого слова ответа; неизвестные и резервные адреса сохраняются raw. Общая сводка `Decoded.summary` содержит имя каждого назначенного параметра, УМП 1/2, десятичный ID, hex-адрес и значение в dec/hex. Поэтому имена видны непосредственно в колонке «Расшифровка» всех клиентов общего декодера: онлайн-монитор, трассировка, фильтр кадров, ручной разбор и DevBoard_V1. Полный текст длинной строки доступен во всплывающей подсказке. Тип сообщения отображается как `GAS (General Address Space)`. Обычные демо-потоки шины и DevBoard также включают назначенные адреса УМП. Низкие Modbus-адреса и старое окно не определяют профиль прибора автоматически. DATA обычного ProtoCAN GAS — до четырёх u16 little-endian; Modbus RTU передаёт каждое слово старшим байтом вперёд. GUI использует этот же словарь через совместимый импорт, без собственной реализации карты. ### Демо УМП в SETGUI Общий список «Протокол» позволяет выбрать `ProtoCAN / GAS`, `УМП / Balsam 167 (legacy CAN)`, карту `GAS 167/v1` отдельно для УМП 1/2 или `УМП / ProtoCAN GAS — новые ID 5000/6000`. Выбор перерисовывает уже полученные кадры. Для старой карты номер УМП выбирается оператором и обозначается «выбран вручную»; низкие адреса 0…127 и окно 0x5000…0x507F сами по себе номер узла не кодируют. Этот режим накладывает словарь на слова ProtoCAN GAS/Modbus Holding; он не является декодером служебных CAN-пакетов с маркером 0x1F00. Профиль Balsam принимает только собственный формат и показывает несоответствие для чужих кадров. В сводке Commands показаны активные биты с названиями команд; это не подтверждение их выполнения. В режиме «Авто» legacy-ID Balsam проверяются первыми. Для корректного ProtoCAN GAS с целыми словами все адреса кадра сверяются с назначенными диапазонами УМП. Если все они принадлежат одному узлу, поля Device Name и Msg Type показывают УМП 1/2; основание выбора записывается в подробности «Автоопределение». Это распознавание назначенной карты, а не подтверждение её поддержки прошивкой. Для старых/неизвестных адресов, смешанных диапазонов и некорректного payload автоматический выбор УМП не выполняется; сводка сообщает «профиль/узел не определены». Номер Device в ProtoCAN сам по себе не считается номером УМП. «Демо УМП» запускается с режимом «Авто». Открыть `CAN → Шина CAN / мост → Настройки → Демо УМП`. Генератор `python/set_devices/bus_demo.py:UmpDemoSource` моделирует два узла с демонстрационными адресами `Device Type=3`, `Device=5/6`. Он передаёт PULSE раз в секунду и четыре GAS-слова каждого узла каждые 250 мс: ID 5000…5127 и 6000…6127, полный обход за 8 секунд. Это имитация назначенной карты, а не эмуляция текущего транспорта 167/v1. Кадры проходят обычное кадрирование AA 55, CRC и общий парсер ProtoCAN. Их можно смотреть в онлайн-мониторе, трассировке и адресном пространстве; в буфере сессии и его CSV источник обозначен `DEMO УМП`. Значения синтетические, в формате raw u16. LOAD_STATUS показывает RUN (бит 3), LOAD_ATTEMPTS — 0, LOAD_CAN_TIMEOUT — 1000 мс. Кнопка «Стоп демо УМП» останавливает поток. Для запуска нужно отключить COM-порт и CAN-снифер; генератор работает локально без передачи в оборудование.