285 lines
8.2 KiB
C++
285 lines
8.2 KiB
C++
/**
|
|
* @file ESP32touchButton.cpp
|
|
*
|
|
* @brief Library for detecting button clicks, doubleclicks and long press
|
|
* pattern on a single button.
|
|
*
|
|
* @author Matthias Hertel, https://www.mathertel.de
|
|
* @Copyright Copyright (c) by Matthias Hertel, https://www.mathertel.de.
|
|
*
|
|
* This work is licensed under a BSD style license. See
|
|
* http://www.mathertel.de/License.aspx
|
|
*
|
|
* More information on: https://www.mathertel.de/Arduino/ESP32touchButtonLibrary.aspx
|
|
*
|
|
* Changelog: see ESP32touchButton.h
|
|
*/
|
|
|
|
#include "ESP32touchButton.h"
|
|
|
|
// ----- Initialization and Default Values -----
|
|
|
|
/**
|
|
* @brief Construct a new ESP32touchButton object but not (yet) initialize the IO pin.
|
|
*/
|
|
ESP32touchButton::ESP32touchButton()
|
|
{
|
|
_pin = -1;
|
|
// further initialization has moved to ESP32touchButton.h
|
|
}
|
|
|
|
ESP32touchButton::ESP32touchButton(int pin, int activeLow, bool pullupActive)
|
|
{
|
|
// ESP32touchButton();
|
|
_pin = pin;
|
|
|
|
if (activeLow) {
|
|
// the button connects the input pin to GND when pressed.
|
|
_buttonPressed = LOW;
|
|
|
|
} else {
|
|
// the button connects the input pin to VCC when pressed.
|
|
_buttonPressed = HIGH;
|
|
} // if
|
|
|
|
if (pullupActive) {
|
|
// use the given pin as input and activate internal PULLUP resistor.
|
|
//pinMode(pin, INPUT_PULLUP);
|
|
} else {
|
|
// use the given pin as input
|
|
//pinMode(pin, INPUT);
|
|
} // if
|
|
} // ESP32touchButton
|
|
|
|
|
|
// explicitly set the number of millisec that have to pass by before a click is
|
|
// assumed as safe.
|
|
void ESP32touchButton::setDebounceTicks(int ticks)
|
|
{
|
|
_debounceTicks = ticks;
|
|
} // setDebounceTicks
|
|
|
|
// explicitly set the number of millisec that have to pass by before a click is
|
|
// detected.
|
|
void ESP32touchButton::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 ESP32touchButton::setPressTicks(int ticks)
|
|
{
|
|
_pressTicks = ticks;
|
|
} // setPressTicks
|
|
|
|
|
|
// save function for click event
|
|
void ESP32touchButton::attachClick(callbackFunction newFunction)
|
|
{
|
|
_clickFunc = newFunction;
|
|
} // attachClick
|
|
|
|
|
|
// save function for parameterized click event
|
|
void ESP32touchButton::attachClick(parameterizedCallbackFunction newFunction, void* parameter)
|
|
{
|
|
_paramClickFunc = newFunction;
|
|
_clickFuncParam = parameter;
|
|
} // attachClick
|
|
|
|
|
|
// save function for doubleClick event
|
|
void ESP32touchButton::attachDoubleClick(callbackFunction newFunction)
|
|
{
|
|
_doubleClickFunc = newFunction;
|
|
} // attachDoubleClick
|
|
|
|
|
|
// save function for parameterized doubleClick event
|
|
void ESP32touchButton::attachDoubleClick(parameterizedCallbackFunction newFunction, void* parameter)
|
|
{
|
|
_paramDoubleClickFunc = newFunction;
|
|
_doubleClickFuncParam = parameter;
|
|
} // attachDoubleClick
|
|
|
|
|
|
// save function for press event
|
|
// DEPRECATED, is replaced by attachLongPressStart, attachLongPressStop,
|
|
// attachDuringLongPress,
|
|
void ESP32touchButton::attachPress(callbackFunction newFunction)
|
|
{
|
|
_pressFunc = newFunction;
|
|
} // attachPress
|
|
|
|
// save function for longPressStart event
|
|
void ESP32touchButton::attachLongPressStart(callbackFunction newFunction)
|
|
{
|
|
_longPressStartFunc = newFunction;
|
|
} // attachLongPressStart
|
|
|
|
// save function for parameterized longPressStart event
|
|
void ESP32touchButton::attachLongPressStart(parameterizedCallbackFunction newFunction, void* parameter)
|
|
{
|
|
_paramLongPressStartFunc = newFunction;
|
|
_longPressStartFuncParam = parameter;
|
|
} // attachLongPressStart
|
|
|
|
// save function for longPressStop event
|
|
void ESP32touchButton::attachLongPressStop(callbackFunction newFunction)
|
|
{
|
|
_longPressStopFunc = newFunction;
|
|
} // attachLongPressStop
|
|
|
|
// save function for parameterized longPressStop event
|
|
void ESP32touchButton::attachLongPressStop(parameterizedCallbackFunction newFunction, void* parameter)
|
|
{
|
|
_paramLongPressStopFunc = newFunction;
|
|
_longPressStopFuncParam = parameter;
|
|
} // attachLongPressStop
|
|
|
|
// save function for during longPress event
|
|
void ESP32touchButton::attachDuringLongPress(callbackFunction newFunction)
|
|
{
|
|
_duringLongPressFunc = newFunction;
|
|
} // attachDuringLongPress
|
|
|
|
// save function for parameterized during longPress event
|
|
void ESP32touchButton::attachDuringLongPress(parameterizedCallbackFunction newFunction, void* parameter)
|
|
{
|
|
_paramDuringLongPressFunc = newFunction;
|
|
_duringLongPressFuncParam = parameter;
|
|
} // attachDuringLongPress
|
|
|
|
// function to get the current long pressed state
|
|
bool ESP32touchButton::isLongPressed(){
|
|
return _isLongPressed;
|
|
}
|
|
|
|
int ESP32touchButton::getPressedTicks(){
|
|
return _stopTime - _startTime;
|
|
}
|
|
|
|
void ESP32touchButton::reset(void){
|
|
_state = 0; // restart.
|
|
_startTime = 0;
|
|
_stopTime = 0;
|
|
_isLongPressed = false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Check input of the configured pin and then advance the finite state
|
|
* machine (FSM).
|
|
*/
|
|
void ESP32touchButton::tick(void)
|
|
{
|
|
if (_pin >= 0) {
|
|
tick((touchRead(_pin) >= 40) == _buttonPressed);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Advance the finite state machine (FSM) using the given level.
|
|
*/
|
|
void ESP32touchButton::tick(bool activeLevel)
|
|
{
|
|
unsigned long now = millis(); // current (relative) time in msecs.
|
|
|
|
// Implementation of the state machine
|
|
|
|
if (_state == 0) { // waiting for menu pin being pressed.
|
|
if (activeLevel) {
|
|
_state = 1; // step to state 1
|
|
_startTime = now; // remember starting time
|
|
} // if
|
|
|
|
} else if (_state == 1) { // waiting for menu pin being released.
|
|
|
|
if ((!activeLevel) &&
|
|
((unsigned long)(now - _startTime) < _debounceTicks)) {
|
|
// button was released to quickly so I assume some debouncing.
|
|
// go back to state 0 without calling a function.
|
|
_state = 0;
|
|
|
|
} else if (!activeLevel) {
|
|
_state = 2; // step to state 2
|
|
_stopTime = now; // remember stopping time
|
|
|
|
} else if ((activeLevel) &&
|
|
((unsigned long)(now - _startTime) > _pressTicks)) {
|
|
_isLongPressed = true; // Keep track of long press state
|
|
if (_pressFunc)
|
|
_pressFunc();
|
|
if (_longPressStartFunc)
|
|
_longPressStartFunc();
|
|
if (_paramLongPressStartFunc)
|
|
_paramLongPressStartFunc(_longPressStartFuncParam);
|
|
if (_duringLongPressFunc)
|
|
_duringLongPressFunc();
|
|
if (_paramDuringLongPressFunc)
|
|
_paramDuringLongPressFunc(_duringLongPressFuncParam);
|
|
_state = 6; // step to state 6
|
|
_stopTime = now; // remember stopping time
|
|
} else {
|
|
// wait. Stay in this state.
|
|
} // if
|
|
|
|
} else if (_state == 2) {
|
|
// waiting for menu pin being pressed the second time or timeout.
|
|
if ((_doubleClickFunc == NULL && _paramDoubleClickFunc == NULL) ||
|
|
(unsigned long)(now - _startTime) > _clickTicks) {
|
|
// this was only a single short click
|
|
if (_clickFunc)
|
|
_clickFunc();
|
|
if (_paramClickFunc)
|
|
_paramClickFunc(_clickFuncParam);
|
|
_state = 0; // restart.
|
|
|
|
} else if ((activeLevel) &&
|
|
((unsigned long)(now - _stopTime) > _debounceTicks)) {
|
|
_state = 3; // step to state 3
|
|
_startTime = now; // remember starting time
|
|
} // if
|
|
|
|
} else if (_state == 3) { // waiting for menu pin being released finally.
|
|
// Stay here for at least _debounceTicks because else we might end up in
|
|
// state 1 if the button bounces for too long.
|
|
if ((!activeLevel) &&
|
|
((unsigned long)(now - _startTime) > _debounceTicks)) {
|
|
// this was a 2 click sequence.
|
|
if (_doubleClickFunc)
|
|
_doubleClickFunc();
|
|
if (_paramDoubleClickFunc)
|
|
_paramDoubleClickFunc(_doubleClickFuncParam);
|
|
_state = 0; // restart.
|
|
_stopTime = now; // remember stopping time
|
|
} // if
|
|
|
|
} else if (_state == 6) {
|
|
// waiting for menu pin being release after long press.
|
|
if (!activeLevel) {
|
|
_isLongPressed = false; // Keep track of long press state
|
|
if (_longPressStopFunc)
|
|
_longPressStopFunc();
|
|
if (_paramLongPressStopFunc)
|
|
_paramLongPressStopFunc(_longPressStopFuncParam);
|
|
_state = 0; // restart.
|
|
_stopTime = now; // remember stopping time
|
|
} else {
|
|
// button is being long pressed
|
|
_isLongPressed = true; // Keep track of long press state
|
|
if (_duringLongPressFunc)
|
|
_duringLongPressFunc();
|
|
if (_paramDuringLongPressFunc)
|
|
_paramDuringLongPressFunc(_duringLongPressFuncParam);
|
|
} // if
|
|
|
|
} // if
|
|
} // ESP32touchButton.tick()
|
|
|
|
|
|
// end.
|