/* Исполняется настоящий автомат и аппаратная обёртка прошивки. * GPIO здесь заменены счётчиками: каждое переключение проверяется * отдельно, в том числе отсутствие кратковременного START+STOP. * В тесте нет main прошивки: этим воспроизводится его задержка на EEPROM. */ #include "ump_pulse.h" static unsigned int irq_mask, start_pin, stop_pin, relay_pin, overlap; static unsigned int start_edges, stop_edges; int Desk = 6; #define dsk_LOAD 6 #define READY_FREQ 1000 static volatile unsigned int command_word; #define Commands command_word volatile unsigned long IMPowse; static unsigned int __disable_interrupts(void) { unsigned int old = irq_mask; irq_mask = 1; return old; } static void __restore_interrupts(unsigned int old) { irq_mask = old; } static void clear_START_DPTB(void) { start_pin = 0; } static void clear_STOP_DPTB(void) { stop_pin = 0; } static void set_START_DPTB(void) { if (!start_pin) start_edges++; start_pin = 1; if (stop_pin) overlap++; } static void set_STOP_DPTB(void) { if (!stop_pin) stop_edges++; stop_pin = 1; if (start_pin) overlap++; } static void set_RES_OUT_2(void) { relay_pin = 1; } static void clear_RES_OUT_2(void) { relay_pin = 0; } #include "ump_control_impl.h" #define CHECK(x) do { if (!(x)) return __LINE__; } while (0) __declspec(dllexport) int run_tests(void) { unsigned int i, edges; /* Команда до окончания инициализации не исполняется; разрешение * обработки не воспроизводит её задним числом. */ UMP_commands_write(0x80); CHECK(!start_pin && !stop_pin); UMP_pulse_init(); UMP_commands_write(0x80); CHECK(!start_pin); UMP_commands_write(0); UMP_commands_write(0x80); CHECK(start_pin && !stop_pin && relay_pin && IMPowse == 1000); CHECK(!irq_mask); /* Длительная единица не продлевает импульс. Ровно тысяча вызовов * таймера снимает выход; основной цикл ни разу не вызывался. */ for (i = 0; i < 999; i++) { UMP_commands_write(0x80); UMP_pulse_tick(); } CHECK(start_pin && IMPowse == 1); UMP_pulse_tick(); CHECK(!start_pin && !stop_pin && relay_pin && !IMPowse); UMP_commands_write(0x80); CHECK(!start_pin); /* Короткий ноль замечается непосредственно в приёмном обработчике. */ UMP_commands_write(0); UMP_commands_write(0x80); CHECK(start_pin && IMPowse == 1000 && start_edges == 2); UMP_pulse_tick(); UMP_commands_write(0); UMP_commands_write(0x80); CHECK(IMPowse == 1000 && start_edges == 2); /* STOP прерывает активный START. Одновременная команда не выдаёт * даже короткого START; проверяется каждая запись мокового GPIO. */ UMP_commands_write(0xC0); CHECK(!start_pin && stop_pin && !relay_pin && !overlap); edges = start_edges; for (i = 0; i < 1000; i++) UMP_pulse_tick(); UMP_commands_write(0xC0); CHECK(!start_pin && !stop_pin && !IMPowse); UMP_commands_write(0x80); CHECK(!start_pin && start_edges == edges); UMP_commands_write(0); UMP_commands_write(0xC0); CHECK(!start_pin && stop_pin && start_edges == edges); UMP_commands_write(0x40); UMP_commands_write(0xC0); CHECK(!start_pin && !overlap); /* Снятый STOP + свежий фронт START могут переключить выход до * окончания STOP-импульса, но никогда не создают перекрытие. */ UMP_commands_write(0); UMP_commands_write(0x80); CHECK(start_pin && !stop_pin && relay_pin && !overlap); /* Default/Load удаляют служебные биты, сохраняя уровень команды * и историю фронтов. Случайный повтор пакета не перезапускает импульс. */ UMP_commands_write(0x88); UMP_pulse_tick(); UMP_reset_parameter_commands(); CHECK(Commands == 0x80 && IMPowse == 999); UMP_commands_write(0x80); CHECK(IMPowse == 999); /* Вложенный вызов не разрешает IRQ, если они были запрещены. */ irq_mask = 1; UMP_commands_write(0x40); UMP_pulse_tick(); UMP_reset_parameter_commands(); CHECK(irq_mask == 1 && stop_pin && !start_pin && !overlap); irq_mask = 0; /* Другие типы платы не получают дискреты нагрузки. */ for (i = 0; i < 1000; i++) UMP_pulse_tick(); Desk = 1; edges = start_edges; UMP_commands_write(0); UMP_commands_write(0x80); CHECK(Commands == 0x80 && start_edges == edges && !start_pin); UMP_reset_parameter_commands(); CHECK(Commands == 0); return 0; }