# Портирование firmware-info ## Назначение и границы Это C-библиотека описания работающего образа: SemVer, дата/время компиляции, 8 символов build ID и сериализация контракта v1. Она не обращается к сети, не читает версию из сервера и не записывает Flash. HAL, RTOS, UART и CAN ядру не нужны. Отправку результата выполняет приложение. Для размещения `.hex/.bin` в каталоге SETGUI уже существуют [`setprotocol.firmware_publish`](../../python/setprotocol/firmware_publish.py) и [`tools/firmware-publish`](../../tools/firmware-publish/README.md). Связь компонентов и перенос публикации описаны в [`tools/firmware-publish/PORTING.md`](../../tools/firmware-publish/PORTING.md). ## 1. Файлы и конфигурация Пример ниже предполагает `lib/templates` внутри нового проекта: ```text project/ inc/firmware_info_config.h generated/firmware_build_id.h # создаётся до сборки lib/templates/c/firmware-info/ src/ ``` Добавьте в сборку оба файла: ```text lib/templates/c/firmware-info/src/firmware_info.c lib/templates/c/firmware-info/src/firmware_info_port.c ``` В include path добавьте `inc`, `generated` и `lib/templates/c/firmware-info/include`. Встроенный `CMakeLists.txt` собирает только ядро и host-тест; `firmware_info_port.c` и каталоги конфигурации нужно добавлять к целевому firmware target самостоятельно. Скопируйте `ports//firmware_info_config.template.h` как `inc/firmware_info_config.h`. Есть варианты STM32F1/F4/G4 и К1921ВК028; они не содержат регистров МК. Для другого МК с обычными 8-битными байтами достаточно такого же config: ```c #ifndef FIRMWARE_INFO_CONFIG_H #define FIRMWARE_INFO_CONFIG_H #define FIRMWARE_VERSION_MAJOR 1U #define FIRMWARE_VERSION_MINOR 2U #define FIRMWARE_VERSION_PATCH 3U #include "firmware_build_id.h" #endif ``` Обязательный include в этом примере позволяет обнаружить пропущенный pre-build. В готовых шаблонах include опциональный через `__has_include`; если заголовок не подключён, порт использует `LOCALDEV`. Для компилятора без `__has_include` используйте явный include. Можно связать три версии с существующими макросами проекта, как это сделано в `KONOR_ds18b20/inc/firmware_info_config.h`. ## 2. Build ID Из корня нового проекта перед компиляцией запустите: ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File "lib/templates/c/firmware-info/tools/make_build_id.ps1" -Repository "." -Output "generated/firmware_build_id.h" ``` Указывайте `-Repository` и `-Output` явно: расположение сабмодуля и рабочий каталог IDE различаются между проектами. `-Repository` должен указывать на исходники прошивки, а не на репозиторий `templates`. Для Keil из каталога `mdk` соответственно используйте `..\lib\templates\...`, `-Repository ".."` и `-Output ".\Generated\firmware_build_id.h"`. При доступном Git чистый checkout получает 8 знаков commit, изменения tracked файлов — 7 знаков и `+`. Если commit определить нельзя, используется `NOGIT000`. Новые untracked-файлы текущий генератор при определении dirty не учитывает. Дата/время берутся из `__DATE__`/`__TIME__` при компиляции `firmware_info_port.c`; для выпуска выполняйте полный Rebuild, чтобы не оставить старый объектный файл. ## 3. Обработчик запроса версии Пример функции подготовки полезной нагрузки, вызываемой вашим обработчиком: ```c #include "firmware_info_port.h" firmware_info_status_t app_make_firmware_info(uint8_t *payload, size_t capacity) { firmware_info_t info; firmware_info_status_t status = firmware_info_port_describe(&info); if (status != FIRMWARE_INFO_OK) return status; return firmware_info_to_le_bytes(&info, payload, capacity); } ``` При успехе передайте ровно `FIRMWARE_INFO_PAYLOAD_SIZE` (24) байта в собственный транспорт. При ошибке верните ошибку протокола, а не содержимое буфера. Не отправляйте `sizeof(firmware_info_t)`: структура не является wire format. В KONOR обработчик `app_send_firmware_info()` отвечает на `PROTO_MSG_FIRMWARE_INFO = 0x03`, сохраняя sequence запроса. Старый 32-байтовый `DEVICE_INFO` остаётся отдельным сообщением. Для нового протокола сначала согласуйте команду с клиентом: подключение библиотеки само по себе не добавит декодер и отображение версии в GUI. Для Modbus вызовите `firmware_info_to_registers()` с массивом из 12 `uint16_t` и разместите его в выбранной карте регистров. Адреса и Modbus-порядок байтов обеспечивает ваш Modbus-стек; LE-буфер в Modbus напрямую не копируйте. ## 4. Контракт v1 | Индекс слова | Содержимое | |---|---| | 0 | Версия контракта: 1 | | 1, 2, 3 | major, minor, patch | | 4 | Год | | 5 | `(month << 8) \| day` | | 6 | `(hour << 8) \| minute` | | 7 | Секунды | | 8–11 | По два ASCII-символа build ID: первый в старшем байте слова | В LE-представлении младший байт каждого слова идёт первым. Например, build ID `ab` в начале строки даёт слово `0x6162`, но байты `62 61`; декодируйте сначала слово, затем символы из старшего/младшего байта. NUL-терминатор не передаётся. Текущая проверка допускает major/minor до 255 и patch до 999. Если в каталоге используется `(major << 16) | (minor << 8) | patch`, ограничьте **все три** части до 255, иначе значения пересекутся. Версия каталога автоматически из C-config не извлекается. Для C2000 с 16-битным `char` нельзя считать готовым байтовый порт: отдельно проверьте наличие `uint8_t` и представление октетов в транспорте. Публикация TMS SCI8-файла с ПК поддерживается независимо от переноса этой C-библиотеки. ## 5. Проверка переноса 1. Соберите host-тест из `tests/test_firmware_info.c` вместе с ядром либо используйте CMake/CTest. Он проверяет дату, регистры и порядок байтов build ID. 2. Соберите целевую прошивку с обоими `.c` и сгенерированным заголовком. 3. Запросите версию у устройства: сравните SemVer, build ID, время и 24-байтовый ответ с конкретной сборкой. Проверьте, что прежний `DEVICE_INFO` не изменился. 4. Подключите выпуск по инструкции публикатора; сравните версию в config и `firmware-release.cmd` перед Rebuild и `--preflight`.