# SETProtocol — переносимое протокольное ядро SETProtocol — общее C99-ядро для `SETGUI`, Android GUI, прошивок и утилит. Оно объединяет основной SET protocol v2 и поддерживаемые форматы переходного периода: ProtoCAN bridge и SETGUI transport v1. Windows, Linux, Android и микроконтроллер используют одинаковые правила кадра, CRC, адресации, телеметрии, обновления и потокового разбора. Ядро **не открывает COM-порт, CAN-адаптер или сокет**. COM, SLCAN, SocketCAN, USB CDC, TCP и аппаратный CAN относятся к портам. Они доставляют байты или CAN-кадры, а SETProtocol проверяет и интерпретирует их одинаково на всех платформах. ## 1. Граница ответственности ```text SETGUI / Android GUI / CLI / firmware │ прикладные команды и события ▼ Python facade / JNI / прямой C API │ стабильный ABI или C99 API ▼ ┌──────────────────────── SETProtocol ────────────────────────┐ │ SET v2 │ ProtoCAN ID │ v1 parsers │ CRC │ GAS │ telemetry │ └─────────────────────────────────────────────────────────────┘ │ байты или нормализованный CAN frame ▼ COM │ SLCAN │ SocketCAN │ USB CDC │ TCP │ STM32 UART/CAN ``` В ядре находятся: - форматы проводных кадров и порядок байт; - SET protocol v2: команды, адресация, подписки и firmware state machines; - проверка длины, версии, DLC и контрольной суммы; - восстановление синхронизации после мусора или оборванного кадра; - упаковка и разбор ProtoCAN Extended ID; - счётчики качества входного потока; - общее адресное пространство регистров (GAS); - стабильная C ABI-граница для `ctypes`, JNI и будущего Swift/FFI. За пределами ядра остаются: - поиск устройств и выбор `COM6`, `can0` или Bluetooth/USB endpoint; - скорость UART и CAN bitrate; - драйверы SLCAN, SocketCAN, PCAN, CANable и vendor SDK; - разрешения Android USB и жизненный цикл приложения; - виджеты, вкладки, таблицы, графики и хранение настроек; - HAL, IRQ, DMA, RTOS, Flash и распиновка платы. Отсюда следует важное правило: **500000 на экране COM — это baud rate последовательного моста, а 500 kbit/s в CAN-настройках — bitrate самой CAN-шины. Ядро не подменяет одно другим и не выбирает эти значения автоматически.** ## 2. Состав исходников | Модуль | Роль | Платформенные зависимости | |---|---|---| | `set_protocol` | SET v2 frame, CRC32, stream/datagram parser | нет | | `set_can` | CAN segmentation, flow control и reassembly | доставка CAN frame и время | | `set_telemetry` | подписки и типизированные PUBLISH-пакеты | часы/callbacks приложения | | `set_firmware` | BEGIN/DATA/END/STATUS и resume state machine | Flash/verify/reboot backend | | `pcan_id` | Упаковка/разбор 29-битного ProtoCAN ID | нет | | `pcan_crc` | CRC-16/CCITT-FALSE | нет | | `pcan_frame` | Формат `AA 55`, encode и потоковый parser | нет | | `gui_frame` | Формат `A5 5A`, CRC32, encode, parser и link | нет | | `pcan_link` | Экземпляр канала, SEQ, RX/TX и статистика | два callback порта | | `pcan_ring` | SPSC-кольцо и непрерывный участок для DMA | нет | | `pcan_gas` | Карта 16-битных регистров и bridge к кадрам | callbacks региона | | `gui_catalog` | C-каталог публикуемых GUI-полей | нет; входит в общий shared build | | `pcan_abi` | Экспорт скалярного ABI для FFI | ABI компилятора C | Общая точка включения для C-кода — `include/setprotocol.h`. Иностранные runtimes должны использовать `include/setprotocol_abi.h`, а не повторять внутреннюю раскладку `pcan_parser_t` или `gui_parser_t`. Shared-библиотека `setprotocol` содержит SET v2 и совместимые legacy-модули. ABI v1 пока экспортирует функции `pcan_abi_*`: имена намеренно сохранены для бинарной совместимости SETGUI/Android. Расширение ABI для прямого SET v2 FFI должно быть совместимым добавлением или новой версией ABI. ## 3. Три поддерживаемых wire format SETProtocol поддерживает основной v2 и два legacy-формата. После первого корректного ответа формат соединения фиксируется до отключения. ### 3.1. CAN bridge: `AA 55` ```text AA 55 | LEN | SEQ | FLAGS | CAN_ID[4] LE | DATA[0..8] | CRC16 LE ``` `LEN = 6 + DLC`, поэтому допустимый диапазон — `6..14`. CRC-16/CCITT-FALSE считается по участку от `LEN` до последнего байта `DATA`. Максимальный размер кадра — 19 байт. Формат переносит один classic CAN 2.0 кадр через COM, USB CDC, RS-232, RS-485 или TCP byte stream. Флаги: | Бит | Имя | Значение | |---:|---|---| | 0 | `IDE` | расширенный 29-битный CAN ID | | 1 | `RTR` | remote frame | | 2 | `DIR` | `0` из CAN в host, `1` из host в CAN | | 3 | `ERR` | служебный кадр диагностики моста | ### 3.2. GUI transport: `A5 5A` ```text A5 5A | VER | TYPE | SEQ[2] BE | SIZE[2] BE | PAYLOAD[0..512] | CRC32 LE ``` Версия сейчас равна `1`. Заголовочные `SEQ` и `SIZE` идут big-endian, CRC32 IEEE — little-endian. Payload до 512 байт нужен для каталога, чтения/записи регистров, диагностики и потока значений. Это не CAN-кадр и у него нет DLC. Оба parser принимают произвольные chunks: один вызов может содержать половину кадра, несколько кадров или мусор между ними. Границы `read()` не считаются границами протокольных сообщений. ### 3.3. SET protocol v2: `A5 5A 02` ```text A5 5A | VER=02 | FLAGS | TYPE u16 LE | SOURCE u16 LE | DEST u16 LE | SEQ u16 LE | SIZE u16 LE | PAYLOAD[0..512] | CRC32 LE ``` Это основной формат новых устройств. Он одинаков поверх RS-232/485, USB CDC, TCP и UDP; CAN переносит байты полного v2-кадра через сегментацию. В v2 объединены запросы/ответы, события телеметрии и firmware flow. Нормативный контракт находится в `PROTOCOL.md`. ## 4. ProtoCAN Extended ID ```text 28 27 26..24 23..20 19..16 15..0 Priority | Route | DeviceType | DeviceID | MsgType | MsgBody ``` Для переносимости используются маски и сдвиги, а не C bit-fields. ABI-функции `pcan_abi_id_pack()` и `pcan_abi_id_unpack()` дают одинаковую раскладку при MSVC, GCC и Clang. ## 5. Стабильный ABI v1 `pcan_abi.h` экспортирует простые числа, указатели и явно ограниченные буферы. Текущая версия возвращается `pcan_abi_version()` и равна `1`. ### CAN bridge API | Функция | Назначение | |---|---| | `pcan_abi_version` | Проверить совместимость загруженной библиотеки | | `pcan_abi_id_pack/unpack` | Преобразовать поля ProtoCAN ID | | `pcan_abi_crc16` | Рассчитать CRC-16/CCITT-FALSE | | `pcan_abi_frame_encode` | Собрать целый `AA55` кадр | | `pcan_abi_parser_size` | Узнать размер opaque parser context | | `pcan_abi_parser_init` | Инициализировать память, принадлежащую вызывающему | | `pcan_abi_parser_push` | Передать один байт; `1` означает готовый кадр | | `pcan_abi_parser_stats` | Получить frames/CRC/bad length/stray bytes | ### GUI API | Функция | Назначение | |---|---| | `pcan_abi_gui_crc32` | Рассчитать CRC32 IEEE | | `pcan_abi_gui_frame_encode` | Собрать целый `A55A` кадр | | `pcan_abi_gui_parser_size/init/push` | Управлять opaque GUI parser context | | `pcan_abi_gui_parser_stats` | Получить frames/CRC/version/length/stray bytes | Возврат `0` из encode означает неверные аргументы или недостаточный output buffer. Parser API возвращает отрицательное значение при неверном context, `0` пока кадр не собран и `1` при готовом кадре. ## 6. Память, состояние и многопоточность В переносимом C-слое нет `malloc`, singleton и скрытого глобального parser. Каждый канал имеет собственное состояние. В ABI вызывающий сначала спрашивает его размер, выделяет байтовый блок и передаёт его в `init`. ```c size_t size = pcan_abi_parser_size(); void *storage = /* память вызывающей стороны размером size */; pcan_abi_parser_init(storage, size); ``` Это позволяет: - держать память статически на MCU; - использовать `ctypes.create_string_buffer()` в Python; - выделять handle только в JNI-адаптере; - одновременно разбирать несколько независимых линий. Один parser context нельзя одновременно изменять из нескольких потоков. Правильная модель — один владелец на канал или внешняя блокировка. Кольцевой буфер рассчитан на одного писателя и одного читателя (SPSC). Для нескольких писателей синхронизацию обеспечивает порт/приложение. ## 7. Порты и адаптеры | Среда | Артефакт | Состояние | |---|---|---| | Windows desktop | `setprotocol.dll` + Python `ctypes` | используется SETGUI, проверено тестами | | Android | `libsetprotocol.so` + JNI + Kotlin facade | сборка ABI `arm64-v8a`, `armeabi-v7a`, `x86`, `x86_64` проверяется Android build | | Linux desktop | `libsetprotocol.so` + тот же ABI | ядро и сборщик готовы; нужен Linux CI/smoke-test приложения | | macOS | `libsetprotocol.dylib` + тот же ABI | исходники совместимы; отдельная упаковка не проверена | | STM32F4 | прямой C99 + UART/DMA port | готовый порт в `ports/stm32f4` | | Другой MCU | прямой C99 | реализуются только callbacks I/O/времени/памяти | | iOS/Swift | C ABI | ABI подходит, Swift wrapper пока не добавлен | ### Linux Само ядро не содержит WinAPI, поэтому собирается GCC или Clang. Для SETGUI под Linux остаются две отдельные задачи: упаковать `libsetprotocol.so` с приложением и подключить нужный физический backend (`pyserial` для USB-COM или SocketCAN для `can0`). Правила кадра, CRC и ID менять не потребуется. SLCAN и SocketCAN — **порты снифера**, а не новая реализация протокола: ```text SLCAN text / struct can_frame │ adapter ▼ can_id + flags + data │ ▼ общий decoder/UI ``` ## 8. Сборка ### CMake: Windows, Linux, macOS ```bash cmake -S c/set-protocol -B build/setprotocol -DSETP_BUILD_TESTS=ON cmake --build build/setprotocol --config Release ctest --test-dir build/setprotocol -C Release --output-on-failure ``` Результат shared-сборки называется `setprotocol.dll`, `libsetprotocol.so` или `libsetprotocol.dylib`. Статическая цель называется `setprotocol_static`; совместимое имя CMake-цели SET v2 — `set_protocol`. ### Упрощённая host-сборка ```powershell python c/set-protocol/tools/build_host.py --output native/setprotocol.dll ``` ```bash python3 c/set-protocol/tools/build_host.py --output native/libsetprotocol.so ``` На Windows tool использует MSVC, на Unix ищет `cc`, `clang` или `gcc`. ### Python ```python from protocan.native import NativeProtocol core = NativeProtocol() raw = core.encode(sequence=1, flags=1, can_id=0x1234567, data=b"\xAA\xBB") frames = core.parser().feed(raw) ``` Если библиотека лежит вне стандартного дерева: ```bash export SETPROTOCOL_LIBRARY=/opt/set/lib/libsetprotocol.so ``` В PowerShell: ```powershell $env:SETPROTOCOL_LIBRARY = 'C:\set\native\setprotocol.dll' ``` ### Android `ports/android/Android.mk` компилирует те же C-файлы. Kotlin-класс `ru.setcorp.setprotocol.NativeSetProtocol` отвечает только за удобный API, а JNI — за преобразование типов и время жизни parser handle. ### Микроконтроллер Добавьте нужные `src/*.c` и каталог `include/` в проект. Порт STM32F4 не входит автоматически в host CMake, потому что ему нужен CMSIS. Для другой платы реализуйте `pcan_io_t.write` и `pcan_io_t.tx_space`; ISR/DMA лишь складывает байты, а `pcan_link_feed()` вызывается в безопасном контексте приложения. ## 9. Пример прямого ABI ```c #include "pcan_abi.h" uint8_t output[19]; const uint8_t data[] = {0xAA, 0xBB}; const uint8_t flags = 0x01U; /* IDE */ uint32_t id = pcan_abi_id_pack(1, 0, 2, 3, 4, 0x1234); size_t written = pcan_abi_frame_encode( 7, flags, id, data, sizeof(data), output, sizeof(output)); ``` Для firmware удобнее полный C API из `protocan_transport.h`: он даёт link, callbacks, ring и GAS без FFI-обёртки. ## 10. Диагностика | Симптом | Что проверить | |---|---| | `crc_errors` растёт | bitrate/baud, ground, termination, порядок байт, потерю chunks | | `bad_len`/`length_errors` | выбран ли правильный формат `AA55` или `A55A` | | `version_errors` | версия GUI transport должна быть `1` | | много `stray_bytes` | начало чтения посреди пакета допустимо; постоянный рост означает неверный порт | | DLL/SO не найдена | путь, архитектуру процесса и `SETPROTOCOL_LIBRARY` | | Android `UnsatisfiedLinkError` | имя `setprotocol`, ABI устройства и упаковку `jniLibs`/NDK | | CAN пустой, но COM открыт | COM baud не равен CAN bitrate; проверьте настройку самого адаптера | ## 11. Совместимость и ограничения - ABI v1 изменяется только совместимым добавлением функций. Ломающее изменение требует нового значения `PCAN_ABI_VERSION`. - Wire format нельзя менять без версии/миграционного документа и тестовых векторов для C, Python и Android. - CAN bridge сейчас рассчитан на classic CAN: `DLC <= 8`; CAN FD не включён. - GUI payload ограничен 512 байтами; на MCU `GUI_RX_PAYLOAD_MAX` можно уменьшить. - В ядре нет готового SocketCAN/SLCAN/vendor backend: это следующий слой портов. - В ядро не входят виджеты GUI, настройки COM/CAN и обновление прошивки целиком. Для firmware flow существует отдельная библиотека `protocan-boot`. ## 12. Проверка изменений Минимальный quality gate: 1. CMake build и `ctest` для `test_transport` и `test_abi`. 2. Сверка машинных векторов `tests/vectors/test-vectors.json`. 3. Python-тесты с обязательной загрузкой native core. 4. Android unit tests и `assembleDebug`, если менялись ABI/JNI/Kotlin. 5. Smoke-test целевого порта на реальной линии. Канонический код находится в `templates/c/set-protocol`. Проекты должны получать его как Git submodule и фиксировать конкретный commit, а не хранить разошедшиеся копии.