Files
templates/c/set-protocol/docs/SETPROTOCOL.md

18 KiB
Raw Blame History

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. Граница ответственности

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

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

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

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

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.

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 — порты снифера, а не новая реализация протокола:

SLCAN text / struct can_frame
             │ adapter
             ▼
      can_id + flags + data
             │
             ▼
       общий decoder/UI

8. Сборка

CMake: Windows, Linux, macOS

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-сборка

python c/set-protocol/tools/build_host.py --output native/setprotocol.dll
python3 c/set-protocol/tools/build_host.py --output native/libsetprotocol.so

На Windows tool использует MSVC, на Unix ищет cc, clang или gcc.

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)

Если библиотека лежит вне стандартного дерева:

export SETPROTOCOL_LIBRARY=/opt/set/lib/libsetprotocol.so

В 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

#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, а не хранить разошедшиеся копии.