Improved button debouncing

This commit is contained in:
P.M. Kuipers 2021-05-16 22:16:07 +02:00
parent 44b729f0e6
commit 29954007e8
7 changed files with 84 additions and 24 deletions

View File

@ -275,7 +275,7 @@ DEFS = -DHAVE_CONFIG_H
DEPDIR = .deps DEPDIR = .deps
DEPS_CFLAGS = -DDBUS_API_SUBJECT_TO_CHANGE -I/usr/include/dbus-c++-1 -I/usr/include/dbus-1.0 -I/usr/lib/arm-linux-gnueabihf/dbus-1.0/include DEPS_CFLAGS = -DDBUS_API_SUBJECT_TO_CHANGE -I/usr/include/dbus-c++-1 -I/usr/include/dbus-1.0 -I/usr/lib/arm-linux-gnueabihf/dbus-1.0/include
DEPS_LIBS = -ldbus-c++-1 -ldbus-1 DEPS_LIBS = -ldbus-c++-1 -ldbus-1
DHMAKE = notfound DHMAKE = /usr/bin/dh_make
ECHO_C = ECHO_C =
ECHO_N = -n ECHO_N = -n
ECHO_T = ECHO_T =
@ -295,10 +295,10 @@ OBJEXT = o
PACKAGE = mediacore-hid PACKAGE = mediacore-hid
PACKAGE_BUGREPORT = bugs@miqra.nl PACKAGE_BUGREPORT = bugs@miqra.nl
PACKAGE_NAME = MediaCore HID Server PACKAGE_NAME = MediaCore HID Server
PACKAGE_STRING = MediaCore HID Server 4.0.0 PACKAGE_STRING = MediaCore HID Server 4.0.1
PACKAGE_TARNAME = mediacore-hid PACKAGE_TARNAME = mediacore-hid
PACKAGE_URL = http://www.miqra.nl/ PACKAGE_URL = http://www.miqra.nl/
PACKAGE_VERSION = 4.0.0 PACKAGE_VERSION = 4.0.1
PATH_SEPARATOR = : PATH_SEPARATOR = :
PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG = /usr/bin/pkg-config
PKG_CONFIG_LIBDIR = PKG_CONFIG_LIBDIR =
@ -306,7 +306,7 @@ PKG_CONFIG_PATH =
SET_MAKE = SET_MAKE =
SHELL = /bin/bash SHELL = /bin/bash
STRIP = STRIP =
VERSION = 4.0.0 VERSION = 4.0.1
abs_builddir = /home/pi/mediacore-hid abs_builddir = /home/pi/mediacore-hid
abs_srcdir = /home/pi/mediacore-hid abs_srcdir = /home/pi/mediacore-hid
abs_top_builddir = /home/pi/mediacore-hid abs_top_builddir = /home/pi/mediacore-hid

View File

@ -11,7 +11,7 @@
#define PACKAGE_NAME "MediaCore HID Server" #define PACKAGE_NAME "MediaCore HID Server"
/* Define to the full name and version of this package. */ /* Define to the full name and version of this package. */
#define PACKAGE_STRING "MediaCore HID Server 4.0.0" #define PACKAGE_STRING "MediaCore HID Server 4.0.1"
/* Define to the one symbol short name of this package. */ /* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "mediacore-hid" #define PACKAGE_TARNAME "mediacore-hid"
@ -20,4 +20,4 @@
#define PACKAGE_URL "http://www.miqra.nl/" #define PACKAGE_URL "http://www.miqra.nl/"
/* Define to the version of this package. */ /* Define to the version of this package. */
#define PACKAGE_VERSION "4.0.0" #define PACKAGE_VERSION "4.0.1"

View File

