diff --git a/firmware/src/brightness.cpp b/firmware/src/brightness.cpp new file mode 100644 index 0000000..03f26db --- /dev/null +++ b/firmware/src/brightness.cpp @@ -0,0 +1,39 @@ +#include "brightness.h" +#include "idle.h" +#include +#include + +// Four-step ramp. The default (index 2) is 200 — identical to the prior +// hard-coded DISPLAY_DEFAULT_BRIGHTNESS, so cycling is purely additive. +static const uint8_t LEVELS[] = {64, 128, 200, 255}; +#define LEVELS_COUNT (sizeof(LEVELS) / sizeof(LEVELS[0])) +#define DEFAULT_IDX 2 + +static uint8_t cur_idx = DEFAULT_IDX; + +void brightness_init(void) { + Preferences prefs; + prefs.begin("clawdmeter", true); + uint8_t saved_idx = prefs.getUChar("brt_idx", 0xFF); + prefs.end(); + + if (saved_idx < LEVELS_COUNT) cur_idx = saved_idx; + idle_set_awake_brightness(LEVELS[cur_idx]); + Serial.printf("Brightness init: level=%u (idx=%u)\n", LEVELS[cur_idx], cur_idx); +} + +void brightness_cycle(void) { + cur_idx = (cur_idx + 1) % LEVELS_COUNT; + + Preferences prefs; + prefs.begin("clawdmeter", false); + prefs.putUChar("brt_idx", cur_idx); + prefs.end(); + + idle_set_awake_brightness(LEVELS[cur_idx]); + Serial.printf("Brightness cycled: level=%u (idx=%u)\n", LEVELS[cur_idx], cur_idx); +} + +uint8_t brightness_get(void) { + return LEVELS[cur_idx]; +} diff --git a/firmware/src/brightness.h b/firmware/src/brightness.h new file mode 100644 index 0000000..c956507 --- /dev/null +++ b/firmware/src/brightness.h @@ -0,0 +1,10 @@ +#pragma once +#include + +// User-controlled display brightness, persisted to NVS. The middle (PWR) +// button short-press cycles through the levels via brightness_cycle(). +// idle owns the actual panel brightness, so this routes the chosen level +// through idle_set_awake_brightness(). +void brightness_init(void); // load saved level from NVS and apply +void brightness_cycle(void); // advance to next level, save, apply +uint8_t brightness_get(void); // current PWM level (0..255) diff --git a/firmware/src/idle.cpp b/firmware/src/idle.cpp index 9552e67..b491655 100644 --- a/firmware/src/idle.cpp +++ b/firmware/src/idle.cpp @@ -17,13 +17,14 @@ static uint32_t fade_started_ms = 0; static uint32_t fade_last_step_ms = 0; static uint8_t fade_from = DISPLAY_DEFAULT_BRIGHTNESS; static uint8_t fade_to = 0; +static uint8_t awake_brightness = DISPLAY_DEFAULT_BRIGHTNESS; // user-set "full" level (brightness.cpp) static void apply_brightness(uint8_t b) { display_hal_set_brightness(b); } static void begin_fade(uint8_t to, uint32_t now) { - fade_from = (to == 0) ? DISPLAY_DEFAULT_BRIGHTNESS : 0; + fade_from = (to == 0) ? awake_brightness : 0; fade_to = to; fade_started_ms = now; fade_last_step_ms = now; @@ -32,7 +33,14 @@ static void begin_fade(uint8_t to, uint32_t now) { void idle_init(void) { state = STATE_AWAKE; last_activity_ms = millis(); - apply_brightness(DISPLAY_DEFAULT_BRIGHTNESS); + apply_brightness(awake_brightness); +} + +void idle_set_awake_brightness(uint8_t level) { + awake_brightness = level; + // Apply now if fully awake so a button press is visible immediately; + // during fades/sleep the next fade-in picks it up. + if (state == STATE_AWAKE) apply_brightness(level); } void idle_note_activity(void) { @@ -41,7 +49,7 @@ void idle_note_activity(void) { if (state == STATE_AWAKE) return; // Asleep/fading-out shouldn't reach here in normal flow (callers gate via // idle_consume_wake_press first), but if it does: trigger a wake. - begin_fade(DISPLAY_DEFAULT_BRIGHTNESS, last_activity_ms); + begin_fade(awake_brightness, last_activity_ms); state = STATE_FADING_IN; } @@ -49,7 +57,7 @@ bool idle_consume_wake_press(void) { if (state == STATE_ASLEEP || state == STATE_FADING_OUT) { uint32_t now = millis(); last_activity_ms = now; - begin_fade(DISPLAY_DEFAULT_BRIGHTNESS, now); + begin_fade(awake_brightness, now); state = STATE_FADING_IN; return true; } @@ -75,7 +83,7 @@ void idle_tick(void) { if (!IDLE_SLEEP_WHEN_CHARGING && power_hal_is_vbus_in()) { last_activity_ms = now; if (state == STATE_ASLEEP || state == STATE_FADING_OUT) { - begin_fade(DISPLAY_DEFAULT_BRIGHTNESS, now); + begin_fade(awake_brightness, now); state = STATE_FADING_IN; } } diff --git a/firmware/src/idle.h b/firmware/src/idle.h index 0ce424c..4dd9c00 100644 --- a/firmware/src/idle.h +++ b/firmware/src/idle.h @@ -5,6 +5,12 @@ void idle_init(void); void idle_tick(void); void idle_note_activity(void); +// Set the "awake" brightness target (0..255). idle owns display brightness +// (it fades between this and 0), so user brightness control routes through +// here. Applied immediately if the screen is currently fully awake; otherwise +// picked up by the next fade-in. See brightness.{h,cpp}. +void idle_set_awake_brightness(uint8_t level); + // Returns true if this press was consumed as a wake-up (caller MUST skip the // button's normal action). Returns false when already awake — also notes the // activity, so callers don't need a separate idle_note_activity() call.