diff options
| author | Luke Hoersten <[email protected]> | 2026-06-14 15:53:33 -0500 |
|---|---|---|
| committer | Luke Hoersten <[email protected]> | 2026-06-14 15:53:33 -0500 |
| commit | d5cdb6b4e4424d80ac9bfd8e12c129334c23d6f2 (patch) | |
| tree | f9b5e838061f76af8160863548758311857b1c75 /main/local_screens.c | |
| parent | 8d740665777af6d74b334e2dee98a53ebb9a29aa (diff) | |
M3 WIP: DSI bring-up + state machine + identity overlay
DSI / panel:
- LDO_VO3 acquired at 2500 mV (VDD_MIPI_DPHY) — without this the PHY
PLL busy-waits forever inside esp_lcd_new_dsi_bus.
- PSRAM bumped to 200 MHz (CONFIG_IDF_EXPERIMENTAL_FEATURES) to keep
the DPI fed without underruns.
- Pi-7"-style 800x480 panel init (REG_POWERON, PORTA/PORTB/PWM/PORTC)
+ 16-bit RGB565 framebuffer with portrait-mode rotation buffer in
PSRAM. Currently shows garbled output — known issue, next commit
switches to the TC358762-bridge-aware init sequence.
State + UX:
- viewport_state simplified to AWAKE/ASLEEP only; "unconfigured" is
a flag, not a state. Tap always toggles; content choice (identity
vs frame) is driven by the configured flag.
- BOOT button arms a 15 s identity overlay via local_screens_overlay;
expired callback returns to prior state.
- Boot-done indicator: two backlight flashes (no usable LED GPIO on
the Waveshare board — GPIO 35 BOOT is shared with EMAC TXD1).
- Best-effort subsystem init in app_main; display init deferred to
its own task so a panel hang can't block networking.
Display test pattern: solid R/G/B for 2 s each on boot to characterize
the garble independent of text rendering.
Diffstat (limited to 'main/local_screens.c')
| -rw-r--r-- | main/local_screens.c | 68 |
1 files changed, 50 insertions, 18 deletions
diff --git a/main/local_screens.c b/main/local_screens.c index 5167d9d..34c242c 100644 --- a/main/local_screens.c +++ b/main/local_screens.c @@ -4,6 +4,7 @@ #include "esp_heap_caps.h" #include "esp_log.h" +#include "esp_timer.h" #include "display.h" #include "net_eth.h" @@ -71,7 +72,9 @@ static const uint8_t FONT[95][8] = { #define FG 0xFFFF // white #define BG 0x0000 // black -static uint16_t *s_fb; // PSRAM scratch at PANEL_W × PANEL_H +static uint16_t *s_fb; // PSRAM scratch at PANEL_W × PANEL_H +static esp_timer_handle_t s_overlay_timer; +static volatile bool s_overlay_active; static void clear(uint16_t color) { @@ -125,6 +128,8 @@ static void draw_centered(uint16_t fb_w, uint16_t fb_h, int y, } } +static void overlay_expired_cb(void *arg); + esp_err_t local_screens_init(void) { s_fb = (uint16_t *)heap_caps_malloc(MAX_BUF_PX * sizeof(uint16_t), @@ -133,9 +138,53 @@ esp_err_t local_screens_init(void) ESP_LOGE(TAG, "PSRAM alloc failed for scratch FB"); return ESP_ERR_NO_MEM; } + esp_timer_create_args_t args = { + .callback = &overlay_expired_cb, + .name = "ident_overlay", + }; + esp_timer_create(&args, &s_overlay_timer); return ESP_OK; } +static void overlay_expired_cb(void *arg) +{ + s_overlay_active = false; + // Backlight off after the overlay. Whether the device is UNCONFIGURED + // or ASLEEP, the result is the same: dark panel until next interaction. + // For AWAKE we leave the backlight on — Scrypted's next /frame + // overwrites the overlay anyway. + viewport_state_lock(); + viewport_run_state_t s = viewport_state_get()->state; + viewport_state_unlock(); + if (s != VIEWPORT_STATE_AWAKE && display_is_up()) { + display_sleep(); + } +} + +esp_err_t local_screens_overlay(uint32_t duration_ms) +{ + if (!display_is_up()) return ESP_ERR_INVALID_STATE; + esp_timer_stop(s_overlay_timer); + display_wake(); + esp_err_t err = local_screens_show_ip(); + if (err != ESP_OK) return err; + s_overlay_active = true; + return esp_timer_start_once(s_overlay_timer, + (uint64_t)duration_ms * 1000ULL); +} + +bool local_screens_overlay_active(void) +{ + return s_overlay_active; +} + +void local_screens_overlay_dismiss(void) +{ + esp_timer_stop(s_overlay_timer); + s_overlay_active = false; + if (display_is_up()) display_sleep(); +} + esp_err_t local_screens_show_ip(void) { if (!s_fb) return ESP_ERR_INVALID_STATE; @@ -225,20 +274,3 @@ esp_err_t local_screens_show_loading(void) return display_present_rgb565(s_fb, w, h); } -esp_err_t local_screens_restore_for_state(void) -{ - if (!s_fb) return ESP_ERR_INVALID_STATE; - - viewport_state_lock(); - viewport_run_state_t s = viewport_state_get()->state; - viewport_state_unlock(); - - if (s == VIEWPORT_STATE_UNCONFIGURED) return local_screens_show_ip(); - - // Awake or asleep: clear the FB to black. For asleep the backlight is - // off anyway; for awake the next /frame will overwrite. - uint16_t w, h; - effective_dims(&w, &h); - clear(BG); - return display_present_rgb565(s_fb, w, h); -} |
