refactor: merge protocol cores as SETProtocol

This commit is contained in:
2026-09-01 09:58:09 +03:00
parent 5504104cc5
commit 19becd7b8c
56 changed files with 1256 additions and 359 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
build/ build/
cmake-build-*/ cmake-build-*/
*.o *.o
*.obj
*.d *.d
*.a *.a
*.elf *.elf

View File

@@ -30,10 +30,9 @@ templates/
| [`c/eeprom-ft24c256`](c/eeprom-ft24c256) | EEPROM 24Cxx по I²C с нарезкой записи по страницам | `stdint.h` | две I²C-транзакции, задержка | | [`c/eeprom-ft24c256`](c/eeprom-ft24c256) | EEPROM 24Cxx по I²C с нарезкой записи по страницам | `stdint.h` | две I²C-транзакции, задержка |
| [`c/can-sensor`](c/can-sensor) | передача 64-битных ROM датчиков парой CAN-кадров | `stdint.h` | отправка и приём CAN-кадра | | [`c/can-sensor`](c/can-sensor) | передача 64-битных ROM датчиков парой CAN-кадров | `stdint.h` | отправка и приём CAN-кадра |
| [`c/ds18b20`](c/ds18b20) | термометры DS18B20 поверх программной 1-Wire | `stdint.h` | Init, DelayUs, Reset, WriteBit, ReadBit — **порты STM32F103, STM32G431 и STM32G474 в комплекте** | | [`c/ds18b20`](c/ds18b20) | термометры DS18B20 поверх программной 1-Wire | `stdint.h` | Init, DelayUs, Reset, WriteBit, ReadBit — **порты STM32F103, STM32G431 и STM32G474 в комплекте** |
| [`c/protocan-transport`](c/protocan-transport) | транспорт ProtoCAN: кадр, канал, CRC, общее адресное пространство, каталог GUI и стабильный host ABI | `stdint.h` | запись в поток и запрос свободного места — **порты STM32F4, Windows/Linux/macOS FFI и Android JNI в комплекте** | | [`c/set-protocol`](c/set-protocol) | единое ядро SETProtocol: SET v2, совместимые ProtoCAN/GUI v1, GAS, телеметрия, firmware flow и стабильный host ABI | C99 | COM/SLCAN/SocketCAN/USB/Ethernet или callbacks — **Windows, Android и STM32F4-порты в комплекте** |
| [`c/protocan-boot`](c/protocan-boot) | адресная прошивка по ProtoCAN: A/B-слоты, сессия, CRC32, verify и rollback-контракт | C99 | CAN TX, erase/write Flash, boot metadata, проверка образа и reboot | | [`c/protocan-boot`](c/protocan-boot) | адресная прошивка по ProtoCAN: A/B-слоты, сессия, CRC32, verify и rollback-контракт | C99 | CAN TX, erase/write Flash, boot metadata, проверка образа и reboot |
| [`c/rs485-boot`](c/rs485-boot) | прошивка по RS-485 в формате SETGUI v1: потоковый parser, CRC32 и resume | C99 | UART TX/RX, DE, Flash — **порты STM32F103 и STM32G474VET в комплекте** | | [`c/rs485-boot`](c/rs485-boot) | прошивка по RS-485 в формате SETGUI v1: потоковый parser, CRC32 и resume | C99 | UART TX/RX, DE, Flash — **порты STM32F103 и STM32G474VET в комплекте** |
| [`c/set-protocol`](c/set-protocol) | единый SET protocol v2: управление, real-time телеметрия и обновление прошивки через UART/CAN/USB/Ethernet | C99 | доставка целого stream/datagram-кадра, часы, backend карты и загрузчика |
| [`c/rtc-service`](c/rtc-service) | RTC с резервированным backup-томом | `stdint.h` | доступ к RTC и backup-памяти — **порт K1921VK028 в комплекте** | | [`c/rtc-service`](c/rtc-service) | RTC с резервированным backup-томом | `stdint.h` | доступ к RTC и backup-памяти — **порт K1921VK028 в комплекте** |
| [`c/firmware-info`](c/firmware-info) | SemVer, build stamp и git build ID работающего образа | C99 | config-порты STM32F1/F4/G4 и К1921ВК028; упаковка для Modbus/SETGUI | | [`c/firmware-info`](c/firmware-info) | SemVer, build stamp и git build ID работающего образа | C99 | config-порты STM32F1/F4/G4 и К1921ВК028; упаковка для Modbus/SETGUI |
@@ -43,9 +42,13 @@ templates/
|---|---|---| |---|---|---|
| [`python/protocan`](python/protocan) | разбор ProtoCAN, транспортный кадр моста, кадр SETGUI, кодеки каталога | stdlib, Python 3.9+ | | [`python/protocan`](python/protocan) | разбор ProtoCAN, транспортный кадр моста, кадр SETGUI, кодеки каталога | stdlib, Python 3.9+ |
Кодировщики `c/protocan-transport` и `python/protocan` дают побайтово Кодировщики `c/set-protocol` и `python/protocan` дают побайтово
одинаковый результат — это зафиксировано эталонами в тестах на C. одинаковый результат — это зафиксировано эталонами в тестах на C.
Интерактивная документация общего ядра: [`doc/setprotocol.html`](doc/setprotocol.html).
В ней отдельно описаны граница ядра, ABI, память, три wire format и состояние
портов Windows, Android, Linux и MCU.
## Как подключить к проекту ## Как подключить к проекту
**Сабмодуль** — когда нужна одна конкретная версия и обновление по команде: **Сабмодуль** — когда нужна одна конкретная версия и обновление по команде:
@@ -78,10 +81,10 @@ git subtree pull --prefix lib/templates https://git.rd12.ru/Andrey/templates.git
|---|---| |---|---|
| `KONOR_ds18b20` | st7789, keypad, menu, eeprom-ft24c256, can-sensor, ds18b20, firmware-info | | `KONOR_ds18b20` | st7789, keypad, menu, eeprom-ft24c256, can-sensor, ds18b20, firmware-info |
| `OpticalTester` | st7789, keypad, menu, eeprom-ft24c256 | | `OpticalTester` | st7789, keypad, menu, eeprom-ft24c256 |
| `CAN_to_RS485` | protocan-transport, python/protocan | | `CAN_to_RS485` | set-protocol legacy transport, python/protocan |
| `candleLight_fw` | эталон разделения общей логики и G431/G474 FDCAN-порта; общий ProtoCAN Boot переносится по контракту `protocan-boot` | | `candleLight_fw` | эталон разделения общей логики и G431/G474 FDCAN-порта; общий ProtoCAN Boot переносится по контракту `protocan-boot` |
| `SETGUI` | python/protocan | | `SETGUI` | python/protocan |
| новые устройства SET и `SETGUI` v2 | set-protocol | | `SETGUI`, Android GUI и новые устройства SET | set-protocol |
| `k1921vk028` | rtc-service | | `k1921vk028` | rtc-service |
## Что сюда не попало и почему ## Что сюда не попало и почему

