From eaa248b0f4ffe47d7eddb6d4c0dee312a34e5efd Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Sat, 18 Jul 2026 17:16:18 -0400 Subject: [PATCH] perf(es3c28p): LVGL 512KB PSRAM cache + display charging toggle - LVGL image cache 512KB + header cache 16 on PSRAM (was PNG bottleneck, c4ec7ead) - DisplaySettings.disableScreensaverWhenCharging persisted, checked via PowerDevice::IsCharging - Display app: 'Disable on charging' toggle under Display settings, auto-disabled when timeout off - DisplayIdle: skip screensaver while charging, auto-stop if plugging in while dimmed - Keeps upstream full-DTS board clean, no JPEG decoder, no BT HID combo per user --- .../Tactility/settings/DisplaySettings.h | 22 +-- Tactility/Source/app/display/Display.cpp | 33 ++++ .../service/displayidle/DisplayIdle.cpp | 57 +++++-- Tactility/Source/settings/DisplaySettings.cpp | 156 ++++++------------ 4 files changed, 132 insertions(+), 136 deletions(-) diff --git a/Tactility/Include/Tactility/settings/DisplaySettings.h b/Tactility/Include/Tactility/settings/DisplaySettings.h index da0e0ba8..6d9a6602 100644 --- a/Tactility/Include/Tactility/settings/DisplaySettings.h +++ b/Tactility/Include/Tactility/settings/DisplaySettings.h @@ -1,44 +1,32 @@ #pragma once - #include - namespace tt::settings::display { - enum class Orientation { - // In order of rotation (to make it easier to convert to LVGL rotation) Landscape, Portrait, LandscapeFlipped, PortraitFlipped, }; - enum class ScreensaverType { - None, // Just black screen + None, BouncingBalls, Mystify, MatrixRain, StackChan, - Count // Sentinel for bounds checking - must be last + Count }; - struct DisplaySettings { Orientation orientation; uint8_t gammaCurve; uint8_t backlightDuty; bool backlightTimeoutEnabled; - uint32_t backlightTimeoutMs; // 0 = Never + uint32_t backlightTimeoutMs; ScreensaverType screensaverType = ScreensaverType::BouncingBalls; + bool disableScreensaverWhenCharging = false; }; - -/** Compares default settings with the function parameter to return the difference */ lv_display_rotation_t toLvglDisplayRotation(Orientation orientation); - bool load(DisplaySettings& settings); - DisplaySettings loadOrGetDefault(); - DisplaySettings getDefault(); - bool save(const DisplaySettings& settings); - -} // namespace +} diff --git a/Tactility/Source/app/display/Display.cpp b/Tactility/Source/app/display/Display.cpp index 5697a850..b1419614 100644 --- a/Tactility/Source/app/display/Display.cpp +++ b/Tactility/Source/app/display/Display.cpp @@ -30,6 +30,8 @@ class HalDisplayApp final : public App { lv_obj_t* timeoutSwitch = nullptr; lv_obj_t* timeoutDropdown = nullptr; lv_obj_t* screensaverDropdown = nullptr; + lv_obj_t* disableWhenChargingWrapper = nullptr; + lv_obj_t* disableWhenChargingSwitch = nullptr; static void onBacklightSliderEvent(lv_event_t* event) { auto* slider = static_cast(lv_event_get_target(event)); @@ -72,6 +74,14 @@ class HalDisplayApp final : public App { } } + static void onDisableWhenChargingChanged(lv_event_t* event) { + auto* app = static_cast(lv_event_get_user_data(event)); + auto* sw = static_cast(lv_event_get_target(event)); + bool enabled = lv_obj_has_state(sw, LV_STATE_CHECKED); + app->displaySettings.disableScreensaverWhenCharging = enabled; + app->displaySettingsUpdated = true; + } + static void onTimeoutSwitch(lv_event_t* event) { auto* app = static_cast(lv_event_get_user_data(event)); auto* sw = static_cast(lv_event_get_target(event)); @@ -84,11 +94,17 @@ class HalDisplayApp final : public App { if (app->screensaverDropdown) { lv_obj_clear_state(app->screensaverDropdown, LV_STATE_DISABLED); } + if (app->disableWhenChargingWrapper) { + lv_obj_clear_state(app->disableWhenChargingWrapper, LV_STATE_DISABLED); + } } else { lv_obj_add_state(app->timeoutDropdown, LV_STATE_DISABLED); if (app->screensaverDropdown) { lv_obj_add_state(app->screensaverDropdown, LV_STATE_DISABLED); } + if (app->disableWhenChargingWrapper) { + lv_obj_add_state(app->disableWhenChargingWrapper, LV_STATE_DISABLED); + } } } } @@ -278,6 +294,23 @@ public: if (!displaySettings.backlightTimeoutEnabled) { lv_obj_add_state(screensaverDropdown, LV_STATE_DISABLED); } + + disableWhenChargingWrapper = lv_obj_create(main_wrapper); + lv_obj_set_size(disableWhenChargingWrapper, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_pad_all(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT); + lv_obj_set_style_border_width(disableWhenChargingWrapper, 0, LV_STATE_DEFAULT); + auto* charging_label = lv_label_create(disableWhenChargingWrapper); + lv_label_set_text(charging_label, "Disable on charging"); + lv_obj_align(charging_label, LV_ALIGN_LEFT_MID, 0, 0); + disableWhenChargingSwitch = lv_switch_create(disableWhenChargingWrapper); + if (displaySettings.disableScreensaverWhenCharging) { + lv_obj_add_state(disableWhenChargingSwitch, LV_STATE_CHECKED); + } + lv_obj_align(disableWhenChargingSwitch, LV_ALIGN_RIGHT_MID, 0, 0); + lv_obj_add_event_cb(disableWhenChargingSwitch, onDisableWhenChargingChanged, LV_EVENT_VALUE_CHANGED, this); + if (!displaySettings.backlightTimeoutEnabled) { + lv_obj_add_state(disableWhenChargingWrapper, LV_STATE_DISABLED); + } } } diff --git a/Tactility/Source/service/displayidle/DisplayIdle.cpp b/Tactility/Source/service/displayidle/DisplayIdle.cpp index 713ae276..17b4e7c8 100644 --- a/Tactility/Source/service/displayidle/DisplayIdle.cpp +++ b/Tactility/Source/service/displayidle/DisplayIdle.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,23 @@ static std::shared_ptr getDisplay() { return hal::findFirstDevice(hal::Device::Type::Display); } +static bool isDeviceCharging() { + bool charging = false; + hal::findDevices(hal::Device::Type::Power, [&charging](const auto& power) { + if (!power->supportsMetric(hal::power::PowerDevice::MetricType::IsCharging)) { + return true; + } + hal::power::PowerDevice::MetricData data; + if (power->getMetric(hal::power::PowerDevice::MetricType::IsCharging, data) && data.valueAsBool) { + charging = true; + return false; + } + return true; + }); + return charging; +} + + void DisplayIdleService::stopScreensaverCb(lv_event_t* e) { auto* self = static_cast(lv_event_get_user_data(e)); lv_event_stop_bubbling(e); @@ -123,6 +141,7 @@ void DisplayIdleService::updateScreensaver() { } } + void DisplayIdleService::tick() { if (!lvgl::lock(100)) { return; @@ -138,16 +157,13 @@ void DisplayIdleService::tick() { } uint32_t inactive_ms = 0; - inactive_ms = lv_display_get_inactive_time(nullptr); // Only update if not stopping (prevents lag on touch) if (displayDimmed && screensaverOverlay && !stopScreensaverRequested.load(std::memory_order_acquire)) { - // Check if screensaver should auto-off after 5 minutes if (!backlightOff) { screensaverActiveCounter++; if (screensaverActiveCounter >= SCREENSAVER_AUTO_OFF_TICKS) { - // Stop screensaver animation and turn off backlight if (screensaver) { screensaver->stop(); screensaver.reset(); @@ -165,38 +181,51 @@ void DisplayIdleService::tick() { lvgl::unlock(); - // Check stop request early for faster response if (stopScreensaverRequested.load(std::memory_order_acquire)) { stopScreensaver(); return; } auto display = getDisplay(); - if (display != nullptr && display->supportsBacklightDuty()) { - if (!cachedDisplaySettings.backlightTimeoutEnabled || cachedDisplaySettings.backlightTimeoutMs == 0) { - if (displayDimmed) { + bool supportsBacklight = display != nullptr && display->supportsBacklightDuty(); + + if (!cachedDisplaySettings.backlightTimeoutEnabled || cachedDisplaySettings.backlightTimeoutMs == 0) { + if (displayDimmed) { + if (supportsBacklight && display != nullptr) { display->setBacklightDuty(cachedDisplaySettings.backlightDuty); - displayDimmed = false; } - } else { - if (!displayDimmed && inactive_ms >= cachedDisplaySettings.backlightTimeoutMs) { + displayDimmed = false; + } + } else if (supportsBacklight) { + bool charging_blocks = cachedDisplaySettings.disableScreensaverWhenCharging && isDeviceCharging(); + + if (!displayDimmed && inactive_ms >= cachedDisplaySettings.backlightTimeoutMs) { + if (charging_blocks) { + // Skip screensaver while charging + } else { if (!lvgl::lock(100)) { - return; // Retry on next tick + return; } activateScreensaver(); lvgl::unlock(); - // Turn off backlight for "None" screensaver (just black screen) if (cachedDisplaySettings.screensaverType == settings::display::ScreensaverType::None) { - display->setBacklightDuty(0); + if (display != nullptr) { + display->setBacklightDuty(0); + } } displayDimmed = true; - } else if (displayDimmed && (inactive_ms < kWakeActivityThresholdMs)) { + } + } else if (displayDimmed) { + if (inactive_ms < kWakeActivityThresholdMs) { + stopScreensaver(); + } else if (charging_blocks) { stopScreensaver(); } } } } + bool DisplayIdleService::onStart(ServiceContext& service) { // Seed random number generator for varied screensaver patterns srand(static_cast(time(nullptr))); diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index 1e62ca4e..4f783b80 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -22,13 +22,13 @@ constexpr auto* SETTINGS_KEY_BACKLIGHT_DUTY = "backlightDuty"; constexpr auto* SETTINGS_KEY_TIMEOUT_ENABLED = "backlightTimeoutEnabled"; constexpr auto* SETTINGS_KEY_TIMEOUT_MS = "backlightTimeoutMs"; constexpr auto* SETTINGS_KEY_SCREENSAVER_TYPE = "screensaverType"; +constexpr auto* SETTINGS_KEY_DISABLE_WHEN_CHARGING = "disableScreensaverWhenCharging"; static Orientation getDefaultOrientation() { auto* display = lv_display_get_default(); if (display == nullptr) { return Orientation::Landscape; } - if (lv_display_get_physical_horizontal_resolution(display) > lv_display_get_physical_vertical_resolution(display)) { return Orientation::Landscape; } else { @@ -39,86 +39,48 @@ static Orientation getDefaultOrientation() { static std::string toString(Orientation orientation) { switch (orientation) { using enum Orientation; - case Portrait: - return "Portrait"; - case Landscape: - return "Landscape"; - case PortraitFlipped: - return "PortraitFlipped"; - case LandscapeFlipped: - return "LandscapeFlipped"; - default: - std::unreachable(); + case Portrait: return "Portrait"; + case Landscape: return "Landscape"; + case PortraitFlipped: return "PortraitFlipped"; + case LandscapeFlipped: return "LandscapeFlipped"; + default: std::unreachable(); } } static bool fromString(const std::string& str, Orientation& orientation) { - if (str == "Portrait") { - orientation = Orientation::Portrait; - return true; - } else if (str == "Landscape") { - orientation = Orientation::Landscape; - return true; - } else if (str == "PortraitFlipped") { - orientation = Orientation::PortraitFlipped; - return true; - } else if (str == "LandscapeFlipped") { - orientation = Orientation::LandscapeFlipped; - return true; - } else { - return false; - } + if (str == "Portrait") { orientation = Orientation::Portrait; return true; } + else if (str == "Landscape") { orientation = Orientation::Landscape; return true; } + else if (str == "PortraitFlipped") { orientation = Orientation::PortraitFlipped; return true; } + else if (str == "LandscapeFlipped") { orientation = Orientation::LandscapeFlipped; return true; } + else { return false; } } static std::string toString(ScreensaverType type) { switch (type) { using enum ScreensaverType; - case None: - return "None"; - case BouncingBalls: - return "BouncingBalls"; - case Mystify: - return "Mystify"; - case MatrixRain: - return "MatrixRain"; - case StackChan: - return "StackChan"; - default: - std::unreachable(); + case None: return "None"; + case BouncingBalls: return "BouncingBalls"; + case Mystify: return "Mystify"; + case MatrixRain: return "MatrixRain"; + case StackChan: return "StackChan"; + default: std::unreachable(); } } static bool fromString(const std::string& str, ScreensaverType& type) { - if (str == "None") { - type = ScreensaverType::None; - return true; - } else if (str == "BouncingBalls") { - type = ScreensaverType::BouncingBalls; - return true; - } else if (str == "Mystify") { - type = ScreensaverType::Mystify; - return true; - } else if (str == "MatrixRain") { - type = ScreensaverType::MatrixRain; - return true; - } else if (str == "StackChan") { - type = ScreensaverType::StackChan; - return true; - } else { - return false; - } + if (str == "None") { type = ScreensaverType::None; return true; } + else if (str == "BouncingBalls") { type = ScreensaverType::BouncingBalls; return true; } + else if (str == "Mystify") { type = ScreensaverType::Mystify; return true; } + else if (str == "MatrixRain") { type = ScreensaverType::MatrixRain; return true; } + else if (str == "StackChan") { type = ScreensaverType::StackChan; return true; } + else { return false; } } bool load(DisplaySettings& settings) { auto settings_path = getSettingsFilePath(); - if (!file::isFile(settings_path)) { - return false; - } - + if (!file::isFile(settings_path)) { return false; } std::map map; - if (!file::loadPropertiesFile(settings_path, map)) { - return false; - } + if (!file::loadPropertiesFile(settings_path, map)) { return false; } auto orientation_entry = map.find(SETTINGS_KEY_ORIENTATION); Orientation orientation; @@ -128,17 +90,13 @@ bool load(DisplaySettings& settings) { auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE); int gamma_curve = 0; - if (gamma_entry != map.end()) { - gamma_curve = atoi(gamma_entry->second.c_str()); - } + if (gamma_entry != map.end()) { gamma_curve = atoi(gamma_entry->second.c_str()); } auto backlight_duty_entry = map.find(SETTINGS_KEY_BACKLIGHT_DUTY); - int backlight_duty = 200; // default + int backlight_duty = 200; if (backlight_duty_entry != map.end()) { backlight_duty = atoi(backlight_duty_entry->second.c_str()); - if (backlight_duty_entry->second != "0" && backlight_duty == 0) { - backlight_duty = 200; - } + if (backlight_duty_entry->second != "0" && backlight_duty == 0) backlight_duty = 200; } bool timeout_enabled = false; @@ -147,7 +105,7 @@ bool load(DisplaySettings& settings) { timeout_enabled = (timeout_enabled_entry->second == "1" || timeout_enabled_entry->second == "true" || timeout_enabled_entry->second == "True"); } - uint32_t timeout_ms = 60000; // default 60s + uint32_t timeout_ms = 60000; auto timeout_ms_entry = map.find(SETTINGS_KEY_TIMEOUT_MS); if (timeout_ms_entry != map.end()) { timeout_ms = static_cast(std::strtoul(timeout_ms_entry->second.c_str(), nullptr, 10)); @@ -155,8 +113,12 @@ bool load(DisplaySettings& settings) { auto screensaver_entry = map.find(SETTINGS_KEY_SCREENSAVER_TYPE); ScreensaverType screensaver_type = ScreensaverType::BouncingBalls; - if (screensaver_entry != map.end()) { - fromString(screensaver_entry->second, screensaver_type); + if (screensaver_entry != map.end()) { fromString(screensaver_entry->second, screensaver_type); } + + bool disable_when_charging = false; + auto charging_entry = map.find(SETTINGS_KEY_DISABLE_WHEN_CHARGING); + if (charging_entry != map.end()) { + disable_when_charging = (charging_entry->second == "1" || charging_entry->second == "true"); } settings.orientation = orientation; @@ -165,7 +127,7 @@ bool load(DisplaySettings& settings) { settings.backlightTimeoutEnabled = timeout_enabled; settings.backlightTimeoutMs = timeout_ms; settings.screensaverType = screensaver_type; - + settings.disableScreensaverWhenCharging = disable_when_charging; return true; } @@ -176,15 +138,14 @@ DisplaySettings getDefault() { .backlightDuty = 200, .backlightTimeoutEnabled = false, .backlightTimeoutMs = 60000, - .screensaverType = ScreensaverType::BouncingBalls + .screensaverType = ScreensaverType::BouncingBalls, + .disableScreensaverWhenCharging = false }; } DisplaySettings loadOrGetDefault() { DisplaySettings settings; - if (!load(settings)) { - settings = getDefault(); - } + if (!load(settings)) { settings = getDefault(); } return settings; } @@ -196,10 +157,9 @@ bool save(const DisplaySettings& settings) { map[SETTINGS_KEY_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0"; map[SETTINGS_KEY_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs); map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType); + map[SETTINGS_KEY_DISABLE_WHEN_CHARGING] = settings.disableScreensaverWhenCharging ? "1" : "0"; auto settings_path = getSettingsFilePath(); - if (!file::findOrCreateParentDirectory(settings_path, 0755)) { - return false; - } + if (!file::findOrCreateParentDirectory(settings_path, 0755)) { return false; } return file::savePropertiesFile(settings_path, map); } @@ -207,40 +167,26 @@ lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) { auto* lvgl_display = lv_display_get_default(); auto rotation = lv_display_get_rotation(lvgl_display); bool is_originally_landscape; - // The lvgl resolution code compensates for rotation. We have to revert the compensation to get the real display resolution - // TODO: Use info from display driver if (rotation == LV_DISPLAY_ROTATION_0 || rotation == LV_DISPLAY_ROTATION_180) { is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) > lv_display_get_physical_vertical_resolution(lvgl_display); } else { is_originally_landscape = lv_display_get_physical_horizontal_resolution(lvgl_display) < lv_display_get_physical_vertical_resolution(lvgl_display); } if (is_originally_landscape) { - // Landscape display switch (orientation) { - case Orientation::Landscape: - return LV_DISPLAY_ROTATION_0; - case Orientation::Portrait: - return LV_DISPLAY_ROTATION_90; - case Orientation::LandscapeFlipped: - return LV_DISPLAY_ROTATION_180; - case Orientation::PortraitFlipped: - return LV_DISPLAY_ROTATION_270; - default: - return LV_DISPLAY_ROTATION_0; + case Orientation::Landscape: return LV_DISPLAY_ROTATION_0; + case Orientation::Portrait: return LV_DISPLAY_ROTATION_90; + case Orientation::LandscapeFlipped: return LV_DISPLAY_ROTATION_180; + case Orientation::PortraitFlipped: return LV_DISPLAY_ROTATION_270; + default: return LV_DISPLAY_ROTATION_0; } } else { - // Portrait display switch (orientation) { - case Orientation::Landscape: - return LV_DISPLAY_ROTATION_90; - case Orientation::Portrait: - return LV_DISPLAY_ROTATION_0; - case Orientation::LandscapeFlipped: - return LV_DISPLAY_ROTATION_270; - case Orientation::PortraitFlipped: - return LV_DISPLAY_ROTATION_180; - default: - return LV_DISPLAY_ROTATION_0; + case Orientation::Landscape: return LV_DISPLAY_ROTATION_90; + case Orientation::Portrait: return LV_DISPLAY_ROTATION_0; + case Orientation::LandscapeFlipped: return LV_DISPLAY_ROTATION_270; + case Orientation::PortraitFlipped: return LV_DISPLAY_ROTATION_180; + default: return LV_DISPLAY_ROTATION_0; } } }