mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-20 16:56:17 +00:00
fix: allow timeout if display update fails
Result is not graceful, but avoids total display lockup requiring power cycle. Typical cause of failure is poor wiring / power supply.
This commit is contained in:
parent
b64729987e
commit
97b36f3783
@ -6,7 +6,7 @@ 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("E-Ink Driver"), width(width), height(height), supportedUpdateTypes(supported)
|
||||
: concurrency::OSThread("EInkDriver"), width(width), height(height), supportedUpdateTypes(supported)
|
||||
{
|
||||
OSThread::disable();
|
||||
}
|
||||
@ -31,8 +31,9 @@ bool EInk::supports(UpdateTypes type)
|
||||
void EInk::beginPolling(uint32_t interval, uint32_t expectedDuration)
|
||||
{
|
||||
updateRunning = true;
|
||||
updateBegunAt = millis();
|
||||
pollingInterval = interval;
|
||||
pollingBegunAt = millis();
|
||||
pollingExpectedDuration = expectedDuration;
|
||||
|
||||
// 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
|
||||
@ -45,10 +46,25 @@ void EInk::beginPolling(uint32_t interval, uint32_t expectedDuration)
|
||||
// This is what allows us to update the display asynchronously
|
||||
int32_t EInk::runOnce()
|
||||
{
|
||||
// Check for polling timeout
|
||||
if (millis() - pollingBegunAt > pollingExpectedDuration * 3)
|
||||
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:
|
||||
// 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
|
||||
|
@ -41,14 +41,16 @@ class EInk : private concurrency::OSThread
|
||||
void beginPolling(uint32_t interval, uint32_t expectedDuration); // Begin checking repeatedly if update finished
|
||||
virtual bool isUpdateDone() = 0; // Check once if update finished
|
||||
virtual void finalizeUpdate() {} // Run any post-update code
|
||||
bool failed = false; // If an error occurred during update
|
||||
|
||||
private:
|
||||
int32_t runOnce() override; // Repeated checking if update finished
|
||||
|
||||
const UpdateTypes supportedUpdateTypes; // Capabilities of a derived display class
|
||||
bool updateRunning = false; // see EInk::busy()
|
||||
uint32_t updateBegunAt = 0; // For initial pause before polling for update completion
|
||||
uint32_t pollingInterval = 0; // How often to check if update complete (ms)
|
||||
uint32_t pollingBegunAt = 0; // To timeout during polling
|
||||
uint32_t pollingExpectedDuration = 0; // To timeout during polling
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
@ -37,11 +37,26 @@ void SSD16XX::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_b
|
||||
reset();
|
||||
}
|
||||
|
||||
void SSD16XX::wait()
|
||||
// Poll the displays busy pin until an operation is complete
|
||||
// Timeout and set fail flag if something went wrong and the display got stuck
|
||||
void SSD16XX::wait(uint32_t timeout)
|
||||
{
|
||||
// Don't bother waiting if part of the update sequence failed
|
||||
// In that situation, we're now just failing-through the process, until we can try again with next update.
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
uint32_t startMs = millis();
|
||||
|
||||
// Busy when HIGH
|
||||
while (digitalRead(pin_busy) == HIGH)
|
||||
while (digitalRead(pin_busy) == HIGH) {
|
||||
// Check for timeout
|
||||
if (millis() - startMs > timeout) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void SSD16XX::reset()
|
||||
@ -62,6 +77,11 @@ void SSD16XX::reset()
|
||||
|
||||
void SSD16XX::sendCommand(const uint8_t command)
|
||||
{
|
||||
// Abort if part of the update sequence failed
|
||||
// This will unlock again once we have failed-through the entire process
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, LOW); // DC pin low indicates command
|
||||
digitalWrite(pin_cs, LOW);
|
||||
@ -78,6 +98,11 @@ void SSD16XX::sendData(uint8_t data)
|
||||
|
||||
void SSD16XX::sendData(const uint8_t *data, uint32_t size)
|
||||
{
|
||||
// Abort if part of the update sequence failed
|
||||
// This will unlock again once we have failed-through the entire process
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, HIGH); // DC pin HIGH indicates data, instead of command
|
||||
digitalWrite(pin_cs, LOW);
|
||||
|
@ -27,7 +27,7 @@ class SSD16XX : public EInk
|
||||
virtual void update(uint8_t *imageData, UpdateTypes type) override;
|
||||
|
||||
protected:
|
||||
virtual void wait();
|
||||
virtual void wait(uint32_t timeout = 1000);
|
||||
virtual void reset();
|
||||
virtual void sendCommand(const uint8_t command);
|
||||
virtual void sendData(const uint8_t data);
|
||||
|
Loading…
Reference in New Issue
Block a user