73 lines
3.0 KiB
Markdown
73 lines
3.0 KiB
Markdown
---
|
|
phase: "07"
|
|
plan: "03"
|
|
subsystem: firmware
|
|
tags: [firmware, micropython, frame-mode, drgb, drgbw, dnrgb, udp]
|
|
dependency_graph:
|
|
requires: [07-01, 07-02]
|
|
provides: [firmware/protocol.py#FrameAssembler, firmware/main.py#frame-mode]
|
|
affects: [lightsync/protocol/drgb.py]
|
|
tech_stack:
|
|
added: []
|
|
patterns: [DNRGB multi-packet reassembly, frame timeout with animation fallback]
|
|
key_files:
|
|
created: [tests/test_firmware_frames.py]
|
|
modified: [firmware/protocol.py, firmware/main.py]
|
|
decisions:
|
|
- "Frame timeout (2s) reverts to last animation, not idle — matches WLED behavior"
|
|
- "frame_is_rgbw flag routes DRGB/DNRGB to write_rgb, DRGBW to write_rgbw"
|
|
- "FrameAssembler keyed by absolute pixel index (start_index + i) — tolerates out-of-order chunks"
|
|
metrics:
|
|
duration: "2 minutes"
|
|
completed: "2026-04-07"
|
|
tasks_completed: 3
|
|
files_changed: 3
|
|
---
|
|
|
|
# Phase 7 Plan 3: Frame Mode Renderer Summary
|
|
|
|
**One-liner:** DRGB/DRGBW/DNRGB raw frame handling with FrameAssembler multi-packet reassembly and 2s animation fallback timeout.
|
|
|
|
## What Was Built
|
|
|
|
Added raw frame mode to the firmware. The device now receives pixel data from the server and writes it directly to the LED strip, supporting three packet types:
|
|
|
|
- **DRGB** (0x02): 3 bytes/pixel RGB, up to 490 pixels per packet — routed to `strip.write_rgb()`
|
|
- **DRGBW** (0x03): 4 bytes/pixel RGBW, up to 367 pixels per packet — routed to `strip.write_rgbw()`
|
|
- **DNRGB** (0x04): chunked RGB with start_index for large strips — reassembled by `FrameAssembler`, then routed to `strip.write_rgb()`
|
|
|
|
Frame mode takes priority over animation mode. When no frame packet arrives for 2 seconds, the firmware reverts to the last animation command.
|
|
|
|
## Tasks Completed
|
|
|
|
| Task | Description | Commit | Files |
|
|
|------|-------------|--------|-------|
|
|
| 1 | Add FrameAssembler to firmware/protocol.py | d14fa3c | firmware/protocol.py |
|
|
| 2 | Replace firmware/main.py with frame mode version | 2a22eef | firmware/main.py |
|
|
| 3 | Create tests/test_firmware_frames.py (19 tests) | ec97600 | tests/test_firmware_frames.py |
|
|
|
|
## Verification
|
|
|
|
- [x] `uv run pytest tests/test_firmware_frames.py -v` — 19 passed in 0.11s
|
|
- [x] `firmware/protocol.py` contains `FrameAssembler` with `feed()`, `reset()`, 200ms timeout
|
|
- [x] `firmware/main.py` handles DRGB (write_rgb), DRGBW (write_rgbw), DNRGB (via FrameAssembler)
|
|
- [x] Frame timeout (2s) reverts to last animation command mode
|
|
- [x] DNRGB 600-LED multi-packet frame: 2 packets (489 + 111 LEDs) round-trip passes
|
|
- [x] 300-LED DRGB = 902 bytes, DRGBW = 1202 bytes — both fit in single UDP packet
|
|
- [x] FrameAssembler clears stale partial frames after 200ms timeout
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written.
|
|
|
|
## Known Stubs
|
|
|
|
None — all frame handling is fully wired.
|
|
|
|
## Self-Check: PASSED
|
|
|
|
- firmware/protocol.py exists with FrameAssembler: FOUND
|
|
- firmware/main.py exists with frame mode: FOUND
|
|
- tests/test_firmware_frames.py exists: FOUND
|
|
- Commits d14fa3c, 2a22eef, ec97600: FOUND
|