Добавить CAN heartbeat и передачу по изменению с повтором через 1,3 с, компактный логгер v4, паспорт прошивки и блочное чтение EEPROM. Подключить автоматическую версию и проверяемую сборку BIN. Сохранить локальные исправления стробов и защиты Timer1. Обновить тесты, документацию, UTF-8 и исключения временных файлов. Проверки: CAN, R3, EEPROM, паспорт, TESTLAMP, логгер, START/STOP; 9 сценариев сборки, включая реальную конверсию TI. Все 17 внутренних модулей скомпилированы TI C2000 без ошибок.
37 lines
5.6 KiB
Python
37 lines
5.6 KiB
Python
"""Проверяет тайм-аут штатного CAN на настоящих функциях проекта 166.""" # Модель не заменяет испытание аппаратного eCAN.
|
|
import os # Передаёт пути библиотек GCC только дочерним процессам.
|
|
from pathlib import Path # Находит исходники независимо от рабочего каталога запуска.
|
|
import re # Удаляет комментарии и выделяет тела проверяемых функций.
|
|
import subprocess # Запускает компилятор и проверяет поведенческий результат модели.
|
|
import tempfile # Изолирует сгенерированные файлы от образов прошивки пользователя.
|
|
import sys # Позволяет проверить отдельно сохранённую старую версию ecan.c.
|
|
|
|
root = Path(__file__).resolve().parents[2] # Корень проекта содержит рабочую реализацию eCAN.
|
|
source_path = Path(sys.argv[1]) if len(sys.argv) > 1 else root / "Source/Internal/ecan.c" # Дополнительный путь нужен для проверки чувствительности к старой ошибке.
|
|
source = re.sub(r"/\*.*?\*/|//[^\n]*", "", source_path.read_text(encoding="utf-8"), flags=re.S) # Комментарии со скобками не участвуют в выделении функций.
|
|
if '#include "can_telemetry_impl.h"' in source: # Новая реализация отправителя вынесена в заголовок и требует модели с подтверждённым кэшем и временем Timer1.
|
|
import runpy # Запускает поведенческую проверку действующего передатчика вместо извлечения отсутствующей функции из ecan.c.
|
|
sys.argv = [str(root / "tests/can_telemetry/run_test.py")] # Не передаёт путь отдельного ecan.c как ошибочный корень проекта новому тесту.
|
|
runpy.run_path(sys.argv[0], run_name="__main__") # Проверяет аппаратный и программный тайм-ауты, отмену TX, ACK и секундную паузу на production-коде.
|
|
raise SystemExit(0) # Старую модель ниже сохраняет только для явно выбранных снимков прежнего передатчика.
|
|
|
|
def function(name): # Извлекает текущий алгоритм вместо поддержания отдельной копии в тесте.
|
|
match = re.search(r"(?:interrupt\s+)?void\s+" + name + r"\([^;{}]*\)\s*\{", source) # Отличает определение от вызова и объявления.
|
|
assert match is not None, name # Исчезновение функции должно останавливать проверку.
|
|
end, depth = match.end(), 1 # Начинает поиск после открывающей скобки тела.
|
|
while depth: # Учитывает вложенные условия до закрытия внешнего блока.
|
|
depth += (source[end] == "{") - (source[end] == "}") # Считает только скобки кода без комментариев.
|
|
end += 1 # Включает найденную закрывающую скобку в результат.
|
|
return source[match.start():end] # Сохраняет все реальные обращения к регистрам и условия.
|
|
|
|
model = Path(__file__).with_name("model.inc").read_text(encoding="utf-8") # Загружает минимальное аппаратное окружение и сценарии потери ACK.
|
|
model = model.replace("/* PRODUCTION */", function("CAN_send") + "\n" + function("CANa_reset_err")) # Проверяет передачу и прерывание в одном жизненном цикле.
|
|
compiler = os.environ.get("CC", "C:/msys64/mingw64/bin/gcc.exe") # Использует установленный GCC, сохраняя возможность явно выбрать другой.
|
|
environment = dict(os.environ) # Не меняет окружение приложения и проекта CCS.
|
|
environment["PATH"] = str(Path(compiler).parent) + os.pathsep + environment.get("PATH", "") # Делает библиотеки MinGW доступными тестовой программе.
|
|
with tempfile.TemporaryDirectory(prefix="can-timeout-") as directory: # Удаляет только собственные временные файлы после завершения проверки.
|
|
c_path, exe_path = Path(directory) / "test.c", Path(directory) / "test.exe" # Разделяет исходник модели и исполняемый результат.
|
|
c_path.write_text(model, encoding="utf-8") # Сохраняет русские пояснения модели в требуемой кодировке.
|
|
subprocess.run([compiler, "-std=c99", "-O3", "-Wall", "-Wextra", "-Wno-unused-parameter", "-Werror", str(c_path), "-o", str(exe_path)], env=environment, check=True) # Проверяет реальные функции под оптимизацией и без скрытых предупреждений.
|
|
subprocess.run([str(exe_path)], env=environment, check=True, timeout=10) # Зависание и нарушенное условие делают сценарий неуспешным.
|