You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
5.0 KiB
C

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.

/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#include "button.h"
#define TICKS_INTERVAL 5 //ms
#define EVENT_CB(ev) if(handle->cb[ev]){handle->cb[ev](handle)}
//According to your need to modify the constants.
const uint8_t kDebounceTicks = 3; //MAX 8
const uint16_t kShortTicks = (350/TICKS_INTERVAL);
const uint16_t kLongTicks = (1000/TICKS_INTERVAL);
//button handle list head.
static struct Button* head_handle = NULL;
/**
* @brief Initializes the button struct handle.
* @param handle: the button handle strcut.
* @param pin_level: read the HAL GPIO of the connet button level.
* @param active_level: pressed GPIO level.
* @retval None
*/
void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level)
{
memset(handle, sizeof(struct Button), 0);
handle->hal_button_Level = pin_level;
handle->button_level = handle->hal_button_Level();
handle->active_level = active_level;
}
/**
* @brief Attach the button event callback function.
* @param handle: the button handle strcut.
* @param event: trigger event type.
* @param cb: callback function.
* @retval None
*/
void button_attach(struct Button* handle, PressEvent event, CallBackFunc cb)
{
handle->cb[event] = cb;
}
/**
* @brief Inquire the button event happen.
* @param handle: the button handle strcut.
* @retval button event.
*/
PressEvent get_button_event(const struct Button* handle)
{
return (handle->event);
}
/**
* @brief Button driver core function, driver state machine.
* @param handle: the button handle strcut.
* @retval None
*/
void button_handler(struct Button* handle)
{
uint8_t read_gpio_level = handle->hal_button_Level();
//ticks counter working..
if((handle->state) > 0) handle->ticks++;
/*------------button debounce handle---------------*/
if(read_gpio_level != handle->button_level) { //not equal to prev one
//continue read 3 times same new level change
if(++(handle->debounce_cnt) >= kDebounceTicks) {
handle->button_level = read_gpio_level;
handle->debounce_cnt = 0;
}
} else { //leved not change ,counter reset.
handle->debounce_cnt = 0;
}
/*-----------------State machine-------------------*/
switch (handle->state) {
case 0:
if(handle->button_level == handle->active_level) { //start press down
handle->event = (uint8_t)PRESS_DOWN;
EVENT_CB(PRESS_DOWN);
handle->ticks = 0;
handle->repeat = 1;
handle->state = 1;
}
break;
case 1:
if(handle->button_level != handle->active_level) { //released press up
handle->event = (uint8_t)PRESS_UP;
EVENT_CB(PRESS_UP);
handle->ticks = 0;
handle->state = 2;
} else if(handle->ticks > kLongTicks) {
handle->event = (uint8_t)LONG_RRESS_START;
EVENT_CB(LONG_RRESS_START);
handle->state = 5;
}
break;
case 2:
if(handle->button_level == handle->active_level) { //press down again
handle->event = (uint8_t)PRESS_DOWN;
EVENT_CB(PRESS_DOWN);
handle->repeat++
if(handle->repeat == 2) {
handle->event = (uint8_t)DOUBLE_CLICK;
EVENT_CB(DOUBLE_CLICK); // repeat hit
} else {
handle->event = (uint8_t)PRESS_REPEAT;
}
EVENT_CB(PRESS_REPEAT); // repeat hit
handle->ticks = 0;
handle->state = 3;
} else if(handle->ticks > kShortTicks) {
if(handle->repeat == 1) {
handle->event = (uint8_t)SINGLE_CLICK;
EVENT_CB(SINGLE_CLICK);
}
handle->state = 0;
handle->event = (uint8_t)NONE_PRESS;
}
break;
case 3:
if(handle->button_level != handle->active_level) { //released press up
handle->event = (uint8_t)PRESS_UP;
EVENT_CB(PRESS_UP);
if(handle->ticks < kShortTicks) {
handle->ticks = 0;
handle->state = 2; //repeat press
} else {
handle->state = 0;
handle->event = (uint8_t)NONE_PRESS;
}
}
break;
case 5:
if(handle->button_level == handle->active_level) {
//continue hold trigger
handle->event = (uint8_t)LONG_PRESS_HOLD;
EVENT_CB(LONG_PRESS_HOLD);
} else { //releasd
handle->event = (uint8_t)PRESS_UP;
EVENT_CB(PRESS_UP)
handle->state = 0; //reset
handle->event = (uint8_t)NONE_PRESS;
}
break;
}
}
/**
* @brief Start the button work, add the handle into work list.
* @param btn: target handle strcut.
* @retval 0: succeed. -1: already exist.
*/
int button_start(struct Button* btn)
{
struct Button* target = head_handle;
while(target) {
if(target == btn) return -1; //already exist.
target = target->next;
}
btn->next = head_handle;
head_handle = btn;
return 0;
}
/**
* @brief Stop the button work, remove the handle off work list.
* @param btn: target handle strcut.
* @retval None
*/
void button_stop(struct Button* btn)
{
struct Button** curr;
for(curr = &head_handle; *curr; ) {
struct Button* entry = *curr;
if (entry == btn) {
*curr = entry->next;
// free(entry);
} else
curr = &entry->next;
}
}
/**
* @brief background ticks, timer repeat invoking interval 5ms.
* @param None.
* @retval None
*/
void button_ticks()
{
struct Button* target;
for(target=head_handle; target; target=target->next) {
button_handler(target);
}
}