mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-04 10:38:57 +00:00
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:
parent
577de1e517
commit
5b5f9c62b5
@ -48,7 +48,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
|||||||
userButton.setPressMs(c_longPressTime);
|
userButton.setPressMs(c_longPressTime);
|
||||||
userButton.setDebounceMs(1);
|
userButton.setDebounceMs(1);
|
||||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
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
|
#ifndef T_DECK // T-Deck immediately wakes up after shutdown, so disable this function
|
||||||
userButton.attachLongPressStart(userButtonPressedLongStart);
|
userButton.attachLongPressStart(userButtonPressedLongStart);
|
||||||
userButton.attachLongPressStop(userButtonPressedLongStop);
|
userButton.attachLongPressStop(userButtonPressedLongStop);
|
||||||
@ -86,7 +86,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
|||||||
|
|
||||||
#ifdef BUTTON_PIN_TOUCH
|
#ifdef BUTTON_PIN_TOUCH
|
||||||
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
|
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);
|
wakeOnIrq(BUTTON_PIN_TOUCH, FALLING);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -138,26 +139,42 @@ int32_t ButtonThread::runOnce()
|
|||||||
|
|
||||||
case BUTTON_EVENT_DOUBLE_PRESSED: {
|
case BUTTON_EVENT_DOUBLE_PRESSED: {
|
||||||
LOG_BUTTON("Double press!\n");
|
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.refreshLocalMeshNode();
|
||||||
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
||||||
if (screen)
|
if (screen) {
|
||||||
screen->print("Sent ad-hoc ping\n");
|
screen->print("Sent ad-hoc ping\n");
|
||||||
break;
|
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
|
||||||
}
|
|
||||||
#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();
|
|
||||||
}
|
}
|
||||||
break;
|
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
|
#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: {
|
case BUTTON_EVENT_LONG_PRESSED: {
|
||||||
LOG_BUTTON("Long press!\n");
|
LOG_BUTTON("Long press!\n");
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
@ -176,12 +193,24 @@ int32_t ButtonThread::runOnce()
|
|||||||
power->shutdown();
|
power->shutdown();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BUTTON_EVENT_TOUCH_PRESSED: {
|
|
||||||
|
#ifdef BUTTON_PIN_TOUCH
|
||||||
|
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
|
||||||
LOG_BUTTON("Touch press!\n");
|
LOG_BUTTON("Touch press!\n");
|
||||||
if (screen)
|
if (config.display.wake_on_tap_or_motion) {
|
||||||
screen->forceDisplay();
|
if (screen) {
|
||||||
|
// Wake if asleep
|
||||||
|
if (powerFSM.getState() == &stateDARK)
|
||||||
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
|
|
||||||
|
// Update display (legacy behaviour)
|
||||||
|
screen->forceDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif // BUTTON_PIN_TOUCH
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -206,6 +235,25 @@ void ButtonThread::wakeOnIrq(int irq, int mode)
|
|||||||
FALLING);
|
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()
|
void ButtonThread::userButtonPressedLongStart()
|
||||||
{
|
{
|
||||||
if (millis() > c_holdOffTime) {
|
if (millis() > c_holdOffTime) {
|
||||||
|
@ -17,11 +17,12 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
BUTTON_EVENT_MULTI_PRESSED,
|
BUTTON_EVENT_MULTI_PRESSED,
|
||||||
BUTTON_EVENT_LONG_PRESSED,
|
BUTTON_EVENT_LONG_PRESSED,
|
||||||
BUTTON_EVENT_LONG_RELEASED,
|
BUTTON_EVENT_LONG_RELEASED,
|
||||||
BUTTON_EVENT_TOUCH_PRESSED
|
BUTTON_EVENT_TOUCH_LONG_PRESSED,
|
||||||
};
|
};
|
||||||
|
|
||||||
ButtonThread();
|
ButtonThread();
|
||||||
int32_t runOnce() override;
|
int32_t runOnce() override;
|
||||||
|
void storeClickCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
@ -40,13 +41,16 @@ class ButtonThread : public concurrency::OSThread
|
|||||||
// set during IRQ
|
// set during IRQ
|
||||||
static volatile ButtonEventType btnEvent;
|
static volatile ButtonEventType btnEvent;
|
||||||
|
|
||||||
|
// Store click count during callback, for later use
|
||||||
|
volatile int multipressClickCount = 0;
|
||||||
|
|
||||||
static void wakeOnIrq(int irq, int mode);
|
static void wakeOnIrq(int irq, int mode);
|
||||||
|
|
||||||
// IRQ callbacks
|
// IRQ callbacks
|
||||||
static void touchPressed() { btnEvent = BUTTON_EVENT_TOUCH_PRESSED; }
|
|
||||||
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
|
static void userButtonPressed() { btnEvent = BUTTON_EVENT_PRESSED; }
|
||||||
static void userButtonDoublePressed() { btnEvent = BUTTON_EVENT_DOUBLE_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 userButtonPressedLongStart();
|
||||||
static void userButtonPressedLongStop();
|
static void userButtonPressedLongStop();
|
||||||
|
static void touchPressedLongStart() { btnEvent = BUTTON_EVENT_TOUCH_LONG_PRESSED; }
|
||||||
};
|
};
|
||||||
|
@ -1153,10 +1153,33 @@ void Screen::setup()
|
|||||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::forceDisplay()
|
void Screen::forceDisplay(bool forceUiUpdate)
|
||||||
{
|
{
|
||||||
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
||||||
#ifdef USE_EINK
|
#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();
|
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class Screen
|
|||||||
void setOn(bool) {}
|
void setOn(bool) {}
|
||||||
void print(const char *) {}
|
void print(const char *) {}
|
||||||
void doDeepSleep() {}
|
void doDeepSleep() {}
|
||||||
void forceDisplay() {}
|
void forceDisplay(bool forceUiUpdate = false) {}
|
||||||
void startBluetoothPinScreen(uint32_t pin) {}
|
void startBluetoothPinScreen(uint32_t pin) {}
|
||||||
void stopBluetoothPinScreen() {}
|
void stopBluetoothPinScreen() {}
|
||||||
void startRebootScreen() {}
|
void startRebootScreen() {}
|
||||||
@ -318,7 +318,7 @@ class Screen : public concurrency::OSThread
|
|||||||
int handleInputEvent(const InputEvent *arg);
|
int handleInputEvent(const InputEvent *arg);
|
||||||
|
|
||||||
/// Used to force (super slow) eink displays to draw critical frames
|
/// 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)
|
/// Draws our SSL cert screen during boot (called from WebServer)
|
||||||
void setSSLFrames();
|
void setSSLFrames();
|
||||||
|
Loading…
Reference in New Issue
Block a user