/* * Copyright (c) 2016 Zibin Zheng * All rights reserved * 修改: kinve.2017-12-11: 长按周期触发 */ #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_Head ( void ) { head_handle = NULL; } void button_init ( struct Button* handle, uint8_t ( *pin_level ) (), uint8_t active_level ) { memset ( handle, 0, sizeof ( struct Button ) ); 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; } else { handle->event = ( uint8_t ) NONE_PRESS; } 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 ) { EVENT_CB ( DOUBLE_CLICK ); // repeat hit } EVENT_CB ( PRESS_REPEAT ); // repeat hit handle->ticks = 0; handle->state = 3; } else if ( handle->ticks > SHORT_TICKS ) //released timeout { if ( handle->repeat == 1 ) { handle->event = ( uint8_t ) SINGLE_CLICK; EVENT_CB ( SINGLE_CLICK ); } else if ( handle->repeat == 2 ) { handle->event = ( uint8_t ) DOUBLE_CLICK; } handle->state = 0; } 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; } } break; case 5: if ( handle->button_level == handle->active_level ) { #ifndef LONG_TICKS_TRIG //continue hold trigger handle->event = ( uint8_t ) LONG_PRESS_HOLD; EVENT_CB ( LONG_PRESS_HOLD ); #else //长按后tick每周期触发 //增加长按周期触发 if ( handle->ticks > ( LONG_TICKS + LONG_TICKS_TRIG ) ) { handle->ticks = LONG_TICKS;//重新启动 handle->event = ( uint8_t ) LONG_PRESS_HOLD; EVENT_CB ( LONG_PRESS_HOLD ); } #endif } else //releasd { handle->event = ( uint8_t ) PRESS_UP; EVENT_CB ( PRESS_UP ); handle->state = 0; //reset } 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 ); } }