Library for detecting button clicks, doubleclicks and long press pattern on a single button.

Dependents:   OneButton_Example ABBlind

OneButton.cpp

Committer:
jaup
Date:
2016-09-01
Revision:
1:fdf67f893a5c
Parent:
0:62d614796022

File content as of revision 1:fdf67f893a5c:

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

	_clickFunc = NULL;
	_pressFunc = NULL;
	_doubleClickFunc = NULL;
	_longPressStartFunc = NULL;
	_longPressStopFunc = NULL;
	_duringLongPressFunc = NULL;
} // 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


// save function for click event
void OneButton::attachClick(callbackFunction newFunction)
{
	_clickFunc = newFunction;
} // attachClick


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


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

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

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

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

// 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 = (uint16_t)(timer->read_ms());

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

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

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

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

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

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

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

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

// end.