Some checks failed
Build and deploy Docs site to GitHub Pages / github-pages (push) Has been cancelled
PR Build Check / build (Heltec_v3_companion_radio_ble) (push) Has been cancelled
PR Build Check / build (Heltec_v3_repeater) (push) Has been cancelled
PR Build Check / build (Heltec_v3_room_server) (push) Has been cancelled
PR Build Check / build (LilyGo_Tlora_C6_repeater_) (push) Has been cancelled
PR Build Check / build (PicoW_repeater) (push) Has been cancelled
PR Build Check / build (RAK_4631_companion_radio_ble) (push) Has been cancelled
PR Build Check / build (RAK_4631_repeater) (push) Has been cancelled
PR Build Check / build (RAK_4631_room_server) (push) Has been cancelled
PR Build Check / build (wio-e5-mini_repeater) (push) Has been cancelled
- MeshCore-based Simple Sensor firmware - Heltec T114 without display - BME280 sensor support (temp/humidity/pressure) - Radio: 868.856018 MHz, SF7, BW62.5 kHz, CR4/7 - 2-byte path hash - PlatformIO project
145 lines
3.7 KiB
C++
145 lines
3.7 KiB
C++
#include "MomentaryButton.h"
|
|
|
|
#define MULTI_CLICK_WINDOW_MS 280
|
|
|
|
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup, bool multiclick) {
|
|
_pin = pin;
|
|
_reverse = reverse;
|
|
_pull = pulldownup;
|
|
down_at = 0;
|
|
prev = _reverse ? HIGH : LOW;
|
|
cancel = 0;
|
|
_long_millis = long_press_millis;
|
|
_threshold = 0;
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_multi_click_window = multiclick ? MULTI_CLICK_WINDOW_MS : 0;
|
|
_pending_click = false;
|
|
}
|
|
|
|
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) {
|
|
_pin = pin;
|
|
_reverse = false;
|
|
_pull = false;
|
|
down_at = 0;
|
|
prev = LOW;
|
|
cancel = 0;
|
|
_long_millis = long_press_millis;
|
|
_threshold = analog_threshold;
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_multi_click_window = MULTI_CLICK_WINDOW_MS;
|
|
_pending_click = false;
|
|
}
|
|
|
|
void MomentaryButton::begin() {
|
|
if (_pin >= 0 && _threshold == 0) {
|
|
pinMode(_pin, _pull ? (_reverse ? INPUT_PULLUP : INPUT_PULLDOWN) : INPUT);
|
|
}
|
|
}
|
|
|
|
bool MomentaryButton::isPressed() const {
|
|
int btn = _threshold > 0 ? (analogRead(_pin) < _threshold) : digitalRead(_pin);
|
|
return isPressed(btn);
|
|
}
|
|
|
|
void MomentaryButton::cancelClick() {
|
|
cancel = 1;
|
|
down_at = 0;
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_pending_click = false;
|
|
}
|
|
|
|
bool MomentaryButton::isPressed(int level) const {
|
|
if (_threshold > 0) {
|
|
return level;
|
|
}
|
|
if (_reverse) {
|
|
return level == LOW;
|
|
} else {
|
|
return level != LOW;
|
|
}
|
|
}
|
|
|
|
int MomentaryButton::check(bool repeat_click) {
|
|
if (_pin < 0) return BUTTON_EVENT_NONE;
|
|
|
|
int event = BUTTON_EVENT_NONE;
|
|
int btn = _threshold > 0 ? (analogRead(_pin) < _threshold) : digitalRead(_pin);
|
|
if (btn != prev) {
|
|
if (isPressed(btn)) {
|
|
down_at = millis();
|
|
} else {
|
|
// button UP
|
|
if (_long_millis > 0) {
|
|
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
|
|
_click_count++;
|
|
_last_click_time = millis();
|
|
_pending_click = true;
|
|
}
|
|
} else {
|
|
_click_count++;
|
|
_last_click_time = millis();
|
|
_pending_click = true;
|
|
}
|
|
if (event == BUTTON_EVENT_CLICK && cancel) {
|
|
event = BUTTON_EVENT_NONE;
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_pending_click = false;
|
|
}
|
|
down_at = 0;
|
|
}
|
|
prev = btn;
|
|
}
|
|
if (!isPressed(btn) && cancel) { // always clear the pending 'cancel' once button is back in UP state
|
|
cancel = 0;
|
|
}
|
|
|
|
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
|
|
if (_pending_click) {
|
|
// long press during multi-click detection - cancel pending clicks
|
|
cancelClick();
|
|
} else {
|
|
event = BUTTON_EVENT_LONG_PRESS;
|
|
down_at = 0;
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_pending_click = false;
|
|
}
|
|
}
|
|
if (down_at > 0 && repeat_click) {
|
|
unsigned long diff = (unsigned long)(millis() - down_at);
|
|
if (diff >= 700) {
|
|
event = BUTTON_EVENT_CLICK; // wait 700 millis before repeating the click events
|
|
}
|
|
}
|
|
|
|
if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) {
|
|
if (down_at > 0) {
|
|
// still pressed - wait for button release before processing clicks
|
|
return event;
|
|
}
|
|
switch (_click_count) {
|
|
case 1:
|
|
event = BUTTON_EVENT_CLICK;
|
|
break;
|
|
case 2:
|
|
event = BUTTON_EVENT_DOUBLE_CLICK;
|
|
break;
|
|
case 3:
|
|
event = BUTTON_EVENT_TRIPLE_CLICK;
|
|
break;
|
|
default:
|
|
// For 4+ clicks, treat as triple click?
|
|
event = BUTTON_EVENT_TRIPLE_CLICK;
|
|
break;
|
|
}
|
|
_click_count = 0;
|
|
_last_click_time = 0;
|
|
_pending_click = false;
|
|
}
|
|
|
|
return event;
|
|
} |