View File

@@ -43,7 +43,7 @@ STM32 HAL / другой MCU / host-тест
| `tests/test_pcan_boot.c` | хостовые тесты с RAM вместо Flash | стандартная библиотека C | | `tests/test_pcan_boot.c` | хостовые тесты с RAM вместо Flash | стандартная библиотека C |
| `CMakeLists.txt` | сборка библиотеки и теста | CMake 3.13+ | | `CMakeLists.txt` | сборка библиотеки и теста | CMake 3.13+ |
Модуль не зависит от `protocan-transport`: разбор пяти полей 29-битного ID Модуль не зависит от legacy-модулей `set-protocol`: разбор пяти полей 29-битного ID
сделан переносимыми сдвигами, без непереносимых C-битовых полей. сделан переносимыми сдвигами, без непереносимых C-битовых полей.
## Карта `MsgType` ## Карта `MsgType`

View File

@@ -1,62 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(protocan_transport C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Ядро библиотеки: платформенных зависимостей нет, собирается под что угодно.
set(PCAN_CORE_SOURCES
src/gui_frame.c
src/pcan_abi.c
src/pcan_crc.c
src/pcan_frame.c
src/pcan_id.c
src/pcan_link.c
src/pcan_ring.c
src/pcan_gas.c
)
add_library(protocan_transport STATIC ${PCAN_CORE_SOURCES})
target_include_directories(protocan_transport PUBLIC include)
option(PCAN_BUILD_SHARED "Build stable host ABI shared library" ON)
if(PCAN_BUILD_SHARED)
add_library(setcore SHARED ${PCAN_CORE_SOURCES})
target_include_directories(setcore PUBLIC include)
target_compile_definitions(setcore PRIVATE PCAN_ABI_BUILD_DLL)
set_target_properties(setcore PROPERTIES
C_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
OUTPUT_NAME setcore
)
endif()
if(MSVC)
target_compile_options(protocan_transport PRIVATE /W4)
else()
target_compile_options(protocan_transport PRIVATE -Wall -Wextra -Wpedantic)
endif()
if(TARGET setcore)
if(MSVC)
target_compile_options(setcore PRIVATE /W4)
else()
target_compile_options(setcore PRIVATE -Wall -Wextra -Wpedantic)
endif()
endif()
# Порт ports/stm32f4 сюда не входит: ему нужен CMSIS-заголовок stm32f4xx.h,
# он подключается напрямую в проект прошивки.
option(PCAN_BUILD_TESTS "Собирать тесты" ON)
if(PCAN_BUILD_TESTS)
enable_testing()
add_executable(test_transport tests/test_transport.c)
target_link_libraries(test_transport PRIVATE protocan_transport)
add_test(NAME transport COMMAND test_transport)
add_executable(test_abi tests/test_abi.c)
target_link_libraries(test_abi PRIVATE protocan_transport)
add_test(NAME abi COMMAND test_abi)
endif()

View File

@@ -1,149 +0,0 @@
# protocan-transport
Переносимая библиотека транспортного уровня для протокола **ProtoCAN**:
кадрирование поверх любого байтового потока (RS485, RS232, USB CDC),
разбор идентификатора и общее адресное пространство регистров.
Написана на C99, без динамической памяти, без ОС, без зависимостей от HAL
и от конкретного микроконтроллера. Состояние живёт в структурах вызывающего,
поэтому в одной прошивке поднимается сколько угодно независимых каналов.
```
ваш код protocan-transport платформа
┌────────┐ ┌────────────────────┐ ┌──────────────┐
│ кадры │─────►│ pcan_link_send() │─────►│ io.write() │──► UART/DMA
│ │◄─────│ on_frame() │◄─────│ pcan_link_feed()
└────────┘ └────────────────────┘ └──────────────┘
pcan_gas_* pcan_id_*
```
## Состав
| Модуль | Назначение |
|---|---|
| `pcan_frame` | кадр `AA 55 … CRC16` и потоковый разборщик с ресинхронизацией |
| `pcan_crc` | CRC-16/CCITT-FALSE, побитовый или табличный |
| `pcan_link` | экземпляр канала: приём, передача, SEQ, счётчики |
| `pcan_ring` | кольцевой буфер, отдаёт непрерывный участок для DMA |
| `pcan_id` | упаковка и разбор 29-битного идентификатора ProtoCAN |
| `pcan_gas` | общее адресное пространство: карта регионов, чтение/запись, мост к кадрам |
| `pcan_abi` | стабильный C ABI для Python, JNI, Swift и других FFI |
| `ports/stm32f4` | готовый порт USART + DMA (пакетная передача, кольцевой приём) |
| `ports/android` | JNI и Kotlin-фасад; собирает `libsetcore.so` из этого же C99-кода |
## Кадр
```
AA 55 | LEN | SEQ | FLAGS | ID0 ID1 ID2 ID3 | DATA[0..8] | CRC_L CRC_H
```
`LEN = 6 + DLC` (6..14), CRC-16/CCITT-FALSE по байтам `LEN..DATA`,
little-endian. Подробности — [docs/FRAME.md](docs/FRAME.md).
Полное описание прикладного ProtoCAN и общего адресного пространства теперь
также хранится здесь: [docs/PROTOCOL.md](docs/PROTOCOL.md) и
[docs/OAP.md](docs/OAP.md). Эталонные данные находятся в
`tests/vectors/test-vectors.json`. Это канонические документы; копии в SETCAN
считаются историческим снимком legacy HAL-адаптера.
## Общее адресное пространство
Плоское пространство 16-битных регистров `0x0000..0xFFFF`, собранное из
регионов. Регион ссылается либо на массив в памяти, либо на пару колбэков —
так в карту попадают и переменные, и вычисляемые значения, и регистры
периферии. Подробности — [docs/GAS.md](docs/GAS.md).
```c
static uint16_t holding[8];
static const pcan_gas_region_t regions[] = {
{ 0x0000, 8, holding, NULL, NULL, 0, NULL, "holding" },
{ 0xFF00, 4, NULL, diag_read, NULL, PCAN_GAS_RDONLY, NULL, "diag" },
};
static const pcan_gas_map_t map = { regions, 2 };
```
## Использование
```c
#include "protocan_transport.h"
static void on_frame(const pcan_frame_t *f, void *user)
{
/* ... */
}
pcan_io_t io;
pcan_uart_io(&uart, &io); /* или свой io */
pcan_link_t link;
pcan_link_init(&link, &io, on_frame, NULL);
pcan_frame_t f = { .flags = PCAN_FLAG_IDE, .id = 0x1234567, .dlc = 2 };
f.data[0] = 0xAA; f.data[1] = 0xBB;
pcan_link_send(&link, &f); /* SEQ проставится сам */
```
Для своей платформы достаточно реализовать две функции:
```c
size_t my_write(void *ctx, const uint8_t *data, size_t len); /* всё-или-ничего */
size_t my_space(void *ctx);
```
## Сборка
Библиотека — шесть файлов в `src/` и заголовки в `include/`. Добавьте их
в проект и укажите `include/` в путях поиска. CMake для тестов и хостовых
сборок:
```bash
cmake -B build && cmake --build build && ctest --test-dir build
```
Для desktop CMake дополнительно собирает shared library `setcore`
(`setcore.dll`, `libsetcore.so` или `libsetcore.dylib`). Публичная граница
для приложений описана в `include/pcan_abi.h`; внутренние структуры ядра через
FFI не экспортируются. Python-обёртка находится в `python/protocan/native.py`.
Android-проект подключает `ports/android/Android.mk` и добавляет
`ports/android/kotlin` в `sourceSets`. JNI-код занимается только преобразованием
типов и временем жизни parser context, а правила кадра и CAN ID остаются в C.
Если на Windows нет CMake, host-библиотеку тем же MSVC можно собрать так:
```powershell
python tools/build_host.py --output native/setcore.dll
```
Либо напрямую:
```bash
clang -std=c99 -Wall -Wextra -Iinclude tests/test_transport.c src/pcan_*.c -o test && ./test
```
Порт `ports/stm32f4` в тесты не входит: ему нужен CMSIS-заголовок
`stm32f4xx.h`, подключайте его в проект прошивки отдельно.
## Настройки
Переопределяются через `-D` либо через свой `pcan_config_user.h`
(с `-DPCAN_USE_USER_CONFIG`):
| Макрос | По умолчанию | Смысл |
|---|---|---|
| `PCAN_DATA_MAX` | 8 | длина поля данных CAN |
| `PCAN_CRC_TABLE` | 0 | 1 — таблица на 512 байт вместо побитового расчёта |
| `PCAN_GAS_MAX_REGIONS` | 16 | предел числа регионов в карте |
| `PCAN_BARRIER()` | барьер компилятора | для очередей, разделяемых с прерыванием |
## Ограничения
- Очереди рассчитаны на схему «один писатель + один читатель». Если
писателей несколько, оборачивайте вызовы своей блокировкой.
- Размер кольцевого буфера обязан быть степенью двойки; `pcan_ring_init()`
вернёт `false`, а не станет молча портить индексы.
- На STM32F407 DMA не видит CCM RAM (`0x10000000`) — буферы держите
в основном SRAM.
- Порядок байт на линии фиксирован (little-endian) и не зависит от порядка
байт хоста.

View File

@@ -1,28 +1,84 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(set_protocol C) project(setprotocol C)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
add_library(set_protocol STATIC # SET protocol v2: управление, телеметрия, CAN segmentation и firmware flow.
set(SETPROTOCOL_V2_SOURCES
src/set_protocol.c src/set_protocol.c
src/set_can.c src/set_can.c
src/set_firmware.c src/set_firmware.c
src/set_telemetry.c src/set_telemetry.c
) )
target_include_directories(set_protocol PUBLIC include) # Совместимые ProtoCAN/SETGUI v1 форматы переходного периода.
set(SETPROTOCOL_LEGACY_SOURCES
src/gui_catalog.c
src/gui_frame.c
src/pcan_abi.c
src/pcan_crc.c
src/pcan_frame.c
src/pcan_gas.c
src/pcan_id.c
src/pcan_link.c
src/pcan_ring.c
)
if(MSVC) set(SETPROTOCOL_SOURCES
target_compile_options(set_protocol PRIVATE /W4 /WX) ${SETPROTOCOL_V2_SOURCES}
else() ${SETPROTOCOL_LEGACY_SOURCES}
target_compile_options(set_protocol PRIVATE -Wall -Wextra -Wpedantic -Werror) )
add_library(setprotocol_static STATIC ${SETPROTOCOL_SOURCES})
target_include_directories(setprotocol_static PUBLIC include)
# Совместимое имя цели для проектов, уже использовавших SET protocol v2.
add_library(set_protocol ALIAS setprotocol_static)
option(SETP_BUILD_SHARED "Build stable host ABI shared library" ON)
if(SETP_BUILD_SHARED)
add_library(setprotocol SHARED ${SETPROTOCOL_SOURCES})
target_include_directories(setprotocol PUBLIC include)
target_compile_definitions(setprotocol PRIVATE PCAN_ABI_BUILD_DLL)
set_target_properties(setprotocol PROPERTIES
C_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
OUTPUT_NAME setprotocol
)
endif() endif()
function(setprotocol_warnings target)
if(MSVC)
target_compile_options(${target} PRIVATE /W4)
else()
target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic)
endif()
endfunction()
setprotocol_warnings(setprotocol_static)
if(TARGET setprotocol)
setprotocol_warnings(setprotocol)
endif()
# JNI/CMSIS-порты подключаются целевым проектом и в host CMake не входят.
option(SETP_BUILD_TESTS "Build host tests" ON) option(SETP_BUILD_TESTS "Build host tests" ON)
if(SETP_BUILD_TESTS) if(SETP_BUILD_TESTS)
enable_testing() enable_testing()
add_executable(test_set_protocol tests/test_set_protocol.c) add_executable(test_set_protocol tests/test_set_protocol.c)
target_link_libraries(test_set_protocol PRIVATE set_protocol) target_link_libraries(test_set_protocol PRIVATE setprotocol_static)
add_test(NAME set_protocol COMMAND test_set_protocol) add_test(NAME set_protocol_v2 COMMAND test_set_protocol)
add_executable(test_transport tests/test_transport.c)
target_link_libraries(test_transport PRIVATE setprotocol_static)
add_test(NAME legacy_transport COMMAND test_transport)
add_executable(test_gui tests/test_gui.c)
target_link_libraries(test_gui PRIVATE setprotocol_static)
add_test(NAME legacy_gui COMMAND test_gui)
add_executable(test_abi tests/test_abi.c)
target_link_libraries(test_abi PRIVATE setprotocol_static)
add_test(NAME stable_abi COMMAND test_abi)
endif() endif()

