# SET protocol v2 — wire contract ## 1. Назначение SETP v2 — единственный прикладной протокол новых устройств SET. Он решает три задачи одним контрактом: 1. запросы и ответы: конфигурация, диагностика, журналы и общая карта данных; 2. события: значения для отрисовки в реальном времени; 3. обновление прошивки с продолжением после разрыва соединения. Носитель не меняет типы сообщений или payload. Меняется только способ доставки целого SETP-кадра. ## 2. Общий кадр ```text offset size field 0 2 SOF = A5 5A 2 1 version = 02 3 1 flags 4 2 message_type u16 LE 6 2 source u16 LE 8 2 destination u16 LE 10 2 sequence u16 LE 12 2 payload_length u16 LE 14 N payload 14+N 4 CRC32 IEEE u32 LE ``` CRC32 считается от `version` (offset 2) до последнего байта payload. Полином `0xEDB88320`, init/final XOR `0xFFFFFFFF`; проверочное значение строки `123456789` — `0xCBF43926`. Максимальный payload базового профиля — 512 байт. Реализация может объявить меньший предел через `CAPABILITIES`, но не может молча принять начало большого кадра и отбросить его конец. Эталонный PING к узлу `0x002A`, sequence `0x1234`, с `ACK_REQUIRED`: ```text A5 5A 02 08 01 00 00 00 2A 00 34 12 00 00 33 EC 33 04 ``` ## 3. Флаги и транзакции | Бит | Имя | Смысл | |---:|---|---| | 0 | `RESPONSE` | ответ; тип и sequence повторяют запрос | | 1 | `EVENT` | самостоятельная публикация, не ответ | | 2 | `ERROR` | status ответа не равен `OK` | | 3 | `ACK_REQUIRED` | отправитель требует явный ответ | | 4 | `MORE` | за этим логическим куском последуют другие | | 5 | `PRIORITY` | приоритет над обычной телеметрией | | 7..6 | — | передавать нулями | Запрос содержит `RESPONSE=0`, `EVENT=0`. Ответ содержит `RESPONSE=1`, тот же `message_type` и `sequence`, а первые два байта payload всегда являются `status u16`. Push-телеметрия содержит `EVENT=1`; её `sequence` — счётчик кадров источника и позволяет заметить потерю. `source/destination = 0` означает локальный узел в точке-точке. `0xFFFF` — broadcast; на broadcast-запрос отвечать нельзя, если прикладная команда явно не задаёт безопасное окно ответа. ## 4. Стабильные типы сообщений | Диапазон | Назначение | |---|---| | `0x0000..0x00FF` | системные команды и карта данных | | `0x0100..0x01FF` | обновление прошивки | | `0x0200..0x0FFF` | зарезервировано общей спецификацией | | `0x1000..0x7FFF` | команды конкретного изделия | | `0x8000..0xFFFF` | зарезервировано | Общие команды: | Код | Имя | Назначение | |---:|---|---| | `0x0001` | `PING` | доступность и uptime | | `0x0002` | `DEVICE_INFO` | модель, версии, серийный номер | | `0x0003` | `CAPABILITIES` | интерфейсы, MTU, функции, лимиты | | `0x0008` | `DIAGNOSTICS` | счётчики транспорта и приложения | | `0x0009` | `READ` | чтение 32-битно адресуемой карты | | `0x000A` | `WRITE` | транзакционная запись карты | | `0x0010` | `LOG_READ` | чтение журналов блоками | | `0x0011` | `CATALOG` | метаданные общей карты | | `0x0012` | `SUBSCRIBE` | создать/изменить поток данных | | `0x0013` | `PUBLISH` | пакет значений для отрисовки | | `0x0014` | `UNSUBSCRIBE` | удалить подписку | | `0x0100..0105` | `FW_*` | обновление и активация прошивки | Неизвестный тип не является ошибкой кадрирования. Устройство отвечает `UNSUPPORTED`, если запрос был адресован ему и требовал ответа. ## 5. Телеметрия реального времени ### SUBSCRIBE ```text subscription_id u16 period_ms u32 (0 = по изменению) address_count u16 addresses u32[address_count] ``` Ответ сообщает status и фактически принятый период. Устройство вправе увеличить слишком короткий период. Подписка принадлежит соединению/источнику и удаляется при его закрытии либо командой `UNSUBSCRIBE`. ### PUBLISH ```text subscription_id u16 sample_sequence u16 timestamp_ms u32 item_count u16 repeat item_count times: address u32 encoding u8 (U16/I16/U32/I32/F32/BYTES) element_count u8 data_length u16 data u8[data_length] ``` `timestamp_ms` — монотонное время устройства. GUI строит графики по нему, а не по моменту прихода в Windows. Большой массив, например спектр, разбивается на несколько `PUBLISH` с `MORE`; адрес и `sample_sequence` остаются теми же. Телеметрия имеет меньший приоритет, чем ответы и прошивка. При переполнении очереди разрешено отбросить старый `PUBLISH`, но нельзя частично передать кадр. ## 6. Прошивка Типы: | Код | Команда | |---:|---| | `0x0100` | `FW_BEGIN` | | `0x0101` | `FW_DATA` | | `0x0102` | `FW_END` | | `0x0103` | `FW_ABORT` | | `0x0104` | `FW_STATUS` | | `0x0105` | `FW_ACTIVATE` | `FW_BEGIN` содержит размер, CRC32 и SHA-256 образа, версию, базовый адрес, целевой слот, желаемый размер блока, ID ключа и необязательную подпись. Подпись проверяется над каноническим manifest, а не над полученными по частям данными: ```text ASCII "SETPFW2\0" || image_size || image_crc32 || image_version || base_address || slot || sha256 ``` Числа manifest также little-endian. Рекомендуемая подпись — Ed25519 (64 байта). Конкретный загрузчик может потребовать подписанный образ и вернуть `AUTH_FAILED` для неподписанного. `FW_DATA`: ```text offset u32 | data_length u16 | flags u16 | data_crc32 u32 | data[] ``` Ответ возвращает status и `next_offset u32`. Повтор уже записанного блока с теми же данными обязан быть идемпотентным. После потери связи GUI запрашивает `FW_STATUS` и продолжает с `next_offset`. `FW_END` повторяет размер, CRC32 и SHA-256. Устройство проверяет весь образ и только затем переводит слот в `READY`. `FW_ACTIVATE` меняет загрузочный слот; операция обновления не должна перезаписывать единственный рабочий образ. Для серийных устройств требуется A/B или эквивалентный механизм rollback. CRC32 защищает линию, SHA-256 — целостность образа, подпись — происхождение. Один CRC не является защитой от подмены прошивки. ## 7. Привязки к физическим интерфейсам ### RS-232, RS-485, USB CDC Кадры передаются подряд как поток байтов. Parser обязан восстанавливаться после мусора и битого CRC. На RS-485 используются `source/destination`; передача broadcast не должна запускать прошивку или запись конфигурации. ### Ethernet TCP TCP несёт тот же поток кадров без дополнительной длины: она уже есть в header. Один `recv()` может вернуть часть кадра или несколько кадров. Порт по умолчанию задаётся приложением; рекомендуемое значение проекта — `25060`, оно не считается зарегистрированным IANA. Для внешних сетей используется TLS, SETP внутри TLS не меняется. ### Ethernet UDP Одна UDP-датаграмма содержит ровно один полный SETP-кадр. Датаграммы с хвостом, двумя кадрами или несовпадающей длиной отбрасываются. Базовый payload 512 байт не превышает безопасный IPv4 MTU. Прошивка по UDP допустима только в режиме stop-and-wait с `ACK_REQUIRED`; предпочтителен TCP. ### CAN Через классический CAN передаются байты того же полного SETP-кадра. Повторно кодировать команды в поля CAN ID нельзя. Extended CAN ID: ```text 28..24 prefix = 0x12 23..16 destination (младшие 8 бит SETP destination) 15..8 source (младшие 8 бит SETP source) 7 priority 6..0 channel ``` CAN-профиль использует node `1..254`; `0` и `255` сохраняют смысл local и broadcast. Поля полного SETP-заголовка остаются обязательными и должны совпасть с CAN ID после reassembly. PCI классического CAN: ```text FIRST: data[0]=0x10, data[1..2]=total_length u16 LE, data[3..7]=5 байт CONSECUTIVE: data[0]=0x20|SN, data[1..7]=до 7 байт, SN начинается с 1 FLOW_CONTROL:data[0]=0x30|status, data[1]=block_size, data[2]=st_min_ms ``` `status`: 0 continue, 1 wait, 2 overflow. Номер сегмента идёт по модулю 16. Timeout сборки по умолчанию 500 мс. Новый FIRST заменяет незавершённую сборку того же канала. CAN-FD может увеличить данные сегмента в следующей версии binding, не меняя SETP frame/message/payload. ## 8. Совместимость GUI protocol v1 и SETP v2 несовместимы. Автоопределение допускается только во время миграции: клиент посылает v2 PING, затем при полном тайм-ауте пробует v1. После первого корректного ответа формат соединения фиксируется до отключения. Новое устройство не должно одновременно публиковать v1 и v2 в одном потоке.