@ -1,4 +1,4 @@
AC_INIT([MediaCore HID Server], [4.0.0], [bugs@miqra.nl], [mediacore-hid], [http://www.miqra.nl/]) AC_INIT([MediaCore HID Server], [4.0.1], [bugs@miqra.nl], [mediacore-hid], [http://www.miqra.nl/])
AC_PREREQ([2.59]) AC_PREREQ([2.59])
AM_INIT_AUTOMAKE([1.11 no-define foreign subdir-objects]) AM_INIT_AUTOMAKE([1.11 no-define foreign subdir-objects])
AC_CONFIG_HEADERS([config.hpp]) AC_CONFIG_HEADERS([config.hpp])

View File

@ -26,7 +26,14 @@ void ButtonTimer::RegisterPress(const uint8_t keycode)
// Prevent trouble when calling this from within one of our event listeners // Prevent trouble when calling this from within one of our event listeners
if(eventLock) { MutexUnlock(); return; } if(eventLock) { MutexUnlock(); return; }
pressRegistry[keycode] = now_ms(); // register current registered time for first triggering press
if(!pressRegistry.count(keycode))
{
pressRegistry[keycode] = now_ms();
}
// register press state to true for debouncing
pressState[keycode] = true;
MutexUnlock(); MutexUnlock();
} }
@ -36,18 +43,44 @@ void ButtonTimer::RegisterRelease(const uint8_t keycode)
MutexLock(); MutexLock();
// Prevent trouble when calling this from within one of our event listeners // Prevent trouble when calling this from within one of our event listeners
if(eventLock) { MutexUnlock(); return; } if(eventLock) { MutexUnlock(); return; }
// register current press state to false
pressState[keycode] = false;
if(pressRegistry.count(keycode)) if(pressRegistry.count(keycode))
{ {
// if it was a long press, the key code would already have been erased, so we // if it was a long press, the key code would already have been erased, so we
// can safely fire the onShortPress event // can safely fire the onShortPress event
uint64_t now = now_ms(); uint64_t now = now_ms();
uint64_t then = pressRegistry[keycode]; uint64_t then = pressRegistry[keycode];
// remove from registry after release, if it was a long press, the event should have already been fired
pressRegistry.erase(keycode);
if(now - then > shortpressMinTime) if(pressHold.count(keycode))
{ {
// debounce locks for release
// pressHold[keycode] == true means wait for release
// pressHold[keycode] == false means we're in the release debounce time
if(pressHold[keycode] == true){
// first release after longpress
// Register time and switch to next mode
pressHold[keycode] = false;
pressRegistry[keycode] = now;
}
else
{
// still in debounce
// release the debounce lock if this release occurs after the shortpresstime
if(now - then > shortpressMinTime){
pressHold.erase(keycode);
pressRegistry.erase(keycode);
}
}
}
else if(now - then > shortpressMinTime)
{
// only trigger this if the release is later than the shortpresstime
// remove from registry after release, if it was a long press, the event should have already been fired
pressRegistry.erase(keycode);
eventLock = true; // lock out trouble eventLock = true; // lock out trouble
onShortPress(keycode); onShortPress(keycode);
eventLock = false; // risk of trouble gone eventLock = false; // risk of trouble gone
@ -74,32 +107,57 @@ void ButtonTimer::CancelPress(const uint8_t keycode)
void ButtonTimer::ThreadLoop() void ButtonTimer::ThreadLoop()
{ {
uint64_t now = now_ms(); uint64_t now = now_ms();
std::list<uint8_t> btnList; std::list<uint8_t> shortPressList;
std::list<uint8_t> longPressList;
boost::optional<bool> valid; boost::optional<bool> valid;
MutexLock(); MutexLock();
// list through all the items // list through all the items
for( std::map<uint8_t,uint64_t>::iterator ii=pressRegistry.begin(); ii!=pressRegistry.end(); ++ii) for( auto const& itm : pressRegistry)
{ {
if(now - (ii->second) >= longpressTime) // if it is in overtime if(now - (itm.second) >= shortpressMinTime && pressState[itm.first] == false) // if the shortpresstime wa exceeded and the value is false
{
if(!pressHold.count(itm.first))
{
shortPressList.push_back(itm.first);
}
else if(pressHold[itm.first] == false)
{
// release debounce lock from longpress
pressRegistry.erase(itm.first);
pressHold.erase(itm.first);
}
}
if(now - (itm.second) >= longpressTime && !pressHold.count(itm.first)) // if it is in overtime and not waiting for release debounce
{ {
// Schedule to process the thing // Schedule to process the thing
btnList.push_back(ii->first); longPressList.push_back(itm.first);
} }
}
}
for (auto const& gpio : shortPressList)
{
pressRegistry.erase(gpio);
// If any validators are connected, they can retun false to indicate that this connection is not
// allowed
eventLock = true; // lock out trouble
onShortPress(gpio);
eventLock = false; // risk of trouble gone
}
// Process listed items // Process listed items
for (std::list<uint8_t>::iterator it=btnList.begin(); it != btnList.end(); ++it) for (auto const& gpio : longPressList)
{ {
pressRegistry.erase(*it); pressHold[gpio] = true; // debounce wait state
// If any validators are connected, they can retun false to indicate that this connection is not // If any validators are connected, they can retun false to indicate that this connection is not
// allowed // allowed
eventLock = true; // lock out trouble eventLock = true; // lock out trouble
valid = onValidatePress(*it); valid = onValidatePress(gpio);
if(valid.get_value_or(true)) if(valid.get_value_or(true))
{ {
onLongPress(*it); onLongPress(gpio);
} }
eventLock = false; // risk of trouble gone eventLock = false; // risk of trouble gone
} }

View File

@ -27,6 +27,8 @@ class ButtonTimer : protected Thread
uint32_t longpressTime; uint32_t longpressTime;
uint32_t shortpressMinTime; uint32_t shortpressMinTime;
std::map<const uint8_t, uint64_t> pressRegistry; std::map<const uint8_t, uint64_t> pressRegistry;
std::map<const uint8_t, bool> pressState;
std::map<const uint8_t, bool> pressHold;
bool eventLock; bool eventLock;
static int64_t now_ms(void); static int64_t now_ms(void);

View File

@ -82,10 +82,10 @@ HidServer::HidServer(DBus::Connection &connection)
{ {
// Initialize button timer // Initialize button timer
btnTimer = new ButtonTimer(10,5000); // Short press should take at leas 10 ms, and a Long press takes 5 seconds btnTimer = new ButtonTimer(70,5000); // 70 ms debounce time, and a Long press takes 5 seconds
onShortPressConnection = this->btnTimer->onShortPress.connect( boost::bind( &HidServer::onShortPress, this, _1) ); onShortPressConnection = this->btnTimer->onShortPress.connect( boost::bind( &HidServer::onShortPress, this, _1) );
onLongPressConnection = this->btnTimer->onLongPress.connect( boost::bind( &HidServer::onLongPress, this, _1) ); onLongPressConnection = this->btnTimer->onLongPress.connect( boost::bind( &HidServer::onLongPress, this, _1) );
onValidatePressConnection = this->btnTimer->onValidatePress.connect( boost::bind( &HidServer::onValidatePress, this, _1) ); //onValidatePressConnection = this->btnTimer->onValidatePress.connect( boost::bind( &HidServer::onValidatePress, this, _1) );
// **** Initialize the GPIO Interrupt pin // **** Initialize the GPIO Interrupt pin

View File

@ -1,2 +1,2 @@
PACKAGE="mediacore-hid" PACKAGE="mediacore-hid"
VERSION="4.0.0" VERSION="4.0.1"