-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathkey.h
More file actions
262 lines (230 loc) · 7.35 KB
/
Copy pathkey.h
File metadata and controls
262 lines (230 loc) · 7.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/**
* @file key.h
* @brief 键盘按键驱动接口(GPIO 边沿中断 + 1ms 定时器锁定去抖 + 事件队列)
* @details
* 本模块将按键输入抽象为“事件队列”:
* - 普通按键(K1..Kn):产生 PRESS / RELEASE 事件(是否上报 RELEASE 可配置)
* - FN 按键(FN1..FNn):按下只记录起始时间,松开时根据持续时间产生 CLICK / LONG 事件
* - BOOT 键:仅提供原始电平读取(不使用中断)
*
* 典型使用:
* @code
* Key_Init();
* while (1) {
* key_event_t e;
* if (Key_GetEvent(&e)) {
* // 处理普通按键事件
* }
*
* fnkey_event_t fe;
* if (FnKey_GetEvent(&fe)) {
* // 处理 FN CLICK/LONG
* }
* }
* @endcode
*
* @note
* - GPIO 输入为上拉模式:按下=0,松开=1(Active-Low)
* - 事件队列满时,新事件会被丢弃(Drop)
*/
#ifndef KBD_KEY_H_
#define KBD_KEY_H_
#include <stdint.h>
#include "kbd_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup KBD_KEY 键盘按键驱动(key)
* @brief GPIO 边沿中断 + 1ms 定时器锁定去抖 + 环形队列上报事件
* @{
*/
/* ============================================================================
* Configuration
* ============================================================================
*/
/**
* @def KEY_LOCKOUT_MS
* @brief 普通按键锁定去抖时间(毫秒)。
* @details
* 每次边沿中断触发后,该按键会进入 lockout 状态:
* - 禁用该引脚中断
* - 由 1ms 定时器递减 lock_ms
* - lock_ms 归零后清中断标志并重新使能引脚中断
*/
#ifndef KEY_LOCKOUT_MS
#define KEY_LOCKOUT_MS 10
#endif
/**
* @def FN_LOCKOUT_MS
* @brief FN 按键锁定去抖时间(毫秒)。
*/
#ifndef FN_LOCKOUT_MS
#define FN_LOCKOUT_MS 15
#endif
/**
* @def FN_LONG_PRESS_MS
* @brief FN 长按阈值(毫秒),松开时用持续时间判定 CLICK 或 LONG。
*/
#ifndef FN_LONG_PRESS_MS
#define FN_LONG_PRESS_MS 800
#endif
/**
* @def KEY_ENABLE_RELEASE_EVENT
* @brief 是否为普通按键上报 RELEASE 事件(1=上报,0=不上报)。
* @note
* 若关闭 RELEASE 事件,则普通键只会上报 PRESS,且内部 expect 不会切到 release;
* 此时 Key_IsDown() 将长期保持为 1(按下后不再被 release 更新),这通常是“只关心触发”的场景。
*/
#ifndef KEY_ENABLE_RELEASE_EVENT
#define KEY_ENABLE_RELEASE_EVENT 1
#endif
/**
* @def KEY_QUEUE_SIZE
* @brief 普通按键事件队列容量(必须为 2 的幂)。
*/
#ifndef KEY_QUEUE_SIZE
#define KEY_QUEUE_SIZE 16
#endif
/**
* @def FNKEY_QUEUE_SIZE
* @brief FN 按键事件队列容量(必须为 2 的幂)。
*/
#ifndef FNKEY_QUEUE_SIZE
#define FNKEY_QUEUE_SIZE 8
#endif
/**
* @def KEY_IRQ_PRIORITY
* @brief GPIO 中断优先级(平台相关)。
*/
#ifndef KEY_IRQ_PRIORITY
#define KEY_IRQ_PRIORITY 3
#endif
/**
* @def TIMER_IRQ_PRIORITY
* @brief 1ms 定时器中断优先级(平台相关)。
*/
#ifndef TIMER_IRQ_PRIORITY
#define TIMER_IRQ_PRIORITY 2
#endif
/* ============================================================================
* Types
* ============================================================================
*/
/**
* @enum key_evt_type_t
* @brief 普通按键事件类型。
*/
typedef enum {
KEY_EVT_PRESS = 1, /**< 按下事件(下降沿触发,Active-Low) */
KEY_EVT_RELEASE = 2, /**< 松开事件(上升沿触发) */
} key_evt_type_t;
/**
* @struct key_event_t
* @brief 普通按键事件结构。
*/
typedef struct {
uint8_t key; /**< 逻辑按键索引(0..KBD_TOTAL_KEYS-1) */
uint8_t type; /**< 事件类型,见 @ref key_evt_type_t */
uint32_t tick_ms; /**< 事件产生时的毫秒计数(自 Key_Init() 起) */
} key_event_t;
/**
* @enum fnkey_id_t
* @brief FN 键 ID。
* @note 这里示例为 2 个 FN 键(FNKEY_1 / FNKEY_2),由 KBD_FN_NUM_KEYS 决定实际数量。
*/
typedef enum {
FNKEY_1 = 0, /**< FN1 */
FNKEY_2 = 1, /**< FN2 */
} fnkey_id_t;
/**
* @enum fnkey_evt_type_t
* @brief FN 键事件类型(松开时产生)。
*/
typedef enum {
FNKEY_EVT_CLICK = 1, /**< 短按(dur < FN_LONG_PRESS_MS) */
FNKEY_EVT_LONG = 2, /**< 长按(dur >= FN_LONG_PRESS_MS) */
} fnkey_evt_type_t;
/**
* @struct fnkey_event_t
* @brief FN 键事件结构。
*/
typedef struct {
uint8_t id; /**< FN 键 ID(0..KBD_FN_NUM_KEYS-1),对应 g_fn_pins[] */
uint8_t type; /**< 事件类型,见 @ref fnkey_evt_type_t */
uint32_t tick_ms; /**< 事件产生时的毫秒计数(自 Key_Init() 起) */
} fnkey_event_t;
/* ============================================================================
* API
* ============================================================================
*/
/**
* @brief 初始化按键驱动。
* @details
* - 配置 BOOT / 普通键 / FN 键为上拉输入
* - 配置 GPIO 边沿中断(普通键根据当前电平决定先等下降沿还是上升沿;FN 键强制先等下降沿)
* - 初始化队列和上下文(ctx)
* - 启动 1ms 定时器,用于:
* - 提供 tick_ms 时间戳
* - lockout 倒计时到 0 时重新打开引脚中断
*/
void Key_Init(void);
/**
* @brief 读取一个普通按键事件(出队)。
* @param[out] evt 事件输出指针(不可为 NULL)。
* @return 1 表示成功读到一个事件;0 表示队列为空或参数无效。
* @note
* - 队列为环形队列:ISR 侧 Push,主循环侧 Pop
* - 队列满时 ISR 会丢弃新事件(不覆盖旧事件)
*/
uint8_t Key_GetEvent(key_event_t *evt);
/**
* @brief 查询普通按键当前是否处于按下状态。
* @param key_index 逻辑按键索引
* @return 1=按下,0=松开,-1=索引非法
* @note
* 若 KEY_ENABLE_RELEASE_EVENT=0,则 is_down 在按下后不会被 release 更新。
* 仅对普通按键扫描链路中的键有效;旋钮转动等虚拟键返回 -1。
*/
int8_t Key_IsDown(uint8_t key_index);
/**
* @brief 读取一个 FN 按键事件(出队)。
* @param[out] evt 事件输出指针(不可为 NULL)。
* @return 1 表示成功读到一个事件;0 表示队列为空或参数无效。
* @details
* FN 键事件在“松开边沿”产生:根据按下持续时间判定 CLICK / LONG。
*/
uint8_t FnKey_GetEvent(fnkey_event_t *evt);
/**
* @brief 查询 FN 按键当前是否处于按下状态。
* @param id FN 键索引(0..KBD_FN_NUM_KEYS-1)
* @return 1=按下,0=松开,-1=索引非法
*/
int8_t FnKey_IsDown(uint8_t id);
/**
* @brief 读取 BOOT 键是否按下(原始电平读取,不使用中断)。
* @return 1=按下,0=松开
* @note Active-Low:按下为 0,松开为 1。
*/
int8_t BootKey_IsPressed(void);
/**
* @brief 进入低功耗前的钩子(可选)。
* @details 当前实现为:停止 1ms 定时器,以降低功耗/避免不必要中断。
*/
void Key_EnterSleep(void);
/**
* @brief 退出低功耗后的钩子(可选)。
* @details 当前实现为:重新启动 1ms 定时器。
*/
void Key_ExitSleep(void);
/**
* @brief 配置深度休眠唤醒:所有按键引脚设置为低电平触发 + 打开 GPIO 唤醒源。
* @note 进入 LowPower_Shutdown() / LowPower_Sleep() 前调用;
* 任意按键 / FN 键按下(低电平)都会唤醒 MCU。
*/
void Key_ConfigDeepSleepWakeup(void);
/** @} */ /* end of KBD_KEY */
#ifdef __cplusplus
}
#endif
#endif /* KBD_KEY_H_ */