Library for detecting button clicks, doubleclicks and long press pattern on a single button. Updated to use Callback class when mbed lib >= 122 is used. Then also member functions can be used as callbacks.

Dependents:   ECH_V004

Fork of OneButton by Zibin Zheng

OneButton.cpp

Committer:
JojoS
Date:
2016-09-22
Revision:
2:26960fb1d783
Parent:
1:fdf67f893a5c
Child:
3:48a593e2d4cf

File content as of revision 2:26960fb1d783:

// Modifyed to support mbed environment, rewrite the state machine.
// by Zibin Zheng <znbin@qq.com>

// -----
// OneButton.cpp - Library for detecting button clicks, doubleclicks and long press pattern on a single button.
// This class is implemented for use with the Arduino environment.
// Copyright (c) by Matthias Hertel, http://www.mathertel.de
// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
// More information on: http://www.mathertel.de/Arduino
// -----


#include "OneButton.h"


// ----- Initialization and Default Values -----

OneButton::OneButton(PinName pin, bool active_level)
{
    btn_pin = new DigitalIn((PinName)pin);      // sets the MenuPin as input

    timer = new Timer;
    timer->start();

    _clickTicks = 400;        // number of millisec that have to pass by before a click is detected.
    _pressTicks = 800;       // number of millisec that have to pass by before a long button press is detected.
    _debounceTicks = 10;

    _state = 0; // starting with state 0: waiting for button to be pressed
    _isLongPressed = false;  // Keep track of long press state

    button_level = (bool)(btn_pin->read());
    active = active_level;

    if (active_level) {
        // button connects VCC to the pin when pressed.
        btn_pin->mode(PullDown);

    } else {
        // turn on pullUp resistor
        btn_pin->mode(PullUp);
    }

#if (MBED_LIBRARY_VERSION < 122)
    clickFn = NULL;
    pressFn = NULL;
    doubleClickFn = NULL;
    longPressStartFn = NULL;
    longPressStopFn = NULL;
    duringLongPressFn = NULL;
#endif
} // OneButton


// explicitly set the number of millisec that have to pass by before a click is detected.
void OneButton::setClickTicks(int ticks)
{
    _clickTicks = ticks;
} // setClickTicks


// explicitly set the number of millisec that have to pass by before a long button press is detected.
void OneButton::setPressTicks(int ticks)
{
    _pressTicks = ticks;
} // setPressTicks


#if (MBED_LIBRARY_VERSION < 122)
// save function for click event
void OneButton::attachClick(callbackFunction newFunction)
{
	clickFn = newFunction;
} // attachClick


// save function for doubleClick event
void OneButton::attachDoubleClick(callbackFunction newFunction)
{
    doubleClickFn = newFunction;
} // attachDoubleClick


// save function for press event
// DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop, attachDuringLongPress,
void OneButton::attachPress(callbackFunction newFunction)
{
    pressFn = newFunction;
} // attachPress

// save function for longPressStart event
void OneButton::attachLongPressStart(callbackFunction newFunction)
{
    longPressStartFn = newFunction;
} // attachLongPressStart

// save function for longPressStop event
void OneButton::attachLongPressStop(callbackFunction newFunction)
{
    longPressStopFn = newFunction;
} // attachLongPressStop

// save function for during longPress event
void OneButton::attachDuringLongPress(callbackFunction newFunction)
{
    duringLongPressFn = newFunction;
} // attachDuringLongPress
#endif

// function to get the current long pressed state
bool OneButton::isLongPressed()
{
    return _isLongPressed;
}

/**
  * @brief  Button driver core function, driver state machine.
  * @param  handle: the button handle strcut.
  * @retval None
  */
void OneButton::tick(void)
{
    int read_gpio_level = btn_pin->read(); // current button signal.

    /*------------button debounce handle---------------*/
    if(ticks != timer->read_ms()) { //1ms scan again.
        if(read_gpio_level != button_level) {
            //continue read 'debounce_cnt' times same new level change
            if(++_debounce_cnt >= _debounceTicks) {
                button_level = read_gpio_level;
                _debounce_cnt = 0;
            }

        } else { //leved not change ,counter reset.
            _debounce_cnt = 0;
        }
    }

    //current (relative) time in msecs.
    ticks = timer->read_ms();

    /*-----------------State machine-------------------*/
    switch (_state) {
        case 0:
            if(button_level == active) {	//start press
                if(clickFn) clickFn();
                timer->reset();
                _state = 1;
            }
            break;

        case 1:
            if(button_level != active) { //released
                _state = 2;

            } else if(ticks > _pressTicks) {
                if(longPressStartFn) longPressStartFn();
                _isLongPressed = 1;
                _state = 5;
            }
            break;

        case 2:
            if(ticks > _clickTicks) {	//released
                //press event
                if(pressFn) pressFn();	//press event
                _state = 0;	//reset

            } else if(button_level == active) { //press again
                if(clickFn) clickFn();
                _state = 3;
            }
            break;

        case 3:	//repeat press pressing
            if(button_level != active) {	//double releasd
                //double click event
                if(doubleClickFn) doubleClickFn();
                _state = 0;
            }
            break;

        case 5:
            if(button_level == active) {
                //continue hold trigger
                if(duringLongPressFn) duringLongPressFn();

            } else { //releasd
                if(longPressStopFn) longPressStopFn();
                _isLongPressed = 0;
                _state = 0; //reset
            }
            break;
    }
}

// end.