View File

@@ -1,75 +1,81 @@
# set-protocol # SETProtocol
Единый переносимый протокол SET для новых устройств и SETGUI. Один и тот же Единое переносимое протокольное ядро SET для `SETGUI`, Android GUI, устройств
прикладной кадр используется для управления, чтения общей карты, потоковой и сервисных утилит. В одном C99-проекте собраны:
телеметрии и безопасной передачи прошивки через:
- RS-232 и RS-485; - SET protocol v2 для управления, карты данных, телеметрии и firmware flow;
- USB CDC; - совместимый ProtoCAN transport для существующих CAN-мостов;
- CAN с сегментацией; - SETGUI transport v1 для приборов переходного периода;
- Ethernet TCP; - стабильный host ABI для Python/JNI/других FFI;
- Ethernet UDP, когда нужен обмен без соединения. - GAS, кольцевые буферы, CRC и потоковые parser.
Протокол не привязан к HAL, ОС или микроконтроллеру. Реализация на C99 не Ядро не зависит от HAL, ОС или конкретного адаптера, не использует
использует динамическую память. Все многобайтные значения little-endian. динамическую память и не открывает COM/CAN само. SLCAN, SocketCAN, USB CDC,
TCP, UART/DMA и аппаратный CAN подключаются портами.
## Что уже реализовано ## Структура
| Файл | Назначение | | Каталог | Назначение |
|---|---| |---|---|
| `set_protocol.*` | кадр v2, CRC32, потоковый parser, статусы ответов | | `include/set_*.h` | публичный SET protocol v2 |
| `set_can.*` | extended CAN ID, сегментация, flow-control и reassembly timeout | | `include/pcan_*.h`, `gui_*.h` | совместимые ProtoCAN/GUI v1 модули |
| `set_firmware.*` | BEGIN/DATA/END/STATUS, resume, CRC блока, SHA-256 и подпись | | `include/setprotocol.h` | единая C99-точка включения |
| `set_telemetry.*` | подписки и типизированные push-пакеты с timestamp | | `include/setprotocol_abi.h` | стабильная FFI-точка включения ABI v1 |
| `PROTOCOL.md` | обязательный wire-контракт и привязки к носителям | | `src/` | общая реализация всех протокольных модулей |
| `MIGRATION.md` | порядок перехода SETGUI и существующих прошивок с v1 | | `ports/android` | JNI и Kotlin facade |
| `PORTING.md` | подключение UART, CAN, USB и Ethernet | | `ports/stm32f4` | UART/DMA port для legacy byte stream |
| `tests/` | host-тесты и фиксированный эталонный кадр | | `docs/SETPROTOCOL.md` | архитектура, ABI, память и переносимость |
| `docs/legacy` | нормативные документы ProtoCAN/SETGUI v1 |
Файл [`PROTOCOL.md`](PROTOCOL.md) является источником истины. Числа из него | `PROTOCOL.md` | нормативный wire contract SET protocol v2 |
нельзя менять без выпуска следующей версии протокола. | `MIGRATION.md` | переход с v1/ProtoCAN на v2 |
| `PORTING.md` | подключение новых транспортов и платформ |
## Минимальный stream-приёмник
```c
#include "set_protocol.h"
static setp_parser_t parser;
static void on_frame(const setp_frame_t *frame, void *user)
{
(void)user;
/* frame->payload действует только до возврата из callback. */
}
void protocol_init(void)
{
setp_parser_init(&parser);
}
void protocol_feed(const uint8_t *data, uint16_t length)
{
(void)setp_parser_feed(&parser, data, length, on_frame, NULL);
}
```
Для RS-232, RS-485, USB CDC и TCP в parser передаются любые принятые chunks.
Для UDP один UDP payload должен содержать ровно один полный SETP-кадр.
## Сборка ## Сборка
```text ```bash
cmake -B build cmake -S c/set-protocol -B build/setprotocol -DSETP_BUILD_TESTS=ON
cmake --build build cmake --build build/setprotocol --config Release
ctest --test-dir build ctest --test-dir build/setprotocol -C Release --output-on-failure
``` ```
Либо добавьте три файла из `src/` и каталог `include/` непосредственно в CMake создаёт:
проект прошивки.
## Версии - `setprotocol_static` — статическое C99-ядро;
- совместимую CMake-цель `set_protocol`;
- `setprotocol.dll`, `libsetprotocol.so` или `libsetprotocol.dylib`;
- тесты SET v2, ProtoCAN transport, GUI v1 и ABI.
- GUI protocol v1 остаётся только переходным форматом старых устройств. Упрощённая host-сборка:
- Все новые устройства используют SET protocol v2 (`SETP_VERSION = 2`).
- v1 и v2 имеют одинаковый SOF `A5 5A`, поэтому номер версии проверяется до ```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
```
## Подключение в C
Для всего ядра:
```c
#include "setprotocol.h"
```
Для минимальной прошивки можно подключать только нужные заголовки и исходники.
Например, новый v2 stream parser использует `set_protocol.*`, а legacy
CAN-мост — `pcan_frame.*`, `pcan_crc.*` и `pcan_id.*`.
FFI-клиенты подключают `setprotocol_abi.h`. Имена функций `pcan_abi_*`
сохраняются в ABI v1 для бинарной совместимости; переименование символов без
повышения версии ABI запрещено.
## Версии wire format
- SET protocol v2 — основной формат новых устройств.
- SETGUI v1 и ProtoCAN bridge остаются поддерживаемыми на время миграции.
- Одинаковый SOF `A5 5A` у GUI v1 и SET v2 различается полем версии.
- Изменение wire contract требует новой версии и тестовых векторов.
Полная интерактивная документация: [`../../doc/setprotocol.html`](../../doc/setprotocol.html).

