<feed xmlns='http://www.w3.org/2005/Atom'>
<title>luke/esp32-poe-scrypted-viewport/main/local_screens.h, branch main</title>
<subtitle>ESP32-POE Scrypted viewport (private)
</subtitle>
<id>https://src.nth.io/luke/esp32-poe-scrypted-viewport/atom?h=main</id>
<link rel='self' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/'/>
<updated>2026-06-14T22:37:51+00:00</updated>
<entry>
<title>Info screen: full /config + /state dump, replaces identity screen</title>
<updated>2026-06-14T22:37:51+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-06-14T22:37:51+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/commit/?id=cbc4904aa35191f59aff93df5ed36f09f4cfa943'/>
<id>urn:sha1:cbc4904aa35191f59aff93df5ed36f09f4cfa943</id>
<content type='text'>
Previously the 4-line "identity" screen showed only viewport name, mDNS
host, IP, and state. Expanded to 15 lines covering the full GET /config
+ GET /state output (name, host, ip, state, configured, scrypted,
orientation, brightness, idle, fw, uptime, frames, errs, free heap,
free PSRAM), label/value pairs left-aligned with auto-scaled font.

Renames "identity" → "info" throughout — symbol, log messages,
README/TESTING references.

Also:
- Move the info-screen render's big locals (~1.6 KiB: lines[16][80] +
  scrypt[256] + vp_name[64]) to BSS. The touch task's 3 KiB stack
  was overflowing on every long-press, leaving whatever frame was
  previously on the panel — gave the appearance of a "blue screen"
  after the M5 test pattern.
- Drop the ≥5 s touch factory-reset gesture and remove all stale
  references to it in docs and comments. NVS wipe is now a USB-side
  `idf.py erase-flash` operation only.
- M5 follow-up TODO in jpeg_decoder.c: solid green renders ~black and
  solid blue renders green; not a byte-order issue (BGR setting turns
  red into blue). Tracked as a known M5 gap.
</content>
</entry>
<entry>
<title>M3 done: drop boot test, fold BOOT button into touch long-press</title>
<updated>2026-06-14T21:41:03+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-06-14T21:41:03+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/commit/?id=c6ce4b3f46a1f1adf700306dadc9034a6a2ac0d3'/>
<id>urn:sha1:c6ce4b3f46a1f1adf700306dadc9034a6a2ac0d3</id>
<content type='text'>
The Waveshare ESP32-P4-ETH board exposes BOOT on GPIO 35, but at runtime
that pin is owned by the EMAC TXD1 signal. No usable GPIO is wired to a
separate user button, so the BOOT-button task could never fire.

Move both BOOT-button behaviours onto the touch panel:
  - ≥1.5s hold → 15s identity overlay (was BOOT short-press)
  - ≥5s hold   → factory reset (was BOOT long-hold)
Short tap (&lt;500ms) still toggles wake/sleep. Long-press fires while the
finger is still down so the user gets immediate feedback at each
threshold.

Also strip the R/G/B 6 s boot test sequence — the panel now renders
correctly, so it's no longer useful diagnostically.

Boot subsystem flags drop the trailing B column: [EMHDJT].
</content>
</entry>
<entry>
<title>M3 WIP: DSI bring-up + state machine + identity overlay</title>
<updated>2026-06-14T20:53:33+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-06-14T20:53:33+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/commit/?id=d5cdb6b4e4424d80ac9bfd8e12c129334c23d6f2'/>
<id>urn:sha1:d5cdb6b4e4424d80ac9bfd8e12c129334c23d6f2</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>Identity screen: name + hostname + IP + state, auto-scaled</title>
<updated>2026-06-14T16:39:08+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-06-14T16:39:08+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/commit/?id=b22d05901dee4000ee012af470ddf898579257ae'/>
<id>urn:sha1:b22d05901dee4000ee012af470ddf898579257ae</id>
<content type='text'>
local_screens_show_ip() now renders four lines instead of two —
all the device's runtime identity at once:

  line 1: viewport name      ("mudroom"  / "viewport" if unconfigured)
  line 2: mDNS hostname      ("viewport-mudroom.local" / "viewport.local")
  line 3: IP                 ("192.168.1.42" / "no network")
  line 4: state              ("awake" / "asleep" / "unconfigured")

