HW_Lib/lib/key/key.cpp

171 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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);
}
}