View File

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

View File

@@ -6,7 +6,7 @@
* оператор отмечает нужное, и прибор шлёт только отмеченное пакетами. * оператор отмечает нужное, и прибор шлёт только отмеченное пакетами.
* Схема повторяет реестр регистров ST Motor Control Workbench. * Схема повторяет реестр регистров ST Motor Control Workbench.
* *
* Двоичный контракт: docs/GUI_CATALOG.md. * Двоичный контракт: docs/legacy/GUI_CATALOG.md.
* Зеркало на Python: gui_desktop/core/gas_catalog.py. * Зеркало на Python: gui_desktop/core/gas_catalog.py.
*/ */
#ifndef GUI_CATALOG_H #ifndef GUI_CATALOG_H

View File

@@ -14,7 +14,7 @@
* устройствами. * устройствами.
* *
* Запрос на чтение кодируется кадром GAS с DLC = 0: в исходном коде * Запрос на чтение кодируется кадром GAS с DLC = 0: в исходном коде
* SETCAN такой кодировки нет, это расширение - см. docs/GAS.md. * SETCAN такой кодировки нет, это расширение - см. docs/legacy/GAS.md.
*/ */
#ifndef PCAN_GAS_H #ifndef PCAN_GAS_H
#define PCAN_GAS_H #define PCAN_GAS_H

