145 lines
8.4 KiB
Markdown
145 lines
8.4 KiB
Markdown
# Портирование 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/<mcu>/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`.
|