src.nth.io/

summaryrefslogtreecommitdiff
path: root/main/state_machine.c
diff options
context:
space:
mode:
authorLuke Hoersten <[email protected]>2026-06-14 15:53:33 -0500
committerLuke Hoersten <[email protected]>2026-06-14 15:53:33 -0500
commitd5cdb6b4e4424d80ac9bfd8e12c129334c23d6f2 (patch)
treef9b5e838061f76af8160863548758311857b1c75 /main/state_machine.c
parent8d740665777af6d74b334e2dee98a53ebb9a29aa (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/state_machine.c')
-rw-r--r--main/state_machine.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/main/state_machine.c b/main/state_machine.c
index 8f0b3e1..c9e4367 100644
--- a/main/state_machine.c
+++ b/main/state_machine.c
@@ -50,24 +50,25 @@ esp_err_t state_machine_set(viewport_run_state_t target)
viewport_state_lock();
viewport_state_t *st = viewport_state_get();
- if (!st->configured) {
- viewport_state_unlock();
- return ESP_ERR_INVALID_STATE;
- }
if (st->state == target) {
viewport_state_unlock();
return ESP_OK; // idempotent no-op
}
st->state = target;
+ bool configured = st->configured;
viewport_state_unlock();
if (target == VIEWPORT_STATE_AWAKE) {
if (display_is_up()) {
display_wake();
- local_screens_show_loading(); // until next /frame paints
+ // Content choice: configured devices show "Loading…" until
+ // Scrypted pushes a /frame; unconfigured devices show the
+ // identity screen since there's no Scrypted to push anything.
+ if (configured) local_screens_show_loading();
+ else local_screens_show_ip();
}
arm_idle_timer_unlocked();
- ESP_LOGI(TAG, "AWAKE");
+ ESP_LOGI(TAG, "AWAKE (%s)", configured ? "configured" : "unconfigured");
} else {
disarm_idle_timer();
if (display_is_up()) display_sleep();
@@ -86,12 +87,14 @@ void state_machine_frame_painted(void)
void state_machine_set_local(viewport_run_state_t target)
{
- // For idempotent no-op (already in target), state_machine_set returns OK
- // without changing state; we still call state_client to keep Scrypted in
- // sync if it's drifted. State POSTs are idempotent on both ends.
esp_err_t err = state_machine_set(target);
- if (err != ESP_OK) return; // unconfigured / invalid
- state_client_post(target);
+ if (err != ESP_OK) return;
+ // Only POST when there's a Scrypted to talk to. Unconfigured tap toggles
+ // change the local display state without notifying anyone.
+ viewport_state_lock();
+ bool configured = viewport_state_get()->configured;
+ viewport_state_unlock();
+ if (configured) state_client_post(target);
}
viewport_run_state_t state_machine_current(void)