Вынеси программные часы, коррекцию по ProtoCAN RTCSETUP и атомарную метку логгера в переносимое ядро без глобального состояния. Подключи eCAN-A и CPU Timer2 отдельным портом F28335; зафиксируй календарные границы, переполнение, задержку RX и защиту IRQ в хостовых тестах.
37 lines
6.7 KiB
Python
37 lines
6.7 KiB
Python
"""Проверяет ядро и настоящий порт на host; опционально компилирует их TI C28x.""" # Описывает границу проверки без обещания аппаратного испытания.
|
||
import argparse # Принимает явные пути TI SDK вместо привязки библиотеки к рабочему компьютеру.
|
||
import os # Настраивает PATH компилятора, чтобы Windows находила его DLL.
|
||
from pathlib import Path # Строит пути относительно самого тестового набора.
|
||
import shutil # Находит GCC или Clang в окружении разработчика.
|
||
import subprocess # Запускает компиляторы аргументами без shell-интерполяции.
|
||
import tempfile # Изолирует все исполняемые и объектные файлы во временном каталоге.
|
||
root = Path(__file__).resolve().parents[1] # Определяет корень c/global-time независимо от текущего каталога.
|
||
parser = argparse.ArgumentParser(description=__doc__) # Показывает назначение host- и TI-проверок при --help.
|
||
parser.add_argument("--cc", default=os.environ.get("CC")) # Разрешает явно выбрать совместимый host-компилятор.
|
||
parser.add_argument("--ti-cgt", type=Path) # Принимает каталог TI C2000 compiler с bin/cl2000 и include.
|
||
parser.add_argument("--ti-headers", type=Path) # Принимает каталог с настоящим DSP2833x_Device.h проекта или TI SDK.
|
||
parser.add_argument("--ti-common", type=Path) # Принимает дополнительный каталог DSP2833x_GlobalPrototypes.h из DSP2833x_common/include.
|
||
args = parser.parse_args() # Проверяет параметры до создания любых файлов сборки.
|
||
candidates = [args.cc, shutil.which("gcc"), shutil.which("clang"), "C:/msys64/ucrt64/bin/gcc.exe"] # Последний путь обеспечивает привычное Windows-окружение без изменения глобального PATH.
|
||
compiler = next((str(Path(p).resolve()) for p in candidates if p and Path(p).is_file()), None) # Выбирает первый существующий компилятор, сохраняя явный --cc в приоритете.
|
||
if not compiler: # Не заменяет отсутствие компилятора успешным пустым запуском.
|
||
parser.error("Укажите --cc с путём к GCC/Clang") # Даёт воспроизводимое требование для запуска регрессий.
|
||
if bool(args.ti_cgt) != bool(args.ti_headers): # TI проверка требует одновременно компилятор и аппаратные заголовки.
|
||
parser.error("--ti-cgt и --ti-headers нужно указать вместе") # Предотвращает случайную проверку порта с host-моделью вместо SDK.
|
||
env = dict(os.environ) # Сохраняет исходное окружение остальных инструментов.
|
||
env["PATH"] = str(Path(compiler).parent) + os.pathsep + env.get("PATH", "") # Добавляет соседние DLL GCC только в дочерние процессы тестов.
|
||
with tempfile.TemporaryDirectory(prefix="global-time-") as output: # Удаляет только собственный временный каталог после завершения проверок.
|
||
for name, sources, includes in [("core", ["src/global_time.c", "tests/test_global_time.c"], ["include"]), ("f28335", ["src/global_time.c", "ports/tms320f28335/global_time_f28335.c", "tests/test_f28335.c"], ["include", "ports/tms320f28335", "tests/f28335_stubs"])]: # Проверяет ядро отдельно и реальный порт с модельными регистрами.
|
||
exe = Path(output) / (name + (".exe" if os.name == "nt" else "")) # Сохраняет host-программы за пределами исходного дерева.
|
||
command = [compiler, "-std=c99", "-Wall", "-Wextra", "-Werror", "-pedantic", *["-I" + str(root / p) for p in includes], *[str(root / p) for p in sources], "-o", str(exe)] # Считает все предупреждения ошибками и использует реальные исходники библиотеки.
|
||
subprocess.run(command, check=True, env=env, timeout=60) # Не маскирует ошибку компиляции успешным запуском старого EXE.
|
||
subprocess.run([str(exe)], check=True, env=env, timeout=30) # Выполняет календарные и аппаратные сценарии с ограниченным временем.
|
||
if args.ti_cgt: # Дополнительная проверка нужна для ABI с 16-битным char и настоящих регистров TI.
|
||
ti = args.ti_cgt.resolve() # Фиксирует абсолютный корень выбранного SDK компилятора.
|
||
for source in ["src/global_time.c", "ports/tms320f28335/global_time_f28335.c"]: # Компилирует оба поставляемых MCU исходника без изменения прошивки потребителя.
|
||
obj = Path(output) / (Path(source).stem + ".obj") # Разделяет объектные файлы ядра и аппаратного адаптера.
|
||
include_paths = [root / "include", root / "ports/tms320f28335", args.ti_headers.resolve(), ti / "include", *([args.ti_common.resolve()] if args.ti_common else [])] # Отдельно подключает common-заголовки старого TI SDK, не смешивая их с host-моделью.
|
||
command = [str(ti / "bin/cl2000.exe"), "--compile_only", "-v28", "-ml", "-mt", "--float_support=fpu32", "--abi=coffabi", "--c99", "-O2", "--opt_for_speed=0", "--display_error_number", *["--include_path=" + str(p) for p in include_paths], "--output_file=" + str(obj), str(root / source)] # Использует large/COFF ABI действующего проекта F28335 и штатные заголовки.
|
||
subprocess.run(command, check=True, timeout=60) # Ошибка TI C28x останавливает проверку вместо объявления host-модели достаточной.
|
||
print("global-time: TI C28x large/COFF compilation OK") # Подтверждает именно компиляцию объектов, не аппаратные испытания или полную линковку прошивки.
|