* Add shared e-ink hardware layer (graphics/eink) alongside legacy drivers Foundation for a target-by-target migration off the GxEPD2-based EInkDisplay2/EInkDynamicDisplay/EInkParallelDisplay stack: - src/graphics/eink/: chipset drivers, panel profiles, backlight helper (promoted from the InkHUD driver set, shared by BaseUI and InkHUD) - src/graphics/BaseUIEInkDisplay: OLEDDisplay adapter driving the new layer, with EINK_* compat macros matching EInkDynamicDisplay - [niche] build helper in platformio.ini; graphics/eink/ excluded from arduino_base so unconverted targets are unaffected - Screen/CannedMessageModule dispatch between the two stacks per env - InkHUD-specific touch code in TouchScreenImpl1 guarded with MESHTASTIC_INCLUDE_INKHUD (no-op today, required once BaseUI variants define MESHTASTIC_INCLUDE_NICHE_GRAPHICS without InkHUD) No variant is converted and no legacy file is removed; every existing env builds identical firmware. * Fix clang-format comment alignment in Screen.cpp * Address review findings in the e-ink driver layer - Screen.cpp: exclude InkHUD builds from all NicheGraphics BaseUI guards - BaseUIEInkDisplay: size the OLEDDisplay buffer from its actual indexing - EInkParallel: defer update() while an async refresh is in flight, honor the selected clear mode in the async task, never delete a live task - ED047TC1: clean up on failed initPanel, fix inverted bbepI2CWrite checks - UC8175: drop bogus 0x12 soft reset (0x12 is display refresh on UC8175) - LCMEN2R13EFC1: guard absent reset pin, bound the busy wait - SSD16XX/SSD1682: build the RAM window from the instance, not statics - Doc corrections in driver banners and Drivers/README * SSD16XX/SSD1682: send inclusive Y-end address (height - 1) * LCMEN213EFC1: adopt the shared wait timeout / fail-through pattern wait() now bounds the busy poll via Throttle and sets the EInk failed flag on timeout; sendCommand/sendData fail through like the SSD16XX and UC8175 drivers. EInk::runOnce clears the flag after the failed cycle.
86 lines
3.1 KiB
C++
86 lines
3.1 KiB
C++
#include "./EInk.h"
|
|
|
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
|
|
using namespace NicheGraphics::Drivers;
|
|
|
|
// Separate from EInk::begin method, as derived class constructors can probably supply these parameters as constants
|
|
EInk::EInk(uint16_t width, uint16_t height, UpdateTypes supported)
|
|
: concurrency::OSThread("EInkDriver"), width(width), height(height), supportedUpdateTypes(supported)
|
|
{
|
|
OSThread::disable();
|
|
}
|
|
|
|
// Used by NicheGraphics implementations to check if a display supports a specific refresh operation.
|
|
// Whether or not the update type is supported is specified in the constructor
|
|
bool EInk::supports(UpdateTypes type)
|
|
{
|
|
// The EInkUpdateTypes enum assigns each type a unique bit. We are checking if that bit is set.
|
|
if (supportedUpdateTypes & type)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
// Begins using the OSThread to detect when a display update is complete
|
|
// This allows the refresh operation to run "asynchronously".
|
|
// Rather than blocking execution waiting for the update to complete, we are periodically checking the hardware's BUSY pin
|
|
// The expectedDuration argument allows us to delay the start of this checking, if we know "roughly" how long an update takes.
|
|
// Potentially, a display without hardware BUSY could rely entirely on "expectedDuration",
|
|
// provided its isUpdateDone() override always returns true.
|
|
void EInk::beginPolling(uint32_t interval, uint32_t expectedDuration)
|
|
{
|
|
updateRunning = true;
|
|
pollingInterval = interval;
|
|
pollingBegunAt = millis();
|
|
|
|
// To minimize load, we can choose to delay polling for a few seconds, if we know roughly how long the update will take
|
|
// By default, expectedDuration is 0, and we'll start polling immediately
|
|
OSThread::setIntervalFromNow(expectedDuration);
|
|
OSThread::enabled = true;
|
|
}
|
|
|
|
// Meshtastic's pseudo-threading layer
|
|
// We're using this as a timer, to periodically check if an update is complete
|
|
// This is what allows us to update the display asynchronously
|
|
int32_t EInk::runOnce()
|
|
{
|
|
// Check for polling timeout
|
|
// Manually set at 10 seconds, in case some big task holds up the firmware's cooperative multitasking
|
|
if (millis() - pollingBegunAt > 10000)
|
|
failed = true;
|
|
|
|
// Handle failure
|
|
// - polling timeout
|
|
// - other error (derived classes)
|
|
if (failed) {
|
|
LOG_WARN("Display update failed. Check wiring & power supply.");
|
|
updateRunning = false;
|
|
failed = false;
|
|
return disable();
|
|
}
|
|
|
|
// If update not yet done
|
|
if (!isUpdateDone())
|
|
return pollingInterval; // Poll again in a few ms
|
|
|
|
// If update done
|
|
finalizeUpdate(); // Any post-update code: power down panel hardware, hibernate, etc
|
|
updateRunning = false; // Change what we report via EInk::busy()
|
|
return disable(); // Stop polling
|
|
}
|
|
|
|
// Wait for an in progress update to complete before continuing
|
|
// Run a normal (async) update first, *then* call await
|
|
void EInk::await()
|
|
{
|
|
// Stop our concurrency thread
|
|
OSThread::disable();
|
|
|
|
// Sit and block until the update is complete
|
|
while (updateRunning) {
|
|
runOnce();
|
|
yield();
|
|
}
|
|
}
|
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|