diff --git a/code/espurna/button.h b/code/espurna/button.h index c1bb8850..22b8c815 100644 --- a/code/espurna/button.h +++ b/code/espurna/button.h @@ -8,25 +8,32 @@ Copyright (C) 2016-2019 by Xose Pérez #pragma once -#include +#include "debounce.h" -struct button_t { +#include + +struct button_event_delays_t { + button_event_delays_t(); + button_event_delays_t(unsigned long debounce, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick); - // TODO: dblclick and debounce delays - right now a global setting, independent of ID - static unsigned long DebounceDelay; - static unsigned long DblclickDelay; + const unsigned long debounce; + const unsigned long dblclick; + const unsigned long lngclick; + const unsigned long lnglngclick; +}; - // Use built-in indexed definitions to configure DebounceEvent - button_t(unsigned char index); +struct button_t { - // Provide custom DebounceEvent parameters instead - button_t(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID); + button_t(std::shared_ptr pin, int mode, unsigned long actions, unsigned char relayID, button_event_delays_t delays); bool state(); - std::unique_ptr event; - unsigned long actions; - unsigned char relayID; + std::unique_ptr event_handler; + button_event_delays_t event_delays; + + const unsigned long actions; + const unsigned char relayID; + }; bool buttonState(unsigned char id); diff --git a/code/espurna/button.ino b/code/espurna/button.ino index 3bb70e79..d32f9bb3 100644 --- a/code/espurna/button.ino +++ b/code/espurna/button.ino @@ -8,7 +8,6 @@ Copyright (C) 2016-2019 by Xose Pérez #if BUTTON_SUPPORT -#include #include #include @@ -19,28 +18,72 @@ Copyright (C) 2016-2019 by Xose Pérez #include "button.h" #include "button_config.h" +#include "debounce.h" + // ----------------------------------------------------------------------------- -// TODO: dblclick and debounce delays - right now a global setting, independent of ID -unsigned long button_t::DebounceDelay = BUTTON_DEBOUNCE_DELAY; -unsigned long button_t::DblclickDelay = BUTTON_DBLCLICK_DELAY; +button_event_delays_t::button_event_delays_t() : + debounce(BUTTON_DEBOUNCE_DELAY), + dblclick(BUTTON_DBLCLICK_DELAY), + lngclick(BUTTON_LNGCLICK_DELAY), + lnglngclick(BUTTON_LNGLNGCLICK_DELAY) +{} -button_t::button_t(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID) : - event(new DebounceEvent(pin, mode, DebounceDelay, DblclickDelay)), - actions(actions), - relayID(relayID) +button_event_delays_t::button_event_delays_t(unsigned long debounce, unsigned long dblclick, unsigned long lngclick, unsigned long lnglngclick) : + debounce(debounce), + dblclick(dblclick), + lngclick(lngclick), + lnglngclick(lnglngclick) {} -button_t::button_t(unsigned char index) : - button_t(_buttonPin(index), _buttonMode(index), _buttonConstructActions(index), _buttonRelay(index)) +button_t::button_t(std::shared_ptr pin, int mode, unsigned long actions, unsigned char relayID, button_event_delays_t delays) : + event_handler(new DebounceEvent::DebounceEvent(pin, mode, delays.debounce, delays.dblclick)), + event_delays(delays), + actions(actions), + relayID(relayID) {} bool button_t::state() { - return event->pressed(); + return event_handler->pressed(); } std::vector _buttons; +// ----------------------------------------------------------------------------- + +constexpr const uint8_t _buttonMapReleased(uint8_t count, uint8_t length, unsigned long lngclick_delay, unsigned long lnglngclick_delay) { + return ( + (1 == count) ? ( + (length > lnglngclick_delay) ? BUTTON_EVENT_LNGLNGCLICK : + (length > lngclick_delay) ? BUTTON_EVENT_LNGCLICK : BUTTON_EVENT_CLICK + ) : + (2 == count) ? BUTTON_EVENT_DBLCLICK : + (3 == count) ? BUTTON_EVENT_TRIPLECLICK : + BUTTON_EVENT_NONE + ); +} + +const uint8_t _buttonMapEvent(button_t& button, DebounceEvent::Types::event_t event) { + using namespace DebounceEvent; + switch (event) { + case Types::EventPressed: + return BUTTON_EVENT_PRESSED; + case Types::EventChanged: + return BUTTON_EVENT_CLICK; + case Types::EventReleased: { + return _buttonMapReleased( + button.event_handler->getEventCount(), + button.event_handler->getEventLength(), + button.event_delays.lngclick, + button.event_delays.lnglngclick + ); + } + case Types::EventNone: + default: + return BUTTON_EVENT_NONE; + } +} + unsigned char buttonCount() { return _buttons.size(); } @@ -148,8 +191,22 @@ void buttonEvent(unsigned char id, unsigned char event) { } +struct DummyPin : virtual public DebounceEvent::PinBase { + DummyPin(unsigned char pin) : DebounceEvent::PinBase(pin) {} + void digitalWrite(int8_t val) {} + void pinMode(int8_t mode) {} + int digitalRead() { return 0; } +}; + unsigned char buttonAdd(unsigned char pin, unsigned char mode, unsigned long actions, unsigned char relayID) { - _buttons.emplace_back(pin, mode, actions, relayID); + const unsigned char index = _buttons.size(); + button_event_delays_t delays { + getSetting({"btnDebDelay", index}, _buttonDebounceDelay(index)), + getSetting({"btnDblCDelay", index}, _buttonDoubleClickDelay(index)), + getSetting({"btnLngCDelay", index}, _buttonLongClickDelay(index)), + getSetting({"btnLngLngCDelay", index}, _buttonLongLongClickDelay(index)) + }; + _buttons.emplace_back(std::make_shared(GPIO_NONE), BUTTON_PUSHBUTTON, actions, relayID, delays); return _buttons.size() - 1; } @@ -214,12 +271,26 @@ void buttonSetup() { _buttons.reserve(buttons); - // TODO: load based on index - button_t::DebounceDelay = getSetting("btnDebounce", BUTTON_DEBOUNCE_DELAY); - button_t::DblclickDelay = getSetting("btnDelay", BUTTON_DBLCLICK_DELAY); + for (unsigned char index = 0; index < buttons; ++index) { + const auto pin = getSetting({"btnGPIO", index}, _buttonPin(index)); + if (!gpioValid(pin)) { + break; + } - for (unsigned char id = 0; id < buttons; ++id) { - _buttons.emplace_back(id); + button_event_delays_t delays { + getSetting({"btnDebDelay", index}, _buttonDebounceDelay(index)), + getSetting({"btnDblCDelay", index}, _buttonDoubleClickDelay(index)), + getSetting({"btnLngCDelay", index}, _buttonLongClickDelay(index)), + getSetting({"btnLngLngCDelay", index}, _buttonLongLongClickDelay(index)) + }; + + _buttons.emplace_back( + std::make_shared(pin), + getSetting({"btnMode", index}, _buttonMode(index)), + getSetting({"btnActions", index}, _buttonConstructActions(index)), + getSetting({"btnRelay", index}, _buttonRelay(index)), + delays + ); } #endif @@ -307,12 +378,8 @@ void buttonLoop() { for (size_t id = 0; id < _buttons.size(); ++id) { auto& button = _buttons[id]; - if (auto event = button.event->loop()) { - buttonEvent(id, _buttonMapEvent( - event, - button.event->getEventCount(), - button.event->getEventLength() - )); + if (auto event = button.event_handler->loop()) { + buttonEvent(id, _buttonMapEvent(button, event)); } } diff --git a/code/espurna/button_config.h b/code/espurna/button_config.h index 9228a923..163fb6f0 100644 --- a/code/espurna/button_config.h +++ b/code/espurna/button_config.h @@ -123,35 +123,66 @@ constexpr const unsigned char _buttonRelay(unsigned char index) { ); } -constexpr const unsigned char _buttonDecodeEventAction(unsigned long actions, unsigned char event) { +constexpr const unsigned long _buttonDebounceDelay(unsigned char index) { return ( - (event == BUTTON_EVENT_PRESSED) ? ((actions) & 0x0F) : - (event == BUTTON_EVENT_CLICK) ? ((actions >> 4) & 0x0F) : - (event == BUTTON_EVENT_DBLCLICK) ? ((actions >> 8) & 0x0F) : - (event == BUTTON_EVENT_LNGCLICK) ? ((actions >> 12) & 0x0F) : - (event == BUTTON_EVENT_LNGLNGCLICK) ? ((actions >> 16) & 0x0F) : - (event == BUTTON_EVENT_TRIPLECLICK) ? ((actions >> 20) & 0x0F) : BUTTON_MODE_NONE + (index == 0) ? BUTTON1_DEBOUNCE_DELAY : + (index == 1) ? BUTTON2_DEBOUNCE_DELAY : + (index == 2) ? BUTTON3_DEBOUNCE_DELAY : + (index == 3) ? BUTTON4_DEBOUNCE_DELAY : + (index == 4) ? BUTTON5_DEBOUNCE_DELAY : + (index == 5) ? BUTTON6_DEBOUNCE_DELAY : + (index == 6) ? BUTTON7_DEBOUNCE_DELAY : + (index == 7) ? BUTTON8_DEBOUNCE_DELAY : BUTTON_DEBOUNCE_DELAY + ); +} + +constexpr const unsigned long _buttonDoubleClickDelay(unsigned char index) { + return ( + (index == 0) ? BUTTON1_DBLCLICK_DELAY : + (index == 1) ? BUTTON2_DBLCLICK_DELAY : + (index == 2) ? BUTTON3_DBLCLICK_DELAY : + (index == 3) ? BUTTON4_DBLCLICK_DELAY : + (index == 4) ? BUTTON5_DBLCLICK_DELAY : + (index == 5) ? BUTTON6_DBLCLICK_DELAY : + (index == 6) ? BUTTON7_DBLCLICK_DELAY : + (index == 7) ? BUTTON8_DBLCLICK_DELAY : BUTTON_DBLCLICK_DELAY ); } -constexpr const uint8_t _buttonMapReleased(uint8_t count, uint8_t length) { +constexpr const unsigned long _buttonLongClickDelay(unsigned char index) { return ( - (1 == count) ? ( - (length > BUTTON_LNGLNGCLICK_DELAY) ? BUTTON_EVENT_LNGLNGCLICK : - (length > BUTTON_LNGCLICK_DELAY) ? BUTTON_EVENT_LNGCLICK : BUTTON_EVENT_CLICK - ) : - (2 == count) ? BUTTON_EVENT_DBLCLICK : - (3 == count) ? BUTTON_EVENT_TRIPLECLICK : - BUTTON_EVENT_NONE + (index == 0) ? BUTTON1_LNGCLICK_DELAY : + (index == 1) ? BUTTON2_LNGCLICK_DELAY : + (index == 2) ? BUTTON3_LNGCLICK_DELAY : + (index == 3) ? BUTTON4_LNGCLICK_DELAY : + (index == 4) ? BUTTON5_LNGCLICK_DELAY : + (index == 5) ? BUTTON6_LNGCLICK_DELAY : + (index == 6) ? BUTTON7_LNGCLICK_DELAY : + (index == 7) ? BUTTON8_LNGCLICK_DELAY : BUTTON_LNGCLICK_DELAY ); } -constexpr const uint8_t _buttonMapEvent(uint8_t event, uint8_t count, uint16_t length) { +constexpr const unsigned long _buttonLongLongClickDelay(unsigned char index) { return ( - (event == EVENT_PRESSED) ? BUTTON_EVENT_PRESSED : - (event == EVENT_CHANGED) ? BUTTON_EVENT_CLICK : - (event == EVENT_RELEASED) ? _buttonMapReleased(count, length) : - BUTTON_EVENT_NONE + (index == 0) ? BUTTON1_LNGLNGCLICK_DELAY : + (index == 1) ? BUTTON2_LNGLNGCLICK_DELAY : + (index == 2) ? BUTTON3_LNGLNGCLICK_DELAY : + (index == 3) ? BUTTON4_LNGLNGCLICK_DELAY : + (index == 4) ? BUTTON5_LNGLNGCLICK_DELAY : + (index == 5) ? BUTTON6_LNGLNGCLICK_DELAY : + (index == 6) ? BUTTON7_LNGLNGCLICK_DELAY : + (index == 7) ? BUTTON8_LNGLNGCLICK_DELAY : BUTTON_LNGLNGCLICK_DELAY + ); +} + +constexpr const unsigned char _buttonDecodeEventAction(unsigned long actions, unsigned char event) { + return ( + (event == BUTTON_EVENT_PRESSED) ? ((actions) & 0x0F) : + (event == BUTTON_EVENT_CLICK) ? ((actions >> 4) & 0x0F) : + (event == BUTTON_EVENT_DBLCLICK) ? ((actions >> 8) & 0x0F) : + (event == BUTTON_EVENT_LNGCLICK) ? ((actions >> 12) & 0x0F) : + (event == BUTTON_EVENT_LNGLNGCLICK) ? ((actions >> 16) & 0x0F) : + (event == BUTTON_EVENT_TRIPLECLICK) ? ((actions >> 20) & 0x0F) : BUTTON_MODE_NONE ); } diff --git a/code/espurna/config/defaults.h b/code/espurna/config/defaults.h index f904820c..fd95dd4a 100644 --- a/code/espurna/config/defaults.h +++ b/code/espurna/config/defaults.h @@ -233,6 +233,131 @@ #define BUTTON8_RELAY RELAY_NONE #endif +#ifndef BUTTON1_EVENT_SOURCE +#define BUTTON1_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON2_EVENT_SOURCE +#define BUTTON2_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON3_EVENT_SOURCE +#define BUTTON3_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON4_EVENT_SOURCE +#define BUTTON4_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON5_EVENT_SOURCE +#define BUTTON5_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON6_EVENT_SOURCE +#define BUTTON6_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON7_EVENT_SOURCE +#define BUTTON7_EVENT_SOURCE DigitalPin +#endif +#ifndef BUTTON8_EVENT_SOURCE +#define BUTTON8_EVENT_SOURCE DigitalPin +#endif + +#ifndef BUTTON1_DEBOUNCE_DELAY +#define BUTTON1_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON2_DEBOUNCE_DELAY +#define BUTTON2_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON3_DEBOUNCE_DELAY +#define BUTTON3_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON4_DEBOUNCE_DELAY +#define BUTTON4_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON5_DEBOUNCE_DELAY +#define BUTTON5_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON6_DEBOUNCE_DELAY +#define BUTTON6_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON7_DEBOUNCE_DELAY +#define BUTTON7_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif +#ifndef BUTTON8_DEBOUNCE_DELAY +#define BUTTON8_DEBOUNCE_DELAY BUTTON_DEBOUNCE_DELAY +#endif + +#ifndef BUTTON1_DBLCLICK_DELAY +#define BUTTON1_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON2_DBLCLICK_DELAY +#define BUTTON2_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON3_DBLCLICK_DELAY +#define BUTTON3_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON4_DBLCLICK_DELAY +#define BUTTON4_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON5_DBLCLICK_DELAY +#define BUTTON5_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON6_DBLCLICK_DELAY +#define BUTTON6_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON7_DBLCLICK_DELAY +#define BUTTON7_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif +#ifndef BUTTON8_DBLCLICK_DELAY +#define BUTTON8_DBLCLICK_DELAY BUTTON_DBLCLICK_DELAY +#endif + +#ifndef BUTTON1_LNGCLICK_DELAY +#define BUTTON1_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON2_LNGCLICK_DELAY +#define BUTTON2_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON3_LNGCLICK_DELAY +#define BUTTON3_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON4_LNGCLICK_DELAY +#define BUTTON4_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON5_LNGCLICK_DELAY +#define BUTTON5_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON6_LNGCLICK_DELAY +#define BUTTON6_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON7_LNGCLICK_DELAY +#define BUTTON7_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif +#ifndef BUTTON8_LNGCLICK_DELAY +#define BUTTON8_LNGCLICK_DELAY BUTTON_LNGCLICK_DELAY +#endif + +#ifndef BUTTON1_LNGLNGCLICK_DELAY +#define BUTTON1_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON2_LNGLNGCLICK_DELAY +#define BUTTON2_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON3_LNGLNGCLICK_DELAY +#define BUTTON3_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON4_LNGLNGCLICK_DELAY +#define BUTTON4_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON5_LNGLNGCLICK_DELAY +#define BUTTON5_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON6_LNGLNGCLICK_DELAY +#define BUTTON6_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON7_LNGLNGCLICK_DELAY +#define BUTTON7_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif +#ifndef BUTTON8_LNGLNGCLICK_DELAY +#define BUTTON8_LNGLNGCLICK_DELAY BUTTON_LNGLNGCLICK_DELAY +#endif + // ----------------------------------------------------------------------------- // Encoders // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 38d28aa6..dc634490 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -44,15 +44,6 @@ #define BUTTON_MODE_DIM_UP 10 #define BUTTON_MODE_DIM_DOWN 11 - -// Needed for ESP8285 boards under Windows using PlatformIO (?) -#ifndef BUTTON_PUSHBUTTON -#define BUTTON_PUSHBUTTON 0 -#define BUTTON_SWITCH 1 -#define BUTTON_DEFAULT_HIGH 2 -#define BUTTON_SET_PULLUP 4 -#endif - //------------------------------------------------------------------------------ // ENCODER //------------------------------------------------------------------------------ diff --git a/code/espurna/debounce.h b/code/espurna/debounce.h new file mode 100644 index 00000000..b1be2858 --- /dev/null +++ b/code/espurna/debounce.h @@ -0,0 +1,230 @@ +/* + + Original code: + + Debounce buttons and trigger events + Copyright (C) 2015-2018 by Xose Pérez + + 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 . + + ---------------------------------------------------------------------------------- + + 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 + +namespace DebounceEvent { + +#include +#include + +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; + + DebounceEvent(std::shared_ptr pin, int mode = Types::ModePushbutton | Types::ModeDefaultHigh, unsigned long delay = DebounceDelay, unsigned long repeat = RepeatDelay); + DebounceEvent(std::shared_ptr 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 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 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 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