InkHUD refactoring (#6216)

* chore: todo.txt
* chore: comments
* fix: no fast refresh on VME290
Reverts a line of code which was accidentally committed
* refactor: god class
Divide the behavior from the old WindowManager class into several subclasses which each have a clear role.
* refactor: cppcheck medium warnings
Enough to pass github CI for now
* refactor: updateType selection
* refactor: don't use a setter for the shared AppletFonts
* fix: update prioritization
forceUpdate calls weren't being prioritized
* refactor: remove unhelpful logging
getTimeString is used for parsing our own time, but also the timestamps of messages. The "one time only" log printing will likely fire in unhelpful situations.
* fix: " "
* refactor: get rid of types.h file for enums
* Keep that sneaky todo file out of commits
This commit is contained in:
todd-herbert
2025-03-06 11:25:41 +01:00
committed by GitHub
parent b2ef92a328
commit e6a98b1d6b
70 changed files with 2381 additions and 1955 deletions
@@ -40,13 +40,11 @@ void LatchingBacklight::setPin(uint8_t pin, bool activeWhen)
// Ensures the backlight is off
int LatchingBacklight::beforeDeepSleep(void *unused)
{
// We shouldn't need to guard the block like this
// Contingency for:
// - settings corruption: settings.optionalMenuItems.backlight guards backlight code in MenuApplet
// - improper use in the future
// Contingency only
// - pin wasn't set
if (pin != (uint8_t)-1) {
off();
pinMode(pin, INPUT); // High impedence - unnecessary?
pinMode(pin, INPUT); // High impedance - unnecessary?
} else
LOG_WARN("LatchingBacklight instantiated, but pin not set");
return 0; // Continue with deep sleep
+1 -1
View File
@@ -12,7 +12,7 @@ EInk::EInk(uint16_t width, uint16_t height, UpdateTypes supported)
}
// Used by NicheGraphics implementations to check if a display supports a specific refresh operation.
// Whether or the update type is supported is specified in the constructor
// 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.
+3 -3
View File
@@ -31,7 +31,7 @@ class EInk : private concurrency::OSThread
virtual void begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst = -1) = 0;
virtual void update(uint8_t *imageData, UpdateTypes type) = 0; // Change the display image
void await(); // Wait for an in-progress update to complete before proceeding
bool supports(UpdateTypes type); // Can display perfom a certain update type
bool supports(UpdateTypes type); // Can display perform a certain update type
bool busy() { return updateRunning; } // Display able to update right now?
const uint16_t width; // Public so that NicheGraphics implementations can access. Safe because const.
@@ -47,8 +47,8 @@ class EInk : private concurrency::OSThread
const UpdateTypes supportedUpdateTypes; // Capabilities of a derived display class
bool updateRunning = false; // see EInk::busy()
uint32_t updateBegunAt; // For initial pause before polling for update completion
uint32_t pollingInterval; // How often to check if update complete (ms)
uint32_t updateBegunAt = 0; // For initial pause before polling for update completion
uint32_t pollingInterval = 0; // How often to check if update complete (ms)
};
} // namespace NicheGraphics::Drivers
@@ -4,7 +4,7 @@
using namespace NicheGraphics::Drivers;
// Map the display controller IC's output to the conected panel
// Map the display controller IC's output to the connected panel
void GDEY0154D67::configScanning()
{
// "Driver output control"
@@ -98,6 +98,7 @@ void LCMEN213EFC1::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t
reset();
}
// Display an image on the display
void LCMEN213EFC1::update(uint8_t *imageData, UpdateTypes type)
{
this->updateType = type;
@@ -161,13 +162,6 @@ void LCMEN213EFC1::sendCommand(const uint8_t command)
void LCMEN213EFC1::sendData(uint8_t data)
{
// spi->beginTransaction(spiSettings);
// digitalWrite(pin_dc, HIGH); // DC pin HIGH indicates data, instead of command
// digitalWrite(pin_cs, LOW);
// spi->transfer(data);
// digitalWrite(pin_cs, HIGH);
// digitalWrite(pin_dc, HIGH);
// spi->endTransaction();
sendData(&data, 1);
}
@@ -45,21 +45,24 @@ class LCMEN213EFC1 : public EInk
void configFull(); // Configure display for FULL refresh
void configFast(); // Configure display for FAST refresh
void writeNewImage();
void writeOldImage();
void writeOldImage(); // Used for "differential update", aka FAST refresh
void detachFromUpdate();
bool isUpdateDone();
void finalizeUpdate();
protected:
uint8_t bufferOffsetX; // In bytes. Panel x=0 does not always align with controller x=0. Quirky internal wiring?
uint8_t bufferRowSize; // In bytes. Rows store 8 pixels per byte. Rounded up to fit (e.g. 122px would require 16 bytes)
uint32_t bufferSize; // In bytes. Rows * Columns
uint8_t *buffer;
UpdateTypes updateType;
uint8_t bufferOffsetX = 0; // In bytes. Panel x=0 does not always align with controller x=0. Quirky internal wiring?
uint8_t bufferRowSize = 0; // In bytes. Rows store 8 pixels per byte. Rounded up to fit (e.g. 122px would require 16 bytes)
uint32_t bufferSize = 0; // In bytes. Rows * Columns
uint8_t *buffer = nullptr;
UpdateTypes updateType = UpdateTypes::UNSPECIFIED;
uint8_t pin_dc, pin_cs, pin_busy, pin_rst;
SPIClass *spi;
uint8_t pin_dc = -1;
uint8_t pin_cs = -1;
uint8_t pin_busy = -1;
uint8_t pin_rst = -1;
SPIClass *spi = nullptr;
SPISettings spiSettings = SPISettings(6000000, MSBFIRST, SPI_MODE0);
};
+7 -4
View File
@@ -3,7 +3,7 @@
A driver for E-Ink SPI displays. Suitable for re-use by various NicheGraphics UIs.
Your UI should use the class `NicheGraphics::Drivers::EInk` .
When you set up a hardware variant, you will use one of specific display model classes, which extend the EInk class.
When you set up a hardware variant, you will use one of the specific display model classes, which extend the EInk class.
An example setup might look like this:
@@ -30,7 +30,7 @@ void setupNicheGraphics()
## Methods
### `update(uint8_t *imageData, UpdateTypes type, bool async=true)`
### `update(uint8_t *imageData, UpdateTypes type)`
Update the image on the display
@@ -39,7 +39,6 @@ Update the image on the display
- `FULL`
- `FAST`
- (Other custom types may be possible)
- _`async`_ whether to wait for update to complete, or continue code execution
The imageData is a 1-bit image. X-Pixels are 8-per byte, with the MSB being the leftmost pixel. This was not an InkHUD design decision; it is the raw format accepted by the E-Ink display controllers ICs.
@@ -63,6 +62,10 @@ uint8_t xBits = (7-x) % 8;
image[yByte + xByte] |= (1 << xBits); // Set pixel x=12, y=2
```
### `await()`
Wait for an in-progress update to complete before continuing
### `supports(UpdateTypes type)`
Check if display supports a specific update type. `true` if supported.
@@ -75,7 +78,7 @@ Check if display is already performing an `update()`. `true` if already updating
### `width()`
Width of the display, in pixels. Note: most displays are portait. Your UI will need to implement rotation in software.
Width of the display, in pixels. Note: most displays are portrait. Your UI will need to implement rotation in software.
### `height()`
+1 -8
View File
@@ -30,7 +30,7 @@ void SSD16XX::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_b
pinMode(pin_busy, INPUT);
// If using a reset pin, hold high
// Reset is active low for solmon systech ICs
// Reset is active low for Solomon Systech ICs
if (pin_rst != 0xFF)
pinMode(pin_rst, INPUT_PULLUP);
@@ -72,13 +72,6 @@ void SSD16XX::sendCommand(const uint8_t command)
void SSD16XX::sendData(uint8_t data)
{
// spi->beginTransaction(spiSettings);
// digitalWrite(pin_dc, HIGH); // DC pin HIGH indicates data, instead of command
// digitalWrite(pin_cs, LOW);
// spi->transfer(data);
// digitalWrite(pin_cs, HIGH);
// digitalWrite(pin_dc, HIGH);
// spi->endTransaction();
sendData(&data, 1);
}
+11 -8
View File
@@ -39,21 +39,24 @@ class SSD16XX : public EInk
virtual void configUpdateSequence(); // Tell controller IC which operations to run
virtual void writeNewImage();
virtual void writeOldImage();
virtual void writeOldImage(); // Image which can be used at *next* update for "differential refresh"
virtual void detachFromUpdate();
virtual bool isUpdateDone() override;
virtual void finalizeUpdate() override;
protected:
uint8_t bufferOffsetX; // In bytes. Panel x=0 does not always align with controller x=0. Quirky internal wiring?
uint8_t bufferRowSize; // In bytes. Rows store 8 pixels per byte. Rounded up to fit (e.g. 122px would require 16 bytes)
uint32_t bufferSize; // In bytes. Rows * Columns
uint8_t *buffer;
UpdateTypes updateType;
uint8_t bufferOffsetX = 0; // In bytes. Panel x=0 does not always align with controller x=0. Quirky internal wiring?
uint8_t bufferRowSize = 0; // In bytes. Rows store 8 pixels per byte. Rounded up to fit (e.g. 122px would require 16 bytes)
uint32_t bufferSize = 0; // In bytes. Rows * Columns
uint8_t *buffer = nullptr;
UpdateTypes updateType = UpdateTypes::UNSPECIFIED;
uint8_t pin_dc, pin_cs, pin_busy, pin_rst;
SPIClass *spi;
uint8_t pin_dc = -1;
uint8_t pin_cs = -1;
uint8_t pin_busy = -1;
uint8_t pin_rst = -1;
SPIClass *spi = nullptr;
SPISettings spiSettings = SPISettings(4000000, MSBFIRST, SPI_MODE0);
};
+1 -1
View File
@@ -1,3 +1,3 @@
# NicheGraphics - Drivers
Common drivers which can be used by various NicheGrapihcs UIs
Common drivers which can be used by various NicheGraphics UIs