Files
Balsam_167/tests/can_timeout/model.inc
Andrey 9ddea2d99a Исправить восстановление CAN после тайм-аута передачи в 166
Перенесено из коммита 985804607d40b84f985eb04fc1f1b0a0dcfbe795 ветки 167.
Конфликты разрешены с сохранением обработчиков проекта 166.
2026-10-13 19:19:57 +03:00

59 lines
9.9 KiB
C++
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.
#include <stdint.h> /* Задаёт размеры 16- и 32-битных типов C28x в хостовой модели. */
#include <stdio.h> /* Печатает конкретное нарушенное условие и итог сценариев. */
#include <string.h> /* Обнуляет модель между независимыми сценариями. */
typedef uint16_t Uint16; /* Воспроизводит тип масок PIE, используемый обработчиком TI. */
typedef uint32_t Uint32; /* Воспроизводит упаковку двух технологических слов в MDH/MDL. */
#define interrupt /* Убирает только аппаратный атрибут функции при компиляции на ПК. */
#define EALLOW ((void)0) /* Модель не воспроизводит механизм защиты регистров ядра. */
#define EDIS ((void)0) /* Защита EALLOW проверяется сборкой настоящего модуля под TI. */
#define EINT ((void)0) /* Входы ISR вызывает сценарий, не поток операционной системы. */
#define DINT ((void)0) /* Отключение прерываний не требует имитации планировщика на ПК. */
#define M_INT9 0x0100U /* Маска CPU INT9 соответствует девятой группе PIE. */
#define MINT9 0x0100U /* Для проверки жизненного цикла сохраняет разрешение группы CAN. */
#define MG96 0x00DFU /* Исключает повторную вложенную обработку INTx6 той же группы. */
struct REG { uint32_t all; }; /* Представляет 32-битные регистры eCAN без зависимости от размеров long на хосте. */
struct ECAN_REGS { struct REG CANTA, CANAA, CANTRR, CANTRS, CANTOC, CANTOS; uint32_t CANTSC; }; /* Даёт рабочим функциям реальные имена используемых регистров. */
static volatile struct ECAN_REGS ECanaRegs; /* Позволяет наблюдать все записи production-функций при оптимизации O3. */
struct ECAN_MBOXES { struct { struct REG MDH, MDL; } MBOX0; }; /* Моделирует только штатный передатчик, который проверяет этот тест. */
static volatile struct ECAN_MBOXES ECanaMboxes; /* Содержимое mailbox остаётся доступным для проверок неизменности занятого кадра. */
static struct { struct { Uint16 all; } PIEIER9; union { unsigned all; struct { unsigned reserved:8, ACK9:1; } bit; } PIEACK; } PieCtrlRegs; /* Связывает запись всей маски PIEACK с битом подтверждения девятой группы в позиции 8. */
static Uint16 IER; /* Представляет маску разрешённых прерываний ядра. */
static int wait, CanTimeOutErrorTR; /* Повторяет состояние штатного передатчика и счётчик обнаруженных тайм-аутов. */
static void led1_toggle(void) {} /* Светодиод передачи не влияет на завершение аппаратной транзакции. */
/* PRODUCTION */
#define CHECK(condition) do { if (!(condition)) { printf("FAIL line %d: %s\n", __LINE__, #condition); return 1; } } while (0) /* Не отключает проверку условий при оптимизации или NDEBUG. */
static void reset_model(void) { /* Начинает сценарий без остаточных запросов и подтверждений предыдущего теста. */
memset((void *)&ECanaRegs, 0, sizeof(ECanaRegs)); /* Сбрасывает моделируемые аппаратные регистры CAN. */
memset((void *)&ECanaMboxes, 0, sizeof(ECanaMboxes)); /* Убирает ранее переданное содержимое mailbox. */
memset(&PieCtrlRegs, 0, sizeof(PieCtrlRegs)); /* Исключает ложное подтверждение PIE из предыдущего сценария. */
PieCtrlRegs.PIEIER9.all = 0x0030U; IER = M_INT9; /* Разрешает оба CAN-прерывания для проверки восстановления маски ISR. */
wait = 0; CanTimeOutErrorTR = 0; /* Повторяет начальные значения production-переменных. */
} /* Завершает начальную установку независимого сценария. */
int main(void) { /* Проверяет потерю ACK, фантомное прерывание, занятый mailbox и восстановление отправки. */
int words[128] = {0}; unsigned calls; /* Хранит данные кнопок и ограничивает имитацию повторных входов ISR. */
reset_model(); ECanaRegs.CANTOC.all = 1; ECanaRegs.CANTOS.all = 1; ECanaRegs.CANTRS.all = 5; wait = 1; /* Тайм-аут относится к mailbox 0, пока служебный mailbox 2 тоже занят. */
for (calls = 0; calls < 4 && ECanaRegs.CANTOS.all; calls++) { /* Повторяет IRQ, пока источник не снят, с явной защитой от зависания старого кода. */
CANa_reset_err(); /* Выполняет настоящий обработчик проекта, включая отмену TX и подтверждение PIE. */
ECanaRegs.CANTOS.all &= ECanaRegs.CANTOC.all; /* По SPRUI07 13.8.18.3 сброс TOC аппаратно снимает TOS и MTOF; одна запись CANTRR этого не гарантирует. */
} /* Проверяет, что обработчик освобождает процессор после первого тайм-аута. */
CHECK(calls == 1 && ECanaRegs.CANTOS.all == 0 && CanTimeOutErrorTR == 1); /* Повторные входы без снятия источника означают блокирование основного цикла. */
CHECK(ECanaRegs.CANTRR.all == 1 && ECanaRegs.CANTRS.all == 5); /* Отмена запрошена только для штатного TX; модель намеренно ещё не завершила аппаратную отмену. */
CHECK(PieCtrlRegs.PIEIER9.all == 0x0030U && PieCtrlRegs.PIEACK.bit.ACK9 == 1); /* ISR сохраняет прежние разрешения обоих каналов CAN и подтверждает свою группу. */
words[16] = 8; ECanaMboxes.MBOX0.MDH.all = 0x12345678UL; /* Подготавливает новое состояние кнопки при ещё занятом предыдущем кадре. */
CAN_send(0, words, 16); CHECK(ECanaMboxes.MBOX0.MDH.all == 0x12345678UL); /* Не допускает перезаписи данных до завершения отмены. */
ECanaRegs.CANTRS.all = 0; ECanaRegs.CANTRR.all = 0; ECanaRegs.CANAA.all = 1; ECanaRegs.CANTSC = 999; /* Имитирует аппаратное завершение отмены и подтверждение CANAA0. */
CAN_send(0, words, 16); /* Проверяет повторный запуск тем же реальным передатчиком после исчезновения тайм-аута. */
CHECK(ECanaRegs.CANTOC.all == 1 && ECanaRegs.CANTSC == 0 && ECanaRegs.CANTRS.all == 1); /* Новая передача вновь получает собственный отсчёт тайм-аута. */
CHECK(ECanaMboxes.MBOX0.MDH.all == 0xE0100008UL && ECanaMboxes.MBOX0.MDL.all == 0); /* После восстановления передаются свежие данные R16, а не старый нулевой кадр. */
reset_model(); ECanaRegs.CANTOC.all = 1; ECanaRegs.CANTRS.all = 1; /* Фантомное PIE-прерывание может прийти, когда начат следующий кадр без тайм-аута. */
CANa_reset_err(); CHECK(ECanaRegs.CANTRR.all == 0 && CanTimeOutErrorTR == 0 && ECanaRegs.CANTOC.all == 1); /* Не отменяет исправную передачу при уже снятом TOS0. */
reset_model(); ECanaRegs.CANTOC.all = 1; ECanaRegs.CANTOS.all = 1; /* Передача успела завершиться, но сценарий сохраняет зафиксированный флаг тайм-аута. */
CANa_reset_err(); CHECK(ECanaRegs.CANTRR.all == 0 && ECanaRegs.CANTOC.all == 0); /* Снимает контроль, не отменяя уже свободный mailbox. */
reset_model(); ECanaRegs.CANTRR.all = 1; ECanaMboxes.MBOX0.MDH.all = 0x11223344UL; /* Аппаратная отмена ещё активна, даже если CANTRS уже снят. */
CAN_send(0, words, 16); CHECK(ECanaMboxes.MBOX0.MDH.all == 0x11223344UL && ECanaRegs.CANTRS.all == 0); /* Не запускает повторный кадр до снятия CANTRR0. */
reset_model(); wait = 1; ECanaRegs.CANTA.all = 1; /* Проверяет обычную передачу после успешного подтверждения предыдущего кадра. */
CAN_send(0, words, 16); CHECK(ECanaRegs.CANTRS.all == 1 && ECanaRegs.CANTOC.all == 1); /* Исправление не блокирует штатный обмен при наличии CAN ACK. */
puts("PASS CAN timeout: IRQ released, phantom ignored, busy mailbox preserved, TX recovered"); /* Сообщает только о проверенных сценариях программной модели. */
return 0; /* Подтверждает прохождение всех проверок оптимизированного рабочего кода. */
} /* Завершает тест без доступа к реальному USB-CAN или питанию платы. */