Files
templates/c/keypad/keypad.h
Andrey Kruchinkin 54f0ba7b0e feat(keypad): опрос шести кнопок с антидребезгом и автоповтором
Перенесён из KONOR_ds18b20/lib/keypad; в OpticalTester лежала такая же копия.

О портах и таймерах библиотека не знает: уровни приходят обратным вызовом
read(), время — параметром Keypad_Poll(). События складываются в очередь
на восемь штук, поэтому быстрое нажатие не теряется, пока приложение
перерисовывает экран.
2026-08-23 01:15:11 +03:00

146 lines
7.9 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file keypad.h
* @brief Портируемый опрос шести кнопок навигации с антидребезгом.
*
* Библиотека не знает ни о портах, ни о таймерах: уровни кнопок она получает
* через обратный вызов порта, а время — параметром Keypad_Poll(). События
* складываются в короткую очередь, поэтому быстрое нажатие не теряется, даже
* если приложение перерисовывает экран.
*
* Кнопок ровно шесть: четыре направления, ввод и возврат. Такой набор
* покрывает навигацию по меню без матрицы и сдвиговых регистров.
*/
#ifndef KEYPAD_H
#define KEYPAD_H
#include <stdint.h>
/** @brief Кнопки клавиатуры; порядок задаёт индексы для обратного вызова. */
typedef enum {
KEYPAD_KEY_UP = 0, /**< Вверх: предыдущий пункт меню. */
KEYPAD_KEY_DOWN, /**< Вниз: следующий пункт меню. */
KEYPAD_KEY_LEFT, /**< Влево: уменьшение значения. */
KEYPAD_KEY_RIGHT, /**< Вправо: увеличение значения. */
KEYPAD_KEY_ENTER, /**< Ввод: вход в пункт или подтверждение. */
KEYPAD_KEY_BACK, /**< Назад: возврат на предыдущий экран. */
KEYPAD_KEY_COUNT /**< Число кнопок; не является кнопкой. */
} Keypad_Key;
/** @brief Вид события клавиатуры. */
typedef enum {
KEYPAD_EVENT_PRESS = 0, /**< Нажатие после подтверждения антидребезгом. */
KEYPAD_EVENT_REPEAT, /**< Автоповтор при удержании. */
KEYPAD_EVENT_LONG, /**< Удержание дольше порога, выдаётся один раз. */
KEYPAD_EVENT_RELEASE /**< Отпускание кнопки. */
} Keypad_EventType;
/** @brief Событие очереди клавиатуры. */
typedef struct {
Keypad_Key key; /**< Кнопка, вызвавшая событие. */
Keypad_EventType type; /**< Вид события. */
} Keypad_Event;
/** Глубина очереди событий; хватает на любой темп нажатий вручную. */
#define KEYPAD_QUEUE_SIZE 8U
/** Маска кнопок направлений для поля repeat_mask. */
#define KEYPAD_MASK_ARROWS ((uint8_t)((1U << KEYPAD_KEY_UP) | (1U << KEYPAD_KEY_DOWN) \
| (1U << KEYPAD_KEY_LEFT) | (1U << KEYPAD_KEY_RIGHT)))
/** Маска всех кнопок клавиатуры. */
#define KEYPAD_MASK_ALL ((uint8_t)((1U << KEYPAD_KEY_COUNT) - 1U))
/**
* @brief Параметры клавиатуры; нулевые поля заменяются значениями по умолчанию.
*/
typedef struct {
/** Читает состояние кнопки: 1 — нажата. Индекс — значение Keypad_Key. */
uint8_t (*read)(void *context, uint8_t key);
void *context; /**< Указатель платы для обратного вызова. */
uint16_t debounce_ms; /**< Время подтверждения уровня, по умолчанию 20. */
uint16_t repeat_delay_ms; /**< Пауза до автоповтора, по умолчанию 400. */
uint16_t repeat_period_ms;/**< Период автоповтора, по умолчанию 120. */
uint16_t long_press_ms; /**< Порог удержания, по умолчанию 800. */
uint8_t repeat_mask; /**< Кнопки с автоповтором, по умолчанию стрелки. */
} Keypad_Config;
/** @brief Состояние одной кнопки. */
typedef struct {
uint8_t raw; /**< Последний прочитанный уровень. */
uint8_t stable; /**< Подтверждённое состояние: 1 — нажата. */
uint8_t long_sent; /**< Признак выданного события удержания. */
uint32_t changed_ms; /**< Момент последнего изменения сырого уровня. */
uint32_t pressed_ms; /**< Момент подтверждённого нажатия. */
uint32_t repeated_ms; /**< Момент последнего события автоповтора. */
} Keypad_KeyState;
/** @brief Состояние клавиатуры; принадлежит вызывающему коду. */
typedef struct {
Keypad_Config config; /**< Копия параметров. */
Keypad_KeyState keys[KEYPAD_KEY_COUNT]; /**< Состояния кнопок. */
Keypad_Event queue[KEYPAD_QUEUE_SIZE]; /**< Кольцевая очередь событий. */
uint8_t head; /**< Индекс чтения очереди. */
uint8_t count; /**< Число событий в очереди. */
uint8_t overflow; /**< Признак потери событий. */
} Keypad;
/**
* @brief Готовит клавиатуру к работе и подставляет значения по умолчанию.
*
* Состояние всех кнопок считается отпущенным, поэтому зажатая при включении
* кнопка даёт обычное событие нажатия после выдержки антидребезга.
*
* @param keypad Состояние клавиатуры.
* @param config Параметры; обязателен только обратный вызов чтения.
* @return 1 при успешной настройке, 0 если обратный вызов не задан.
*/
uint8_t Keypad_Init(Keypad *keypad, const Keypad_Config *config);
/**
* @brief Опрашивает кнопки и наполняет очередь событий.
*
* Вызывается из главного цикла с любым темпом: шаг антидребезга задаётся не
* периодом вызова, а метками времени.
*
* @param keypad Состояние клавиатуры.
* @param now_ms Текущее монотонное время в миллисекундах.
*/
void Keypad_Poll(Keypad *keypad, uint32_t now_ms);
/**
* @brief Забирает следующее событие из очереди.
*
* @param keypad Состояние клавиатуры.
* @param event Приёмник события.
* @return 1, если событие получено, 0 если очередь пуста.
*/
uint8_t Keypad_GetEvent(Keypad *keypad, Keypad_Event *event);
/**
* @brief Сообщает подтверждённое состояние кнопки.
*
* @param keypad Состояние клавиатуры.
* @param key Опрашиваемая кнопка.
* @return 1, если кнопка нажата.
*/
uint8_t Keypad_IsDown(const Keypad *keypad, Keypad_Key key);
/**
* @brief Возвращает и сбрасывает признак переполнения очереди.
*
* @param keypad Состояние клавиатуры.
* @return 1, если события терялись с прошлого вызова.
*/
uint8_t Keypad_Overflow(Keypad *keypad);
/**
* @brief Даёт короткое имя кнопки для отладочных сообщений и экранов.
*
* @param key Кнопка.
* @return Строка вида "UP"; для неизвестного кода — "?".
*/
const char *Keypad_KeyName(Keypad_Key key);
#endif /* KEYPAD_H */