111 lines
8.0 KiB
C
111 lines
8.0 KiB
C
/*
|
||
* Проверки led_indicator: фиксируют ожидаемое поведение на воспроизводимых входных данных.
|
||
* Тестовые значения и подмены окружения относятся к проверке контракта; они не являются
|
||
* настройками рабочего устройства.
|
||
*/
|
||
|
||
#include "led_indicator.h"
|
||
|
||
#include <stdio.h>
|
||
|
||
typedef struct {
|
||
uint32_t now;
|
||
uint8_t outputs[3];
|
||
uint32_t writes[3];
|
||
} FakePort;
|
||
|
||
static void fake_write(void *context, uint8_t channel, uint8_t on)
|
||
{
|
||
FakePort *fake = (FakePort *)context;
|
||
fake->outputs[channel] = on;
|
||
fake->writes[channel]++;
|
||
}
|
||
|
||
static uint32_t fake_now(void *context)
|
||
{
|
||
return ((FakePort *)context)->now;
|
||
}
|
||
|
||
#define CHECK(condition) \
|
||
do { \
|
||
if (!(condition)) { \
|
||
fprintf(stderr, "check failed at line %d: %s\n", __LINE__, \
|
||
#condition); \
|
||
return 1; \
|
||
} \
|
||
} while (0)
|
||
|
||
int main(void)
|
||
{
|
||
LedIndicator indicator;
|
||
LedIndicator_Channel channels[3];
|
||
LedIndicator_Config config;
|
||
LedIndicator_Pattern patterns[LED_INDICATOR_MODE_COUNT];
|
||
FakePort fake = {0};
|
||
LedIndicator_Port port = {fake_write, fake_now, &fake};
|
||
|
||
LedIndicator_ConfigDefault(&config);
|
||
CHECK(LedIndicator_ValidateConfig(&config) != 0U);
|
||
CHECK(LedIndicator_CopyDefaultPatterns(patterns, LED_INDICATOR_MODE_COUNT) ==
|
||
LED_INDICATOR_MODE_COUNT);
|
||
patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] = 25U;
|
||
CHECK(patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] == 25U);
|
||
CHECK(LedIndicator_Init(&indicator, channels, 3U, &port, &config) != 0U);
|
||
CHECK(fake.writes[0] == 1U && fake.writes[1] == 1U && fake.writes[2] == 1U);
|
||
|
||
CHECK(LedIndicator_SetMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
|
||
CHECK(fake.outputs[0] == 1U);
|
||
fake.now = 99U;
|
||
CHECK(LedIndicator_SetMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
|
||
LedIndicator_Process(&indicator);
|
||
CHECK(fake.outputs[0] == 1U);
|
||
fake.now = 100U;
|
||
LedIndicator_Process(&indicator);
|
||
CHECK(fake.outputs[0] == 0U);
|
||
fake.now = 1000U;
|
||
LedIndicator_Process(&indicator);
|
||
CHECK(fake.outputs[0] == 1U);
|
||
fake.now = 1050U;
|
||
CHECK(LedIndicator_RestartMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
|
||
fake.now = 1150U;
|
||
LedIndicator_Process(&indicator);
|
||
CHECK(fake.outputs[0] == 0U);
|
||
|
||
CHECK(LedIndicator_SetModeAt(&indicator, 1U, LED_INDICATOR_MODE_ERROR,
|
||
0xFFFFFFF0UL) != 0U);
|
||
LedIndicator_ProcessAt(&indicator, 0x00000054UL);
|
||
CHECK(fake.outputs[1] == 0U); /* 100 ms после старта, переход во второй шаг. */
|
||
LedIndicator_ProcessAt(&indicator, 0x000000B8UL);
|
||
CHECK(fake.outputs[1] == 1U); /* 200 ms после старта, второй импульс. */
|
||
|
||
CHECK(LedIndicator_SetModeAt(&indicator, 2U, LED_INDICATOR_MODE_STARTUP, 10U) != 0U);
|
||
LedIndicator_ProcessAt(&indicator, 610U);
|
||
CHECK(fake.outputs[2] == 1U); /* Однократный startup завершён постоянным ON. */
|
||
|
||
CHECK(LedIndicator_SetMode(&indicator, 3U, LED_INDICATOR_MODE_ON) == 0U);
|
||
CHECK(LedIndicator_GetMode(&indicator, 0U) == LED_INDICATOR_MODE_WORK);
|
||
|
||
CHECK(patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[0] == 100U && patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[1] == 900U && patterns[LED_INDICATOR_MODE_ACTIVITY].repeat == 0U); /* Фиксирует согласованные 10% свечения и один цикл на приём в канонической таблице. */
|
||
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 2500U) != 0U && fake.outputs[0] == 1U); /* Приём сразу включает канал независимо от фазы прежнего WORK. */
|
||
LedIndicator_ProcessAt(&indicator, 2599U); CHECK(fake.outputs[0] == 1U); /* До истечения 100 мс светодиод продолжает гореть. */
|
||
LedIndicator_ProcessAt(&indicator, 2600U); CHECK(fake.outputs[0] == 0U); /* Ровно через 100 мс начинается оставшаяся пауза 900 мс. */
|
||
LedIndicator_ProcessAt(&indicator, 3499U); CHECK(fake.outputs[0] == 0U); /* Конец первого периода не порождает дополнительную вспышку. */
|
||
LedIndicator_ProcessAt(&indicator, 3500U); CHECK(fake.outputs[0] == 0U); /* Однократный ACTIVITY завершается выключенным уровнем на границе 1000 мс. */
|
||
LedIndicator_ProcessAt(&indicator, 4500U); CHECK(fake.outputs[0] == 0U); /* Без новых пакетов свободное периодическое мигание отсутствует. */
|
||
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5000U) != 0U); /* Начинает новый приём после долгого отсутствия обмена. */
|
||
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5050U) != 0U); /* Второй пакет приходит внутри текущей фазы свечения. */
|
||
LedIndicator_ProcessAt(&indicator, 5100U); CHECK(fake.outputs[0] == 1U); /* Старый срок выключения больше не действует: отсчёт перезапущен новым пакетом. */
|
||
LedIndicator_ProcessAt(&indicator, 5149U); CHECK(fake.outputs[0] == 1U); /* Новый пакет получает собственные полные 100 мс свечения. */
|
||
LedIndicator_ProcessAt(&indicator, 5150U); CHECK(fake.outputs[0] == 0U); /* Новая фаза паузы начинается ровно от последнего приёма. */
|
||
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5400U) != 0U && fake.outputs[0] == 1U); /* Приём во время паузы сразу включает LED вместо ожидания границы старого периода. */
|
||
LedIndicator_ProcessAt(&indicator, 5500U); CHECK(fake.outputs[0] == 0U); /* Повторный запуск в паузе не создаёт очередь пропущенных циклов. */
|
||
fake.now = 7000U; CHECK(LedIndicator_TriggerActivity(&indicator, 1U) != 0U && fake.outputs[1] == 1U); /* Проверяет вариант событийного API с часами аппаратного порта и другим каналом. */
|
||
fake.now = 7100U; LedIndicator_Process(&indicator); CHECK(fake.outputs[1] == 0U && fake.outputs[0] == 0U); /* Каналы не перезапускают друг другу фазы и не создают фоновую активность. */
|
||
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, UINT32_MAX - 49U) != 0U); /* Начинает импульс непосредственно перед переполнением 32-битного времени. */
|
||
LedIndicator_ProcessAt(&indicator, 49U); CHECK(fake.outputs[0] == 1U); /* Через переполнение прошло 99 мс, поэтому свечение ещё активно. */
|
||
LedIndicator_ProcessAt(&indicator, 50U); CHECK(fake.outputs[0] == 0U); /* Через переполнение прошло ровно 100 мс, и LED гаснет без зависания. */
|
||
CHECK(LedIndicator_TriggerActivityAt(NULL, 0U, 0U) == 0U && LedIndicator_TriggerActivityAt(&indicator, 3U, 0U) == 0U); /* Ошибочный экземпляр и канал не вызывают запись чужого GPIO. */
|
||
puts("led indicator tests passed: receive 100/900 ms, immediate retrigger, no repeat, timer wrap"); /* Показывает прохождение новых событийных сценариев вместе с прежней диагностикой. */
|
||
return 0;
|
||
}
|