|
|
- /*
-
- Original code:
-
- Debounce buttons and trigger events
- Copyright (C) 2015-2018 by Xose Pérez <xose dot perez at gmail dot com>
-
- The DebounceEvent library is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- The DebounceEvent library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with the DebounceEvent library. If not, see <http://www.gnu.org/licenses/>.
-
- ----------------------------------------------------------------------------------
-
- Modified to include generic INPUT / OUTPUT pin support through a custom interface.
-
- Definitions are incompatible with DebounceEvent, you should not include it's headers.
-
- */
-
- #pragma once
-
- #include <Arduino.h>
-
- namespace DebounceEvent {
-
- #include <functional>
- #include <memory>
-
- namespace Types {
- enum event_t {
- EventNone,
- EventChanged,
- EventPressed,
- EventReleased
- };
-
- enum mode_t {
- ModePushbutton = 1 << 0,
- ModeSwitch = 1 << 1,
- ModeDefaultHigh = 1 << 2,
- ModeSetPullup = 1 << 3
- };
- }
-
- constexpr const unsigned long DebounceDelay = 50UL;
- constexpr const unsigned long RepeatDelay = 500UL;
-
- // base interface for generic pin handler.
- class PinBase {
- public:
- PinBase(unsigned char pin) :
- pin(pin)
- {}
-
- virtual void pinMode(int8_t mode) = 0;
- virtual void digitalWrite(int8_t val) = 0;
- virtual int digitalRead() = 0;
-
- const unsigned char pin;
- };
-
- // real hardware pin
- class DigitalPin : public PinBase {
- public:
- DigitalPin(unsigned char pin) :
- PinBase(pin)
- {}
-
- void pinMode(int8_t mode) {
- // Note: proxy for pinMode so it doesn't ignore INPUT_PULLUP with GPIO16
- if (((mode == INPUT) || (mode == INPUT_PULLUP)) && this->pin == 16) {
- ::pinMode(this->pin, ((mode == INPUT_PULLUP) ? INPUT : INPUT_PULLDOWN_16));
- return;
- }
- ::pinMode(this->pin, mode);
- }
- void digitalWrite(int8_t val) {
- ::digitalWrite(this->pin, val);
- }
- int digitalRead() {
- return ::digitalRead(this->pin);
- }
- };
-
- class DebounceEvent {
-
-
- public:
-
- // TODO: not used in espurna buttons node
- using callback_f = std::function<void(DebounceEvent* self, uint8_t event, uint8_t count, uint16_t length)>;
-
- DebounceEvent(std::shared_ptr<PinBase> pin, int mode = Types::ModePushbutton | Types::ModeDefaultHigh, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
- DebounceEvent(std::shared_ptr<PinBase> pin, callback_f callback, int mode = Types::ModePushbutton | Types::ModeDefaultHigh, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay);
-
- Types::event_t loop();
- bool pressed();
-
- unsigned long getEventLength();
- unsigned long getEventCount();
-
- std::shared_ptr<PinBase> pin;
- callback_f callback;
-
- const int mode;
-
- private:
-
- const bool _is_switch;
- const bool _default_status;
-
- const unsigned long _delay;
- const unsigned long _repeat;
-
- bool _status;
-
- bool _ready;
- bool _reset_count;
-
- unsigned long _event_start;
- unsigned long _event_length;
- unsigned char _event_count;
-
- };
-
- DebounceEvent::DebounceEvent(std::shared_ptr<PinBase> pin, DebounceEvent::callback_f callback, int mode, unsigned long debounce_delay, unsigned long repeat) :
- pin(pin),
- callback(callback),
- mode(mode),
- _is_switch(mode & Types::ModeSwitch),
- _default_status(mode & Types::ModeDefaultHigh),
- _delay(debounce_delay),
- _repeat(repeat),
- _status(false),
- _ready(false),
- _reset_count(true),
- _event_start(0),
- _event_length(0),
- _event_count(0)
- {
- pin->pinMode((mode & Types::ModeSetPullup) ? INPUT_PULLUP : INPUT);
- _status = (mode & Types::ModeSwitch) ? pin->digitalRead() : _default_status;
- }
-
- DebounceEvent::DebounceEvent(std::shared_ptr<PinBase> pin, int mode, unsigned long delay, unsigned long repeat) :
- DebounceEvent(pin, nullptr, mode, delay, repeat)
- {}
-
- bool DebounceEvent::pressed() {
- return (_status != _default_status);
- }
-
- unsigned long DebounceEvent::getEventLength() {
- return _event_length;
- }
- unsigned long DebounceEvent::getEventCount() {
- return _event_count;
- }
-
- Types::event_t DebounceEvent::loop() {
-
- auto event = Types::EventNone;
-
- if (pin->digitalRead() != _status) {
-
- // TODO: check each loop instead of blocking?
- auto start = millis();
- while (millis() - start < _delay) delay(1);
-
- if (pin->digitalRead() != _status) {
-
- _status = !_status;
-
- if (_is_switch) {
- event = Types::EventChanged;
- } else {
- if (_status == _default_status) {
- _event_length = millis() - _event_start;
- _ready = true;
- } else {
- event = Types::EventPressed;
- _event_start = millis();
- _event_length = 0;
- if (_reset_count) {
- _event_count = 1;
- _reset_count = false;
- } else {
- ++_event_count;
- }
- _ready = false;
- }
- }
- }
- }
-
- if (_ready && (millis() - _event_start > _repeat)) {
- _ready = false;
- _reset_count = true;
- event = Types::EventReleased;
- }
-
- if (callback && (event != Types::EventNone)) {
- callback(this, event, _event_count, _event_length);
- }
-
- return event;
-
- }
-
- // compat definitions from the original lib
- #define BUTTON_PUSHBUTTON DebounceEvent::Types::ModePushbutton
- #define BUTTON_SWITCH DebounceEvent::Types::ModeSwitch
- #define BUTTON_DEFAULT_HIGH DebounceEvent::Types::ModeDefaultHigh
- #define BUTTON_SET_PULLUP DebounceEvent::Types::ModeSetPullup
-
- #define EVENT_NONE DebounceEvent::Types::EventNone
- #define EVENT_CHANGED DebounceEvent::Types::EventChanged
- #define EVENT_PRESSED DebounceEvent::Types::EventPressed
- #define EVENT_RELEASED DebounceEvent::Types::EventReleased
-
- } // namespace DebounceEvent
|