From 87bb149afb9d9e17ef744aad5fbc010c3371f4dc Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 30 Jun 2026 00:28:24 -0500 Subject: [PATCH] adds VARIANT_TOUCHSCREEN and ENABLE_TOUCH_INT (#10815) * addsVARIANT_TOUCHSCREEN and ENABLE_TOUCH_INT * Remove a duplicated _getTouch function pointer --- src/graphics/Screen.cpp | 2 +- src/input/TouchScreenBase.cpp | 6 ++++ src/input/TouchScreenBase.h | 1 + src/input/TouchScreenImpl1.cpp | 62 ++++++++++++++++++++++++++++++++++ src/input/TouchScreenImpl1.h | 16 +++++++++ variants/esp32/tbeam/variant.h | 1 + 6 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index d028487fef..ab5ae8ae9b 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -885,7 +885,7 @@ void Screen::setup() touchScreenImpl1->init(); } } -#elif HAS_TOUCHSCREEN && !defined(USE_EINK) && !HAS_CST226SE +#elif HAS_TOUCHSCREEN && !defined(USE_EINK) && !VARIANT_TOUCHSCREEN touchScreenImpl1 = new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast(dispdev)->getTouch); touchScreenImpl1->init(); diff --git a/src/input/TouchScreenBase.cpp b/src/input/TouchScreenBase.cpp index a3d03d4acf..2e39e52d69 100644 --- a/src/input/TouchScreenBase.cpp +++ b/src/input/TouchScreenBase.cpp @@ -66,8 +66,14 @@ void TouchScreenBase::init(bool hasTouch) int32_t TouchScreenBase::runOnce() { + uint32_t nowMs = millis(); + if (nowMs - _lastRun < 20) { // suppress too fast consecutive runOnce() executions + return 20; + } + _lastRun = nowMs; TouchEvent e; e.touchEvent = static_cast(TOUCH_ACTION_NONE); + this->setInterval(TOUCH_POLL_INTERVAL_IDLE); const bool fastTapMode = fastTapModeEnabled(); const bool allowLongPress = longPressEnabled(); diff --git a/src/input/TouchScreenBase.h b/src/input/TouchScreenBase.h index e08c4832b6..91ec165ec7 100644 --- a/src/input/TouchScreenBase.h +++ b/src/input/TouchScreenBase.h @@ -53,6 +53,7 @@ class TouchScreenBase : public Observable, public concurrenc time_t _start; // for LONG_PRESS uint32_t _lastTouchSeenMs; // helps suppress brief touch-controller dropouts bool _tapped; // for DOUBLE_TAP + uint32_t _lastRun = 0; // helps suppress too fast consecutive runOnce() executions const char *_originName; }; diff --git a/src/input/TouchScreenImpl1.cpp b/src/input/TouchScreenImpl1.cpp index 0f1c9d023a..1b0a938966 100644 --- a/src/input/TouchScreenImpl1.cpp +++ b/src/input/TouchScreenImpl1.cpp @@ -2,7 +2,9 @@ #include "InputBroker.h" #include "PowerFSM.h" #include "configuration.h" +#include "main.h" #include "modules/ExternalNotificationModule.h" +#include "sleep.h" #include #ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS @@ -16,6 +18,28 @@ TouchScreenImpl1 *touchScreenImpl1; +// Hardware-interrupt wake on the touch IRQ line. Some touch boards +// either drive this pin differently (RAK14014 already owns this interrupt in TFTDisplay) or +// route it through an IO expander, which can't be used with attachInterrupt(). + +// use ENABLE_TOUCH_INT to indicate that we should enable the interrupt here. +#if defined(SCREEN_TOUCH_INT) && defined(ENABLE_TOUCH_INT) + +// The touch controller pulls SCREEN_TOUCH_INT low when a new touch begins. Wake the polling +// thread immediately so the touch is handled without waiting for the next idle poll. The +// periodic poll in TouchScreenBase::runOnce() remains as a fallback. Mirrors the button +// interrupt handling in ButtonThread/InputBroker. +static void touchScreenInterruptHandler() +{ + if (touchScreenImpl1) { + touchScreenImpl1->setIntervalFromNow(0); + runASAP = true; + BaseType_t higherWake = 0; + concurrency::mainDelay.interruptFromISR(&higherWake); + } +} +#endif + TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *)) : TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch) { @@ -27,6 +51,7 @@ void TouchScreenImpl1::init() if (portduino_config.touchscreenModule) { TouchScreenBase::init(true); inputBroker->registerSource(this); + attachTouchInterrupt(); } else { TouchScreenBase::init(false); } @@ -37,9 +62,46 @@ void TouchScreenImpl1::init() TouchScreenBase::init(true); if (inputBroker) inputBroker->registerSource(this); + attachTouchInterrupt(); +#endif + +#if defined(ENABLE_TOUCH_INT) && defined(ARCH_ESP32) + // Detach/reattach our interrupt around light sleep, so sleep.cpp can configure the touch + // pin as a wake source without our handler interfering. + lsObserver.observe(¬ifyLightSleep); + lsEndObserver.observe(¬ifyLightSleepEnd); #endif } +// Attach the touch-controller IRQ so a new touch wakes the polling thread immediately. +// No-op on boards without a usable touch interrupt line. +void TouchScreenImpl1::attachTouchInterrupt() +{ +#ifdef ENABLE_TOUCH_INT + pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP); + attachInterrupt(SCREEN_TOUCH_INT, touchScreenInterruptHandler, FALLING); + LOG_INFO("TouchScreen interrupt attached on pin %d", SCREEN_TOUCH_INT); +#endif +} + +#ifdef ARCH_ESP32 +// Detach our interrupt before light sleep; sleep.cpp configures its own wake-on-touch. +int TouchScreenImpl1::beforeLightSleep(void *unused) +{ +#ifdef ENABLE_TOUCH_INT + detachInterrupt(SCREEN_TOUCH_INT); +#endif + return 0; // Indicates success +} + +// Reattach our interrupt after waking from light sleep. +int TouchScreenImpl1::afterLightSleep(esp_sleep_wakeup_cause_t cause) +{ + attachTouchInterrupt(); + return 0; // Indicates success +} +#endif + bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y) { return _getTouch(&x, &y); diff --git a/src/input/TouchScreenImpl1.h b/src/input/TouchScreenImpl1.h index 3629982ef6..4ad8a68c89 100644 --- a/src/input/TouchScreenImpl1.h +++ b/src/input/TouchScreenImpl1.h @@ -13,7 +13,23 @@ class TouchScreenImpl1 : public TouchScreenBase bool fastTapModeEnabled() const override; bool longPressEnabled() const override; + // Attach/detach a hardware interrupt on the touch IRQ pin (SCREEN_TOUCH_INT) so a new touch + // wakes the polling thread immediately. No-op on boards without a usable touch interrupt line. + void attachTouchInterrupt(); + bool (*_getTouch)(int16_t *, int16_t *); + +#ifdef ARCH_ESP32 + // Detach the touch interrupt before light sleep (so sleep.cpp can own the wake config), + // and reattach it afterwards. Mirrors ButtonThread's interrupt handling. + int beforeLightSleep(void *unused); + int afterLightSleep(esp_sleep_wakeup_cause_t cause); + + CallbackObserver lsObserver = + CallbackObserver(this, &TouchScreenImpl1::beforeLightSleep); + CallbackObserver lsEndObserver = + CallbackObserver(this, &TouchScreenImpl1::afterLightSleep); +#endif }; extern TouchScreenImpl1 *touchScreenImpl1; diff --git a/variants/esp32/tbeam/variant.h b/variants/esp32/tbeam/variant.h index 18cb8bc02b..1bab8c3c3d 100644 --- a/variants/esp32/tbeam/variant.h +++ b/variants/esp32/tbeam/variant.h @@ -55,6 +55,7 @@ #define HAS_SPI_TFT 1 #define HAS_CST226SE 1 #define HAS_TOUCHSCREEN 1 +#define VARIANT_TOUCHSCREEN 1 // #define TOUCH_IRQ 35 // broken in this version of the lib 0.3.1 #ifndef TOUCH_IRQ #define TOUCH_IRQ -1