Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.8 KiB

  1. /*
  2. Original code:
  3. Debounce buttons and trigger events
  4. Copyright (C) 2015-2018 by Xose Pérez <xose dot perez at gmail dot com>
  5. The DebounceEvent library is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. The DebounceEvent library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with the DebounceEvent library. If not, see <http://www.gnu.org/licenses/>.
  15. ----------------------------------------------------------------------------------
  16. Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
  17. Modified to include generic INPUT / OUTPUT pin support through a custom interface.
  18. Definitions are incompatible with DebounceEvent, you should not include it's headers.
  19. */
  20. #include <functional>
  21. #include <memory>
  22. #include "libs/DebounceEvent.h"
  23. namespace debounce_event {
  24. EventEmitter::EventEmitter(types::Pin pin, types::EventHandler callback, const types::Config& config, unsigned long debounce_delay, unsigned long repeat) :
  25. _pin(pin),
  26. _callback(callback),
  27. _config(config),
  28. _is_switch(config.mode == types::Mode::Switch),
  29. _delay(debounce_delay),
  30. _repeat(repeat)
  31. {
  32. if (!pin) return;
  33. switch (_config.pin_mode) {
  34. case types::PinMode::InputPullup:
  35. _pin->pinMode(INPUT_PULLUP);
  36. break;
  37. case types::PinMode::InputPulldown:
  38. // ESP8266 does not have INPUT_PULLDOWN definition, and instead
  39. // has a GPIO16-specific INPUT_PULLDOWN_16:
  40. // - https://github.com/esp8266/Arduino/issues/478
  41. // - https://github.com/esp8266/Arduino/commit/1b3581d55ebf0f8c91e081f9af4cf7433d492ec9
  42. #ifdef ESP8266
  43. if (_pin->pin == 16) {
  44. _pin->pinMode(INPUT_PULLDOWN_16);
  45. } else {
  46. _pin->pinMode(INPUT);
  47. }
  48. #else
  49. _pin->pinMode(INPUT_PULLDOWN);
  50. #endif
  51. break;
  52. case types::PinMode::Input:
  53. _pin->pinMode(INPUT);
  54. break;
  55. }
  56. switch (config.default_value) {
  57. case types::PinValue::Low:
  58. _default_value = false;
  59. break;
  60. case types::PinValue::High:
  61. _default_value = true;
  62. break;
  63. case types::PinValue::Initial:
  64. _default_value = ((HIGH) == _pin->digitalRead());
  65. break;
  66. }
  67. _value = _default_value;
  68. }
  69. EventEmitter::EventEmitter(types::Pin pin, const types::Config& config, unsigned long delay, unsigned long repeat) :
  70. EventEmitter(pin, nullptr, config, delay, repeat)
  71. {}
  72. bool EventEmitter::isPressed() {
  73. return (_value != _default_value);
  74. }
  75. const types::Pin EventEmitter::getPin() const {
  76. return _pin;
  77. }
  78. const types::Config EventEmitter::getConfig() const {
  79. return _config;
  80. }
  81. unsigned long EventEmitter::getEventLength() {
  82. return _event_length;
  83. }
  84. unsigned long EventEmitter::getEventCount() {
  85. return _event_count;
  86. }
  87. // TODO: current implementation allows pin == nullptr
  88. types::Event EventEmitter::loop() {
  89. static_assert((HIGH) == 1, "Arduino API HIGH is not 1");
  90. static_assert((LOW) == 0, "Arduino API LOW is not 0");
  91. auto event = types::EventNone;
  92. bool value = _pin->digitalRead() == (HIGH);
  93. if (value != _value) {
  94. // TODO: check each loop instead of blocking?
  95. auto start = millis();
  96. while (millis() - start < _delay) delay(1);
  97. value = _pin->digitalRead() == (HIGH);
  98. if (value != _value) {
  99. _value = !_value;
  100. if (_is_switch) {
  101. event = isPressed()
  102. ? types::EventPressed
  103. : types::EventReleased;
  104. } else {
  105. if (_value == _default_value) {
  106. _event_length = millis() - _event_start;
  107. _ready = true;
  108. } else {
  109. event = types::EventPressed;
  110. _event_start = millis();
  111. _event_length = 0;
  112. if (_reset_count) {
  113. _event_count = 1;
  114. _reset_count = false;
  115. } else {
  116. ++_event_count;
  117. }
  118. _ready = false;
  119. }
  120. }
  121. }
  122. }
  123. if (_ready && (millis() - _event_start > _repeat)) {
  124. _ready = false;
  125. _reset_count = true;
  126. event = types::EventReleased;
  127. }
  128. if (_callback && (event != types::EventNone)) {
  129. _callback(*this, event, _event_count, _event_length);
  130. }
  131. return event;
  132. }
  133. } // namespace debounce_event