mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-25 17:42:48 +00:00
Handle edge cases for E-Ink screensaver (#3518)
* remove redundant logic * Handle special screens for old EInkDisplayClass * Handle special screens for EInkDynamicDisplay class * Join an async refresh in progress to avoid skipping screensaver * attempt trunk fix
This commit is contained in:
parent
279464f96d
commit
46a63bf293
@ -463,10 +463,33 @@ void EInkDynamicDisplay::onNotify(uint32_t notification)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_EINK_ASYNCFULL
|
#ifdef HAS_EINK_ASYNCFULL
|
||||||
// Run the post-update code if the hardware is ready
|
// Public: wait for an refresh already in progress, then run the post-update code. See Screen::setScreensaverFrames()
|
||||||
|
void EInkDynamicDisplay::joinAsyncRefresh()
|
||||||
|
{
|
||||||
|
// If no async refresh running, nothing to do
|
||||||
|
if (!asyncRefreshRunning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_DEBUG("Joining an async refresh in progress\n");
|
||||||
|
|
||||||
|
// Continually poll the BUSY pin
|
||||||
|
while (adafruitDisplay->epd2.isBusy())
|
||||||
|
yield();
|
||||||
|
|
||||||
|
// If asyncRefreshRunning flag is still set, but display's BUSY pin reports the refresh is done
|
||||||
|
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
|
||||||
|
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
|
||||||
|
asyncRefreshRunning = false; // Unset the flag
|
||||||
|
LOG_DEBUG("Refresh complete\n");
|
||||||
|
|
||||||
|
// Note: this code only works because of a modification to meshtastic/GxEPD2.
|
||||||
|
// It is only equipped to intercept calls to nextPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called from NotifiedWorkerThread. Run the post-update code if the hardware is ready
|
||||||
void EInkDynamicDisplay::pollAsyncRefresh()
|
void EInkDynamicDisplay::pollAsyncRefresh()
|
||||||
{
|
{
|
||||||
// We shouldn't be here..
|
// In theory, this condition should never be met
|
||||||
if (!asyncRefreshRunning)
|
if (!asyncRefreshRunning)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -119,20 +119,30 @@ class EInkDynamicDisplay : public EInkDisplay, protected concurrency::NotifiedWo
|
|||||||
|
|
||||||
// Conditional - async full refresh - only with modified meshtastic/GxEPD2
|
// Conditional - async full refresh - only with modified meshtastic/GxEPD2
|
||||||
#if defined(HAS_EINK_ASYNCFULL)
|
#if defined(HAS_EINK_ASYNCFULL)
|
||||||
|
public:
|
||||||
|
void joinAsyncRefresh(); // Main thread joins an async refresh already in progress. Blocks, then runs post-update code
|
||||||
|
|
||||||
|
protected:
|
||||||
void pollAsyncRefresh(); // Run the post-update code if the hardware is ready
|
void pollAsyncRefresh(); // Run the post-update code if the hardware is ready
|
||||||
void checkBusyAsyncRefresh(); // Check if display is busy running an async full-refresh (rejecting new frames)
|
void checkBusyAsyncRefresh(); // Check if display is busy running an async full-refresh (rejecting new frames)
|
||||||
void awaitRefresh(); // Hold control while an async refresh runs
|
void awaitRefresh(); // Hold control while an async refresh runs
|
||||||
void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay()
|
void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay()
|
||||||
bool asyncRefreshRunning = false; // Flag, checked by checkBusyAsyncRefresh()
|
bool asyncRefreshRunning = false; // Flag, checked by checkBusyAsyncRefresh()
|
||||||
#else
|
#else
|
||||||
|
public:
|
||||||
|
void joinAsyncRefresh() {} // Dummy method
|
||||||
|
|
||||||
|
protected:
|
||||||
void pollAsyncRefresh() {} // Dummy method. In theory, not reachable
|
void pollAsyncRefresh() {} // Dummy method. In theory, not reachable
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tidier calls to addFrameFlag() from outside class
|
// Hide the ugly casts used in Screen.cpp
|
||||||
#define EINK_ADD_FRAMEFLAG(display, flag) static_cast<EInkDynamicDisplay *>(display)->addFrameFlag(EInkDynamicDisplay::flag)
|
#define EINK_ADD_FRAMEFLAG(display, flag) static_cast<EInkDynamicDisplay *>(display)->addFrameFlag(EInkDynamicDisplay::flag)
|
||||||
|
#define EINK_JOIN_ASYNCREFRESH(display) static_cast<EInkDynamicDisplay *>(display)->joinAsyncRefresh()
|
||||||
|
|
||||||
#else // !USE_EINK_DYNAMICDISPLAY
|
#else // !USE_EINK_DYNAMICDISPLAY
|
||||||
// Dummy-macro, removes the need for include guards
|
// Dummy-macro, removes the need for include guards
|
||||||
#define EINK_ADD_FRAMEFLAG(display, flag)
|
#define EINK_ADD_FRAMEFLAG(display, flag)
|
||||||
|
#define EINK_JOIN_ASYNCREFRESH(display)
|
||||||
#endif
|
#endif
|
@ -1349,6 +1349,12 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver)
|
|||||||
static FrameCallback screensaverFrame;
|
static FrameCallback screensaverFrame;
|
||||||
static OverlayCallback screensaverOverlay;
|
static OverlayCallback screensaverOverlay;
|
||||||
|
|
||||||
|
#if defined(HAS_EINK_ASYNCFULL) && defined(USE_EINK_DYNAMICDISPLAY)
|
||||||
|
// Join (await) a currently running async refresh, then run the post-update code.
|
||||||
|
// Avoid skipping of screensaver frame. Would otherwise be handled by NotifiedWorkerThread.
|
||||||
|
EINK_JOIN_ASYNCREFRESH(dispdev);
|
||||||
|
#endif
|
||||||
|
|
||||||
// If: one-off screensaver frame passed as argument. Handles doDeepSleep()
|
// If: one-off screensaver frame passed as argument. Handles doDeepSleep()
|
||||||
if (einkScreensaver != NULL) {
|
if (einkScreensaver != NULL) {
|
||||||
screensaverFrame = einkScreensaver;
|
screensaverFrame = einkScreensaver;
|
||||||
@ -1370,10 +1376,9 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver)
|
|||||||
ui->update();
|
ui->update();
|
||||||
} while (ui->getUiState()->lastUpdate < startUpdate);
|
} while (ui->getUiState()->lastUpdate < startUpdate);
|
||||||
|
|
||||||
#ifndef USE_EINK_DYNAMICDISPLAY
|
// Old EInkDisplay class
|
||||||
// Retrofit to EInkDisplay class
|
#if !defined(USE_EINK_DYNAMICDISPLAY)
|
||||||
delay(10);
|
static_cast<EInkDisplay *>(dispdev)->forceDisplay(0); // Screen::forceDisplay(), but override rate-limit
|
||||||
screen->forceDisplay();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Prepare now for next frame, shown when display wakes
|
// Prepare now for next frame, shown when display wakes
|
||||||
@ -1490,8 +1495,11 @@ void Screen::handleShutdownScreen()
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("showing shutdown screen\n");
|
LOG_DEBUG("showing shutdown screen\n");
|
||||||
showingNormalScreen = false;
|
showingNormalScreen = false;
|
||||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Use fast-refresh for next frame, no skip please
|
#ifdef USE_EINK
|
||||||
|
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please
|
||||||
EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update
|
EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update
|
||||||
|
handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?)
|
||||||
|
#endif
|
||||||
|
|
||||||
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||||
drawFrameText(display, state, x, y, "Shutting down...");
|
drawFrameText(display, state, x, y, "Shutting down...");
|
||||||
@ -1499,14 +1507,17 @@ void Screen::handleShutdownScreen()
|
|||||||
static FrameCallback frames[] = {frame};
|
static FrameCallback frames[] = {frame};
|
||||||
|
|
||||||
setFrameImmediateDraw(frames);
|
setFrameImmediateDraw(frames);
|
||||||
forceDisplay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::handleRebootScreen()
|
void Screen::handleRebootScreen()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("showing reboot screen\n");
|
LOG_DEBUG("showing reboot screen\n");
|
||||||
showingNormalScreen = false;
|
showingNormalScreen = false;
|
||||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
#ifdef USE_EINK
|
||||||
|
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please
|
||||||
|
EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update
|
||||||
|
handleSetOn(true); // Power-on to show rebooting screen (PowerFSM should handle?)
|
||||||
|
#endif
|
||||||
|
|
||||||
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||||
drawFrameText(display, state, x, y, "Rebooting...");
|
drawFrameText(display, state, x, y, "Rebooting...");
|
||||||
|
@ -150,7 +150,7 @@ class Screen : public concurrency::OSThread
|
|||||||
// We handle off commands immediately, because they might be called because the CPU is shutting down
|
// We handle off commands immediately, because they might be called because the CPU is shutting down
|
||||||
handleSetOn(false, einkScreensaver);
|
handleSetOn(false, einkScreensaver);
|
||||||
else
|
else
|
||||||
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
|
enqueueCmd(ScreenCmd{.cmd = Cmd::SET_ON});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "NRF52Bluetooth.h"
|
#include "NRF52Bluetooth.h"
|
||||||
#include "BluetoothCommon.h"
|
#include "BluetoothCommon.h"
|
||||||
|
#include "PowerFSM.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/PhoneAPI.h"
|
#include "mesh/PhoneAPI.h"
|
||||||
@ -318,6 +319,7 @@ void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
|
|||||||
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
||||||
{
|
{
|
||||||
LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3);
|
LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3);
|
||||||
|
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||||
screen->startBluetoothPinScreen(configuredPasskey);
|
screen->startBluetoothPinScreen(configuredPasskey);
|
||||||
|
|
||||||
if (match_request) {
|
if (match_request) {
|
||||||
|
Loading…
Reference in New Issue
Block a user