#include "../SimpleButton.h" namespace simplebutton { Button::Button() { setup(255, false); } Button::Button(uint8_t pin) { setup(pin, false); } Button::Button(uint8_t pin, bool inverted) { setup(pin, inverted); } Button::~Button() {} void Button::setup(uint8_t pin, bool inverted) { this->button_pin = pin; this->button_inverted = inverted; enable(); } void Button::enable() { button_enabled = true; if ((button_pin < 255) && !button_setup) { pinMode(button_pin, INPUT); button_setup = true; } } void Button::disable() { button_enabled = false; } void Button::reset() { pushedFlag = false; releasedFlag = false; holdFlag = false; } void Button::push() { if (!state) { state = true; prevPushTime = pushTime; prevReleaseTime = releaseTime; pushedFlag = true; pushTime = millis(); holdTime = millis(); holdFlag = false; } } void Button::release() { if (state) { state = false; releasedFlag = true; releaseTime = millis(); } } void Button::click() { click(defaultMinPushTime); } void Button::click(uint32_t time) { push(); pushTime = millis() - time - defaultMinReleaseTime; release(); releaseTime = millis() - defaultMinReleaseTime; updateEvents(); } int Button::read() { bool currentState = false; if (button_enabled && button_setup) { currentState = digitalRead(button_pin); if (button_inverted) currentState = !currentState; } return (int)currentState; } void Button::update() { if (millis() - updateTime >= updateInterval) { updateEvents(); if (button_enabled && button_setup) update(read()); } } void Button::update(int state) { // update time updateTime = millis(); // check events updateEvents(); // update state if (state > 0) push(); else release(); } void Button::updateEvents() { Event* e = this->events; while (e != NULL) { switch (e->getMode()) { case e->MODE::PUSHED: if (this->pushed()) e->run(); break; case e->MODE::RELEASED: if (this->released()) e->run(); break; case e->MODE::CLICKED: if (this->clicked(e->getMinPushTime(), e->getMinReleaseTime())) e->run(); break; case e->MODE::DOUBLECLICKED: if (this->doubleClicked(e->getMinPushTime(), e->getMinReleaseTime(), e->getTimeSpan())) e->run(); break; case e->MODE::HOLDING: if (this->holding(e->getInterval())) e->run(); break; } e = e->next; } } bool Button::isInverted() { return button_inverted; } bool Button::isEnabled() { return button_enabled; } bool Button::isSetup() { return button_setup; } bool Button::getState() { return state; } int Button::getClicks() { return (int)clicks; } int Button::getPushTime() { return (int)(millis() - pushTime); } bool Button::pushed() { if (pushedFlag) { pushedFlag = false; return true; } return false; } bool Button::released() { if (releasedFlag && (pushTime < releaseTime)) { releasedFlag = false; return true; } return false; } bool Button::clicked() { return clicked(defaultMinPushTime); } bool Button::clicked(uint32_t minPushTime) { return clicked(minPushTime, defaultMinReleaseTime); } bool Button::clicked(uint32_t minPushTime, uint32_t minReleaseTime) { bool notHolding = !holdFlag; bool minTime = millis() - pushTime >= minPushTime; bool releaseTimeout = millis() - releaseTime >= minReleaseTime; if (notHolding && minTime && releaseTimeout) { if (released()) { clicks++; return true; } } return false; } bool Button::doubleClicked() { return doubleClicked(defaultMinPushTime); } bool Button::doubleClicked(uint32_t minPushTime) { return doubleClicked(minPushTime, defaultTimeSpan); } bool Button::doubleClicked(uint32_t minPushTime, uint32_t timeSpan) { return doubleClicked(minPushTime, defaultMinReleaseTime, timeSpan); } bool Button::doubleClicked(uint32_t minPushTime, uint32_t minReleaseTime, uint32_t timeSpan) { bool wasPrevClicked = prevReleaseTime - prevPushTime >= minPushTime; bool inTimeSpan = millis() - prevPushTime <= timeSpan; bool releaseTimeout = millis() - prevReleaseTime >= minReleaseTime; if (wasPrevClicked && inTimeSpan && releaseTimeout) { if (clicked(minPushTime)) { pushTime = 0; return true; } } return false; } bool Button::holding() { return holding(defaultHoldInterval); } bool Button::holding(uint32_t interval) { if (getState() && (millis() - holdTime >= interval)) { holdTime = millis(); holdFlag = true; return true; } return false; } void Button::setUpdateInterval(uint32_t updateInterval) { this->updateInterval = updateInterval; } void Button::setDefaultMinPushTime(uint32_t defaultMinPushTime) { this->defaultMinPushTime = defaultMinPushTime; } void Button::setDefaultMinReleaseTime(uint32_t defaultMinReleaseTime) { this->defaultMinReleaseTime = defaultMinReleaseTime; } void Button::setDefaultTimeSpan(uint32_t defaultTimeSpan) { this->defaultTimeSpan = defaultTimeSpan; } void Button::setDefaultHoldTime(uint32_t defaultHoldInterval) { this->defaultHoldInterval = defaultHoldInterval; } void Button::setOnPushed(ButtonEventFunction) { this->addEvent(new PushEvent(fnct)); } void Button::setOnReleased(ButtonEventFunction) { this->addEvent(new ReleaseEvent(fnct)); } void Button::setOnClicked(ButtonEventFunction) { setOnClicked(fnct, defaultMinPushTime, defaultMinReleaseTime); } void Button::setOnClicked(ButtonEventFunction, uint32_t minPushTime) { setOnClicked(fnct, minPushTime, defaultMinReleaseTime); } void Button::setOnClicked(ButtonEventFunction, uint32_t minPushTime, uint32_t minReleaseTime) { this->addEvent(new ClickEvent(fnct, minPushTime, minReleaseTime)); } void Button::setOnDoubleClicked(ButtonEventFunction) { setOnDoubleClicked(fnct, defaultMinPushTime, defaultMinReleaseTime, defaultTimeSpan); } void Button::setOnDoubleClicked(ButtonEventFunction, uint32_t minPushTime) { setOnDoubleClicked(fnct, minPushTime, defaultMinReleaseTime, defaultTimeSpan); } void Button::setOnDoubleClicked(ButtonEventFunction, uint32_t minPushTime, uint32_t timeSpan) { setOnDoubleClicked(fnct, minPushTime, defaultMinReleaseTime, timeSpan); } void Button::setOnDoubleClicked(ButtonEventFunction, uint32_t minPushTime, uint32_t minReleaseTime, uint32_t timeSpan) { this->addEvent(new DoubleclickEvent(fnct, minPushTime, minReleaseTime, timeSpan)); } void Button::setOnHolding(ButtonEventFunction) { setOnHolding(fnct, defaultHoldInterval); } void Button::setOnHolding(ButtonEventFunction, uint32_t interval) { this->addEvent(new HoldEvent(fnct, interval)); } void Button::clearEvents() { delete events; events = NULL; } void Button::addEvent(Event* e) { if (events == NULL) events = e; else { Event* tmp = events; while (tmp->next != NULL) tmp = tmp->next; tmp->next = e; } } }