This commit is contained in:
Michael 2025-08-28 09:25:40 -04:00 committed by GitHub
commit a57ca88e41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 235 additions and 0 deletions

View File

@ -108,6 +108,10 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
ButtonThread *TouchButtonThread = nullptr;
#endif
#if defined(TTGO_T_ECHO) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
#include "../variants/nrf52840/t-echo/TEchoBacklight.h"
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
ButtonThread *UserButtonThread = nullptr;
#endif
@ -1016,8 +1020,13 @@ void setup()
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
#if defined(TTGO_T_ECHO) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_NONE;
#else
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#endif
TouchButtonThread->initButton(touchConfig);
#endif
@ -1491,6 +1500,14 @@ void setup()
// We manually run this to update the NodeStatus
nodeDB->notifyObservers(true);
#if defined(TTGO_T_ECHO) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
if (!tEchoBacklight) {
tEchoBacklight = new TEchoBacklight();
tEchoBacklight->setPin(PIN_EINK_EN);
tEchoBacklight->start();
}
#endif
}
#endif

View File

@ -0,0 +1,174 @@
#include "TEchoBacklight.h"
#if defined(TTGO_T_ECHO) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
#include "RadioLibInterface.h"
#include "configuration.h"
TEchoBacklight *tEchoBacklight = nullptr;
TEchoBacklight::TEchoBacklight() : OSThread("TEchoBacklight")
{
setInterval(POLL_INTERVAL_MS);
OSThread::disable();
}
void TEchoBacklight::setPin(uint8_t pin)
{
pinMode(pin, OUTPUT);
off();
}
void TEchoBacklight::start()
{
pinMode(PIN_BUTTON_TOUCH, INPUT_PULLUP);
attachInterrupt(PIN_BUTTON_TOUCH, touchISR, FALLING);
}
int32_t TEchoBacklight::runOnce()
{
bool awaitingRelease = false;
switch (state) {
case REST:
break;
case IRQ:
if (!RadioLibInterface::instance || RadioLibInterface::instance->isSending()) {
LOG_INFO("TEchoBacklight: Touch ignored - radio transmitting");
state = REST;
break;
}
LOG_INFO("TEchoBacklight: Touch detected - peek()");
peek();
state = POLLING_UNFIRED;
awaitingRelease = true;
break;
case POLLING_UNFIRED: {
uint32_t length = millis() - irqAtMillis;
if (!isTouchPressed()) {
state = REST;
if (length > DEBOUNCE_MS && length < LATCH_TIME_MS) {
LOG_INFO("TEchoBacklight: Short press (%lums) - off()", length);
off();
} else {
LOG_INFO("TEchoBacklight: Touch released too quick (%lums) - debounced", length);
}
} else {
awaitingRelease = true;
if (length >= LATCH_TIME_MS) {
LOG_INFO("TEchoBacklight: Long press (%lums) - starting latch blink", length);
state = BLINKING;
blinkStartTime = millis();
blinkStep = 0;
setBacklight(false);
}
}
break;
}
case BLINKING: {
uint32_t elapsed = millis() - blinkStartTime;
if (elapsed >= BLINK_DELAY_MS) {
blinkStep++;
blinkStartTime = millis();
setBacklight(blinkStep % 2 == 1);
if (blinkStep == BLINK_STEPS) {
backlightLatched = true;
state = POLLING_FIRED;
LOG_INFO("TEchoBacklight: Blink complete - latched ON");
}
}
awaitingRelease = true;
break;
}
case POLLING_FIRED:
if (!isTouchPressed()) {
LOG_INFO("TEchoBacklight: Long press released");
state = REST;
} else {
awaitingRelease = true;
}
break;
}
if (!awaitingRelease) {
stopThread();
}
return POLL_INTERVAL_MS;
}
void TEchoBacklight::setBacklight(bool on)
{
digitalWrite(PIN_EINK_EN, on ? HIGH : LOW);
}
bool TEchoBacklight::isTouchPressed()
{
return digitalRead(PIN_BUTTON_TOUCH) == LOW;
}
void TEchoBacklight::peek()
{
setBacklight(true);
backlightLatched = false;
}
void TEchoBacklight::latch()
{
if (backlightLatched) {
LOG_INFO("TEchoBacklight: latch() - turning OFF");
backlightLatched = false;
setBacklight(false);
} else {
LOG_INFO("TEchoBacklight: latch() - turning ON");
backlightLatched = true;
setBacklight(true);
}
}
void TEchoBacklight::off()
{
backlightLatched = false;
setBacklight(false);
}
void TEchoBacklight::touchISR()
{
static volatile bool isrRunning = false;
if (!isrRunning && tEchoBacklight) {
isrRunning = true;
if (tEchoBacklight->state == REST) {
tEchoBacklight->state = IRQ;
tEchoBacklight->irqAtMillis = millis();
tEchoBacklight->startThread();
LOG_INFO("TEchoBacklight: ISR triggered - starting thread");
}
isrRunning = false;
}
}
void TEchoBacklight::startThread()
{
if (!OSThread::enabled) {
OSThread::setInterval(POLL_INTERVAL_MS);
OSThread::enabled = true;
}
}
void TEchoBacklight::stopThread()
{
if (OSThread::enabled) {
OSThread::disable();
}
state = REST;
}
#endif

View File

@ -0,0 +1,43 @@
#pragma once
#include "configuration.h"
#if defined(TTGO_T_ECHO) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
#include "concurrency/OSThread.h"
class TEchoBacklight : public concurrency::OSThread
{
public:
TEchoBacklight();
int32_t runOnce() override;
void setPin(uint8_t pin);
void start();
void peek();
void latch();
void off();
private:
static constexpr uint32_t LATCH_TIME_MS = 5000;
static constexpr uint32_t POLL_INTERVAL_MS = 10;
static constexpr uint32_t DEBOUNCE_MS = 50;
static constexpr uint32_t BLINK_DELAY_MS = 25;
static constexpr uint8_t BLINK_STEPS = 3;
enum State { REST, IRQ, POLLING_UNFIRED, POLLING_FIRED, BLINKING };
bool backlightLatched = false;
uint32_t irqAtMillis = 0;
State state = REST;
uint32_t blinkStartTime = 0;
uint8_t blinkStep = 0;
void setBacklight(bool on);
bool isTouchPressed();
static void touchISR();
void startThread();
void stopThread();
};
extern TEchoBacklight *tEchoBacklight;
#endif

View File

@ -22,6 +22,7 @@
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
#include "TEchoBacklight.h"
const uint32_t g_ADigitalPinMap[] = {
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled