Files
Balsam_167/UKSSTMS320F28335/prepare_identity.py
Andrey fe95dbff3d Перенести паспорт и проверку прошивки из 167 в 166
Добавить неизменяемое окно firmware-info v1 0x1200 из 12 слов для FC03 и служебного CAN, запретить запись. Сохранить текущую технологическую карту и логгер v4 с записью 12 слов.

Подключить общий генератор версии 1.0.0 для Balsam-166-PM35, prebuild CCS и локальный выпуск BIN с manifest и SHA-256. Проверять соответствие встроенных слов манифесту до публикации; старый OUT без паспорта отклонять.

Проверка: реальные обработчики RS/CAN и CRC под GCC O3, прежний тест логгера, анализатор установленного SetGUI, полная сборка TI C2000 22.6.0.LTS. BIN 30248 байт при границе параметров 32508 байт. Аппаратная проверка требует установки нового образа и перезапуска платы.
2026-10-16 12:05:44 +03:00

36 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Подготавливает паспорт 166 тем же генератором firmware-info, что используется в 167.""" # Версия, время UTC и ревизии фиксируются до компиляции.
import argparse # Разбирает одинаковые с проектом 167 пути prebuild.
import importlib.util # Подключает общую реализацию без копирования генератора в прошивку.
import json # Объединяет идентификаторы продукта с версией из C-заголовка.
from pathlib import Path # Нормализует пути независимо от рабочего каталога CCS.
import re # Проверяет единственное допустимое целое определение каждого компонента версии.
import tempfile # Хранит объединённые настройки только на время вызова общего генератора.
def read_version(header): # Сохраняет правила исходного адаптера 167 и ограничения firmware-info v1.
text = re.sub(r"/\*.*?\*/|//[^\n]*", "", header.read_text(encoding="utf-8-sig"), flags=re.S) # Не принимает комментарии или примеры за действующую версию.
result = [] # Накапливает major, minor и patch в порядке регистров контракта.
for part, limit in (("MAJOR", 255), ("MINOR", 255), ("PATCH", 999)): # Два первых компонента ограничены октетом, исправление допускает 0..999.
name = "FIRMWARE_VERSION_" + part # Использует тот же интерфейс заголовка версии, что 167.
definitions = re.findall(r"^\s*#\s*define\s+" + name + r"\b([^\n]*)", text, re.M) # Требует единственного определения без условных альтернатив.
if len(definitions) != 1 or not re.fullmatch(r"(?:0|[1-9][0-9]*)[uU]?", definitions[0].strip()): # Не допускает выражений, шестнадцатеричных литералов и неоднозначной версии.
raise ValueError(f"{header}: define {name} exactly once as a decimal integer") # Останавливает сборку вместо выпуска ложного паспорта.
value = int(definitions[0].strip().rstrip("uU")) # Суффикс C не является частью десятичного числа Python.
if value > limit: # Проверяет границы до записи какого-либо заголовка сборки.
raise ValueError(f"{name} must be in 0..{limit}") # Сохраняет ограничения отображения и Modbus-контракта 167.
result.append(value) # Записывает проверенную компоненту в правильное поле паспорта.
return result # Номер версии формируется только из firmware_version.h.
def prepare(project, templates, output): # Генерирует заголовок и JSON для одной конкретной конфигурации CCS.
settings = json.loads((project / "firmware_identity.json").read_text(encoding="utf-8-sig")) # Сохраняет собственный product 166 и тот же target TMS320F28335.
settings["version"] = read_version(project / "firmware_version.h") # Не дублирует SemVer в двух редактируемых файлах.
spec = importlib.util.spec_from_file_location("shared_firmware_identity", templates / "c/firmware-info/tools/identity.py") # Берёт проверенную общую реализацию из той же зависимости, что 167.
identity = importlib.util.module_from_spec(spec) # Создаёт изолированный модуль генератора без изменения системного Python.
spec.loader.exec_module(identity) # Загружает формат заголовка, UTC и правила формирования Build ID.
with tempfile.TemporaryDirectory(prefix="balsam166-identity-") as directory: # Удаляет только временные объединённые настройки этого вызова.
config = Path(directory) / "settings.json" # Настройки не записываются в исходники и не попадают в историю Git.
config.write_text(json.dumps(settings), encoding="utf-8") # Передаёт общему генератору проверенную версию и product.
return identity.prepare(project, templates, config, output) # Создаёт обязательные generated/firmware_identity.h и JSON до компиляции.
if __name__ == "__main__": # Импорт из теста не запускает изменение файлов сборки.
parser = argparse.ArgumentParser(description=__doc__) # Объясняет назначение prebuild при ручном вызове.
for name in ("project", "templates", "output"): parser.add_argument("--" + name, type=Path, required=True) # Совместим с параметрами prebuild исходного проекта 167.
args = parser.parse_args() # Проверяет обязательные каталоги перед генерацией.
print(json.dumps(prepare(args.project.resolve(), args.templates.resolve(), args.output.resolve()))) # Показывает фактическую идентичность текущей сборки.