117 lines
3.0 KiB
C++
117 lines
3.0 KiB
C++
/**
|
|
* @file button.h
|
|
* @author Adam Wonak (https://github.com/awonak)
|
|
* @brief Wrapper class for interacting with trigger / gate inputs.
|
|
* @version 0.1
|
|
* @date 2025-04-20
|
|
*
|
|
* @copyright MIT - (c) 2025 - Adam Wonak - adam.wonak@gmail.com
|
|
*
|
|
*/
|
|
#ifndef BUTTON_H
|
|
#define BUTTON_H
|
|
|
|
#include <Arduino.h>
|
|
|
|
const uint8_t DEBOUNCE_MS = 10;
|
|
const uint16_t LONG_PRESS_DURATION_MS = 750;
|
|
|
|
class Button {
|
|
protected:
|
|
typedef void (*CallbackFunction)(void);
|
|
|
|
public:
|
|
// Enum constants for active change in button state.
|
|
enum ButtonChange {
|
|
CHANGE_UNCHANGED,
|
|
CHANGE_PRESSED,
|
|
CHANGE_RELEASED,
|
|
CHANGE_RELEASED_LONG,
|
|
};
|
|
|
|
Button() {}
|
|
Button(int pin) { Init(pin); }
|
|
~Button() {}
|
|
|
|
/**
|
|
* Initializes a CV Input object.
|
|
*
|
|
* @param pin gpio pin for the cv output.
|
|
*/
|
|
void Init(uint8_t pin) {
|
|
pinMode(pin, INPUT_PULLUP);
|
|
pin_ = pin;
|
|
old_read_ = digitalRead(pin_);
|
|
}
|
|
|
|
/**
|
|
* Provide a handler function for executing when button is pressed.
|
|
*
|
|
* @param f Callback function to attach push behavior to this button.
|
|
*/
|
|
void AttachPressHandler(CallbackFunction f) {
|
|
on_press_ = f;
|
|
}
|
|
/**
|
|
* Provide a handler function for executing when button is pressed.
|
|
*
|
|
* @param f Callback function to attach push behavior to this button.
|
|
*/
|
|
void AttachLongPressHandler(CallbackFunction f) {
|
|
on_long_press_ = f;
|
|
}
|
|
|
|
/**
|
|
* Read the state of the cv input.
|
|
*/
|
|
void Process() {
|
|
int read = digitalRead(pin_);
|
|
bool debounced = (millis() - last_press_) > DEBOUNCE_MS;
|
|
bool pressed = read == 0 && old_read_ == 1 && debounced;
|
|
bool released = read == 1 && old_read_ == 0 && debounced;
|
|
|
|
// Determine current clock input state.
|
|
change_ = CHANGE_UNCHANGED;
|
|
if (pressed) {
|
|
change_ = CHANGE_PRESSED;
|
|
} else if (released) {
|
|
// Call appropriate button press handler upon release.
|
|
if (last_press_ + LONG_PRESS_DURATION_MS > millis()) {
|
|
change_ = CHANGE_RELEASED;
|
|
if (on_press_ != NULL) on_press_();
|
|
} else {
|
|
change_ = CHANGE_RELEASED_LONG;
|
|
if (on_long_press_ != NULL) on_long_press_();
|
|
}
|
|
}
|
|
|
|
// Update variables for next loop
|
|
last_press_ = (pressed || released) ? millis() : last_press_;
|
|
old_read_ = read;
|
|
}
|
|
|
|
/**
|
|
* Get the state change for the button.
|
|
*
|
|
* @return ButtonChange
|
|
*/
|
|
inline ButtonChange Change() { return change_; }
|
|
|
|
/**
|
|
* Current cv state represented as a bool.
|
|
*
|
|
* @return true if cv signal is high, false if cv signal is low
|
|
*/
|
|
inline bool On() { return digitalRead(pin_) == 0; }
|
|
|
|
private:
|
|
uint8_t pin_;
|
|
uint8_t old_read_ = 1;
|
|
unsigned long last_press_;
|
|
ButtonChange change_ = CHANGE_UNCHANGED;
|
|
CallbackFunction on_press_;
|
|
CallbackFunction on_long_press_;
|
|
};
|
|
|
|
#endif
|