feat(plip): firmware skeleton on ES8388 dev kit
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).
This commit is contained in:
@@ -41,7 +41,9 @@ YAML scenario → compile_runtime3.py → Runtime 3 IR → ESP32 / Web player
|
|||||||
Key surfaces:
|
Key surfaces:
|
||||||
- **Scenario IR**: `game/scenarios/zacus_v2.yaml` → `tools/scenario/compile_runtime3.py` → portable Runtime 3 IR. Contract: `specs/ZACUS_RUNTIME_3_SPEC.md`.
|
- **Scenario IR**: `game/scenarios/zacus_v2.yaml` → `tools/scenario/compile_runtime3.py` → portable Runtime 3 IR. Contract: `specs/ZACUS_RUNTIME_3_SPEC.md`.
|
||||||
- **Authoring**: `frontend-v3/` (pnpm monorepo: `apps/atelier/` Scratch-like studio + `apps/dashboard/` game-master live view).
|
- **Authoring**: `frontend-v3/` (pnpm monorepo: `apps/atelier/` Scratch-like studio + `apps/dashboard/` game-master live view).
|
||||||
- **Firmware**: `ESP32_ZACUS/` submodule (separate repo, separate CI). Freenove ESP32-S3 + PlatformIO. NPC engine, voice pipeline, vision/QR, media manager.
|
- **Firmware**:
|
||||||
|
- `ESP32_ZACUS/` submodule — Freenove ESP32-S3 master (NPC engine, voice pipeline, vision/QR, media manager).
|
||||||
|
- `PLIP_FIRMWARE/` — retro telephone annex (ES8388 dev kit bringup, Si3210 PCB target). REST endpoint consumed by the master ESP32.
|
||||||
- **Voice / NPC**: Piper TTS on Tower:8001 (zacus voice = tom-medium). NPC phrases in `game/scenarios/npc_phrases.yaml`. MP3 pool generator: `tools/tts/generate_npc_pool.py`.
|
- **Voice / NPC**: Piper TTS on Tower:8001 (zacus voice = tom-medium). NPC phrases in `game/scenarios/npc_phrases.yaml`. MP3 pool generator: `tools/tts/generate_npc_pool.py`.
|
||||||
- **MCP hardware**: `tools/dev/mcp_hardware_server.py` (stdio, 6 tools).
|
- **MCP hardware**: `tools/dev/mcp_hardware_server.py` (stdio, 6 tools).
|
||||||
- **Desktop hub**: `desktop/` (Electron, macOS, bundles V3 frontends, talks USB serial).
|
- **Desktop hub**: `desktop/` (Electron, macOS, bundles V3 frontends, talks USB serial).
|
||||||
@@ -56,7 +58,8 @@ Key surfaces:
|
|||||||
| Zacus Studio macOS app | `desktop/` |
|
| Zacus Studio macOS app | `desktop/` |
|
||||||
| Add or change a contract spec | `specs/` |
|
| Add or change a contract spec | `specs/` |
|
||||||
| Python tests (Runtime 3, NPC) | `tests/` |
|
| Python tests (Runtime 3, NPC) | `tests/` |
|
||||||
| Firmware code | `ESP32_ZACUS/` submodule (own repo) |
|
| Firmware code (Zacus master) | `ESP32_ZACUS/` submodule (own repo) |
|
||||||
|
| Firmware code (PLIP retro phone) | `PLIP_FIRMWARE/` (inlined; see README for submodule conversion) |
|
||||||
|
|
||||||
## Canonical Files
|
## Canonical Files
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.pio/
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
build/
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# PLIP Firmware
|
||||||
|
|
||||||
|
ESP32 firmware for the retro telephone annex. Bringup target: ESP32-A1S
|
||||||
|
Audio Kit (ES8388 codec). End target: custom PCB with Si3210 SLIC.
|
||||||
|
|
||||||
|
See `README.md` for architecture, REST contract, pin map, and the
|
||||||
|
submodule conversion procedure when a remote URL is ready.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd PLIP_FIRMWARE
|
||||||
|
pio run # compile
|
||||||
|
pio run -t upload # flash via USB
|
||||||
|
pio device monitor # serial @ 115200
|
||||||
|
```
|
||||||
|
|
||||||
|
## Source layout
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|------|------|
|
||||||
|
| `src/main.cpp` | `setup()` boots the three FreeRTOS tasks |
|
||||||
|
| `src/phone_task.cpp` | Off-hook GPIO interrupt + ring control |
|
||||||
|
| `src/audio_task.cpp` | ES8388 / Si3210 audio routing, drains a command queue |
|
||||||
|
| `src/network_task.cpp` | WiFi station + REST server (`/ring`, `/play`, `/stop`, `/status`) |
|
||||||
|
|
||||||
|
## Anti-patterns
|
||||||
|
|
||||||
|
- Hardcoding pin numbers in source — they live in `platformio.ini`
|
||||||
|
`build_flags` so the dev kit ↔ PCB swap stays mechanical.
|
||||||
|
- Adding I2S/SPI calls outside `audio_task` or `phone_task` — codec
|
||||||
|
access must stay single-threaded per peripheral.
|
||||||
|
- Skipping NVS for WiFi credentials in committed code. Compile-time
|
||||||
|
defaults are OK for local bringup but never merge them.
|
||||||
|
- Implementing OTA before the bringup loop (REST `/ring` round-trip) is
|
||||||
|
rock solid — chasing OTA bugs on top of audio bugs is misery.
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
# PLIP firmware
|
||||||
|
|
||||||
|
Bringup target: **AI-Thinker ESP32-A1S Audio Kit V2.2** (ES8388 codec).
|
||||||
|
End target: the custom **PLIP-Téléphone** PCB with Si3210 SLIC + RJ9 retro
|
||||||
|
handset (see `../hardware/projects/plip-telephone/` and
|
||||||
|
`../docs/superpowers/specs/2026-04-08-plip-telephone-design.md`).
|
||||||
|
|
||||||
|
We start on the dev kit so the audio + network state machine can be
|
||||||
|
debugged without waiting for the PCB. The codec is swapped (ES8388 →
|
||||||
|
Si3210) on the PCB; everything else stays.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Three FreeRTOS tasks, message-passing through a queue:
|
||||||
|
|
||||||
|
| Task | Core | Stack | Role |
|
||||||
|
|------|------|-------|------|
|
||||||
|
| `phone` | 1 | 4096 | Off-hook GPIO interrupt (dev kit: BOOT button on GPIO4; PCB: Si3210 INT). Drives ring on the codec. |
|
||||||
|
| `audio` | 0 | 8192 | Drains `audio_command_queue`. Routes `Stop` / `PlaySdMp3` / `PlayHttpStream` through `ESP32-audioI2S`. |
|
||||||
|
| `network` | 0 | 8192 | WiFi station + REST endpoint. Translates HTTP requests into audio queue messages. |
|
||||||
|
|
||||||
|
## REST contract
|
||||||
|
|
||||||
|
The Zacus master ESP32 talks to PLIP over the LAN:
|
||||||
|
|
||||||
|
| Method | Path | Body | Effect |
|
||||||
|
|--------|------|------|--------|
|
||||||
|
| POST | `/ring` | `{"duration_ms": 4000}` | Trigger ring (SLIC -72V; dev kit: short audio beep) |
|
||||||
|
| POST | `/play` | `{"source": "sd:/intro.mp3"}` or `{"source": "http://tower:8001/zacus/welcome.wav"}` | Start playback |
|
||||||
|
| POST | `/stop` | — | Stop current playback |
|
||||||
|
| GET | `/status` | — | `{"off_hook": bool, "playing": bool}` |
|
||||||
|
|
||||||
|
The Piper TTS server on Tower:8001 streams WAV; the audio task consumes
|
||||||
|
it directly via the I2S library's `connecttohost`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd PLIP_FIRMWARE
|
||||||
|
pio run # compile
|
||||||
|
pio run -t upload # flash over USB
|
||||||
|
pio device monitor # serial monitor (115200 8N1)
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO will pull `espressif32@6.5.0` + Arduino framework + the audio
|
||||||
|
library on first build (~3 min).
|
||||||
|
|
||||||
|
## Pin map (dev kit)
|
||||||
|
|
||||||
|
Defined in `platformio.ini` build flags:
|
||||||
|
|
||||||
|
```
|
||||||
|
ES8388_ADDR = 0x10 (I2C)
|
||||||
|
IIS_BCLK = 27 (I2S bit clock)
|
||||||
|
IIS_LCLK = 26 (I2S word select)
|
||||||
|
IIS_DSIN = 25 (DAC in)
|
||||||
|
IIS_DOUT = 35 (ADC out)
|
||||||
|
SD_CS = 13
|
||||||
|
SD_MOSI = 15
|
||||||
|
SD_MISO = 2
|
||||||
|
SD_SCK = 14
|
||||||
|
OFF_HOOK_GPIO = 4 (BOOT/KEY1 stand-in)
|
||||||
|
```
|
||||||
|
|
||||||
|
When the PCB lands: rewire to Si3210 SPI + INT, swap the codec init in
|
||||||
|
`audio_task`, ring goes from "ES8388 beep" to "Si3210 ring control
|
||||||
|
register". The build_flags file is the only place pins live; source
|
||||||
|
code reads them via macros.
|
||||||
|
|
||||||
|
## MVP scope (Phase 3 = b in the brainstorm)
|
||||||
|
|
||||||
|
- Sonnerie (ring) on demand
|
||||||
|
- Off-hook GPIO interrupt → notify master
|
||||||
|
- MP3 playback from SD
|
||||||
|
- WiFi REST endpoint (4 routes above)
|
||||||
|
|
||||||
|
**Out of scope for v1**:
|
||||||
|
|
||||||
|
- Bluetooth Classic (A2DP sink + HFP) — the design doc specs it but the
|
||||||
|
bringup focus is REST + SD first.
|
||||||
|
- Si3210 driver — comes when the PCB arrives.
|
||||||
|
- OTA via the desktop FirmwareManager — comes after the bringup loop is
|
||||||
|
stable.
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
| Step | Goal | Status |
|
||||||
|
|------|------|--------|
|
||||||
|
| 0 | Skeleton (this commit) — tasks fire `Serial.println` only | ✅ |
|
||||||
|
| 1 | I2C + ES8388 init in audio task; play a 1 kHz tone on demand | TODO |
|
||||||
|
| 2 | SD card mount + MP3 file playback | TODO |
|
||||||
|
| 3 | WiFi station + REST `/ring` `/play` `/stop` `/status` | TODO |
|
||||||
|
| 4 | Off-hook button → REST status update | TODO |
|
||||||
|
| 5 | HTTP stream from Tower:8001 Piper TTS | TODO |
|
||||||
|
| 6 | NVS provisioning via desktop NvsConfigurator | TODO |
|
||||||
|
| 7 | OTA via desktop FirmwareManager | TODO |
|
||||||
|
| 8 | Port to Si3210 SLIC on the custom PCB | TODO |
|
||||||
|
| 9 | Bluetooth A2DP sink (game-master streaming) | TODO |
|
||||||
|
|
||||||
|
## Convert to a git submodule
|
||||||
|
|
||||||
|
The directory is currently inlined in the parent repo for convenience.
|
||||||
|
Once you have a remote URL ready:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Create a separate repo for PLIP_FIRMWARE on your Git host
|
||||||
|
# 2. From this directory:
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit"
|
||||||
|
git remote add origin <url>
|
||||||
|
git push -u origin main
|
||||||
|
|
||||||
|
# 3. From the parent repo (le-mystere-professeur-zacus):
|
||||||
|
git rm -r PLIP_FIRMWARE
|
||||||
|
git submodule add <url> PLIP_FIRMWARE
|
||||||
|
git commit -m "chore: PLIP_FIRMWARE -> submodule"
|
||||||
|
```
|
||||||
|
|
||||||
|
This mirrors the existing `ESP32_ZACUS/` submodule layout.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Partitions for PLIP firmware on 4 MB flash (ESP32-A1S Audio Kit)
|
||||||
|
# Layout: bootloader + 2 OTA app slots + LittleFS data
|
||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x180000,
|
||||||
|
app1, app, ota_1, 0x190000, 0x180000,
|
||||||
|
storage, data, spiffs, 0x310000, 0xF0000,
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
; PLIP firmware — bringup target: AI-Thinker ESP32-A1S Audio Kit V2.2
|
||||||
|
; Board has ES8388 codec, SD slot, dual mic, headphone + speaker out.
|
||||||
|
; Will retarget to the custom PCB (Si3210 SLIC) once it arrives.
|
||||||
|
|
||||||
|
[platformio]
|
||||||
|
default_envs = devkit_es8388
|
||||||
|
|
||||||
|
[env:devkit_es8388]
|
||||||
|
platform = espressif32@6.5.0
|
||||||
|
; AI-Thinker ESP32-A1S has no PlatformIO board entry. esp32dev is close
|
||||||
|
; enough; we override partitions and pins via build flags / source.
|
||||||
|
board = esp32dev
|
||||||
|
framework = arduino
|
||||||
|
board_build.flash_size = 4MB
|
||||||
|
board_build.partitions = partitions/plip_4mb.csv
|
||||||
|
board_build.filesystem = littlefs
|
||||||
|
monitor_speed = 115200
|
||||||
|
monitor_filters = time, esp32_exception_decoder
|
||||||
|
monitor_echo = yes
|
||||||
|
monitor_eol = LF
|
||||||
|
lib_deps =
|
||||||
|
esphome/ESP32-audioI2S@2.3.0
|
||||||
|
bblanchon/ArduinoJson@6.21.5
|
||||||
|
; ES8388 driver. Several Arduino ports exist; pick whichever the
|
||||||
|
; bringup engineer validates first.
|
||||||
|
schreibfaul1/ESP32-audioI2S@^2.0.0
|
||||||
|
build_flags =
|
||||||
|
-DCORE_DEBUG_LEVEL=3
|
||||||
|
; ES8388 I2C address on ESP32-A1S
|
||||||
|
-DES8388_ADDR=0x10
|
||||||
|
; I2S pins matching ESP32-A1S V2.2
|
||||||
|
-DIIS_BCLK=27
|
||||||
|
-DIIS_LCLK=26
|
||||||
|
-DIIS_DSIN=25
|
||||||
|
-DIIS_DOUT=35
|
||||||
|
; SD on SPI (HSPI on ESP32-A1S)
|
||||||
|
-DSD_CS=13
|
||||||
|
-DSD_MOSI=15
|
||||||
|
-DSD_MISO=2
|
||||||
|
-DSD_SCK=14
|
||||||
|
; Off-hook: dev kit board uses BOOT (KEY1, GPIO4) as a stand-in for
|
||||||
|
; the SLIC interrupt. Replace with GPIO4 from Si3210 INT on the PCB.
|
||||||
|
-DOFF_HOOK_GPIO=4
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// audio_task — drains an audio command queue and routes the source to
|
||||||
|
// ES8388 (dev kit) or Si3210 PCM (PCB).
|
||||||
|
//
|
||||||
|
// Sources:
|
||||||
|
// - SD MP3 via ESP32-audioI2S (file://...)
|
||||||
|
// - HTTP stream from Tower:8001 Piper TTS (http://... .wav/.mp3)
|
||||||
|
// - Future: A2DP sink (BT classic) — out of P3=b MVP scope.
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
QueueHandle_t g_queue = nullptr;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QueueHandle_t audio_command_queue() {
|
||||||
|
return g_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct AudioCommand {
|
||||||
|
enum Kind { Stop, PlaySdMp3, PlayHttpStream };
|
||||||
|
Kind kind;
|
||||||
|
char path[192];
|
||||||
|
};
|
||||||
|
|
||||||
|
void audio_task(void*) {
|
||||||
|
Serial.println(F("[audio] task ready, awaiting commands"));
|
||||||
|
AudioCommand cmd;
|
||||||
|
for (;;) {
|
||||||
|
if (xQueueReceive(g_queue, &cmd, pdMS_TO_TICKS(100)) == pdTRUE) {
|
||||||
|
switch (cmd.kind) {
|
||||||
|
case AudioCommand::Stop:
|
||||||
|
Serial.println(F("[audio] stop"));
|
||||||
|
// TODO(bringup): audio.stopSong();
|
||||||
|
break;
|
||||||
|
case AudioCommand::PlaySdMp3:
|
||||||
|
Serial.printf("[audio] sd: %s\n", cmd.path);
|
||||||
|
// TODO(bringup): audio.connecttoSD(cmd.path);
|
||||||
|
break;
|
||||||
|
case AudioCommand::PlayHttpStream:
|
||||||
|
Serial.printf("[audio] http: %s\n", cmd.path);
|
||||||
|
// TODO(bringup): audio.connecttohost(cmd.path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(bringup): audio.loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void start_audio_task() {
|
||||||
|
g_queue = xQueueCreate(8, sizeof(AudioCommand));
|
||||||
|
xTaskCreatePinnedToCore(audio_task, "audio", 8192, nullptr, 4, nullptr, 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// PLIP firmware — bringup skeleton on ESP32-A1S Audio Kit (ES8388 codec).
|
||||||
|
//
|
||||||
|
// Three FreeRTOS tasks share state via a queue:
|
||||||
|
// - phone_task: drives the ring + handles off-hook GPIO interrupt
|
||||||
|
// - audio_task: streams MP3 from SD or PCM from network to ES8388
|
||||||
|
// - network_task: WiFi + REST server (POST /ring, POST /play, /status)
|
||||||
|
//
|
||||||
|
// State transitions live in src/phone_state.cpp; they fire commands onto
|
||||||
|
// the audio queue. Network commands are translated to phone-state events.
|
||||||
|
//
|
||||||
|
// Pin assignments come from platformio.ini build flags so we can swap the
|
||||||
|
// dev kit for the Si3210 PCB without touching source.
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
extern void start_phone_task();
|
||||||
|
extern void start_audio_task();
|
||||||
|
extern void start_network_task();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(200);
|
||||||
|
Serial.println(F("[PLIP] boot — bringup skeleton (ES8388 dev kit)"));
|
||||||
|
|
||||||
|
// TODO(bringup): I2C init + ES8388 codec init before audio task starts.
|
||||||
|
// TODO(bringup): SD.begin() before audio task.
|
||||||
|
// TODO(bringup): WiFi.begin() inside network_task.
|
||||||
|
|
||||||
|
start_phone_task();
|
||||||
|
start_audio_task();
|
||||||
|
start_network_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// All work runs in FreeRTOS tasks. Idle loop is intentionally empty.
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// network_task — WiFi station + REST endpoint.
|
||||||
|
//
|
||||||
|
// REST contract (consumed by the Zacus master ESP32):
|
||||||
|
// POST /ring { "duration_ms": 4000 } -> trigger SLIC ring (or beep on dev kit)
|
||||||
|
// POST /play { "source": "sd:/intro.mp3" | "http://tower:8001/..." }
|
||||||
|
// POST /stop -> stop current playback
|
||||||
|
// GET /status -> { "off_hook": bool, "playing": bool }
|
||||||
|
//
|
||||||
|
// WiFi credentials come from NVS (provisioned via the desktop NvsConfigurator).
|
||||||
|
// The dev kit can fall back to compile-time defaults via build_flags for
|
||||||
|
// quick bringup; remove them once the desktop NVS flow is wired.
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void network_task(void*) {
|
||||||
|
Serial.println(F("[net] task ready"));
|
||||||
|
// TODO(bringup): WiFi.begin(ssid, password) using NVS-provisioned creds.
|
||||||
|
// TODO(bringup): wait for IP, advertise via mDNS as plip.local.
|
||||||
|
// TODO(bringup): start ESPAsyncWebServer with the 4 handlers above.
|
||||||
|
for (;;) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void start_network_task() {
|
||||||
|
xTaskCreatePinnedToCore(network_task, "net", 8192, nullptr, 3, nullptr, 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// phone_task — ring control + off-hook GPIO interrupt.
|
||||||
|
//
|
||||||
|
// On the ESP32-A1S dev kit the SLIC is replaced by an ES8388 audio path
|
||||||
|
// and a button (BOOT/KEY1) acting as a stand-in for the off-hook signal.
|
||||||
|
// On the Si3210 PCB the same task drives ring control over SPI and
|
||||||
|
// listens to Si3210 INT for off-hook / on-hook transitions.
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
extern QueueHandle_t audio_command_queue(); // audio_task.cpp
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
volatile bool g_off_hook_pending = false;
|
||||||
|
|
||||||
|
void IRAM_ATTR on_off_hook_isr() {
|
||||||
|
g_off_hook_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void phone_task(void*) {
|
||||||
|
pinMode(OFF_HOOK_GPIO, INPUT_PULLUP);
|
||||||
|
attachInterrupt(digitalPinToInterrupt(OFF_HOOK_GPIO), on_off_hook_isr, FALLING);
|
||||||
|
Serial.println(F("[phone] task ready, watching off-hook"));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (g_off_hook_pending) {
|
||||||
|
g_off_hook_pending = false;
|
||||||
|
Serial.println(F("[phone] off-hook detected"));
|
||||||
|
// TODO(bringup): debounce in software; SLIC INT will already debounce
|
||||||
|
// in hardware but the dev kit button needs ~30 ms.
|
||||||
|
// TODO(bringup): notify network_task so the Zacus master sees the event.
|
||||||
|
// TODO(bringup): tell audio_task to start the appropriate audio cue.
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void start_phone_task() {
|
||||||
|
xTaskCreatePinnedToCore(phone_task, "phone", 4096, nullptr, 5, nullptr, 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user