Project overview

Spangap is built out of straddles — self-contained modules that each bundle their metadata, an ESP-IDF firmware component and (where relevant) a browser NPM package. The build system stitches the ones you select into a single firmware image and a single web app. The platform straddles below are the foundation every device gets; this is the map of which straddle owns what.

The build system

spangap — the build system and command-line tool itself. A single-file launcher that provisions a Docker build container, resolves straddle dependencies, stages the firmware/browser/LCD halves, gates Kconfig, generates the boot glue, and drives flashing and the serial monitor from a small Python venv. All the host needs is Docker, git and Python 3.

The base runtime

spangap-core — the firmware runtime every device links; its symbols read as language primitives (empty prefix). It owns the platform subsystems:

  • init — the boot dispatcher that brings straddles up in ordered bands, from build-generated glue (no hand-written app_main).
  • storage — the hierarchical value store that synchronizes device (cJSON) ↔ browser (Pinia): set net.wifi.enable=1 in the CLI moves the toggle in the web UI and on the LCD.
  • its — Inter-Task Streaming, the notification-based IPC that lets tasks exchange streams and queues without polling. The primitive the whole platform is built on.
  • fs — the flash/SD filesystem service (LittleFS), run on a DRAM-stacked task so other tasks can keep their stacks in PSRAM.
  • cli — the unix-like command line, reachable over serial, web and SSH.
  • auth — credential/session realms (such as the admin password) that the CLI, web and SSH gates enforce.
  • cron — the scheduled/periodic job runner.
  • logging — the device log and its relay/paste plumbing.
  • power-management — RTOS-integrated tickless idle, so the chip sleeps while tasks are blocked.
  • memory — the central allocator and heap tooling.
  • idf-tweaks, ota (signed firmware updates), plus cross-cutting flash-partitions and remote-access handling.

Networking and the browser

spangap-net — the IP stack, pulled in by anything needing WiFi or the Internet. Subsystems: net (WiFi STA/AP state machine, TCP/UDP relay, event bus, wget), tls (shared mbedTLS server with hot cert reload), ntp (time sync, date) and mdns (<host>.local). Owns the well-known port config keys, and bundles the remote-access services below by default.

spangap-web — the device web stack and browser shell. Subsystems: web (HTTPS server, file serving, WebDAV, cookie-session auth), webrtc (the DataChannel plumbing carrying every device↔browser path) and the browser-shell SPA (Dock launcher, generated settings panels, config sync, login/setup). At build time it folds every other straddle’s browser/ half into one web app.

spangap-lcd — the on-device phone-style UI (LVGL v9): status bar, scrolling launcher, recents switcher, and built-in Settings, Log and CLI apps, plus a libvterm VT100 terminal. Straddles register their own LCD apps and settings panes through its API; input stays board-specific via an lcd_input_t HAL.

Built on those five

viewer — a tiny HTML/Markdown document reader (READMEs, help, CHANGELOGs), with an LCD “Info” app and a Web “Viewer” app.

audio — a generic I2S full-duplex audio engine and packet server (live-mic streaming, mixing, WAV playback) exposed over a browser DataChannel.

tinylcd — the small-display counterpart to spangap-lcd: a paged status display on a monochrome OLED/LCD over u8g2, one page per straddle, advanced by a button. For a board with a screen too small for a phone-style UI.

Generic peripheral straddles

Each owns one part and couples to everything else only over the storage bus. A board stages the ones it has and supplies their pins as Kconfig.

  • gps — a GNSS receiver (u-blox M10 or Quectel L76K, told apart by autobaud): NMEA parsing, receiver power management, and clock discipline as a time authority.
  • spangap-rtc — a PCF8563 battery-backed wall clock: adopted at boot, mirrored from the system clock while a live time authority is running, and keeping time once that authority goes quiet.
  • imu — a QMI8658 accelerometer in Wake-on-Motion, answering one question: is this device moving? Its first consumer is gps, which stops tracking a device that is standing still.

Board support

hw-lilygo-tdeck — the board-support (HAL) straddle for the LilyGo T-Deck Plus: power/CS bring-up, the input HAL, battery monitor, microSD and pin maps (the GNSS receiver itself is the gps straddle, which this board stages). It is non-buildable — it makes the board usable but decides nothing about what the device does. The hw-* family covers the other supported boards the same way; they are listed with their radios and peripherals on the Reticulous site.

Remote-access services

Bundled by spangap-net by default, each independent.

  • acme — ACMEv2 client that fetches and renews publicly-trusted TLS certs (Let’s Encrypt) via DNS-01 or HTTP-01.
  • duckdns — DuckDNS dynamic-DNS updater; also publishes the TXT record acme needs for DNS-01.
  • upnp — UPnP-IGD port mapping so the HTTPS and WebRTC ports are reachable through NAT.
  • wg — a WireGuard client tunnel, the CG-NAT-friendly alternative to upnp + duckdns + acme.
  • sshd — an SSH-2 server and client that bridge into the cli and log (post-quantum key exchange, publickey or password auth).

And the mesh stack

The mesh-networking straddles — the Reticulum stack (rns), the LoRa, TCP, ESP-NOW and Auto interfaces, LXMF messaging, Nomad browsing and more — live in the sibling Reticulous project, the reference application built on this platform.