LED Indicator
Неблокирующая C99-библиотека для индикации состояний STARTUP, WORK,
ACTIVITY, WARNING, ERROR и CRITICAL с разными рисунками и частотами.
Один экземпляр обслуживает несколько светодиодов.
Ядро не знает о GPIO, PWM, сдвиговом регистре, RTOS и модели таймера. Порт передаёт логическое состояние канала наружу и читает монотонное время в миллисекундах. В библиотеке нет задержек, динамической памяти, прерываний и изменяемого глобального состояния.
приложение -> LedIndicator_SetMode/Process -> ядро -> write/now_ms -> GPIO/PWM/expander + TIM
Файлы
| Файл | Назначение | Зависимости |
|---|---|---|
led_indicator.h/.c |
режимы, шаблоны и планировщик | C99, stdint.h |
ports/stm32-hal |
GPIO и выбранный аппаратный TIM | STM32 HAL |
tests/test_led_indicator.c |
host-тесты, включая переполнение uint32_t |
libc |
Встроенные режимы
| Режим | Сигнал |
|---|---|
OFF / ON |
постоянно выключен / включён |
STARTUP |
три коротких импульса, затем постоянно включён |
WORK |
100 мс включён, 900 мс выключен |
ACTIVITY |
50/50 мс |
WARNING |
250/250 мс |
ERROR |
два импульса и пауза |
CRITICAL |
три импульса и пауза |
Частоты не зашиты в алгоритм. Скопируйте встроенную таблицу и измените
duration_ms до инициализации:
static LedIndicator_Pattern patterns[LED_INDICATOR_MODE_COUNT];
LedIndicator_CopyDefaultPatterns(patterns, LED_INDICATOR_MODE_COUNT);
patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] = 50U;
patterns[LED_INDICATOR_MODE_WORK].duration_ms[1] = 1950U;
config.patterns = patterns;
config.pattern_count = LED_INDICATOR_MODE_COUNT;
Таблица должна существовать всё время работы экземпляра. До восьми шагов
описываются длительностями и битовой маской levels; шаблон может повторяться
или после одного прохода перейти в final_level.
Контракт порта
void write(void *context, uint8_t channel, uint8_t logical_on);
uint32_t now_ms(void *context);
write получает именно логический уровень. Инверсию active-low, управление
PWM или запись общего регистра расширителя выполняет порт. Переполнение
32-битной миллисекундной метки обработано разностью беззнаковых чисел.
Если время уже есть в планировщике приложения, now_ms можно оставить NULL
и вызывать варианты LedIndicator_SetModeAt/LedIndicator_ProcessAt.
Быстрый старт без привязки к HAL
static LedIndicator led;
static LedIndicator_Channel state[2];
LedIndicator_Config cfg;
LedIndicator_Port port = {Board_LedWrite, Board_TimerMs, &board};
LedIndicator_ConfigDefault(&cfg);
LedIndicator_Init(&led, state, 2U, &port, &cfg);
LedIndicator_SetMode(&led, 0U, LED_INDICATOR_MODE_WORK);
LedIndicator_SetMode(&led, 1U, LED_INDICATOR_MODE_ERROR);
for (;;) {
LedIndicator_Process(&led);
}
SetMode идемпотентен: повторный вызов того же режима в каждом проходе цикла
не начинает рисунок заново. Для нового импульса события служит
LedIndicator_RestartMode.
STM32F103, STM32F4, STM32G431 и STM32G474
Порт ports/stm32-hal принимает конкретный TIM_HandleTypeDef *; библиотека
не использует HAL_GetTick() и не занимает SysTick. Настройте TIM как
free-running, запустите его и передайте частоту счётчика после prescaler.
Скопируйте подходящий led_indicator_stm32_hal_config.*.template.h в каталог
платы под именем led_indicator_stm32_hal_config.h.
static const LedIndicator_Stm32HalOutput outputs[] = {
{STATUS_GPIO_Port, STATUS_Pin, 0U},
{ERROR_GPIO_Port, ERROR_Pin, 1U}
};
static LedIndicator_Stm32HalPort hw;
static LedIndicator_Port port;
HAL_TIM_Base_Start(&htim6); /* CNT = 1 кГц в данном примере. */
LedIndicator_Stm32HalPortInit(&hw, &htim6, 1000U,
outputs, 2U, &port);
LedIndicator_Process() должен вызываться чаще, чем переполняется выбранный
TIM. Для 16-битного CNT на 1 кГц это не реже одного раза за 65 секунд. Сам
таймер и его prescaler/period задаются в CubeMX или board-порте, а не в ядре.
Для К1921ВК028 и C28x используется тот же основной порт: now_ms возвращает
счётчик, увеличиваемый обработчиком выбранного TIMER/CPU Timer, а write
обращается к GPIO SDK. Такое разделение оставляет номер таймера и выводы в
проекте конкретной платы.
Проверка
cmake -S c/led-indicator -B build/led-indicator
cmake --build build/led-indicator
ctest --test-dir build/led-indicator --output-on-failure