mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-14 14:52:32 +00:00
166 lines
5.6 KiB
C++
166 lines
5.6 KiB
C++
#include "UpDownInterruptBase.h"
|
|
#include "configuration.h"
|
|
|
|
UpDownInterruptBase::UpDownInterruptBase(const char *name) : concurrency::OSThread(name)
|
|
{
|
|
this->_originName = name;
|
|
}
|
|
|
|
void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, input_broker_event eventDown,
|
|
input_broker_event eventUp, input_broker_event eventPressed, input_broker_event eventPressedLong,
|
|
input_broker_event eventUpLong, input_broker_event eventDownLong, void (*onIntDown)(),
|
|
void (*onIntUp)(), void (*onIntPress)(), unsigned long updownDebounceMs)
|
|
{
|
|
this->_pinDown = pinDown;
|
|
this->_pinUp = pinUp;
|
|
this->_pinPress = pinPress;
|
|
this->_eventDown = eventDown;
|
|
this->_eventUp = eventUp;
|
|
this->_eventPressed = eventPressed;
|
|
this->_eventPressedLong = eventPressedLong;
|
|
this->_eventUpLong = eventUpLong;
|
|
this->_eventDownLong = eventDownLong;
|
|
|
|
// Store debounce configuration passed by caller
|
|
this->updownDebounceMs = updownDebounceMs;
|
|
bool isRAK = false;
|
|
#ifdef RAK_4631
|
|
isRAK = true;
|
|
#endif
|
|
|
|
if (!isRAK || pinPress != 0) {
|
|
pinMode(pinPress, INPUT_PULLUP);
|
|
attachInterrupt(pinPress, onIntPress, FALLING);
|
|
}
|
|
if (!isRAK || this->_pinDown != 0) {
|
|
pinMode(this->_pinDown, INPUT_PULLUP);
|
|
attachInterrupt(this->_pinDown, onIntDown, FALLING);
|
|
}
|
|
if (!isRAK || this->_pinUp != 0) {
|
|
pinMode(this->_pinUp, INPUT_PULLUP);
|
|
attachInterrupt(this->_pinUp, onIntUp, FALLING);
|
|
}
|
|
|
|
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
|
|
|
|
this->setInterval(20);
|
|
}
|
|
|
|
int32_t UpDownInterruptBase::runOnce()
|
|
{
|
|
InputEvent e = {};
|
|
e.inputEvent = INPUT_BROKER_NONE;
|
|
unsigned long now = millis();
|
|
|
|
// Read all button states once at the beginning
|
|
bool pressButtonPressed = !digitalRead(_pinPress);
|
|
bool upButtonPressed = !digitalRead(_pinUp);
|
|
bool downButtonPressed = !digitalRead(_pinDown);
|
|
|
|
// Handle initial button press detection - only if not already detected
|
|
if (this->action == UPDOWN_ACTION_PRESSED && pressButtonPressed && !pressDetected) {
|
|
pressDetected = true;
|
|
pressStartTime = now;
|
|
} else if (this->action == UPDOWN_ACTION_UP && upButtonPressed && !upDetected) {
|
|
upDetected = true;
|
|
upStartTime = now;
|
|
} else if (this->action == UPDOWN_ACTION_DOWN && downButtonPressed && !downDetected) {
|
|
downDetected = true;
|
|
downStartTime = now;
|
|
}
|
|
|
|
// Handle long press detection for press button
|
|
if (pressDetected && pressStartTime > 0) {
|
|
uint32_t pressDuration = now - pressStartTime;
|
|
|
|
if (!pressButtonPressed) {
|
|
// Button released
|
|
if (pressDuration < LONG_PRESS_DURATION && now - lastPressKeyTime >= pressDebounceMs) {
|
|
lastPressKeyTime = now;
|
|
e.inputEvent = this->_eventPressed;
|
|
}
|
|
// Reset state
|
|
pressDetected = false;
|
|
pressStartTime = 0;
|
|
lastPressLongEventTime = 0;
|
|
} else if (pressDuration >= LONG_PRESS_DURATION && lastPressLongEventTime == 0) {
|
|
// First long press event only - avoid repeated events causing lag
|
|
e.inputEvent = this->_eventPressedLong;
|
|
lastPressLongEventTime = now;
|
|
}
|
|
}
|
|
|
|
// Handle long press detection for up button
|
|
if (upDetected && upStartTime > 0) {
|
|
uint32_t upDuration = now - upStartTime;
|
|
|
|
if (!upButtonPressed) {
|
|
// Button released
|
|
if (upDuration < LONG_PRESS_DURATION && now - lastUpKeyTime >= updownDebounceMs) {
|
|
lastUpKeyTime = now;
|
|
e.inputEvent = this->_eventUp;
|
|
}
|
|
// Reset state
|
|
upDetected = false;
|
|
upStartTime = 0;
|
|
lastUpLongEventTime = 0;
|
|
} else if (upDuration >= LONG_PRESS_DURATION) {
|
|
// Auto-repeat long press events
|
|
if (lastUpLongEventTime == 0 || (now - lastUpLongEventTime) >= LONG_PRESS_REPEAT_INTERVAL) {
|
|
e.inputEvent = this->_eventUpLong;
|
|
lastUpLongEventTime = now;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle long press detection for down button
|
|
if (downDetected && downStartTime > 0) {
|
|
uint32_t downDuration = now - downStartTime;
|
|
|
|
if (!downButtonPressed) {
|
|
// Button released
|
|
if (downDuration < LONG_PRESS_DURATION && now - lastDownKeyTime >= updownDebounceMs) {
|
|
lastDownKeyTime = now;
|
|
e.inputEvent = this->_eventDown;
|
|
}
|
|
// Reset state
|
|
downDetected = false;
|
|
downStartTime = 0;
|
|
lastDownLongEventTime = 0;
|
|
} else if (downDuration >= LONG_PRESS_DURATION) {
|
|
// Auto-repeat long press events
|
|
if (lastDownLongEventTime == 0 || (now - lastDownLongEventTime) >= LONG_PRESS_REPEAT_INTERVAL) {
|
|
e.inputEvent = this->_eventDownLong;
|
|
lastDownLongEventTime = now;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e.inputEvent != INPUT_BROKER_NONE) {
|
|
e.source = this->_originName;
|
|
e.kbchar = INPUT_BROKER_NONE;
|
|
this->notifyObservers(&e);
|
|
}
|
|
|
|
if (!pressDetected && !upDetected && !downDetected) {
|
|
this->action = UPDOWN_ACTION_NONE;
|
|
}
|
|
|
|
return 20; // This will control how the input frequency
|
|
}
|
|
|
|
void UpDownInterruptBase::intPressHandler()
|
|
{
|
|
this->action = UPDOWN_ACTION_PRESSED;
|
|
}
|
|
|
|
void UpDownInterruptBase::intDownHandler()
|
|
{
|
|
this->action = UPDOWN_ACTION_DOWN;
|
|
}
|
|
|
|
void UpDownInterruptBase::intUpHandler()
|
|
{
|
|
this->action = UPDOWN_ACTION_UP;
|
|
}
|