diff --git a/protobufs b/protobufs index 24c7a3d28..cec9223ae 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 24c7a3d287a4bd269ce191827e5dabd8ce8f57a7 +Subproject commit cec9223ae1151fff326d94337570c0e46bacb6f4 diff --git a/src/ButtonThread.h b/src/ButtonThread.h new file mode 100644 index 000000000..1fbc38672 --- /dev/null +++ b/src/ButtonThread.h @@ -0,0 +1,118 @@ +#pragma once + +#include "OneButton.h" +#include "concurrency/OSThread.h" +#include "configuration.h" + +#ifndef BUTTON_CLICK_MS +#define BUTTON_CLICK_MS 250 +#endif + +#ifndef BUTTON_LONGPRESS_MS +#define BUTTON_LONGPRESS_MS 5000 +#endif + +#ifndef BUTTON_TOUCH_MS +#define BUTTON_TOUCH_MS 400 +#endif + +#ifndef BUTTON_COMBO_TIMEOUT_MS +#define BUTTON_COMBO_TIMEOUT_MS 2000 // 2 seconds to complete the combination +#endif + +#ifndef BUTTON_LEADUP_MS +#define BUTTON_LEADUP_MS 2200 // Play lead-up sound after 2.5 seconds of holding +#endif + +class ButtonThread : public concurrency::OSThread +{ + public: + static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot + + enum ButtonEventType { + BUTTON_EVENT_NONE, + BUTTON_EVENT_PRESSED, + BUTTON_EVENT_PRESSED_SCREEN, + BUTTON_EVENT_DOUBLE_PRESSED, + BUTTON_EVENT_MULTI_PRESSED, + BUTTON_EVENT_LONG_PRESSED, + BUTTON_EVENT_LONG_RELEASED, + BUTTON_EVENT_TOUCH_LONG_PRESSED, + BUTTON_EVENT_COMBO_SHORT_LONG, + }; + + ButtonThread(); + int32_t runOnce() override; + void attachButtonInterrupts(); + void detachButtonInterrupts(); + void storeClickCount(); + bool isBuzzing() { return buzzer_flag; } + void setScreenFlag(bool flag) { screen_flag = flag; } + bool getScreenFlag() { return screen_flag; } + bool isInterceptingAndFocused(); + bool isButtonPressed(int buttonPin) + { +#ifdef BUTTON_ACTIVE_LOW + return !digitalRead(buttonPin); // Active low: pressed = LOW +#else + return digitalRead(buttonPin); // Most buttons are active low by default +#endif + } + + // Disconnect and reconnect interrupts for light sleep +#ifdef ARCH_ESP32 + int beforeLightSleep(void *unused); + int afterLightSleep(esp_sleep_wakeup_cause_t cause); +#endif + private: +#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN) + static OneButton userButton; // Static - accessed from an interrupt +#endif +#ifdef BUTTON_PIN_ALT + OneButton userButtonAlt; +#endif +#ifdef BUTTON_PIN_TOUCH + OneButton userButtonTouch; +#endif + +#ifdef ARCH_ESP32 + // Get notified when lightsleep begins and ends + CallbackObserver lsObserver = + CallbackObserver(this, &ButtonThread::beforeLightSleep); + CallbackObserver lsEndObserver = + CallbackObserver(this, &ButtonThread::afterLightSleep); +#endif + + // set during IRQ + static volatile ButtonEventType btnEvent; + bool buzzer_flag = false; + bool screen_flag = true; + + // Store click count during callback, for later use + volatile int multipressClickCount = 0; + + // Combination tracking state + bool waitingForLongPress = false; + uint32_t shortPressTime = 0; + + // Long press lead-up tracking + bool leadUpPlayed = false; + uint32_t lastLeadUpNoteTime = 0; + bool leadUpSequenceActive = false; + + static void wakeOnIrq(int irq, int mode); + + static void sendAdHocPosition(); + static void switchPage(); + + // IRQ callbacks + static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; } + static void userButtonPressedScreen() { btnEvent = BUTTON_EVENT_PRESSED_SCREEN; } + static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_PRESSED; } + static void userButtonMultiPressed(void *callerThread); // Retrieve click count from non-static Onebutton while still valid + static void userButtonPressedLongStart(); + static void userButtonPressedLongStop(); + static void touchPressedLongStart() { btnEvent = BUTTON_EVENT_TOUCH_LONG_PRESSED; } +}; + +extern ButtonThread *buttonThread; diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index 4311055d6..21d788b25 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -18,7 +18,7 @@ #include "platform/portduino/PortduinoGlue.h" #endif -#define DEBUG_BUTTONS 0 +#define DEBUG_BUTTONS 1 #if DEBUG_BUTTONS #define LOG_BUTTON(...) LOG_DEBUG(__VA_ARGS__) #else