View File

@@ -0,0 +1,19 @@
/**
* @file setprotocol.h
* @brief Единственная C99-точка включения полного SETProtocol.
*/
#ifndef SETPROTOCOL_H
#define SETPROTOCOL_H
/* Основной SET protocol v2. */
#include "set_protocol.h"
#include "set_can.h"
#include "set_firmware.h"
#include "set_telemetry.h"
/* Поддерживаемые форматы переходного периода. */
#include "protocan_transport.h"
#include "gui_frame.h"
#include "gui_catalog.h"
#endif /* SETPROTOCOL_H */

View File

@@ -0,0 +1,15 @@
/**
* @file setprotocol_abi.h
* @brief Стабильная FFI-граница SETProtocol ABI v1.
*
* Имена pcan_abi_* сохранены ради бинарной совместимости существующих
* SETGUI и Android-клиентов. Новые ABI-группы добавляются через этот facade.
*/
#ifndef SETPROTOCOL_ABI_H
#define SETPROTOCOL_ABI_H
#include "pcan_abi.h"
#define SETPROTOCOL_ABI_VERSION PCAN_ABI_VERSION
#endif /* SETPROTOCOL_ABI_H */

View File

@@ -1,9 +1,14 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := setcore LOCAL_MODULE := setprotocol
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include
LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \
../../src/set_protocol.c \
../../src/set_can.c \
../../src/set_firmware.c \
../../src/set_telemetry.c \
../../src/gui_catalog.c \
../../src/gui_frame.c \ ../../src/gui_frame.c \
../../src/pcan_abi.c \ ../../src/pcan_abi.c \
../../src/pcan_crc.c \ ../../src/pcan_crc.c \
@@ -12,7 +17,7 @@ LOCAL_SRC_FILES := \
../../src/pcan_link.c \ ../../src/pcan_link.c \
../../src/pcan_ring.c \ ../../src/pcan_ring.c \
../../src/pcan_gas.c \ ../../src/pcan_gas.c \
setcore_jni.c setprotocol_jni.c
LOCAL_CFLAGS := -std=c99 -Wall -Wextra -Wpedantic -fvisibility=hidden LOCAL_CFLAGS := -std=c99 -Wall -Wextra -Wpedantic -fvisibility=hidden
LOCAL_LDLIBS := -llog LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,7 +1,7 @@
# Android port # Android port
`Android.mk` builds `libsetcore.so` from the same C99 sources used by MCU and `Android.mk` builds `libsetprotocol.so` from the same C99 sources used by MCU
desktop builds. `setcore_jni.c` contains only JNI marshalling; protocol rules and desktop builds. `setprotocol_jni.c` contains only JNI marshalling; protocol rules
remain in the core. Add the Kotlin directory as an Android source directory remain in the core. Add the Kotlin directory as an Android source directory
and include this `Android.mk` from the application NDK build. and include this `Android.mk` from the application NDK build.

