#include "DSP2833x_Device.h" /* Использует host-модель регистров, а не альтернативную реализацию драйвера. */ #include "global_time_f28335.h" /* Тестирует публичные hooks настоящего аппаратного порта. */ #ifdef NDEBUG /* Не позволяет Release-сборке превратить аппаратные проверки в пустую программу. */ #undef NDEBUG /* Включает assert независимо от флагов конфигурации CMake. */ #endif /* Завершает настройку обязательных проверяющих утверждений. */ #include /* Проверяет сохранность соседних ресурсов, обработку CAN и период Timer2. */ #include /* Выводит краткое подтверждение проверенных сценариев. */ struct gt_test_mboxes ECanaMboxes; /* Выделяет модельные MBOX7 и MBOX8. */ struct gt_test_ecan ECanaRegs; /* Выделяет модель управляющих регистров eCAN-A. */ struct gt_test_lam ECanaLAMRegs; /* Выделяет локальную маску RX. */ struct gt_test_timer CpuTimer2Regs; /* Выделяет модель CPU Timer2. */ struct gt_test_vectors PieVectTable; /* Хранит реальный адрес ISR, назначенный портом. */ uint16_t IER, IFR; /* Выделяет модель CPU-масок INT14 и соседних прерываний. */ static uint16_t masked; /* Сохраняет модельное состояние глобальной маски INTM. */ uint16_t __disable_interrupts(void) /* Моделирует атомарный запрет IRQ и возвращаемый предыдущий INTM. */ { /* Повторный запрет из ISR обязан вернуть уже установленную маску. */ uint16_t old = masked; /* Сохраняет прежнюю маску до её изменения. */ masked = 1U; /* Имитирует запрет маскируемых IRQ. */ return old; /* Позволяет реальному порту точно восстановить предыдущий режим. */ } /* Завершает модель intrinsic запрета. */ void __restore_interrupts(uint16_t state) /* Восстанавливает маску, полученную соответствующим входом. */ { /* Проверяет, что порт действительно вызвал вход в критическую секцию. */ assert(masked == 1U); /* Восстановление без предшествующего запрета нарушило бы вложенность. */ masked = state; /* Сохраняет исходный ISR-контекст без безусловного разрешения IRQ. */ } /* Завершает модель intrinsic восстановления. */ static void inject(const gt_frame *frame) /* Доставляет wire-данные в аппаратный RX и вызывает настоящий ISR hook. */ { /* Не вызывает gt_receive напрямую, проверяя весь путь распаковки MDL/MDH. */ uint16_t i; /* Перебирает восемь проводных октетов фиксированного classic CAN. */ ECanaMboxes.MBOX7.MSGID.all = 0xC0000000UL | frame->id; /* Имитирует расширенный ID и включённую локальную фильтрацию eCAN. */ ECanaMboxes.MBOX7.MSGCTRL.all = frame->dlc | ((uint32_t)frame->remote << 4U); /* Укладывает DLC и RTR в модельный регистр сообщения. */ ECanaMboxes.MBOX7.MDL.all = ECanaMboxes.MBOX7.MDH.all = 0UL; /* Сбрасывает старый payload перед имитацией нового приёма. */ for (i = 0U; i < 8U; ++i) { /* Укладывает данные младшим октетом вперёд, как eCAN при DBO=0. */ if (i < 4U) ECanaMboxes.MBOX7.MDL.all |= (uint32_t)frame->data[i] << (8U * i); /* Первые четыре октета занимают MDL. */ else ECanaMboxes.MBOX7.MDH.all |= (uint32_t)frame->data[i] << (8U * (i - 4U)); /* Следующие четыре октета занимают MDH. */ } /* Завершает аппаратное размещение кадра. */ ECanaRegs.CANRMP.all = 0x82UL; /* Выставляет RX7 и независимый pending legacy mailbox1. */ gt_f28335_rx_isr(); /* Захватывает временную привязку и кадр в очередь настоящего порта. */ assert(ECanaRegs.CANRMP.all == 0x80UL); /* Запись W1C должна содержать только бит собственного mailbox, сохраняя pending соседа на аппаратуре. */ ECanaRegs.CANRMP.all = 2UL; /* Вручную применяет W1C к обычной RAM модели: RX7 снят, RX1 сохранён. */ } /* Завершает модель получения кадра без подмены алгоритма порта. */ int main(void) /* Проверяет аппаратную настройку и общий путь ISR → main → метка логгера. */ { /* Модель не утверждает электрические тайминги или CAN ACK настоящего трансивера. */ gt_stamp stamp; /* Читает время через тот же атомарный API, которым будет пользоваться логгер. */ gt_datetime date = {2026U, 10U, 19U, 1U, 12U, 34U, 56U, 0U}; /* Независимый календарный эталон: понедельник 19 октября 2026 года. */ gt_frame frame; /* Содержит broadcast мастера для доставки через модель eCAN. */ uint16_t i; /* Управляет известным числом тиков до обработки кадра в main. */ gt_f28335_tick_1ms(); gt_f28335_rx_isr(); gt_f28335_service(); /* Ранние hooks до init обязаны безопасно завершаться. */ ECanaRegs.CANME.all = 0x7FUL; /* Резервирует существующие mailbox0..6 для legacy CAN, Boot и pulse. */ ECanaRegs.CANMD.all = 0xFFFFFFFAUL; /* Воспроизводит исходные направления legacy mailbox проекта 28335_periph. */ ECanaRegs.CANMIM.all = 0x4AUL; /* Имитирует разрешённые RX1/RX3/RX6 других CAN-сервисов. */ ECanaRegs.CANMIL.all = 0x40UL; /* Фиксирует чужую маршрутизацию IRQ, которую порт обязан сохранить. */ assert(!gt_f28335_init_periph(32U)); /* Некорректный физический адрес не должен открыть новый CAN-сервис. */ assert(gt_f28335_init_periph(5U)); /* Настраивает УМП1 как PERIPH5, Type1/ID5. */ assert(ECanaRegs.CANME.all == 0x1FFUL && (ECanaRegs.CANMD.all & 0x7FUL) == 0x7AUL); /* Проверяет добавление только mailbox7/8 и сохранность чужих направлений. */ assert(ECanaRegs.CANMIM.all == 0xCAUL && ECanaRegs.CANMIL.all == 0x40UL); /* Проверяет RX7 IRQ line0 без изменения RX1/RX3/RX6. */ assert(ECanaMboxes.MBOX7.MSGID.all == 0xC0000030UL && ECanaLAMRegs.LAM7.all == 0x10000000UL); /* Фильтр принимает только время мастера с любым приоритетом. */ ECanaRegs.CANTA.all = ECanaRegs.CANAA.all = ECanaRegs.CANRMP.all = 0UL; /* Применяет к RAM модели W1C, выполненные init на реальной аппаратуре. */ gt_f28335_service(); /* Проверяет первый проход main при отсутствии входящего кадра. */ assert(ECanaRegs.CANTRS.all == 0UL); /* Сам init не должен объявить готовность прикладной платы. */ gt_f28335_ready(); gt_f28335_service(); /* Публикует прикладной успех и запускает передачу из main. */ assert(ECanaRegs.CANTRS.all == 0x100UL && ECanaMboxes.MBOX8.MSGID.all == 0x99513000UL && ECanaMboxes.MBOX8.MDL.all == 1UL); /* Проверяет точный аппаратный запрос READY с правильным адресом. */ assert(gt_make_rtc(&date, &frame)); /* Строит штатный RTCSETUP без аппаратного RTC мастера в тесте. */ inject(&frame); /* Проверяет разбор всех календарных полей через настоящий RX ISR. */ for (i = 0U; i < 37U; ++i) gt_f28335_tick_1ms(); /* Имитирует 37 мс задержки main при продолжающемся такте. */ gt_f28335_service(); /* Применяет отложенный RX и сохраняет привязку к исходному моменту приёма. */ gt_get(gt_f28335_clock(), &stamp); /* Снимает тот же экземпляр часов, что обслуживает порт. */ assert(gt_calendar(&stamp, &date) && date.year == 2026U && date.month == 10U && date.day == 19U && date.hour == 12U && date.minute == 34U && date.second == 56U && date.millisecond == 37U); /* Проверяет календарь и компенсацию задержки всего пути приёма. */ assert(stamp.sync_uptime_ms == 0UL && stamp.uptime_ms == 37UL); /* Очередь не должна подменить время RX временем обработки main. */ ECanaRegs.CANTA.all = 0x100UL; ECanaRegs.CANTRS.all = 0UL; /* Имитирует аппаратный ACK ранее отправленной готовности. */ gt_f28335_service(); /* Освобождает собственный TX без повторной отправки после синхронизации. */ ECanaRegs.CANTA.all = ECanaRegs.CANAA.all = 0UL; /* Применяет аппаратное W1C к RAM модели ACK. */ assert(ECanaRegs.CANTRS.all == 0UL); /* Синхронизация прекращает повторную стартовую рассылку. */ IER = 0x1001U; IFR = 0x3001U; /* Подготавливает чужие CPU IRQ и старый pending INT14. */ assert(!gt_f28335_timer2_start(150000001UL)); /* Некратная 1000 частота не должна давать скрытый дробный период. */ assert(gt_f28335_timer2_start(150000000UL)); /* Настраивает аппаратные 1 мс для типичной частоты F28335 150 МГц. */ assert(CpuTimer2Regs.PRD.all == 149999UL && CpuTimer2Regs.TPR.all == 0UL && CpuTimer2Regs.TPRH.all == 0UL); /* Проверяет включительный период PRD..0 и отсутствие предделителей. */ assert(IER == 0x3001U && IFR == 0x1001U && CpuTimer2Regs.TCR.all == 0xC020UL); /* Сохраняет чужие CPU маски и запускает только Timer2. */ PieVectTable.TINT2(); /* Вызывает реальное тело ISR через вектор, назначенный портом. */ gt_get(gt_f28335_clock(), &stamp); /* Проверяет единственный миллисекундный шаг собственного ISR. */ assert(stamp.uptime_ms == 38UL && stamp.millisecond == 38U); /* Timer2 должен добавлять ровно один тик на прерывание. */ assert(!gt_f28335_init_periph(6U)); /* Повторный init не должен потерять владение работающим Timer2. */ gt_f28335_timer2_stop(); /* Освобождает ранее захваченный аппаратный такт. */ assert(IER == 0x1001U && CpuTimer2Regs.TCR.all == 0x8010UL && masked == 0U); /* Остановка сохраняет чужие IRQ и исходный глобальный INTM. */ ECanaRegs.CANMC.bit.DBO = 1U; /* Имитирует несовместимый порядок октетов контроллера. */ assert(!gt_f28335_init_periph(6U)); /* Не позволяет молча декодировать другую аппаратную раскладку payload. */ puts("global-time F28335: eCAN isolation, RX delay, ACK and Timer2 OK"); /* Выводит компактный результат аппаратных сценариев. */ return 0; /* Завершает проверку после всех обязательных утверждений. */ } /* Завершает host-регрессию порта TI F28335. */