Перенесено из коммита 985804607d40b84f985eb04fc1f1b0a0dcfbe795 ветки 167. Конфликты разрешены с сохранением обработчиков проекта 166.
59 lines
9.9 KiB
C++
59 lines
9.9 KiB
C++
#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 или питанию платы. */
|