-
Notifications
You must be signed in to change notification settings - Fork 3
MoonI80 streaming ring: 48×256 (12,288 lights) via '595 expander, dual-core prime, WDT self-heal, expert mode #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 15 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
7c1ce57
Add 74HCT595 shift-register expander to the parallel LED drivers (dor…
ewowi 930fee1
Fix WiFi self-healing, a shift-encoder bug, and baseline shift mode a…
ewowi 8639888
Add MoonI80: our own gapless i80 DMA driver, and find the real shift-…
ewowi a0f6bf2
Hoist the shift encoder's frame constants; fix the AP-retry dropping …
ewowi 6040a7c
Hoist the shift encoder's transpose; free MoonI80's DC/WR pins
ewowi 2873ec9
Loopback self-test verified on a spare '595 strand; panel-dots mapping
ewowi 2f5f531
Add MoonI80 streaming ring: 128 lights/strand via '595 expander (from…
ewowi db67b0d
Fix shift-ring wedge + windowed snapshot; loopback toggles live now
ewowi 616d34e
Add MoonI80 shift-ring reuse diagnosis + no-reuse stopgap (clean to 2…
ewowi 0d75fdb
Rename the LED driver surface so the UI reads in plain language
ewowi da67edf
Drive the shift ring one light per DMA buffer (constant RAM at any le…
ewowi 8d11d5e
Revert "Drive the shift ring one light per DMA buffer (constant RAM a…
ewowi 270862a
Make the pin-expander ring's geometry a live control, not a constant
ewowi 36f5563
Ring reset-tail + prime-only gate; flash last_port; MoonLive guard
ewowi 5b0e6bc
Ring prime-only self-termination (192/strand clean); rabbit fixes
ewowi 2d60024
Run the S3 at 240 MHz; IRAM ring-encode chain; correcting snapshot
ewowi d263c27
Stream 256 lights/strand: the MoonI80 clock-oracle lapping ring
ewowi 5ab8d81
48x256 achieved: auto ring geometry, validated viability rule, instru…
ewowi a425a84
Dual-core ring: fork-join prime + memcpy snapshot, heap accounting, f…
ewowi 2ca3138
Fix per-strand '595 corruption: shiftOverclock switch; pre-merge fixes
ewowi 87b941c
Ring completion + prime barrier + WDT self-heal; expert mode; doc reorg
ewowi 8cdb9ff
Process CodeRabbit review; record the 48x256 flash investigation
ewowi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| # Migrating | ||
|
|
||
| The log of **breaking changes** — what changed between versions, and the action to take. | ||
|
|
||
| projectMM ships **no migration code**: the persistence layer is robust by default (an absent key keeps the control's default, a stale value clamps to the new bounds, an unknown key is ignored), which absorbs almost all schema drift with zero migration-specific code. The rare change that a robust reader *cannot* absorb is **documented here instead of migrated** — see [ADR-0013](adr/0013-no-migration-code-robust-persistence-plus-documented-breaks.md) for the decision and its rationale. | ||
|
|
||
| **Read this when upgrading a device that already holds persisted state.** Entries are newest first. Each says what changed and what to do; most need nothing at all, because the lost value re-populates on next use. | ||
|
|
||
| **Action legend** — how much work an entry costs you: | ||
|
|
||
| | Action | Meaning | | ||
| |---|---| | ||
| | *nothing* | Self-heals. The value re-populates on next use, or the default is correct. | | ||
| | *re-set a control* | One value resets to its default; set it again in the UI if you had changed it. | | ||
| | *re-add a module* | The module vanishes from the tree on boot; add it again and re-enter its controls. | | ||
| | *update a file* | An on-device file must be edited or replaced. | | ||
| | *erase flash* | A full flash erase is required (the heaviest — a full reconfigure follows). | | ||
|
|
||
| --- | ||
|
|
||
| ## Unreleased (`next-iteration`) | ||
|
|
||
| ### `MoonLedDriver`: `forceRing` → `useRing`, and the ring's geometry is now settable (2026-07-17) | ||
|
|
||
| The pin-expander path selector was a three-option Select (`auto` / `ring` / `wholeFrame`) named for a *diagnostic override*. The auto-router is gone — at the size the expander exists for (48 strands × 256 lights) a whole frame never fits internal DMA RAM, so "auto" had exactly one right answer while presenting itself as a choice, and its silent fallback hid which path was actually running. What remains is the honest question, as a switch: | ||
|
|
||
| | Old | New | | ||
| |---|---| | ||
| | control `forceRing` (Select: `auto`/`ring`/`wholeFrame`) | `useRing` (a switch: on = ring, off = whole frame) | | ||
| | — | `ringRows` (new: lights per DMA buffer, 1..64) | | ||
| | — | `ringBufs` (new: buffers the DMA circulates, 2..32) | | ||
|
|
||
| **Action: re-set `useRing` if you had `forceRing` on `wholeFrame`.** | ||
|
|
||
| `forceRing` reads as absent → ignored, and `useRing` takes its default (**on**, the ring). A device that had explicitly selected whole-frame therefore comes up on the ring; flip `useRing` off to get it back. `ringRows`/`ringBufs` default to 16 and 12 — the geometry the driver effectively ran. (It shipped with a pool of 16, but 16 buffers never fit the S3's internal DMA heap, so the ring build failed its own fit check and the driver quietly fell back to whole-frame; 12 is what actually held. A config on the old defaults may therefore start *ringing* where it used to fall back.) They exist so the RAM / encode-overhead / interrupt-rate / lap-time trade-off can be swept on a live board rather than fixed at compile time. | ||
|
|
||
| ### LED driver + control rename — a human-readable UI (2026-07-16) | ||
|
|
||
| The LED driver module types and several controls were renamed so the UI reads in plain language rather than peripheral jargon (the UI shows a control's name verbatim, so the name *is* the label). | ||
|
|
||
| | Old | New | | ||
| |---|---| | ||
| | module type `I80LedDriver` | `MultiPinLedDriver` | | ||
| | module type `MoonI80LedDriver` | `MoonLedDriver` | | ||
| | control `shiftRegister` | `pinExpander` | | ||
| | control `asyncTransmit` | `doubleBuffer` | | ||
| | read-only `wireUs` | `frameTime` | | ||
| | read-only `stall` (Drivers) | `renderWait` | | ||
|
|
||
| **Action: re-add the module, then re-set `pinExpander` / `doubleBuffer` if you had changed them.** | ||
|
|
||
| A device whose persisted config names the old module type loads a module type that no longer exists — the unknown type is ignored, so **the driver is absent from the tree on boot**. Re-add it (`MultiPinLedDriver` or `MoonLedDriver`) and re-enter its controls. Within a re-added driver, the two renamed *settable* controls (`pinExpander`, `doubleBuffer`) read as absent → they take their defaults (`pinExpander` off, `doubleBuffer` on); set them again if your board needs otherwise. `frameTime` and `renderWait` are read-only KPIs — nothing to restore. | ||
|
|
||
| `RmtLedDriver` and `ParlioLedDriver` are unchanged. The `pins` / `ledsPerPin` / `clockPin` / `latchPin` / `loopback*` controls are unchanged. | ||
|
|
||
| --- | ||
|
|
||
| ## Earlier | ||
|
|
||
| These pre-date this log and were recorded in ADR-0013's Consequences list. A device that persisted state on an older build and loads a newer one loses only the noted value, which re-populates on next use. | ||
|
|
||
| ### Container config filenames (`LayoutGroup.json` → `Layouts.json`) | ||
|
|
||
| `.config/LayoutGroup.json` → `Layouts.json`, `.config/DriverGroup.json` → `Drivers.json` (container type rename). The stale files are ignored (unknown-type config isn't loaded); they linger harmlessly on disk until a flash erase. | ||
|
|
||
| **Action: nothing.** Lost: the container's `enabled` flag (defaults back on). | ||
|
|
||
| ### UI last-selected module (`mm.selectedModule` → `mm_selected`) | ||
|
|
||
| The browser localStorage key for the UI's last-selected module. | ||
|
|
||
| **Action: nothing.** Lost: the remembered selection resets to the first module. | ||
|
|
||
| ### Device-list `colour` → `color` (US-spelling rename) | ||
|
|
||
| The DevicesModule persisted-list key for a Hue bridge's color-capable light count (`DevicesModule::restoreList()`). A device list persisted under the old key reads the count as absent → 0. | ||
|
|
||
| **Action: nothing.** The cached bridge count resets to 0 until the bridge is re-heard live and re-populates it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Move the historical rationale out of
CLAUDE.md.Keep the current workflow rule here, but move the backward-looking explanation about prior agent behavior to
docs/history/,docs/adr/, orlessons.md, then link to it if needed. As per coding guidelines, historical contrasts belong in those history-oriented documents rather than general documentation.🤖 Prompt for AI Agents
Source: Coding guidelines