diff --git a/multi_button.c b/multi_button.c new file mode 100644 index 0000000..6f77e4b --- /dev/null +++ b/multi_button.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016 Zibin Zheng + * All rights reserved + */ + +#include "multi_button.h" + +#define EVENT_CB(ev) if(handle->cb[ev])handle->cb[ev]((Button*)handle) + + +//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->event = (uint8_t)NONE_PRESS; + 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, BtnCallback cb) +{ + handle->cb[event] = cb; +} + +/** + * @brief Inquire the button event happen. + * @param handle: the button handle strcut. + * @retval button event. + */ +PressEvent get_button_event(struct Button* handle) +{ + return (PressEvent)(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) >= DEBOUNCE_TICKS) { + 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 > LONG_TICKS) { + 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 > SHORT_TICKS) { + 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 < SHORT_TICKS) { + 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 handle: target handle strcut. + * @retval 0: succeed. -1: already exist. + */ +int button_start(struct Button* handle) +{ + struct Button* target = head_handle; + while(target) { + if(target == handle) return -1; //already exist. + target = target->next; + } + handle->next = head_handle; + head_handle = handle; + return 0; +} + +/** + * @brief Stop the button work, remove the handle off work list. + * @param handle: target handle strcut. + * @retval None + */ +void button_stop(struct Button* handle) +{ + struct Button** curr; + for(curr = &head_handle; *curr; ) { + struct Button* entry = *curr; + if (entry == handle) { + *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); + } +} + diff --git a/multi_button.h b/multi_button.h new file mode 100644 index 0000000..a6199d6 --- /dev/null +++ b/multi_button.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Zibin Zheng + * All rights reserved + */ + +#ifndef _MULTI_BUTTON_H_ +#define _MULTI_BUTTON_H_ + +#include "stdint.h" +#include "string.h" + +//According to your need to modify the constants. +#define TICKS_INTERVAL 5 //ms +#define DEBOUNCE_TICKS 4 //MAX 8 +#define SHORT_TICKS (300 /TICKS_INTERVAL) +#define LONG_TICKS (1000 /TICKS_INTERVAL) + + +typedef void (*BtnCallback)(void*); + +typedef enum { + PRESS_DOWN = 0, + PRESS_UP, + PRESS_REPEAT, + SINGLE_CLICK, + DOUBLE_CLICK, + LONG_RRESS_START, + LONG_PRESS_HOLD, + number_of_event, + NONE_PRESS +}PressEvent; + +typedef struct Button { + uint16_t ticks; + uint8_t repeat : 4; + uint8_t event : 4; + uint8_t state : 3; + uint8_t debounce_cnt : 3; + uint8_t active_level : 1; + uint8_t button_level : 1; + uint8_t (*hal_button_Level)(void); + BtnCallback cb[number_of_event]; + struct Button* next; +}Button; + +#ifdef __cplusplus +extern "C" { +#endif + +void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level); +void button_attach(struct Button* handle, PressEvent event, BtnCallback cb); +PressEvent get_button_event(struct Button* handle); +int button_start(struct Button* handle); +void button_stop(struct Button* handle); +void button_ticks(void); + +#ifdef __cplusplus +} +#endif + +#endif