Files
firmware/src/graphics/Backlight.h
Thomas Göttgens 7b0004806a fix(graphics): drive GPIO backlights from the stored brightness level (#11588)
* fix(graphics): drive GPIO backlights from the stored brightness level

Screen::handleSetOn restored PIN_EINK_EN only when screen_brightness was
exactly 1. The field is 0..255 and defaults to 153, so the frontlight stayed
off after a screen timeout until the next reboot.

InputBroker read screen_brightness as "currently lit" for the touch backlight,
so a stored level made touch-to-light a no-op. The HAPTIC_FEEDBACK_PIN block
then reassigned touchConfig.onPress and onRelease, dropping those handlers on
any variant defining both.

MINI_EPAPER_S3 names its panel power rail PIN_EINK_EN. It was switched off with
the screen and never restored.

graphics::Backlight gains a GPIO backend covering PIN_EINK_EN and
PCA_PIN_EINK_EN, so Screen, MenuHandler and InputBroker call backlightOn,
backlightOff, backlightToggle and backlightIsLit instead of touching pins.
backlightIsLit reports the driven state, separate from the configured level.

Power-up state is declared per variant with GPIO_BACKLIGHT_DEFAULT_ON rather
than hardcoded in the e-ink driver. The backend stores only 0 or 255, so any
other stored level falls back to the variant default and no board changes its
existing behaviour. MINI_EPAPER_S3 is excluded and keeps its rail powered.

Touch handlers are merged so backlight and haptic feedback compose.

Verified on ThinkNode M1: lit at boot, off on timeout, lit on wake, and an
explicit off surviving both wake and reboot.

* chore(thinknode_m1): correct the LED pin comments

P0.13 drives the blue indicator, not a green one. P1.06 is a second drive for
the same red LED as LED_POWER, which is why it stays disabled.

* fix(graphics): clamp GPIO backlight levels at the setter

backlightSet stored whatever level it was given, so a caller passing an
intermediate value left backlightGet and the persisted config holding a level
the rail cannot drive. Clamp to off or on in the setter, which keeps the
invariant at the single write point instead of only at init.
2026-08-25 08:49:37 +00:00

82 lines
2.1 KiB
C++

#pragma once
#include "configuration.h"
// Backlight control for a PWM rail (PIN_PWM_BACKLIGHT) or an on/off GPIO rail (PIN_EINK_EN,
// PCA_PIN_EINK_EN). uiconfig.screen_brightness is the configured level, not the live pin state.
#if defined(PIN_PWM_BACKLIGHT)
#define HAS_PWM_BACKLIGHT 1
#else
#define HAS_PWM_BACKLIGHT 0
#endif
// MINI_EPAPER_S3 names its panel power rail PIN_EINK_EN. That is not a backlight and has to stay
// powered for the panel to work, so EInkDisplay::connect() drives it instead.
#if !HAS_PWM_BACKLIGHT && (defined(PIN_EINK_EN) || defined(PCA_PIN_EINK_EN)) && !defined(MINI_EPAPER_S3)
#define HAS_GPIO_BACKLIGHT 1
#else
#define HAS_GPIO_BACKLIGHT 0
#endif
#define HAS_BACKLIGHT (HAS_PWM_BACKLIGHT || HAS_GPIO_BACKLIGHT)
#if HAS_PWM_BACKLIGHT
#ifndef PWM_BACKLIGHT_DEFAULT
#define PWM_BACKLIGHT_DEFAULT 128
#endif
#ifndef PWM_BACKLIGHT_MIN
#define PWM_BACKLIGHT_MIN 8
#endif
#ifndef PWM_BACKLIGHT_MAX
#define PWM_BACKLIGHT_MAX 248
#endif
#ifndef PWM_BACKLIGHT_STEP
#define PWM_BACKLIGHT_STEP 20
#endif
#endif // HAS_PWM_BACKLIGHT
#if HAS_GPIO_BACKLIGHT
// On or off only, so these are the sole levels this backend stores. A variant defines
// GPIO_BACKLIGHT_DEFAULT_ON to power up lit.
#define GPIO_BACKLIGHT_ON_LEVEL 255
#if defined(GPIO_BACKLIGHT_DEFAULT_ON)
#define GPIO_BACKLIGHT_DEFAULT_LEVEL GPIO_BACKLIGHT_ON_LEVEL
#else
#define GPIO_BACKLIGHT_DEFAULT_LEVEL 0
#endif
#endif // HAS_GPIO_BACKLIGHT
#if HAS_BACKLIGHT
namespace graphics
{
void backlightInit(); // configure the pin, settle the stored level, then drive it. Idempotent
void backlightSet(uint8_t level);
uint8_t backlightGet(); // configured level, unchanged by backlightOff()
bool backlightIsLit(); // what the hardware is being driven at right now
void backlightOn(); // drive the stored level
void backlightMomentaryOn(); // light it regardless of the stored level, for press-and-hold
void backlightOff(); // drive 0, leaving the stored level alone
void backlightToggle();
#if HAS_PWM_BACKLIGHT
void backlightStepUp();
void backlightStepDown();
#endif
} // namespace graphics
#endif // HAS_BACKLIGHT