Bringup target: AI-Thinker ESP32-A1S Audio Kit V2.2
(ES8388 codec). End target: custom PLIP PCB with Si3210
SLIC + RJ9 retro handset (per
docs/superpowers/specs/2026-04-08-plip-telephone-design.md).
Three FreeRTOS tasks share state via a queue:
- phone_task (core 1): off-hook GPIO interrupt + ring
- audio_task (core 0): drains command queue, routes to
ES8388 (dev kit) / Si3210 (PCB) via ESP32-audioI2S
- network_task (core 0): WiFi station + REST server
REST contract for the Zacus master ESP32 to drive PLIP:
- POST /ring {duration_ms}
- POST /play {source: "sd:/..." | "http://tower:8001/..."}
- POST /stop
- GET /status -> {off_hook, playing}
Pin assignments live in platformio.ini build_flags so the
dev kit -> PCB swap stays mechanical (just rewire to
Si3210 SPI + INT and switch the codec init in
audio_task).
MVP scope (option b in the brainstorm):
- ring on demand
- off-hook GPIO -> notify master
- MP3 playback from SD
- WiFi REST endpoint
Out of v1 (deliberately deferred):
- Bluetooth Classic A2DP/HFP (still in the design doc)
- Si3210 driver (when PCB lands)
- OTA via desktop FirmwareManager (after bringup stable)
Files:
- platformio.ini (espressif32@6.5.0, esp32dev board with
custom partitions + ESP32-A1S build flags)
- partitions/plip_4mb.csv (2x OTA app slots + LittleFS)
- src/main.cpp + 3 task .cpp files (skeleton, log-only)
- README.md (architecture, REST contract, pin map,
9-step roadmap, submodule conversion)
- CLAUDE.md (nested guidance for Claude Code)
- .gitignore
Inlined for now; convert to a git submodule once a remote
URL is provisioned (procedure documented in README).
Root CLAUDE.md "Firmware" surface and "Where to Look"
table updated.
Acceptance: directory layout + build config + skeleton
sources land. No compile validation in this commit
(PlatformIO not on the workstation per the Q1=ESP32-A1S
dev kit bringup decision).