2020-09-02 12:39:50 -07:00
|
|
|
/**
|
|
|
|
* @file debounce.cpp
|
|
|
|
* @brief Generic button debounce class
|
|
|
|
*
|
|
|
|
* @date Aug 31, 2020
|
|
|
|
* @author David Holdeman, (c) 2020
|
|
|
|
*/
|
2021-08-03 19:05:01 -07:00
|
|
|
#include "pch.h"
|
|
|
|
|
2020-09-02 12:39:50 -07:00
|
|
|
#include "debounce.h"
|
2020-09-08 08:29:38 -07:00
|
|
|
#include "hardware.h"
|
2020-09-02 12:39:50 -07:00
|
|
|
|
2020-09-08 08:29:38 -07:00
|
|
|
ButtonDebounce* ButtonDebounce::s_firstDebounce = nullptr;
|
2020-11-06 20:48:35 -08:00
|
|
|
|
2020-12-24 04:30:56 -08:00
|
|
|
ButtonDebounce::ButtonDebounce(const char *name)
|
|
|
|
: m_name(name)
|
|
|
|
{
|
2020-11-06 20:48:35 -08:00
|
|
|
}
|
2020-09-08 08:29:38 -07:00
|
|
|
|
2020-09-20 11:01:00 -07:00
|
|
|
/**
|
|
|
|
We need to have a separate init function because we do not have the pin or mode in the context in which the class is originally created
|
|
|
|
*/
|
2020-09-28 16:17:17 -07:00
|
|
|
void ButtonDebounce::init (efitimems_t threshold, brain_pin_e &pin, pin_input_mode_e &mode) {
|
2020-09-20 11:01:00 -07:00
|
|
|
// we need to keep track of whether we have already been initialized due to the way unit tests run.
|
2020-12-16 19:24:19 -08:00
|
|
|
if (!isInstanceRegisteredInGlobalList) {
|
2020-09-20 11:01:00 -07:00
|
|
|
// Link us to the list that is used to track ButtonDebounce instances, so that when the configuration changes,
|
|
|
|
// they can be looped through and updated.
|
|
|
|
nextDebounce = s_firstDebounce;
|
|
|
|
s_firstDebounce = this;
|
2020-09-08 08:29:38 -07:00
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
m_threshold = MS2NT(threshold);
|
2020-09-02 12:39:50 -07:00
|
|
|
timeLast = 0;
|
2020-09-28 16:17:17 -07:00
|
|
|
m_pin = &pin;
|
|
|
|
m_mode = &mode;
|
2020-09-20 11:01:00 -07:00
|
|
|
startConfiguration();
|
2020-12-16 19:24:19 -08:00
|
|
|
isInstanceRegisteredInGlobalList = true;
|
2020-09-08 08:29:38 -07:00
|
|
|
}
|
|
|
|
|
2020-09-20 11:01:00 -07:00
|
|
|
void ButtonDebounce::stopConfigurationList () {
|
2020-09-08 08:29:38 -07:00
|
|
|
ButtonDebounce *listItem = s_firstDebounce;
|
|
|
|
while (listItem != nullptr) {
|
2020-09-20 11:01:00 -07:00
|
|
|
listItem->stopConfiguration();
|
|
|
|
listItem = listItem->nextDebounce;
|
2020-09-08 08:29:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-20 11:01:00 -07:00
|
|
|
void ButtonDebounce::startConfigurationList () {
|
|
|
|
ButtonDebounce *listItem = s_firstDebounce;
|
|
|
|
while (listItem != nullptr) {
|
|
|
|
listItem->startConfiguration();
|
|
|
|
listItem = listItem->nextDebounce;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonDebounce::stopConfiguration () {
|
|
|
|
// If the configuration has changed
|
2020-12-16 19:00:42 -08:00
|
|
|
#if ! EFI_ACTIVE_CONFIGURATION_IN_FLASH
|
2020-09-20 11:01:00 -07:00
|
|
|
if (*m_pin != active_pin || *m_mode != active_mode) {
|
2020-09-08 08:29:38 -07:00
|
|
|
#else
|
2022-04-28 14:32:39 -07:00
|
|
|
if (*m_pin != active_pin || *m_mode != active_mode || (isActiveConfigurationVoid && ((int)(*m_pin) != 0 || (int)(*m_mode) != 0))) {
|
2020-09-08 08:29:38 -07:00
|
|
|
#endif /* EFI_ACTIVE_CONFIGURATION_IN_FLASH */
|
2020-12-16 19:53:26 -08:00
|
|
|
#if EFI_PROD_CODE
|
2020-11-26 07:41:22 -08:00
|
|
|
efiSetPadUnused(active_pin);
|
2020-09-08 11:27:23 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2020-12-16 19:53:26 -08:00
|
|
|
needsPinInitialization = true;
|
2020-09-08 08:29:38 -07:00
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonDebounce::startConfiguration () {
|
2020-12-16 19:53:26 -08:00
|
|
|
#if EFI_PROD_CODE
|
2020-12-16 19:24:19 -08:00
|
|
|
if (needsPinInitialization) {
|
2020-12-24 04:30:56 -08:00
|
|
|
efiSetPadMode(m_name, *m_pin, getInputMode(*m_mode));
|
2020-12-16 19:24:19 -08:00
|
|
|
needsPinInitialization = false;
|
2020-09-21 15:25:24 -07:00
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
#endif
|
|
|
|
active_pin = *m_pin;
|
|
|
|
active_mode = *m_mode;
|
2020-09-02 12:39:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
@returns true if the button is pressed, and will not return true again within the set timeout
|
|
|
|
*/
|
|
|
|
bool ButtonDebounce::readPinEvent() {
|
2020-09-20 11:01:00 -07:00
|
|
|
storedValue = false;
|
2020-09-09 14:18:54 -07:00
|
|
|
return readPinState();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ButtonDebounce::readPinState() {
|
2021-01-08 17:01:26 -08:00
|
|
|
if (!isBrainPinValid(*m_pin)) {
|
2020-09-02 12:39:50 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
efitick_t timeNow = getTimeNowNt();
|
|
|
|
// If it's been less than the threshold since we were last called
|
2020-09-20 11:01:00 -07:00
|
|
|
if ((timeNow - timeLast) < m_threshold) {
|
|
|
|
return storedValue;
|
2020-09-02 12:39:50 -07:00
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
// storedValue is a class variable, so it needs to be reset.
|
2020-09-02 12:39:50 -07:00
|
|
|
// We don't actually need it to be a class variable in this method,
|
|
|
|
// but when a method is implemented to actually get the pin's state,
|
2020-11-06 21:43:42 -08:00
|
|
|
// for example to implement long button presses, it will be needed.
|
2020-09-10 19:16:20 -07:00
|
|
|
#if EFI_PROD_CODE || EFI_UNIT_TEST
|
2020-09-20 11:01:00 -07:00
|
|
|
storedValue = efiReadPin(active_pin);
|
2020-11-06 21:46:59 -08:00
|
|
|
#else
|
|
|
|
storedValue = false;
|
2020-09-10 19:16:20 -07:00
|
|
|
#endif
|
2020-09-02 12:39:50 -07:00
|
|
|
// Invert
|
2020-11-18 18:45:17 -08:00
|
|
|
if (active_mode == PI_PULLUP) {
|
2020-09-20 11:01:00 -07:00
|
|
|
storedValue = !storedValue;
|
2020-09-02 12:39:50 -07:00
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
if (storedValue) {
|
2020-09-02 12:39:50 -07:00
|
|
|
timeLast = timeNow;
|
|
|
|
}
|
2020-09-20 11:01:00 -07:00
|
|
|
return storedValue;
|
2020-09-02 12:39:50 -07:00
|
|
|
}
|
2020-11-06 20:48:35 -08:00
|
|
|
|
|
|
|
void ButtonDebounce::debug() {
|
|
|
|
ButtonDebounce *listItem = s_firstDebounce;
|
|
|
|
while (listItem != nullptr) {
|
|
|
|
#if EFI_PROD_CODE || EFI_UNIT_TEST
|
2021-04-21 09:53:13 -07:00
|
|
|
efiPrintf("%s timeLast %d", listItem->m_name, listItem->timeLast);
|
|
|
|
efiPrintf("physical state %d value %d", efiReadPin(listItem->active_pin), listItem->storedValue);
|
2020-11-06 20:48:35 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
listItem = listItem->nextDebounce;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-21 09:53:13 -07:00
|
|
|
void initButtonDebounce() {
|
2020-11-06 20:48:35 -08:00
|
|
|
#if !EFI_UNIT_TEST
|
|
|
|
addConsoleAction("debounce", ButtonDebounce::debug);
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
}
|