137 lines
3.8 KiB
C++
137 lines
3.8 KiB
C++
#include "Button.h"
|
|
|
|
namespace Dough
|
|
{
|
|
// Constructor for a button instance.
|
|
//
|
|
// As a necessary evil, because of the way attachinterrupt() works in
|
|
// Arduino, construction needs a bit of extra work to get the button
|
|
// working. An interrupt service routine (ISR) function must be created
|
|
// and linked to the button to get the interrupts working. Pattern:
|
|
//
|
|
// // A function for handling interrupts.
|
|
// void myButtonISR() {
|
|
// myButton.handleButtonState();
|
|
// }
|
|
//
|
|
// // Construct the button instance.
|
|
// Button myButton(MYBUTTON_PIN, myButtonISR);
|
|
Button::Button(int pin, ButtonISR isr)
|
|
{
|
|
_pin = pin;
|
|
attachInterrupt(digitalPinToInterrupt(_pin), isr, CHANGE);
|
|
}
|
|
|
|
void Button::setup()
|
|
{
|
|
pinMode(_pin, INPUT_PULLUP);
|
|
}
|
|
|
|
// Assign an event handler for short and long button presses.
|
|
// When specific handlers for long and/or short presses are
|
|
// configured as well, those have precedence over this one.
|
|
void Button::onPress(ButtonISR handler)
|
|
{
|
|
_pressHandler = handler;
|
|
}
|
|
|
|
// Assign an event handler for long button presses.
|
|
void Button::onLongPress(ButtonISR handler)
|
|
{
|
|
_longPressHandler = handler;
|
|
}
|
|
|
|
// Assign an event handler for short button presses.
|
|
void Button::onShortPress(ButtonISR handler)
|
|
{
|
|
_shortPressHandler = handler;
|
|
}
|
|
|
|
void Button::loop()
|
|
{
|
|
handleButtonState();
|
|
if (_state == UP_AFTER_SHORT)
|
|
{
|
|
if (_shortPressHandler != nullptr)
|
|
{
|
|
_shortPressHandler();
|
|
}
|
|
else if (_pressHandler != nullptr)
|
|
{
|
|
_pressHandler();
|
|
}
|
|
_state = READY_FOR_NEXT_PRESS;
|
|
}
|
|
else if (_state == DOWN_LONG || _state == UP_AFTER_LONG)
|
|
{
|
|
if (_longPressHandler != nullptr)
|
|
{
|
|
_longPressHandler();
|
|
}
|
|
else if (_pressHandler != nullptr)
|
|
{
|
|
_pressHandler();
|
|
}
|
|
_state = READY_FOR_NEXT_PRESS;
|
|
}
|
|
else if (_state == DOWN && _shortPressHandler == nullptr && _longPressHandler == nullptr)
|
|
{
|
|
if (_pressHandler != nullptr)
|
|
{
|
|
_pressHandler();
|
|
}
|
|
_state = READY_FOR_NEXT_PRESS;
|
|
}
|
|
}
|
|
|
|
void Button::clearEvents()
|
|
{
|
|
_state = READY_FOR_NEXT_PRESS;
|
|
}
|
|
|
|
void Button::handleButtonState()
|
|
{
|
|
bool buttonIsDown = digitalRead(_pin) == 0;
|
|
bool buttonIsUp = !buttonIsDown;
|
|
|
|
// When the button state has changed since the last time, then
|
|
// start the debounce timer.
|
|
if (buttonIsDown != _debounceState)
|
|
{
|
|
_debounceTimer = millis();
|
|
_debounceState = buttonIsDown;
|
|
}
|
|
|
|
unsigned long interval = (millis() - _debounceTimer);
|
|
|
|
// Only when the last state change has been stable for longer than the
|
|
// configured debounce delay, then we accept the current state as
|
|
// a stabilized button state.
|
|
if (interval < BUTTON_DEBOUNCE_DELAY)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Handle button state changes.
|
|
if (_state == READY_FOR_NEXT_PRESS && buttonIsUp)
|
|
{
|
|
_state = UP;
|
|
}
|
|
else if (_state == UP && buttonIsDown)
|
|
{
|
|
_state = DOWN;
|
|
}
|
|
else if (_state == DOWN && buttonIsDown && interval > BUTTON_LONGPRESS_DELAY)
|
|
{
|
|
_state = DOWN_LONG;
|
|
}
|
|
else if (_state == DOWN && buttonIsUp)
|
|
{
|
|
_state = UP_AFTER_SHORT;
|
|
}
|
|
else if (_state == DOWN_LONG && buttonIsUp)
|
|
{
|
|
_state = UP_AFTER_LONG;
|
|
}
|
|
}
|
|
} // namespace Dough
|