LCOV - code coverage report
Current view: top level - firmware/hw_layer - debounce.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 56 67 83.6 %
Date: 2024-05-26 17:59:41 Functions: 11 12 91.7 %

          Line data    Source code
       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             : 
      13             : ButtonDebounce* ButtonDebounce::s_firstDebounce = nullptr;
      14             : 
      15         400 : ButtonDebounce::ButtonDebounce(const char *name)
      16         400 :         : m_name(name)
      17             : {
      18         400 : }
      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         791 : 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.
      25         791 :     if (!isInstanceRegisteredInGlobalList) {
      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.
      28         318 :         nextDebounce = s_firstDebounce;
      29         318 :         s_firstDebounce = this;
      30             :     }
      31         791 :     m_threshold = MS2NT(threshold);
      32         791 :     m_pin = &pin;
      33         791 :     m_mode = &mode;
      34         791 :     m_inverted = inverted;
      35         791 :     startConfiguration();
      36         791 :     isInstanceRegisteredInGlobalList = true;
      37         791 : }
      38             : 
      39         159 : void ButtonDebounce::stopConfigurationList() {
      40         159 :     ButtonDebounce *listItem = s_firstDebounce;
      41         159 :     int loopLimitCounter = 0;
      42         318 :     while (listItem != nullptr) {
      43         159 :         criticalAssertVoid(loopLimitCounter++ < 10000, "dead stopConfigurationList?");
      44         159 :         listItem->stopConfiguration();
      45         159 :         listItem = listItem->nextDebounce;
      46             :     }
      47             : }
      48             : 
      49         159 : void ButtonDebounce::startConfigurationList() {
      50         159 :     ButtonDebounce *listItem = s_firstDebounce;
      51         159 :     int loopLimitCounter = 0;
      52         318 :     while (listItem != nullptr) {
      53         159 :         criticalAssertVoid(loopLimitCounter++ < 10000, "dead startConfigurationList?");
      54         159 :         listItem->startConfiguration();
      55         159 :         listItem = listItem->nextDebounce;
      56             :     }
      57             : }
      58             : 
      59         159 : void ButtonDebounce::stopConfiguration() {
      60             :     // If the configuration has changed
      61             : #if ! EFI_ACTIVE_CONFIGURATION_IN_FLASH
      62         159 :     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
      67             :         efiSetPadUnused(active_pin);
      68             : #endif /* EFI_UNIT_TEST */
      69           0 :         needsPinInitialization = true;
      70             :     }
      71         159 : }
      72             : 
      73         950 : void ButtonDebounce::startConfiguration() {
      74             : #if EFI_PROD_CODE
      75             :     if (needsPinInitialization) {
      76             :         efiSetPadMode(m_name, *m_pin, getInputMode(*m_mode));
      77             :         needsPinInitialization = false;
      78             :     }
      79             : #endif
      80         950 :     active_pin = *m_pin;
      81         950 :     active_mode = *m_mode;
      82         950 : }
      83             : 
      84             : /**
      85             : @returns true if the button is pressed, and will not return true again within the set timeout
      86             : */
      87           6 : bool ButtonDebounce::readPinEvent() {
      88           6 :     storedValue = readPinState2(false);
      89           6 :     return storedValue;
      90             : }
      91             : 
      92          20 : bool ButtonDebounce::getPhysicalState() {
      93             : #if EFI_PROD_CODE || EFI_UNIT_TEST
      94          20 :     return efiReadPin(active_pin) ^ m_inverted;
      95             : #else
      96             :     return false;
      97             : #endif
      98             : }
      99             : 
     100          15 : bool ButtonDebounce::readPinState2(bool valueWithinThreshold) {
     101          15 :     if (!isBrainPinValid(*m_pin)) {
     102           0 :         return false;
     103             :     }
     104          15 :     efitick_t timeNowNt = getTimeNowNt();
     105             :     // If it's been less than the threshold since we were last called
     106          15 :     if (timeLast.getElapsedNt(timeNowNt) < m_threshold) {
     107           1 :         return valueWithinThreshold;
     108             :     }
     109          14 :     bool value = getPhysicalState();
     110             : //    efiPrintf("[debounce] %s value %d", m_name, value);
     111             :     // Invert
     112          14 :     if (active_mode == PI_PULLUP) {
     113           8 :         value = !value;
     114             : //        efiPrintf("[debounce] %s inverted %d", m_name, value);
     115             :     }
     116          14 :     if (value) {
     117           5 :         timeLast.reset();
     118             :     }
     119          14 :     return value;
     120             : }
     121             : 
     122           9 : bool ButtonDebounce::readPinState() {
     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.
     128           9 :     storedValue = readPinState2(storedValue);
     129           9 :     return storedValue;
     130             : }
     131             : 
     132           0 : void ButtonDebounce::debug() {
     133           0 :     ButtonDebounce *listItem = s_firstDebounce;
     134           0 :     while (listItem != nullptr) {
     135             : #if EFI_PROD_CODE || EFI_UNIT_TEST
     136           0 :         efiPrintf("%s timeLast %d", listItem->m_name, listItem->timeLast);
     137           0 :         efiPrintf("physical pin state %d", listItem->getPhysicalState());
     138           0 :         efiPrintf("state %d", listItem->storedValue);
     139           0 :         efiPrintf("mode %d", listItem->active_mode);
     140             : #endif
     141             : 
     142           0 :         listItem = listItem->nextDebounce;
     143             :     }
     144           0 : }
     145             : 
     146         317 : void initButtonDebounce() {
     147             : #if !EFI_UNIT_TEST
     148             :         addConsoleAction("debounce", ButtonDebounce::debug);
     149             : #endif /* EFI_UNIT_TEST */
     150         317 : }

Generated by: LCOV version 1.14