171 lines
4.7 KiB
C++
171 lines
4.7 KiB
C++
#include <malloc.h>
|
||
#include "key.h"
|
||
|
||
|
||
#define EVENT_CB(ev) if(key->cb[ev])key->cb[ev](key)
|
||
#define PRESS_REPEAT_MAX_NUM 15
|
||
|
||
|
||
static Key_t *head_key = NULL;
|
||
|
||
static void key_state_switch(Key_t *key);
|
||
|
||
|
||
void key_init(Key_t *key, uint8_t key_id, uint8_t active_level, uint8_t(*read_pin)(uint8_t)) {
|
||
memset(key, 0, sizeof(Key_t));
|
||
key->event = (uint8_t) NONE_PRESS;
|
||
key->hal_read_pin = read_pin;
|
||
key->key_level = !active_level;
|
||
key->active_level = active_level;
|
||
key->key_id = key_id;
|
||
}
|
||
|
||
|
||
void key_attach(Key_t *key, PressEvent event, Key_Callback_t cb, bool start) {
|
||
// 如果事件类型为ALL_EVENT,则将回调函数cb分别赋值给所有事件类型
|
||
if (event == KEY_ALL_EVENT) {
|
||
for (uint8_t i = KEY_PRESS_UP; i < number_of_event; i++) {
|
||
key->cb[i] = cb;
|
||
}
|
||
} else {
|
||
// 否则,将回调函数cb赋值给指定的事件类型
|
||
key->cb[event] = cb;
|
||
}
|
||
if (start)key_start(key);
|
||
}
|
||
|
||
PressEvent get_key_event(Key_t *key) {
|
||
return (PressEvent) (key->event);
|
||
}
|
||
|
||
static void key_state_switch(Key_t *key) {
|
||
// 读取按键的GPIO电平
|
||
uint8_t read_gpio_level = key->hal_read_pin(key->key_id);
|
||
|
||
// 如果按键状态大于0,则增加ticks计数
|
||
if ((key->state) > 0) key->ticks++;
|
||
|
||
// 按键去抖动处理
|
||
if (read_gpio_level != key->key_level) {
|
||
if (++(key->debounce_cnt) >= DEBOUNCE_TICKS) {
|
||
key->key_level = read_gpio_level;
|
||
key->debounce_cnt = 0;
|
||
}
|
||
} else {
|
||
key->debounce_cnt = 0;
|
||
}
|
||
|
||
// 状态机处理按键事件
|
||
switch (key->state) {
|
||
case 0:
|
||
if (key->key_level == key->active_level) {
|
||
key->event = (uint8_t) KEY_PRESS_DOWN;
|
||
EVENT_CB(KEY_PRESS_DOWN);
|
||
key->ticks = 0;
|
||
key->repeat = 1;
|
||
key->state = 1;
|
||
} else {
|
||
key->event = (uint8_t) NONE_PRESS;
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
if (key->key_level != key->active_level) {
|
||
key->event = (uint8_t) KEY_PRESS_UP;
|
||
EVENT_CB(KEY_PRESS_UP);
|
||
key->ticks = 0;
|
||
key->state = 2;
|
||
} else if (key->ticks > LONG_TICKS) {
|
||
key->event = (uint8_t) KEY_LONG_PRESS_START;
|
||
EVENT_CB(KEY_LONG_PRESS_START);
|
||
key->state = 5;
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
if (key->key_level == key->active_level) {
|
||
key->event = (uint8_t) KEY_PRESS_DOWN;
|
||
EVENT_CB(KEY_PRESS_DOWN);
|
||
if (key->repeat != PRESS_REPEAT_MAX_NUM) {
|
||
key->repeat++;
|
||
}
|
||
EVENT_CB(KEY_PRESS_REPEAT);
|
||
key->ticks = 0;
|
||
key->state = 3;
|
||
} else if (key->ticks > SHORT_TICKS) {
|
||
if (key->repeat == 1) {
|
||
key->event = (uint8_t) KEY_SINGLE_CLICK;
|
||
EVENT_CB(KEY_SINGLE_CLICK);
|
||
} else if (key->repeat == 2) {
|
||
key->event = (uint8_t) KEY_DOUBLE_CLICK;
|
||
EVENT_CB(KEY_DOUBLE_CLICK);
|
||
}
|
||
key->state = 0;
|
||
}
|
||
break;
|
||
|
||
case 3:
|
||
if (key->key_level != key->active_level) {
|
||
key->event = (uint8_t) KEY_PRESS_UP;
|
||
EVENT_CB(KEY_PRESS_UP);
|
||
if (key->ticks < SHORT_TICKS) {
|
||
key->ticks = 0;
|
||
key->state = 2;
|
||
} else {
|
||
key->state = 0;
|
||
}
|
||
} else if (key->ticks > SHORT_TICKS) {
|
||
key->state = 1;
|
||
}
|
||
break;
|
||
|
||
case 5:
|
||
if (key->key_level == key->active_level) {
|
||
key->event = (uint8_t) KEY_LONG_PRESS_HOLD;
|
||
EVENT_CB(KEY_LONG_PRESS_HOLD);
|
||
} else {
|
||
key->event = (uint8_t) KEY_PRESS_UP;
|
||
EVENT_CB(KEY_PRESS_UP);
|
||
key->state = 0;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
key->state = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
int key_start(Key_t *key) {
|
||
Key_t *target = head_key;
|
||
while (target) {
|
||
if (target == key) return -1;
|
||
target = target->next;
|
||
}
|
||
key->next = head_key;
|
||
head_key = key;
|
||
return 0;
|
||
}
|
||
|
||
void key_stop(Key_t *key) {
|
||
Key_t **curr;
|
||
for (curr = &head_key; *curr;) {
|
||
Key_t *entry = *curr;
|
||
if (entry == key) {
|
||
*curr = entry->next;
|
||
#if KEY_STOP_FREE
|
||
free(entry);
|
||
#endif
|
||
return;
|
||
} else {
|
||
curr = &entry->next;
|
||
}
|
||
}
|
||
}
|
||
|
||
void key_ticks(void) {
|
||
Key_t *target;
|
||
for (target = head_key; target; target = target->next) {
|
||
key_state_switch(target);
|
||
}
|
||
} |