From 988723d985239785326f79129afc396f8831a6e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maik=20Allg=C3=B6wer?= Date: Wed, 28 Jan 2026 18:26:27 +0100 Subject: [PATCH] feat: Implement fix for sunlight fading issue --- lib/GfxRenderer/GfxRenderer.cpp | 4 ++-- lib/GfxRenderer/GfxRenderer.h | 6 +++++- lib/hal/HalDisplay.cpp | 4 ++-- lib/hal/HalDisplay.h | 4 ++-- src/CrossPointSettings.cpp | 5 ++++- src/CrossPointSettings.h | 2 ++ src/activities/settings/SettingsActivity.cpp | 6 ++++-- src/main.cpp | 2 ++ 8 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index fa1c61c6..ff8f8387 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -411,7 +411,7 @@ void GfxRenderer::invertScreen() const { } } -void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { display.displayBuffer(refreshMode); } +void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { display.displayBuffer(refreshMode, fadingFix); } std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth, const EpdFontFamily::Style style) const { @@ -661,7 +661,7 @@ void GfxRenderer::copyGrayscaleLsbBuffers() const { display.copyGrayscaleLsbBuff void GfxRenderer::copyGrayscaleMsbBuffers() const { display.copyGrayscaleMsbBuffers(display.getFrameBuffer()); } -void GfxRenderer::displayGrayBuffer() const { display.displayGrayBuffer(); } +void GfxRenderer::displayGrayBuffer() const { display.displayGrayBuffer(fadingFix); } void GfxRenderer::freeBwBufferChunks() { for (auto& bwBufferChunk : bwBufferChunks) { diff --git a/lib/GfxRenderer/GfxRenderer.h b/lib/GfxRenderer/GfxRenderer.h index 733975f4..9e545964 100644 --- a/lib/GfxRenderer/GfxRenderer.h +++ b/lib/GfxRenderer/GfxRenderer.h @@ -28,6 +28,7 @@ class GfxRenderer { HalDisplay& display; RenderMode renderMode; Orientation orientation; + bool fadingFix; uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr}; std::map fontMap; void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState, @@ -36,7 +37,7 @@ class GfxRenderer { void rotateCoordinates(int x, int y, int* rotatedX, int* rotatedY) const; public: - explicit GfxRenderer(HalDisplay& halDisplay) : display(halDisplay), renderMode(BW), orientation(Portrait) {} + explicit GfxRenderer(HalDisplay& halDisplay) : display(halDisplay), renderMode(BW), orientation(Portrait), fadingFix(false) {} ~GfxRenderer() { freeBwBufferChunks(); } static constexpr int VIEWABLE_MARGIN_TOP = 9; @@ -51,6 +52,9 @@ class GfxRenderer { void setOrientation(const Orientation o) { orientation = o; } Orientation getOrientation() const { return orientation; } + // Fading fix control + void setFadingFix(const bool enabled) { fadingFix = enabled; } + // Screen ops int getScreenWidth() const; int getScreenHeight() const; diff --git a/lib/hal/HalDisplay.cpp b/lib/hal/HalDisplay.cpp index 6f69d7fc..0b4308ff 100644 --- a/lib/hal/HalDisplay.cpp +++ b/lib/hal/HalDisplay.cpp @@ -28,7 +28,7 @@ EInkDisplay::RefreshMode convertRefreshMode(HalDisplay::RefreshMode mode) { } } -void HalDisplay::displayBuffer(HalDisplay::RefreshMode mode) { einkDisplay.displayBuffer(convertRefreshMode(mode)); } +void HalDisplay::displayBuffer(HalDisplay::RefreshMode mode, bool turnOffScreen) { einkDisplay.displayBuffer(convertRefreshMode(mode), turnOffScreen); } void HalDisplay::refreshDisplay(HalDisplay::RefreshMode mode, bool turnOffScreen) { einkDisplay.refreshDisplay(convertRefreshMode(mode), turnOffScreen); @@ -48,4 +48,4 @@ void HalDisplay::copyGrayscaleMsbBuffers(const uint8_t* msbBuffer) { einkDisplay void HalDisplay::cleanupGrayscaleBuffers(const uint8_t* bwBuffer) { einkDisplay.cleanupGrayscaleBuffers(bwBuffer); } -void HalDisplay::displayGrayBuffer() { einkDisplay.displayGrayBuffer(); } +void HalDisplay::displayGrayBuffer(bool turnOffScreen) { einkDisplay.displayGrayBuffer(turnOffScreen); } diff --git a/lib/hal/HalDisplay.h b/lib/hal/HalDisplay.h index 6eb7156b..238832b0 100644 --- a/lib/hal/HalDisplay.h +++ b/lib/hal/HalDisplay.h @@ -31,7 +31,7 @@ class HalDisplay { void drawImage(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool fromProgmem = false) const; - void displayBuffer(RefreshMode mode = RefreshMode::FAST_REFRESH); + void displayBuffer(RefreshMode mode = RefreshMode::FAST_REFRESH, bool turnOffScreen = false); void refreshDisplay(RefreshMode mode = RefreshMode::FAST_REFRESH, bool turnOffScreen = false); // Power management @@ -45,7 +45,7 @@ class HalDisplay { void copyGrayscaleMsbBuffers(const uint8_t* msbBuffer); void cleanupGrayscaleBuffers(const uint8_t* bwBuffer); - void displayGrayBuffer(); + void displayGrayBuffer(bool turnOffScreen = false); private: EInkDisplay einkDisplay; diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index 232c7c57..f74b0c78 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -22,7 +22,7 @@ void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) { namespace { constexpr uint8_t SETTINGS_FILE_VERSION = 1; // Increment this when adding new persisted settings fields -constexpr uint8_t SETTINGS_COUNT = 23; +constexpr uint8_t SETTINGS_COUNT = 24; constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin"; } // namespace @@ -61,6 +61,7 @@ bool CrossPointSettings::saveToFile() const { serialization::writeString(outputFile, std::string(opdsPassword)); serialization::writePod(outputFile, sleepScreenCoverFilter); // New fields added at end for backward compatibility + serialization::writePod(outputFile, fadingFix); outputFile.close(); Serial.printf("[%lu] [CPS] Settings saved to file\n", millis()); @@ -148,6 +149,8 @@ bool CrossPointSettings::loadFromFile() { if (++settingsRead >= fileSettingsCount) break; readAndValidate(inputFile, sleepScreenCoverFilter, SLEEP_SCREEN_COVER_FILTER_COUNT); if (++settingsRead >= fileSettingsCount) break; + serialization::readPod(inputFile, fadingFix); + if (++settingsRead >= fileSettingsCount) break; // New fields added at end for backward compatibility } while (false); diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index c450d348..6ccde287 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -137,6 +137,8 @@ class CrossPointSettings { uint8_t hideBatteryPercentage = HIDE_NEVER; // Long-press chapter skip on side buttons uint8_t longPressChapterSkip = 1; + // Sunlight fading compensation + uint8_t fadingFix = 0; ~CrossPointSettings() = default; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 7316db05..a1ca135d 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -11,7 +11,7 @@ const char* SettingsActivity::categoryNames[categoryCount] = {"Display", "Reader", "Controls", "System"}; namespace { -constexpr int displaySettingsCount = 6; +constexpr int displaySettingsCount = 7; const SettingInfo displaySettings[displaySettingsCount] = { // Should match with SLEEP_SCREEN_MODE SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}), @@ -22,7 +22,9 @@ const SettingInfo displaySettings[displaySettingsCount] = { {"None", "No Progress", "Full w/ Percentage", "Full w/ Progress Bar", "Progress Bar"}), SettingInfo::Enum("Hide Battery %", &CrossPointSettings::hideBatteryPercentage, {"Never", "In Reader", "Always"}), SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency, - {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"})}; + {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}), + SettingInfo::Enum("Sunlight Fading Fix", &CrossPointSettings::fadingFix, {"OFF", "ON"}), +}; constexpr int readerSettingsCount = 9; const SettingInfo readerSettings[readerSettingsCount] = { diff --git a/src/main.cpp b/src/main.cpp index 2308f0a2..91db0380 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -333,6 +333,8 @@ void loop() { gpio.update(); + renderer.setFadingFix(SETTINGS.fadingFix); + if (Serial && millis() - lastMemPrint >= 10000) { Serial.printf("[%lu] [MEM] Free: %d bytes, Total: %d bytes, Min Free: %d bytes\n", millis(), ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getMinFreeHeap());