implemented button - #708

This commit is contained in:
proddy
2021-03-01 22:19:28 +01:00
parent 7521ce6ad3
commit 3eb8ac9194
9 changed files with 560 additions and 216 deletions

187
lib/PButton/PButon.cpp Normal file
View File

@@ -0,0 +1,187 @@
/*
* Paul's Button Library
*
* Handles recognition of button presses, short, long, double-click and special sequences
* Used to send specific commands to the ESP8
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PButton.h"
// Constructor
PButton::PButton() {
// Initialization of default properties
Debounce_ = 40; // Debounce period to prevent flickering when pressing or releasing the button (in ms)
DblClickDelay_ = 250; // Max period between clicks for a double click event (in ms)
LongPressDelay_ = 750; // Hold period for a long press event (in ms)
VLongPressDelay_ = 3000; // Hold period for a very long press event (in ms)
cb_onClick = nullptr;
cb_onDblClick = nullptr;
cb_onLongPress = nullptr;
cb_onVLongPress = nullptr;
// Initialization of variables
state_ = true; // Value read from button
lastState_ = true; // Last value of button state
dblClickWaiting_ = false; // whether we're waiting for a double click (down)
dblClickOnNextUp_ = false; // whether to register a double click on next release, or whether to wait and click
singleClickOK_ = true; // whether it's OK to do a single click (default is true)
downTime_ = -1; // time the button was pressed down
upTime_ = -1; // time the button was released
ignoreUP_ = true; // whether to ignore the button release because the click+hold was triggered, changed from false for ESP32
waitForUP_ = false; // when held, whether to wait for the up event
longPressHappened_ = false; // whether or not the hold event happened already
vLongPressHappened_ = false; // whether or not the long hold event happened already
buttonBusy_ = false; // idle
}
bool PButton::init(uint8_t pin, bool pullMode) {
pin_ = pin;
pullMode_ = pullMode; // 1=HIGH (pullup) 0=LOW (pulldown)
#if defined(ESP8266)
pinMode(pin_, pullMode ? INPUT_PULLUP : INPUT_PULLDOWN);
enabled_ = (digitalRead(pin_) != pullMode); // see if a button is connected
#else
// ESP32
pinMode(pin_, INPUT);
enabled_ = (digitalRead(pin_) == pullMode); // see if a button is connected
#endif
return enabled_;
}
void PButton::onClick(uint16_t t, buttonEventHandler handler) {
Debounce_ = t; // Debounce period to prevent flickering when pressing or releasing the button (in ms)
cb_onClick = handler;
}
void PButton::onDblClick(uint16_t t, buttonEventHandler handler) {
DblClickDelay_ = t; // Max period between clicks for a double click event (in ms)
cb_onDblClick = handler;
}
void PButton::onLongPress(uint16_t t, buttonEventHandler handler) {
LongPressDelay_ = t; // Hold period for a long press event (in ms)
cb_onLongPress = handler;
}
void PButton::onVLongPress(uint16_t t, buttonEventHandler handler) {
VLongPressDelay_ = t; // Hold period for a very long press event (in ms)
cb_onVLongPress = handler;
}
bool PButton::check(void) {
if (!enabled_) {
return false;
}
int resultEvent = 0;
long millisRes = millis();
state_ = digitalRead(pin_) == pullMode_;
// Button pressed down
if (state_ != pullMode_ && lastState_ == pullMode_ && (millisRes - upTime_) > Debounce_) {
// Serial.println("*pressed*");
downTime_ = millisRes;
ignoreUP_ = false;
waitForUP_ = false;
singleClickOK_ = true;
longPressHappened_ = false;
vLongPressHappened_ = false;
if ((millisRes - upTime_) < DblClickDelay_ && dblClickOnNextUp_ == false && dblClickWaiting_ == true) {
dblClickOnNextUp_ = true;
// Serial.println("*double up next*");
} else {
dblClickOnNextUp_ = false;
}
dblClickWaiting_ = false;
buttonBusy_ = true; // something is happening so we'll wait and see what action it is
}
// Button released
else if (state_ == pullMode_ && lastState_ != pullMode_ && (millisRes - downTime_) > Debounce_) {
if (ignoreUP_ == false) {
upTime_ = millisRes;
// Serial.println("*released*");
if (dblClickOnNextUp_ == false) {
dblClickWaiting_ = true;
} else {
resultEvent = 2;
// Serial.println("*double*");
dblClickOnNextUp_ = false;
dblClickWaiting_ = false;
singleClickOK_ = false;
}
}
}
// Test for normal click event: DblClickDelay expired
if (state_ == pullMode_ && (millisRes - upTime_) >= DblClickDelay_ && dblClickWaiting_ == true && dblClickOnNextUp_ == false && singleClickOK_ == true && resultEvent != 2) {
// Serial.println("*single click pressed*");
resultEvent = 1;
dblClickWaiting_ = false;
}
// added code: raise OnLongPress event when only when the button is released
if (state_ == pullMode_ && longPressHappened_ && !vLongPressHappened_) {
resultEvent = 3;
longPressHappened_ = false;
}
// Test for hold
if (state_ != pullMode_ && (millisRes - downTime_) >= LongPressDelay_) {
// Trigger "normal" hold
if (longPressHappened_ == false) {
// resultEvent = 3;
waitForUP_ = true;
ignoreUP_ = true;
dblClickOnNextUp_ = false;
dblClickWaiting_ = false;
// _downTime = millis();
longPressHappened_ = true;
}
// Trigger "long" hold
if ((millisRes - downTime_) >= VLongPressDelay_) {
if (vLongPressHappened_ == false) {
resultEvent = 4;
vLongPressHappened_ = true;
// _longPressHappened = false;
}
}
}
lastState_ = state_;
if (resultEvent == 1 && cb_onClick) {
cb_onClick(*this);
} else if (resultEvent == 2 && cb_onDblClick) {
cb_onDblClick(*this);
} else if (resultEvent == 3 && cb_onLongPress) {
cb_onLongPress(*this);
} else if (resultEvent == 4 && cb_onVLongPress) {
cb_onVLongPress(*this);
}
// if any action has been prefromed we can stop waiting, and become idle
if (resultEvent >= 1 && resultEvent <= 4) {
buttonBusy_ = false;
}
return buttonBusy_;
}

69
lib/PButton/PButton.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* Paul's Button Library
*
* Handles recognition of button presses, short, long, double-click and special sequences
* Used to send specific commands to the ESP8
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PButton_H_
#define _PButton_H_
#include <Arduino.h>
class PButton {
public:
PButton();
~PButton() = default;
typedef void (*buttonEventHandler)(PButton &);
void onClick(uint16_t t, buttonEventHandler handler);
void onDblClick(uint16_t, buttonEventHandler handler);
void onLongPress(uint16_t t, buttonEventHandler handler);
void onVLongPress(uint16_t, buttonEventHandler handler);
bool init(uint8_t pin, bool pullMode);
bool check(void);
private:
uint16_t Debounce_; // Debounce period to prevent flickering when pressing or releasing the button (in ms)
uint16_t DblClickDelay_; // Max period between clicks for a double click event (in ms)
uint16_t LongPressDelay_; // Hold period for a long press event (in ms)
uint16_t VLongPressDelay_; // Hold period for a very long press event (in ms)
uint8_t pin_;
bool pullMode_;
bool enabled_;
bool state_; // Value read from button
bool lastState_; // Last value of button state
bool dblClickWaiting_; // whether we're waiting for a double click (down)
bool dblClickOnNextUp_; // whether to register a double click on next release, or whether to wait and click
bool singleClickOK_; // whether it's OK to do a single click
uint32_t downTime_; // time the button was pressed down
uint32_t upTime_; // time the button was released
bool ignoreUP_; // whether to ignore the button release because the click+hold was triggered
bool waitForUP_; // when held, whether to wait for the up event
bool longPressHappened_; // whether or not the hold event happened already
bool vLongPressHappened_; // whether or not the long hold event happened already
bool buttonBusy_; // false if idle
buttonEventHandler cb_onClick, cb_onDblClick, cb_onLongPress, cb_onVLongPress;
};
#endif