Same screen is shown on first boot, after factory reset, and as a
15s BOOT short-press overlay — operator always has the device's full
identity one button-press away (find it on the LAN, confirm name +
configuration without curling).

Font scale is auto-picked: the largest integer scale (1×–6×) where
the longest line fits within 90% of width AND all four lines plus
inter-line spacing fit within 90% of height. Works for both portrait
(480×800) and landscape (800×480) without separate code paths.

Font expanded to cover the new strings:
- All lowercase a–z (added b, f, h, j, k, m, q, s, u, x, y, z).
- Punctuation: dash, slash (digits, period, colon already covered).

Fallback policy unchanged: unsupported chars render as blank, which
keeps the table tight and the failure mode visible rather than
crashing.

README "Local rendering" + TESTING.md M8 updated to describe the
four-line identity layout and show both the unconfigured-boot and
configured-overlay example outputs.

Build verified clean against ESP-IDF 5.4 (binary ~873 KB, +1.6 KB
for the expanded font).
</content>
</entry>
<entry>
<title>M8: local screens (IP + Loading) + BOOT button</title>
<updated>2026-06-14T04:15:27+00:00</updated>
<author>
<name>Luke Hoersten</name>
<email>luke@hoersten.org</email>
</author>
<published>2026-06-14T04:15:27+00:00</published>
<link rel='alternate' type='text/html' href='https://src.nth.io/luke/esp32-poe-scrypted-viewport/commit/?id=fdb8a1299eafdedf68902c4c785f9fb0390e80c4'/>
<id>urn:sha1:fdb8a1299eafdedf68902c4c785f9fb0390e80c4</id>
<content type='text'>
local_screens.{h,c}:
- Embedded 8x8 bitmap font sized to a 95-char table; only the glyphs
  used by today's strings (viewport.local, the IPv4 string, Loading...)
  are populated. Unsupported chars render blank.
- 768 KB PSRAM scratch FB at panel-native dims.
- local_screens_show_ip() — two centered lines:
    "viewport.local"
    &lt;current IP&gt;
  Scale 3x portrait / 4x landscape; centered vertically.
- local_screens_show_loading() — centered "Loading..." at scale 4x/5x.
- local_screens_restore_for_state() — repaint after BOOT-overlay expiry:
  UNCONFIGURED -&gt; IP screen; AWAKE/ASLEEP -&gt; black FB (next /frame or
  sleep handles the rest).
- All paths go through display_present_rgb565() so orientation rotation
  is automatic.

button.{h,c}:
- Polling task at 30ms, active-low with internal pull-up.
- Short press (&lt;5s, released) → backlight on, IP overlay for 15s via
  esp_timer one-shot, then restore.
- Hold ≥ 5s → nvs_config_reset() + esp_restart().
- PIN_BOOT_BUTTON = GPIO 0 is a TODO placeholder. ESP32-P4 strap pin
  GPIO35 is owned by RMII TXD1 at runtime so Waveshare must expose a
  separate user button on a free pin; confirm against the schematic.
  Fail-soft if mis-wired: input reads stuck-high and the task never
  fires.

state_machine on AWAKE transition now calls local_screens_show_loading()
right after display_wake() — so every wake (tap or POST /state) flashes
a clear "Loading..." until the next /frame paints over it.

app_main on boot:
- Calls local_screens_init() after display_init().
- UNCONFIGURED → paint IP screen (replaces the M3 test pattern).
- ASLEEP → backlight off (unchanged).
- After all subsystems: button_init().

Build clean against ESP-IDF 5.4 (binary ~870 KB; the font/glyph data is
under 800 bytes).

TESTING.md M8 documents the visual checks, the BOOT-pin placeholder
caveat, the AWAKE-overlay-overwrite behavior, the open follow-up about
post-overlay backlight when ASLEEP, and the font fallback policy.
</content>
</entry>
</feed>
