Перенесён из KONOR_ds18b20/lib/keypad; в OpticalTester лежала такая же копия. О портах и таймерах библиотека не знает: уровни приходят обратным вызовом read(), время — параметром Keypad_Poll(). События складываются в очередь на восемь штук, поэтому быстрое нажатие не теряется, пока приложение перерисовывает экран.
146 lines
7.9 KiB
C
146 lines
7.9 KiB
C
/**
|
||
* @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 */
|