Добавить протокол Altera Logic и общие клиенты прошивки

This commit is contained in:
2026-09-19 07:12:09 +03:00
parent def3eb08f3
commit 80ba17d77d
38 changed files with 3271 additions and 10 deletions

View File

@@ -0,0 +1,178 @@
# База прошивок как в SETGUI
Это общий сервис **базы файлов прошивок**: получить список опубликованных
образов, выбрать изделие/версию/транспорт, скачать файл, проверить SHA-256 и
передать его загрузчику. Также можно опубликовать новый образ в эту же базу.
Модуль не зависит от версии самого приложения и от `c/firmware-info`.
## Состав
| Файл | Ответственность |
|---|---|
| [`firmware_database.py`](../../python/setprotocol/firmware_database.py) | Готовый HTTPS-клиент, чтение базы, кэш скачанных образов, публикация в Gitea |
| [`firmware_catalog.py`](../../python/setprotocol/firmware_catalog.py) | Общий формат записей базы, используемый SETGUI |
| [`firmware_publish.py`](../../python/setprotocol/firmware_publish.py) | Метаданные образа, SHA-256, объединение записей каталога |
| [`firmware_db.py`](firmware_db.py) | Самостоятельный консольный запуск без SETGUI |
Требования: Python 3.10+ и стандартная библиотека. Qt, Windows Credential
Manager, установленный SETGUI и библиотеки МК не требуются. Это сервис и CLI;
готовое Qt-окно остаётся в SETGUI, а другой GUI подключает сервис по API ниже.
## Как устроена база
В текущей конфигурации SETGUI файлы находятся в Gitea Releases репозитория
`setcorp/SETRD12-Releases` на `https://git.rd12.ru`. Список файлов лежит в
`firmware.releases` файла `update.json` ветки `main`. Запись содержит изделие,
версию, транспорт, адрес образа, имя файла, SHA-256, описание и необязательный
адрес приложения во Flash. Это файловый каталог; SQL-сервер не нужен.
Новый сервис использует тот же JSON-контракт, поэтому выпуски видны клиентам
SETGUI, поддерживающим указанный транспорт. В текущем SETGUI транспорт `tms`
фильтруется; общий сервис его сохраняет. Публикация не добавляет новый
загрузочный протокол в приложение или МК.
```text
публикация .hex/.bin → Gitea release asset → скачать и проверить SHA-256
обновить firmware.releases
GUI: «Обновить каталог» → выбрать запись → «Скачать и выбрать» → загрузчик МК
```
Для своего сервера задайте `server`, `owner`, `repository`, `branch` и
`manifest_path`. Репозиторий, ветка и JSON-файл должны уже существовать.
Для пустой базы достаточно файла `{"firmware":{"catalogVersion":0,"releases":[]}}`.
Если `update.json` общий с обновлениями приложения, его другие разделы
сохраняются при добавлении прошивки.
## Консоль: проверить, опубликовать, посмотреть, скачать
Из корня `templates` в PowerShell (параметры сервера стоят перед командой):
```powershell
$db = @('--server', 'https://git.rd12.ru', '--owner', 'setcorp', '--repo', 'SETRD12-Releases')
# Без сети: проверить файл и сформировать запись каталога.
python tools/firmware-publish/firmware_db.py @db preflight --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000
# Публикация образа в базу (изменяет сервер).
python tools/firmware-publish/firmware_db.py @db publish --file C:/build/device.hex --product MY_DEVICE --version 1.2.3 --version-code 0x010203 --transport can --base-address 0x08003000
# Получить список записей и скачать конкретную.
python tools/firmware-publish/firmware_db.py @db list --product MY_DEVICE
python tools/firmware-publish/firmware_db.py @db download --product MY_DEVICE --version-code 0x010203 --transport can --cache C:/firmware-cache
```
`MY_DEVICE`, версия, транспорт и адрес — примеры, замените их данными изделия.
SCI8 для TMS публикуйте как `.bin` с `--transport tms`, без `--base-address`.
Инструмент не конвертирует `.axf/.out` и не проверяет пригодность образа для МК.
CLI читает логин и пароль/токен из переменных окружения `FIRMWARE_DB_LOGIN` и
`FIRMWARE_DB_PASSWORD`. Задавайте их средствами своего секрет-хранилища/CI,
а не в файлах проекта и не в аргументах командной строки. Для интерактивного
ввода в PowerShell можно использовать:
```powershell
$fwCredential = Get-Credential -Message 'Gitea: логин и пароль либо токен вместо пароля'
$env:FIRMWARE_DB_LOGIN = $fwCredential.UserName
$env:FIRMWARE_DB_PASSWORD = $fwCredential.GetNetworkCredential().Password
# Выполнить нужные команды; после работы убрать переменные из текущего процесса.
Remove-Item Env:FIRMWARE_DB_LOGIN, Env:FIRMWARE_DB_PASSWORD
```
Публичный каталог можно читать без входа. Публикация через CLI требует обе
переменные. Сервис не извлекает сохранённый пароль SETGUI автоматически.
Команда `publish` явно разрешает запись и не запрашивает дополнительного
подтверждения; `preflight` ничего не загружает. Старый BAT и конфигурации
`firmware-release.cmd` продолжают использовать прежний путь через SETGUI.
## Портирование в другое Python-приложение
Подключите `templates/python` в import path приложения; переносите зависимость
целиком, не одну копию файла. Сеть и кэш реализованы в сервисе, UI и хранение
учётных данных задаёт приложение:
```python
from pathlib import Path
from setprotocol.firmware_database import (
Credentials, FirmwareDatabase, GiteaRepository, GiteaFirmwarePublisher,
)
from setprotocol.firmware_publish import FirmwarePublication
repo = GiteaRepository('https://git.rd12.ru', 'setcorp', 'SETRD12-Releases')
# login и password получает ваше приложение из формы/хранилища.
credentials = Credentials(login, password)
database = FirmwareDatabase(repo.manifest_url, Path('firmware'), credentials=credentials)
# «Обновить каталог»: результат заполнит список в вашем UI.
releases = database.read_catalog(product='MY_DEVICE', transport='can')
# После выбора пользователем строки списка:
selected = releases[selected_index]
path = database.download(selected, progress=lambda percent: print(percent))
# Передайте path, selected.transport и selected.base_address своему загрузчику.
# Публикация нового образа: отдельное действие оператора.
publisher = GiteaFirmwarePublisher(repo, credentials)
publication = FirmwarePublication(
Path('build/device.hex'), 'MY_DEVICE', '1.2.3', 0x010203, 'can', 0x08003000,
'Описание выпуска',
)
preview = publisher.preflight(publication) # можно показать перед выпуском
entry = publisher.publish(publication)
```
Для публичного каталога передайте `credentials=None`. Для чтения каталога,
расположенного вне стандартного Gitea URL, передайте его HTTPS-адрес прямо в
`FirmwareDatabase`; `GiteaRepository` нужен сетевому публикатору.
В Qt выполняйте `read_catalog`, `download`, `publish` в worker/QThread,
передавайте прогресс сигналами в главный поток. По аналогии с SETGUI:
1. Кнопка «Обновить каталог» вызывает `read_catalog`, заполняет combo/table.
2. В строке показываются `product`, `version`, `transport`; в деталях —
`file_name`, `notes`, `base_address`.
3. «Скачать и выбрать» вызывает `download`, возвращает проверенный путь.
4. Сигнал в основное окно передаёт путь и выбранную `FirmwareRelease`;
окно выставляет файл и транспорт на вкладке прошивки.
Скачивание не запускает прошивку устройства автоматически. Для C++/Android
можно использовать CLI как отдельный процесс на ПК или реализовать клиент
этого JSON-контракта на языке платформы; Python-модуль не является C-библиотекой.
## Поведение и ошибки
- Кэш: `<cache>/<sha256>/<fileName>`. Одинаковые имена разных образов не
конфликтуют. Проверенный кэш используется повторно; незавершённые временные
файлы удаляются. Результат появляется только после совпадения SHA-256.
- Только HTTPS. Учётные данные отправляются лишь исходному origin (схема,
хост, порт); на сторонний CDN и при смене origin в redirect не передаются.
Redirect для запросов записи отклоняется.
- Публикация использует asset с SHA-256 в имени: новые байты не заменяют файл,
на который ещё ссылается старый каталог. `fileName` в каталоге остаётся
исходным именем. В этом деталь реализации отличается от старого публикатора
SETGUI, но формат каталога совместим.
- Каталог меняется только после обратного скачивания образа. Запись проверяет
ревизию файла (`sha`). При конфликте операция завершается ошибкой: повторите
выпуск после проверки причины. Загруженный asset может остаться без записи
каталога; повторный запуск использует его и снова проверит скачивание.
- Повтор той же записи не увеличивает `catalogVersion`. Обновление одного
`product + versionCode + transport` заменяет запись. Полный rollback и
автоматическая очистка старых assets не выполняются.
- Текущий upload держит образ в памяти (лимит 128 MiB), чтобы параллельная
пересборка не подменила байты между вычислением хэша и отправкой.
## Проверка
Из `templates`:
```powershell
$env:PYTHONPATH = "$PWD/python"
python -m unittest discover -s python/tests -p test_firmware_database.py -v
python -m unittest discover -s python/tests -p test_firmware_publish.py -v
```
Тесты используют сервер в памяти: каталог → публикация → скачивание, повторный
выпуск, сохранение других разделов, ошибки SHA-256 и конфликты ревизии,
изоляцию авторизации при redirect. Проверка реальной Gitea и загрузка на МК
в эти тесты не входят. Перед производственным подключением проверьте выпуск
в тестовом репозитории вашей Gitea и чтение каталога целевым GUI.