Remap backlight toggle and touch button (#3560)

* Update E-Ink display after sending adhoc ping or disable/enable GPS

* Resume display updates when touch button pressed

* Use touch hold as modifier; change double-click behavior for user button

* Fix preprocessor exclusions

* Purge backlight behavior

* Distinguish between 3x and 4x multi-presses

* Touch button considers "Wake screen on tap or motion" user-setting

* Don't assume device has BUTTON_PIN

* Rename misleading method
This commit is contained in:
todd-herbert 2024-04-07 02:04:26 +13:00 committed by GitHub
parent 577de1e517
commit 5b5f9c62b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 99 additions and 24 deletions

View File

@ -48,7 +48,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
userButton.setPressMs(c_longPressTime);
userButton.setDebounceMs(1);
userButton.attachDoubleClick(userButtonDoublePressed);
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachMultiClick(userButtonMultiPressed, this); // Reference to instance: get click count from non-static OneButton
#ifndef T_DECK // T-Deck immediately wakes up after shutdown, so disable this function
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
@ -86,7 +86,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
#ifdef BUTTON_PIN_TOUCH
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
userButtonTouch.attachClick(touchPressed);
userButtonTouch.setPressMs(400);
userButtonTouch.attachLongPressStart(touchPressedLongStart); // Better handling with longpress than click?
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
#endif
}
@ -138,26 +139,42 @@ int32_t ButtonThread::runOnce()
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!\n");
#if defined(USE_EINK) && defined(PIN_EINK_EN)
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
if (screen)
if (screen) {
screen->print("Sent ad-hoc ping\n");
break;
}
#if HAS_GPS
case BUTTON_EVENT_MULTI_PRESSED: {
LOG_BUTTON("Multi press!\n");
if (!config.device.disable_triple_click && (gps != nullptr)) {
gps->toggleGpsMode();
if (screen)
screen->forceDisplay();
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;
}
case BUTTON_EVENT_MULTI_PRESSED: {
LOG_BUTTON("Mulitipress! %hux\n", multipressClickCount);
switch (multipressClickCount) {
#if HAS_GPS
// 3 clicks: toggle GPS
case 3:
if (!config.device.disable_triple_click && (gps != nullptr)) {
gps->toggleGpsMode();
if (screen)
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;
#endif
#if defined(USE_EINK) && defined(PIN_EINK_EN) // i.e. T-Echo
// 4 clicks: toggle backlight
case 4:
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
break;
#endif
// No valid multipress action
default:
break;
} // end switch: click count
break;
} // end multipress event
case BUTTON_EVENT_LONG_PRESSED: {
LOG_BUTTON("Long press!\n");
powerFSM.trigger(EVENT_PRESS);
@ -176,12 +193,24 @@ int32_t ButtonThread::runOnce()
power->shutdown();
break;
}
case BUTTON_EVENT_TOUCH_PRESSED: {
#ifdef BUTTON_PIN_TOUCH
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
LOG_BUTTON("Touch press!\n");
if (screen)
screen->forceDisplay();
if (config.display.wake_on_tap_or_motion) {
if (screen) {
// Wake if asleep
if (powerFSM.getState() == &stateDARK)
powerFSM.trigger(EVENT_PRESS);
// Update display (legacy behaviour)
screen->forceDisplay();
}
}
break;
}
#endif // BUTTON_PIN_TOUCH
default:
break;
}
@ -206,6 +235,25 @@ void ButtonThread::wakeOnIrq(int irq, int mode)
FALLING);
}
// Static callback
void ButtonThread::userButtonMultiPressed(void *callerThread)
{
// Grab click count from non-static button, while the info is still valid
ButtonThread *thread = (ButtonThread *)callerThread;
thread->storeClickCount();
// Then handle later, in the usual way
btnEvent = BUTTON_EVENT_MULTI_PRESSED;
}
// Non-static method, runs during callback. Grabs info while still valid
void ButtonThread::storeClickCount()
{
#ifdef BUTTON_PIN
multipressClickCount = userButton.getNumberClicks();
#endif
}
void ButtonThread::userButtonPressedLongStart()
{
if (millis() > c_holdOffTime) {

View File

@ -17,11 +17,12 @@ class ButtonThread : public concurrency::OSThread
BUTTON_EVENT_MULTI_PRESSED,
BUTTON_EVENT_LONG_PRESSED,
BUTTON_EVENT_LONG_RELEASED,
BUTTON_EVENT_TOUCH_PRESSED
BUTTON_EVENT_TOUCH_LONG_PRESSED,
};
ButtonThread();
int32_t runOnce() override;
void storeClickCount();
private:
#ifdef BUTTON_PIN
@ -40,13 +41,16 @@ class ButtonThread : public concurrency::OSThread
// set during IRQ
static volatile ButtonEventType btnEvent;
// Store click count during callback, for later use
volatile int multipressClickCount = 0;
static void wakeOnIrq(int irq, int mode);
// IRQ callbacks
static void touchPressed() { btnEvent = BUTTON_EVENT_TOUCH_PRESSED; }
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_PRESSED; }
static void userButtonMultiPressed() { btnEvent = BUTTON_EVENT_MULTI_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; }
};

View File

@ -1153,10 +1153,33 @@ void Screen::setup()
MeshModule::observeUIEvents(&uiFrameEventObserver);
}
void Screen::forceDisplay()
void Screen::forceDisplay(bool forceUiUpdate)
{
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef USE_EINK
// If requested, make sure queued commands are run, and UI has rendered a new frame
if (forceUiUpdate) {
// No delay between UI frame rendering
setFastFramerate();
// Make sure all CMDs have run first
while (!cmdQueue.isEmpty())
runOnce();
// Ensure at least one frame has drawn
uint64_t startUpdate;
do {
startUpdate = millis(); // Handle impossibly unlikely corner case of a millis() overflow..
delay(10);
ui->update();
} while (ui->getUiState()->lastUpdate < startUpdate);
// Return to normal frame rate
targetFramerate = IDLE_FRAMERATE;
ui->setTargetFPS(targetFramerate);
}
// Tell EInk class to update the display
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
#endif
}

View File

@ -20,7 +20,7 @@ class Screen
void setOn(bool) {}
void print(const char *) {}
void doDeepSleep() {}
void forceDisplay() {}
void forceDisplay(bool forceUiUpdate = false) {}
void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {}
void startRebootScreen() {}
@ -318,7 +318,7 @@ class Screen : public concurrency::OSThread
int handleInputEvent(const InputEvent *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
void forceDisplay(bool forceUiUpdate = false);
/// Draws our SSL cert screen during boot (called from WebServer)
void setSSLFrames();