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.

230 lines
6.5 KiB

4 years ago
  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. Modified to include generic INPUT / OUTPUT pin support through a custom interface.
  17. Definitions are incompatible with DebounceEvent, you should not include it's headers.
  18. */
  19. #pragma once
  20. #include <Arduino.h>
  21. namespace DebounceEvent {
  22. #include <functional>
  23. #include <memory>
  24. namespace Types {
  25. enum event_t {
  26. EventNone,
  27. EventChanged,
  28. EventPressed,
  29. EventReleased
  30. };
  31. enum mode_t {
  32. ModePushbutton = 1 << 0,
  33. ModeSwitch = 1 << 1,
  34. ModeDefaultHigh = 1 << 2,
  35. ModeSetPullup = 1 << 3
  36. };
  37. }
  38. constexpr const unsigned long DebounceDelay = 50UL;
  39. constexpr const unsigned long RepeatDelay = 500UL;
  40. // base interface for generic pin handler.
  41. class PinBase {
  42. public:
  43. PinBase(unsigned char pin) :
  44. pin(pin)
  45. {}
  46. virtual void pinMode(int8_t mode) = 0;
  47. virtual void digitalWrite(int8_t val) = 0;
  48. virtual int digitalRead() = 0;
  49. const unsigned char pin;
  50. };
  51. // real hardware pin
  52. class DigitalPin : public PinBase {
  53. public:
  54. DigitalPin(unsigned char pin) :
  55. PinBase(pin)
  56. {}
  57. void pinMode(int8_t mode) {
  58. // Note: proxy for pinMode so it doesn't ignore INPUT_PULLUP with GPIO16
  59. if (((mode == INPUT) || (mode == INPUT_PULLUP)) && this->pin == 16) {
  60. ::pinMode(this->pin, ((mode == INPUT_PULLUP) ? INPUT : INPUT_PULLDOWN_16));
  61. return;
  62. }
  63. ::pinMode(this->pin, mode);
  64. }
  65. void digitalWrite(int8_t val) {
  66. ::digitalWrite(this->pin, val);
  67. }
  68. int digitalRead() {
  69. return ::digitalRead(this->pin);
  70. }
  71. };
  72. class DebounceEvent {
  73. public:
  74. // TODO: not used in espurna buttons node
  75. using callback_f = std::function<void(DebounceEvent* self, uint8_t event, uint8_t count, uint16_t length)>;
  76. DebounceEvent(std::shared_ptr<PinBase> pin, int mode = Types::ModePushbutton | Types::ModeDefaultHigh, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
  77. DebounceEvent(std::shared_ptr<PinBase> pin, callback_f callback, int mode = Types::ModePushbutton | Types::ModeDefaultHigh, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
  78. Types::event_t loop();
  79. bool pressed();
  80. unsigned long getEventLength();
  81. unsigned long getEventCount();
  82. std::shared_ptr<PinBase> pin;
  83. callback_f callback;
  84. const int mode;
  85. private:
  86. const bool _is_switch;
  87. const bool _default_status;
  88. const unsigned long _delay;
  89. const unsigned long _repeat;
  90. bool _status;
  91. bool _ready;
  92. bool _reset_count;
  93. unsigned long _event_start;
  94. unsigned long _event_length;
  95. unsigned char _event_count;
  96. };
  97. DebounceEvent::DebounceEvent(std::shared_ptr<PinBase> pin, DebounceEvent::callback_f callback, int mode, unsigned long debounce_delay, unsigned long repeat) :
  98. pin(pin),
  99. callback(callback),
  100. mode(mode),
  101. _is_switch(mode & Types::ModeSwitch),
  102. _default_status(mode & Types::ModeDefaultHigh),
  103. _delay(debounce_delay),
  104. _repeat(repeat),
  105. _status(false),
  106. _ready(false),
  107. _reset_count(true),
  108. _event_start(0),
  109. _event_length(0),
  110. _event_count(0)
  111. {
  112. pin->pinMode((mode & Types::ModeSetPullup) ? INPUT_PULLUP : INPUT);
  113. _status = (mode & Types::ModeSwitch) ? pin->digitalRead() : _default_status;
  114. }
  115. DebounceEvent::DebounceEvent(std::shared_ptr<PinBase> pin, int mode, unsigned long delay, unsigned long repeat) :
  116. DebounceEvent(pin, nullptr, mode, delay, repeat)
  117. {}
  118. bool DebounceEvent::pressed() {
  119. return (_status != _default_status);
  120. }
  121. unsigned long DebounceEvent::getEventLength() {
  122. return _event_length;
  123. }
  124. unsigned long DebounceEvent::getEventCount() {
  125. return _event_count;
  126. }
  127. Types::event_t DebounceEvent::loop() {
  128. auto event = Types::EventNone;
  129. if (pin->digitalRead() != _status) {
  130. // TODO: check each loop instead of blocking?
  131. auto start = millis();
  132. while (millis() - start < _delay) delay(1);
  133. if (pin->digitalRead() != _status) {
  134. _status = !_status;
  135. if (_is_switch) {
  136. event = Types::EventChanged;
  137. } else {
  138. if (_status == _default_status) {
  139. _event_length = millis() - _event_start;
  140. _ready = true;
  141. } else {
  142. event = Types::EventPressed;
  143. _event_start = millis();
  144. _event_length = 0;
  145. if (_reset_count) {
  146. _event_count = 1;
  147. _reset_count = false;
  148. } else {
  149. ++_event_count;
  150. }
  151. _ready = false;
  152. }
  153. }
  154. }
  155. }
  156. if (_ready && (millis() - _event_start > _repeat)) {
  157. _ready = false;
  158. _reset_count = true;
  159. event = Types::EventReleased;
  160. }
  161. if (callback && (event != Types::EventNone)) {
  162. callback(this, event, _event_count, _event_length);
  163. }
  164. return event;
  165. }
  166. // compat definitions from the original lib
  167. #define BUTTON_PUSHBUTTON DebounceEvent::Types::ModePushbutton
  168. #define BUTTON_SWITCH DebounceEvent::Types::ModeSwitch
  169. #define BUTTON_DEFAULT_HIGH DebounceEvent::Types::ModeDefaultHigh
  170. #define BUTTON_SET_PULLUP DebounceEvent::Types::ModeSetPullup
  171. #define EVENT_NONE DebounceEvent::Types::EventNone
  172. #define EVENT_CHANGED DebounceEvent::Types::EventChanged
  173. #define EVENT_PRESSED DebounceEvent::Types::EventPressed
  174. #define EVENT_RELEASED DebounceEvent::Types::EventReleased
  175. } // namespace DebounceEvent