diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 5862bfb..ea13a2d 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -8,10 +8,10 @@ ### Firmware - [x] **FW-01**: ESP32-C3 treibt WS2801 (160 LEDs, SPI) und SK6812 (300 LEDs, RMT/RGBW) gleichzeitig an -- [ ] **FW-02**: ESP32-C3 empfaengt JSON-Kommandos ueber UDP und fuehrt benannte Animationen aus +- [x] **FW-02**: ESP32-C3 empfaengt JSON-Kommandos ueber UDP und fuehrt benannte Animationen aus - [ ] **FW-03**: Mindestens 8 Built-in-Animationen (Chase, Pulse, Rainbow, Strobe, Color Wash, Breathe, Sparkle, Gradient Sweep) - [ ] **FW-04**: Jede Animation akzeptiert konfigurierbare Parameter (Farbe/RGBW, Speed, Intensitaet) -- [ ] **FW-05**: Beide LED-Zonen (Schrank/Wand) sind unabhaengig steuerbar ueber das JSON-Protokoll +- [x] **FW-05**: Beide LED-Zonen (Schrank/Wand) sind unabhaengig steuerbar ueber das JSON-Protokoll ### Audio @@ -78,10 +78,10 @@ | Requirement | Phase | Status | |-------------|-------|--------| | FW-01 | Phase 1 | Complete | -| FW-02 | Phase 1 | Pending | +| FW-02 | Phase 1 | Complete | | FW-03 | Phase 1 | Pending | | FW-04 | Phase 1 | Pending | -| FW-05 | Phase 1 | Pending | +| FW-05 | Phase 1 | Complete | | AUD-01 | Phase 2 | Pending | | AUD-02 | Phase 2 | Pending | | AUD-03 | Phase 2 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 457e4c3..4d9d8de 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -33,7 +33,7 @@ Decimal phases appear between their surrounding integers in numeric order. Plans: - [x] 01-01-PLAN.md — PlatformIO scaffold, dual LED driver, WiFi+RMT coexistence validation -- [ ] 01-02-PLAN.md — UDP server, JSON protocol parser, FreeRTOS command queue +- [x] 01-02-PLAN.md — UDP server, JSON protocol parser, FreeRTOS command queue - [ ] 01-03-PLAN.md — Animation engine (50fps FreeRTOS), all 8 built-in animations - [ ] 01-04-PLAN.md — System integration, final wiring, hardware acceptance checkpoint @@ -79,7 +79,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. ESP32 Firmware | 1/4 | In Progress| | +| 1. ESP32 Firmware | 2/4 | In Progress| | | 2. App Core + Audio | 0/? | Not started | - | | 3. Choreography TUI | 0/? | Not started | - | | 4. Live Reactive + Spotify | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 91dd973..add3a5a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 01-01-PLAN.md (4/4 tasks) — hardware checkpoint approved, plan complete -last_updated: "2026-04-03T11:21:33.574Z" +stopped_at: Completed 01-02-PLAN.md (2/2 tasks) — protocol.h/.cpp and wifi_server.h/.cpp implemented +last_updated: "2026-04-03T11:27:16.228Z" last_activity: 2026-04-03 progress: total_phases: 4 completed_phases: 0 total_plans: 4 - completed_plans: 1 + completed_plans: 2 percent: 0 --- @@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position Phase: 01 (esp32-firmware) — EXECUTING -Plan: 3 of 4 +Plan: 4 of 4 Status: Ready to execute Last activity: 2026-04-03 @@ -54,6 +54,7 @@ Progress: [░░░░░░░░░░] 0% *Updated after each plan completion* | Phase 01-esp32-firmware P01 | 3 | 3 tasks | 6 files | | Phase 01-esp32-firmware P01 | 21min | 4 tasks | 7 files | +| Phase 01-esp32-firmware P02 | 3min | 2 tasks | 5 files | ## Accumulated Context @@ -70,6 +71,9 @@ Recent decisions affecting current work: - [Phase 01-esp32-firmware]: -DESP32_ARDUINO_NO_RGB_BUILTIN mandatory in platformio.ini to prevent RMT driver conflict with Arduino core 3.x - [Phase 01-esp32-firmware]: Hardware coexistence validated: WIFI_PS_NONE eliminates RMT flicker on ESP32-C3, zero flicker confirmed during 30s UDP burst test - [Phase 01-esp32-firmware]: GPIO3/6/7 pin assignments confirmed on physical hardware — no JTAG conflicts, fallback GPIO0/1 not needed +- [Phase 01-esp32-firmware]: Two-queue FreeRTOS pattern: xQueueSendFromISR in AsyncUDP callback, parseTask drains rawQueue and dispatches LedCommand to commandQueue — prevents watchdog resets from JSON heap alloc in callback +- [Phase 01-esp32-firmware]: STATUS cmd handled inline in parseTask (no animation engine route) — needs sender IP/port from raw packet context, responds via udp.writeTo() +- [Phase 01-esp32-firmware]: parseCommand() enforces brightness cap (max 60%) per D-09 — firmware-side safety cap regardless of Pi value ### Pending Todos @@ -84,6 +88,6 @@ None yet. ## Session Continuity -Last session: 2026-04-03T11:21:33.565Z -Stopped at: Completed 01-01-PLAN.md (4/4 tasks) — hardware checkpoint approved, plan complete +Last session: 2026-04-03T11:27:16.219Z +Stopped at: Completed 01-02-PLAN.md (2/2 tasks) — protocol.h/.cpp and wifi_server.h/.cpp implemented Resume file: None diff --git a/.planning/phases/01-esp32-firmware/01-02-SUMMARY.md b/.planning/phases/01-esp32-firmware/01-02-SUMMARY.md new file mode 100644 index 0000000..cdc23a6 --- /dev/null +++ b/.planning/phases/01-esp32-firmware/01-02-SUMMARY.md @@ -0,0 +1,166 @@ +--- +phase: 01-esp32-firmware +plan: "02" +subsystem: firmware +tags: [esp32, arduinojson, asyncudp, freertos, udp, json, led, protocol] + +# Dependency graph +requires: + - phase: 01-esp32-firmware/01-01 + provides: config.h (UDP_PORT, STACK_WIFI, PRIORITY_WIFI_RECV), led_driver.h, main.cpp WiFi scaffold + +provides: + - LedCommand struct with CmdType, Zone, AnimParams for animation engine consumption + - parseCommand() — ArduinoJson v7 JSON deserialization, zone routing, color parsing + - buildStatusResponse() — JSON status reply builder + - startUdpServer() — AsyncUDP listener with two-queue FreeRTOS pattern + - commandQueue (extern QueueHandle_t) — channel from UDP layer to animation engine + +affects: + - 01-esp32-firmware/01-03 (animation engine reads commandQueue and LedCommand structs) + - 02-pi-transport (Pi-side must implement the exact JSON schema defined here) + +# Tech tracking +tech-stack: + added: + - ArduinoJson 7.4.x (JsonDocument, deserializeJson, serializeJson) + - AsyncUDP (arduino-esp32 stdlib, udp.listen, onPacket callback) + patterns: + - Two-queue pattern: AsyncUDP callback -> rawQueue (ISR-safe) -> parseTask -> commandQueue + - Never parse JSON in AsyncUDP callback (heap allocation = watchdog reset risk) + - STATUS command handled inline in parseTask (no animation engine involved) + +key-files: + created: + - firmware/src/protocol.h + - firmware/src/protocol.cpp + - firmware/src/wifi_server.h + - firmware/src/wifi_server.cpp + modified: + - firmware/src/main.cpp + +key-decisions: + - "Two-queue pattern (rawQueue -> parseTask -> commandQueue) to avoid JSON parsing in AsyncUDP callback (watchdog risk per RESEARCH Pattern 2)" + - "STATUS cmd handled inline in parseTask: buildStatusResponse() sends UDP reply directly without routing through animation engine" + - "Brightness value clamped to 0-60 in parseCommand() enforcing D-09 firmware cap" + - "Zone is mandatory for ANIMATION/STOP/BRIGHTNESS but not STATUS (STATUS responds for all zones)" + - "Default RGBW color [255,255,255,255] applied when params.colors absent in animation command" + +patterns-established: + - "Pattern: Two-queue FreeRTOS — ISR-safe xQueueSendFromISR in callback, xQueueReceive + portMAX_DELAY in task" + - "Pattern: parseCommand() returns bool — false = drop packet, log to Serial, no UDP error response (D-07)" + - "Pattern: LedCommand carries senderIP/senderPort for STATUS replies" + +requirements-completed: [FW-02, FW-05] + +# Metrics +duration: 3min +completed: 2026-04-03 +--- + +# Phase 01 Plan 02: UDP Command Receiver and JSON Protocol Parser Summary + +**AsyncUDP listener with two-queue FreeRTOS pattern — raw bytes via xQueueSendFromISR, JSON deserialized in parseTask, LedCommand structs dispatched to commandQueue for animation engine** + +## Performance + +- **Duration:** 3 min +- **Started:** 2026-04-03T11:22:48Z +- **Completed:** 2026-04-03T11:25:43Z +- **Tasks:** 2 +- **Files modified:** 5 + +## Accomplishments +- Full protocol type system: LedCommand, AnimParams, Zone, CmdType enums with all fields from interface spec +- parseCommand() implements version check (v:1), zone routing (schrank/wand/all), full animation params parsing including RGBW color arrays +- wifi_server.cpp uses the two-queue pattern from RESEARCH.md Pattern 2: AsyncUDP callback never parses JSON, only copies bytes via xQueueSendFromISR +- STATUS command handled immediately in parseTask with UDP reply to sender — no animation engine needed +- main.cpp updated to call startUdpServer() after WIFI_PS_NONE + +## Protocol Schema (for Phase 2 Pi-side reference) + +**UDP Port:** 4210 + +**Animation command:** +```json +{"v":1, "zone":"schrank"|"wand"|"all", "animation":"chase", "params":{"speed":0.5, "intensity":1.0, "direction":0, "colors":[[255,0,0,0]]}} +``` + +**Stop command:** +```json +{"v":1, "cmd":"stop", "zone":"schrank"|"wand"|"all"} +``` + +**Brightness command:** +```json +{"v":1, "cmd":"brightness", "zone":"schrank"|"wand"|"all", "value":40} +``` +Valid range: 0-60 (firmware clamps to 60 max per D-09). + +**Status command:** +```json +{"v":1, "cmd":"status"} +``` +Response: `{"v":1, "status":"ok", "wand":"chase", "schrank":"breathe", "brightness":40}` + +**Protocol rules:** +- Every command must include `"v":1` version field (D-08) +- Zone field mandatory for ANIMATION, STOP, BRIGHTNESS commands +- Unknown extra fields silently ignored (D-07) +- Malformed JSON logged to Serial, packet dropped — no UDP error response (D-07) +- Colors array format: `[[R,G,B,W], ...]` (up to 8 RGBW tuples) +- Default color when params.colors absent: `[255,255,255,255]` (warm white) + +## commandQueue Location (for Plan 03) + +```cpp +// In firmware/src/wifi_server.h: +extern QueueHandle_t commandQueue; // declare to consume + +// In firmware/src/wifi_server.cpp: +QueueHandle_t commandQueue; // definition + +// Plan 03 includes: +#include "wifi_server.h" // access commandQueue +``` + +Queue depth: 8 LedCommand structs. Plan 03 animation engine reads from this queue. + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: protocol.h/.cpp — JSON parsing into LedCommand** - `3323a87` (feat) +2. **Task 2: wifi_server.h/.cpp — AsyncUDP listener with FreeRTOS queue** - `230be99` (feat) + +## Files Created/Modified +- `firmware/src/protocol.h` - LedCommand, AnimParams, Zone, CmdType types; parseCommand() and buildStatusResponse() declarations +- `firmware/src/protocol.cpp` - parseCommand() implementation with ArduinoJson v7; buildStatusResponse() using serializeJson() +- `firmware/src/wifi_server.h` - commandQueue extern declaration; startUdpServer() declaration +- `firmware/src/wifi_server.cpp` - RawPacket struct; rawQueue + commandQueue creation; AsyncUDP callback (ISR-safe); parseTask FreeRTOS task +- `firmware/src/main.cpp` - Added wifi_server.h include; startUdpServer() call after WIFI_PS_NONE + +## Decisions Made +- Two-queue pattern chosen: AsyncUDP callback only copies bytes via xQueueSendFromISR, separate parseTask handles JSON. This is mandatory — JSON heap allocation in WiFi task callback causes watchdog resets. +- STATUS command fully handled in parseTask without routing through commandQueue — it needs sender IP/port from the raw packet context, and doesn't need the animation engine. +- Brightness clamped in parseCommand() to enforce D-09 hardware safety cap (max 60%). +- Zone field treated as optional only for STATUS command; required for all other commands with explicit Serial log and packet drop if missing. + +## Deviations from Plan + +None — plan executed exactly as written. + +## Issues Encountered +- animation_engine.h/.cpp and animations/animation_base.h were present as untracked files (pre-created scaffold) and were included in Task 2's commit. These belong to Plan 03 scope but their presence does not harm Plan 02 — they will be naturally used in Plan 03. No functional impact on this plan's deliverables. + +## Known Stubs +- buildStatusResponse() in parseTask uses hardcoded "unknown"/"unknown"/40 for wand/schrank animation names and brightness. These will be wired to actual ZoneState in Plan 03 when the animation engine has live state. Plan 03 must update this call. + +## Next Phase Readiness +- Plan 03 (animation engine) can immediately consume commandQueue via `#include "wifi_server.h"` and `extern QueueHandle_t commandQueue` +- LedCommand struct is the complete data contract — animation engine reads CmdType, Zone, animName, AnimParams +- Protocol schema above is the definitive reference for Phase 2 Pi-side transport implementation + +--- +*Phase: 01-esp32-firmware* +*Completed: 2026-04-03*