View File

@@ -1,10 +1,10 @@
package ru.setcorp.setcore package ru.setcorp.setprotocol
/** Thin Kotlin facade over the shared C99 ProtoCAN core. */ /** Thin Kotlin facade over the shared C99 SETProtocol core. */
object NativeProtoCan { object NativeSetProtocol {
val available: Boolean by lazy { val available: Boolean by lazy {
runCatching { runCatching {
System.loadLibrary("setcore") System.loadLibrary("setprotocol")
nativeAbiVersion() == 1 nativeAbiVersion() == 1
}.getOrDefault(false) }.getOrDefault(false)
} }

View File

@@ -3,7 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "pcan_abi.h" #include "setprotocol_abi.h"
typedef struct { typedef struct {
uint8_t *storage; uint8_t *storage;
@@ -18,7 +18,7 @@ typedef struct {
} android_gui_parser_t; } android_gui_parser_t;
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeAbiVersion(JNIEnv *env, jobject self) Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeAbiVersion(JNIEnv *env, jobject self)
{ {
(void)env; (void)env;
(void)self; (void)self;
@@ -26,7 +26,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeAbiVersion(JNIEnv *env, jobject sel
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativePackId( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativePackId(
JNIEnv *env, jobject self, jint priority, jint route, jint device_type, JNIEnv *env, jobject self, jint priority, jint route, jint device_type,
jint device_id, jint message_type, jint body) jint device_id, jint message_type, jint body)
{ {
@@ -38,7 +38,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativePackId(
} }
JNIEXPORT jintArray JNICALL JNIEXPORT jintArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeUnpackId( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeUnpackId(
JNIEnv *env, jobject self, jlong raw) JNIEnv *env, jobject self, jlong raw)
{ {
(void)self; (void)self;
@@ -56,7 +56,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeUnpackId(
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeCrc16( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCrc16(
JNIEnv *env, jobject self, jbyteArray input) JNIEnv *env, jobject self, jbyteArray input)
{ {
(void)self; (void)self;
@@ -71,7 +71,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeCrc16(
} }
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeEncodeFrame( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeEncodeFrame(
JNIEnv *env, jobject self, jint sequence, jint flags, jlong can_id, JNIEnv *env, jobject self, jint sequence, jint flags, jlong can_id,
jbyteArray input) jbyteArray input)
{ {
@@ -103,7 +103,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeEncodeFrame(
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeCreateParser(JNIEnv *env, jobject self) Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCreateParser(JNIEnv *env, jobject self)
{ {
(void)env; (void)env;
(void)self; (void)self;
@@ -124,7 +124,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeCreateParser(JNIEnv *env, jobject s
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeDestroyParser( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeDestroyParser(
JNIEnv *env, jobject self, jlong handle) JNIEnv *env, jobject self, jlong handle)
{ {
(void)env; (void)env;
@@ -138,7 +138,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeDestroyParser(
/* Each returned record is 15 bytes: seq, flags, id LE, dlc, data[8]. */ /* Each returned record is 15 bytes: seq, flags, id LE, dlc, data[8]. */
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeFeedParser( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeFeedParser(
JNIEnv *env, jobject self, jlong handle, jbyteArray input) JNIEnv *env, jobject self, jlong handle, jbyteArray input)
{ {
(void)self; (void)self;
@@ -194,7 +194,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeFeedParser(
} }
JNIEXPORT jintArray JNICALL JNIEXPORT jintArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeParserStats( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeParserStats(
JNIEnv *env, jobject self, jlong handle) JNIEnv *env, jobject self, jlong handle)
{ {
(void)self; (void)self;
@@ -214,7 +214,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeParserStats(
} }
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeGuiEncode( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGuiEncode(
JNIEnv *env, jobject self, jint message_type, jint sequence, JNIEnv *env, jobject self, jint message_type, jint sequence,
jbyteArray input) jbyteArray input)
{ {
@@ -237,7 +237,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeGuiEncode(
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeCreateGuiParser(JNIEnv *env, jobject self) Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeCreateGuiParser(JNIEnv *env, jobject self)
{ {
(void)env; (void)self; (void)env; (void)self;
android_gui_parser_t *parser = (android_gui_parser_t *)calloc(1U, sizeof *parser); android_gui_parser_t *parser = (android_gui_parser_t *)calloc(1U, sizeof *parser);
@@ -252,7 +252,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeCreateGuiParser(JNIEnv *env, jobjec
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeDestroyGuiParser( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeDestroyGuiParser(
JNIEnv *env, jobject self, jlong handle) JNIEnv *env, jobject self, jlong handle)
{ {
(void)env; (void)self; (void)env; (void)self;
@@ -262,7 +262,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeDestroyGuiParser(
/* Records: type[1], sequence LE[2], size LE[2], payload[size]. */ /* Records: type[1], sequence LE[2], size LE[2], payload[size]. */
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeFeedGuiParser( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeFeedGuiParser(
JNIEnv *env, jobject self, jlong handle, jbyteArray input) JNIEnv *env, jobject self, jlong handle, jbyteArray input)
{ {
(void)self; (void)self;
@@ -300,7 +300,7 @@ Java_ru_setcorp_setcore_NativeProtoCan_nativeFeedGuiParser(
} }
JNIEXPORT jintArray JNICALL JNIEXPORT jintArray JNICALL
Java_ru_setcorp_setcore_NativeProtoCan_nativeGuiParserStats( Java_ru_setcorp_setprotocol_NativeSetProtocol_nativeGuiParserStats(
JNIEnv *env, jobject self, jlong handle) JNIEnv *env, jobject self, jlong handle)
{ {
(void)self; (void)self;

View File

@@ -1,4 +1,4 @@
"""Build the SETCore shared library without imposing one host toolchain. """Build the SETProtocol shared library without imposing one host toolchain.
CMake remains the primary build. On a Windows workstation where CMake is CMake remains the primary build. On a Windows workstation where CMake is
absent, the script locates Visual Studio and invokes MSVC directly. Unix-like absent, the script locates Visual Studio and invokes MSVC directly. Unix-like
@@ -19,8 +19,10 @@ ROOT = Path(__file__).resolve().parent.parent
INCLUDE = ROOT / "include" INCLUDE = ROOT / "include"
SOURCES = [ SOURCES = [
ROOT / "src" / name for name in ( ROOT / "src" / name for name in (
"gui_frame.c", "pcan_abi.c", "pcan_crc.c", "pcan_frame.c", "pcan_id.c", "set_protocol.c", "set_can.c", "set_firmware.c", "set_telemetry.c",
"pcan_link.c", "pcan_ring.c", "pcan_gas.c", "gui_catalog.c", "gui_frame.c", "pcan_abi.c", "pcan_crc.c",
"pcan_frame.c", "pcan_id.c", "pcan_link.c", "pcan_ring.c",
"pcan_gas.c",
) )
] ]
@@ -48,7 +50,7 @@ def _build_msvc(output: Path, build_dir: Path) -> None:
if vcvars is None: if vcvars is None:
raise SystemExit("Visual Studio C++ tools were not found") raise SystemExit("Visual Studio C++ tools were not found")
quoted_sources = " ".join(f'"{source}"' for source in SOURCES) quoted_sources = " ".join(f'"{source}"' for source in SOURCES)
import_library = build_dir / "setcore.lib" import_library = build_dir / "setprotocol.lib"
command = ( command = (
f'call "{vcvars}" && cl /nologo /W4 /std:c11 ' f'call "{vcvars}" && cl /nologo /W4 /std:c11 '
f'/DPCAN_ABI_BUILD_DLL /I"{INCLUDE}" /LD {quoted_sources} ' f'/DPCAN_ABI_BUILD_DLL /I"{INCLUDE}" /LD {quoted_sources} '
@@ -75,7 +77,7 @@ def main() -> int:
args = parser.parse_args() args = parser.parse_args()
output = args.output.resolve() output = args.output.resolve()
output.parent.mkdir(parents=True, exist_ok=True) output.parent.mkdir(parents=True, exist_ok=True)
build_dir = output.parent / ".setcore-build" build_dir = output.parent / ".setprotocol-build"
build_dir.mkdir(parents=True, exist_ok=True) build_dir.mkdir(parents=True, exist_ok=True)
if platform.system() == "Windows": if platform.system() == "Windows":
_build_msvc(output, build_dir) _build_msvc(output, build_dir)

View File

@@ -0,0 +1,32 @@
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$outputPath = Join-Path $PSScriptRoot 'setprotocol.html'
$sourcePath = Join-Path $PSScriptRoot '..\c\set-protocol\docs\SETPROTOCOL.md'
$markdown = Get-Content -Raw -LiteralPath $sourcePath -Encoding UTF8
$html = (ConvertFrom-Markdown -InputObject $markdown).Html
$generatedBlock = @"
<!-- SETPROTOCOL:START -->
<article class="card full-doc" data-source="c/set-protocol/docs/SETPROTOCOL.md">
$html
</article>
<!-- SETPROTOCOL:END -->
"@
$page = Get-Content -Raw -LiteralPath $outputPath -Encoding UTF8
$pattern = '(?s)<!-- SETPROTOCOL:START -->.*?<!-- SETPROTOCOL:END -->'
if ($page -notmatch $pattern) {
throw 'Не найдены маркеры SETPROTOCOL:START/END в doc/setprotocol.html.'
}
$page = [regex]::Replace($page, $pattern, [System.Text.RegularExpressions.MatchEvaluator]{
param($match)
$generatedBlock
}, 1)
$page = $page.TrimEnd("`r", "`n") + [Environment]::NewLine
$utf8WithoutBom = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText($outputPath, $page, $utf8WithoutBom)
Write-Host "[DONE] SETProtocol HTML: $outputPath"

File diff suppressed because one or more lines are too long

608
doc/setprotocol.html Normal file

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More