Files
Andrey 05be38a04a Обновить Flash/CAN, версии сборок и управление периферией
Добавить защищённое обновление приложения через RS и CAN с сохранением
загрузчика, проверкой CRC, восстановлением передачи и защитой EEPROM.
Подключить общий процесс сборки C2000 и автоматический счётчик версии
для согласованных RAM, Flash, CAN и паспортов бинарных образов.

Уточнить запуск ЦАП, обработку измерений и параметров нагрузки,
начальную индикацию и документацию регистров GAS.
Дополнить модели аппаратуры и изолировать заголовки CAN в тестах.

Проверка: 26 тестов выпуска, 4 теста восстановления CAN и восемь
программных моделей CAN, Flash, EEPROM, ЦАП, параметров и TESTLAMP.
2026-11-06 16:11:11 +03:00

54 lines
10 KiB
Python

"""Компилирует реальные декодеры Flash RS на host и проверяет формат готового образа.""" # Проверяет производственную проверку границ независимо от реализации GUI.
import ctypes # Вызывает декодер C с точными 16- и 32-битными типами, соответствующими ABI C28x.
import importlib.util # Подключает общий подписыватель FAB1 из фактически компилируемой зависимости templates.
import os # Даёт GCC доступ к DLL установленного runtime Windows.
from pathlib import Path # Находит производственный источник и результаты сборки относительно теста.
import struct # Создаёт таблицы TI с заведомо известными допустимыми и запрещёнными адресами.
import subprocess # Компилирует настоящие функции производственного загрузчика.
import tempfile # Изолирует временный C-модуль и библиотеку от исходников прошивки.
ROOT = Path(__file__).resolve().parents[2] # Корень содержит проверяемый flash_rs.c и транспортный BIN текущей сборки.
PORT = ROOT.parent / 'newProject/SETGUI/third_party/templates/c/protocan-boot/ports/tms320f28335' # Общий C-валидатор совпадает с кодом постоянного boot.
spec = importlib.util.spec_from_file_location('flash_contract', ROOT.parent / 'newProject/SETGUI/third_party/templates/python/protocan/f28335_flash.py') # Тестовые данные подписываются производственным форматом FAB1.
contract = importlib.util.module_from_spec(spec) # Изолирует импорт от установленного пакета protocan.
spec.loader.exec_module(contract) # Отсутствующая новая зависимость останавливает проверку вместо принятия старого Flash.
GCC = Path('C:/msys64/mingw64/bin/gcc.exe') # Использует тот же host-компилятор, что существующие проверки прошивки.
os.environ['PATH'] = str(GCC.parent) + os.pathsep + os.environ['PATH'] # Подключает runtime DLL GCC только к процессам проверки.
source = (ROOT / 'Source/Internal/flash_rs.c').read_text(encoding='utf-8') # Читает реальные функции, а не переписывает алгоритм в тестовой модели.
helpers = source[source.index('#pragma CODE_SECTION(byte_at'):source.index('#pragma CODE_SECTION(reply_status')] # Берёт производственное преобразование упаковки RS и расчёт CRC.
validator = source[source.index('#pragma CODE_SECTION(validate_image'):source.index('#pragma CODE_SECTION(program_image')] # Берёт производственную проверку всех блоков и запрещённых диапазонов.
prefix = '#include <stdint.h> /* Задаёт точные типы host-модели ABI C28x. */\ntypedef uint16_t Uint16; /* Слово C28x содержит 16 бит. */\ntypedef uint32_t Uint32; /* Адрес и длина C28x занимают 32 бита. */\nvoid ServiceDog(void) {} /* Предварительная CRC обслуживает watchdog платы; у host таймера нет. */\n' # Сохраняет арифметические размеры и точку аппаратного обслуживания оригинального кода.
wrapper = '__declspec(dllexport) Uint16 check_image(const Uint16 *octets, Uint32 length) /* Открывает реальный валидатор для Python. */\n{ /* Начинает упаковку RS-октетов host-модели. */\nstatic Uint16 packed[64512]; /* Внешняя RAM ZONE7A содержит 0xFC00 слов. */\nUint32 i; /* Счётчик октетов проверяемого массива. */\nfor(i=0;i<(length+1)/2;++i) packed[i]=0; /* Исключает остатки предыдущего сценария. */\nfor(i=0;i<length;++i) packed[i/2] |= octets[i] << ((i&1)?0:8); /* Повторяет реальную упаковку RS_RX_Handler. */\nreturn validate_image(packed,length); /* Вызывает производственную проверку таблицы. */\n} /* Завершает экспортируемый тестовый адаптер. */\n' # Адаптер меняет только упаковку входа, не критерии проверки образа.
def block(address, words): # Формирует одну секцию таблицы SCI8 для проверок адресных границ.
return struct.pack('<HHH', len(words), address >> 16, address & 65535) + struct.pack('<' + 'H' * len(words), *words) # Длина выражена словами, адрес содержит старшую половину перед младшей.
header = b'\xaa\x08' + bytes(16) + struct.pack('<HH', 0x30, 0x10) # Точка входа 0x300010 следует после фиксированного FAB1.
signed = struct.unpack('<16H', contract.descriptor(0x300010, {0x300010: 0x1234, 0x300011: 0x5678})) # Формирует описание и CRC точных слов тестового кода.
valid = header + block(0x300000, signed) + block(0x300010, [0x1234, 0x5678]) + bytes(2) # Полный образ содержит FAB1, код ниже сектора A и терминатор SCI8.
with tempfile.TemporaryDirectory(prefix='flash-rs-test-') as directory: # Все промежуточные host-файлы принадлежат только текущей проверке.
directory = Path(directory) # Строит пути временной C-библиотеки и исходника.
model = directory / 'validator.c' # Модель содержит извлечённые производственные функции без аппаратных регистров.
model.write_text(prefix + helpers + validator + wrapper, encoding='utf-8') # Сохраняет русский текст комментариев в UTF-8.
library = directory / 'validator.dll' # Вызывает C-код через DLL вместо имитации алгоритма на Python.
subprocess.run([str(GCC), '-shared', '-std=c99', '-Wno-unknown-pragmas', '-include', str(PORT / 'f28335_flash_app.c'), str(model), '-o', str(library)], check=True) # Компилирует настоящий FAB1/CRC вместе с извлечённой структурной проверкой RS.
native = ctypes.CDLL(str(library)) # Загружает скомпилированную производственную проверку.
native.check_image.argtypes = [ctypes.POINTER(ctypes.c_uint16), ctypes.c_uint32] # Каждая октета тестового входа передаётся как отдельное слово адаптера.
native.check_image.restype = ctypes.c_uint16 # Сохраняет точный 16-битный код отказа загрузчика.
scenarios = [(valid, 0), (valid[:-2], 0x1002), (valid + bytes(2), 0x1002), (header + block(0x33FFF6, [1, 2]) + bytes(2), 0x1002)] # Проверяет структуру, терминатор, хвост и наличие загружаемого C runtime независимо от наличия локального build.
image = Path(os.environ.get('FLASH_RS_IMAGE', ROOT / 'Bin/ProtectedBoot20261019/application/rs/firmware_flash_rs.bin')) # Старый самостоятельный Flash намеренно не принимается новым защищённым контрактом.
if image.is_file(): # На компьютере без TI-сборки остаются обязательными все искусственные граничные сценарии.
scenarios.append((image.read_bytes(), 0)) # Production-валидатор MCU дополнительно принимает настоящий проверяемый SCI8, созданный hex2000.
for address in (0x2FFFFF, 0x340000, 0x33FF80, 0x33FFF8, 0x380400): # Адреса охватывают нижнюю/верхнюю границы, CSM и OTP в словах C28x.
scenarios.append((header + block(0x300000, [1]) + block(address, [1]) + block(0x33FFF6, [1, 2]) + bytes(2), 0x1002)) # Каждая запрещённая секция должна остановить запись до стирания.
scenarios.append((valid[:-2] + block(0x300000, [1]) + bytes(2), 0x1002)) # Перекрытие слов программы запрещено даже при правильном общем формате.
for payload, expected in scenarios: # Выполняет каждый сценарий на одном и том же производственном C-алгоритме.
octets = (ctypes.c_uint16 * len(payload))(*payload) # Предоставляет байты адаптеру с контролируемым размером.
assert native.check_image(octets, len(payload)) == expected # Код отказа должен совпадать с контрактом GUI и BIOS.
unload = ctypes.WinDLL('kernel32').FreeLibrary # Windows не позволяет удалить временный DLL, пока библиотека загружена процессом.
unload.argtypes = [ctypes.c_void_p] # Передаёт полный размер указателя на DLL в 64-битной среде Windows.
unload.restype = ctypes.c_int # Проверяет результат освобождения библиотеки перед очисткой каталога.
assert unload(native._handle) # Освобождает только DLL этой проверки, не затрагивая реальные файлы сборки.
print('PASS: production Flash RS validator, real image, CSM/OTP/range/overlap rejection') # Сообщает проверенные свойства без заявления о физической записи платы.