rusEFI
The most advanced open source ECU
debounce.cpp
Go to the documentation of this file.
1 /**
2  * @file debounce.cpp
3  * @brief Generic button debounce class
4  *
5  * @date Aug 31, 2020
6  * @author David Holdeman, (c) 2020
7  */
8 #include "pch.h"
9 
10 #include "debounce.h"
11 #include "hardware.h"
12 
14 
16  : m_name(name)
17 {
18 }
19 
20 /**
21 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
22 */
23 void ButtonDebounce::init (efitimems_t threshold, brain_pin_e &pin, pin_input_mode_e &mode, bool inverted) {
24  // we need to keep track of whether we have already been initialized due to the way unit tests run.
26  // Link us to the list that is used to track ButtonDebounce instances, so that when the configuration changes,
27  // they can be looped through and updated.
29  s_firstDebounce = this;
30  }
31  m_threshold = MS2NT(threshold);
32  m_pin = &pin;
33  m_mode = &mode;
34  m_inverted = inverted;
37 }
38 
40  ButtonDebounce *listItem = s_firstDebounce;
41  int loopLimitCounter = 0;
42  while (listItem != nullptr) {
43  criticalAssertVoid(loopLimitCounter++ < 10000, "dead stopConfigurationList?");
44  listItem->stopConfiguration();
45  listItem = listItem->nextDebounce;
46  }
47 }
48 
50  ButtonDebounce *listItem = s_firstDebounce;
51  int loopLimitCounter = 0;
52  while (listItem != nullptr) {
53  criticalAssertVoid(loopLimitCounter++ < 10000, "dead startConfigurationList?");
54  listItem->startConfiguration();
55  listItem = listItem->nextDebounce;
56  }
57 }
58 
60  // If the configuration has changed
61 #if ! EFI_ACTIVE_CONFIGURATION_IN_FLASH
62  if (*m_pin != active_pin || *m_mode != active_mode) {
63 #else
64  if (*m_pin != active_pin || *m_mode != active_mode || (isActiveConfigurationVoid && ((int)(*m_pin) != 0 || (int)(*m_mode) != 0))) {
65 #endif /* EFI_ACTIVE_CONFIGURATION_IN_FLASH */
66 #if EFI_PROD_CODE
68 #endif /* EFI_UNIT_TEST */
70  }
71 }
72 
74 #if EFI_PROD_CODE
77  needsPinInitialization = false;
78  }
79 #endif
80  active_pin = *m_pin;
82 }
83 
84 /**
85 @returns true if the button is pressed, and will not return true again within the set timeout
86 */
88  storedValue = readPinState2(false);
89  return storedValue;
90 }
91 
93 #if EFI_PROD_CODE || EFI_UNIT_TEST
95 #else
96  return false;
97 #endif
98 }
99 
100 bool ButtonDebounce::readPinState2(bool valueWithinThreshold) {
101  if (!isBrainPinValid(*m_pin)) {
102  return false;
103  }
104  efitick_t timeNowNt = getTimeNowNt();
105  // If it's been less than the threshold since we were last called
106  if (timeLast.getElapsedNt(timeNowNt) < m_threshold) {
107  return valueWithinThreshold;
108  }
109  bool value = getPhysicalState();
110 // efiPrintf("[debounce] %s value %d", m_name, value);
111  // Invert
112  if (active_mode == PI_PULLUP) {
113  value = !value;
114 // efiPrintf("[debounce] %s inverted %d", m_name, value);
115  }
116  if (value) {
117  timeLast.reset();
118  }
119  return value;
120 }
121 
123  // code comment could be out of date:
124  // storedValue is a class variable, so it needs to be reset.
125  // We don't actually need it to be a class variable in this method,
126  // but when a method is implemented to actually get the pin's state,
127  // for example to implement long button presses, it will be needed.
129  return storedValue;
130 }
131 
132 void ButtonDebounce::debug() {
133  ButtonDebounce *listItem = s_firstDebounce;
134  while (listItem != nullptr) {
135 #if EFI_PROD_CODE || EFI_UNIT_TEST
136  efiPrintf("%s timeLast %f", listItem->m_name, listItem->timeLast.getElapsedSeconds());
137  efiPrintf("physical pin state %d", listItem->getPhysicalState());
138  efiPrintf("state %d", listItem->storedValue);
139  efiPrintf("mode %d", listItem->active_mode);
140 #endif
141 
142  listItem = listItem->nextDebounce;
143  }
144 }
145 
146 void initButtonDebounce() {
147 #if !EFI_UNIT_TEST
149 #endif /* EFI_UNIT_TEST */
150 }
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
void stopConfiguration()
Definition: debounce.cpp:59
bool isInstanceRegisteredInGlobalList
Definition: debounce.h:43
pin_input_mode_e active_mode
Definition: debounce.h:40
const char *const m_name
Definition: debounce.h:34
bool storedValue
Definition: debounce.h:41
pin_input_mode_e * m_mode
Definition: debounce.h:39
void startConfiguration()
bool readPinEvent()
Timer timeLast
Definition: debounce.h:36
void init(efitimems_t threshold, brain_pin_e &pin, pin_input_mode_e &mode, bool inverted=false)
Definition: debounce.cpp:23
bool getPhysicalState()
ButtonDebounce(const char *name)
Definition: debounce.cpp:15
brain_pin_e active_pin
Definition: debounce.h:38
bool readPinState2(bool valueWithinThreshold)
static void debug()
static void startConfigurationList()
Definition: debounce.cpp:49
static ButtonDebounce * s_firstDebounce
Definition: debounce.h:46
ButtonDebounce * nextDebounce
Definition: debounce.h:45
static void stopConfigurationList()
Definition: debounce.cpp:39
bool needsPinInitialization
Definition: debounce.h:44
efidur_t m_threshold
Definition: debounce.h:35
brain_pin_e * m_pin
Definition: debounce.h:37
bool m_inverted
Definition: debounce.h:42
bool readPinState()
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
Gpio
Generic button debounce class https://en.wikipedia.org/wiki/Switch#Contact_bounce If we don't 'deboun...
void initButtonDebounce()
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
bool isActiveConfigurationVoid
iomode_t getInputMode(pin_input_mode_e mode)
Definition: io_pins.cpp:103
bool efiReadPin(brain_pin_e pin)
Definition: io_pins.cpp:89
void efiSetPadUnused(brain_pin_e brainPin)
Definition: io_pins.cpp:20
bool isBrainPinValid(brain_pin_e brainPin)
pin_input_mode_e
Definition: rusefi_enums.h:247
uint32_t efitimems_t
Definition: rusefi_types.h:44
brain_pin_e pin
Definition: stm32_adc.cpp:15