Skip to content

fix(firmware): make STACKCHAN.RON writeback work via short-name overwrite#579

Merged
andymai merged 1 commit into
mainfrom
fix/sd-config-writeback
May 29, 2026
Merged

fix(firmware): make STACKCHAN.RON writeback work via short-name overwrite#579
andymai merged 1 commit into
mainfrom
fix/sd-config-writeback

Conversation

@andymai
Copy link
Copy Markdown
Owner

@andymai andymai commented May 29, 2026

Summary

Completes the SD config feature: it could mount (#575) and read (#577) but not save. PUT /settings writeback was broken the same way the read path was — the staging file STACKCHAN.NEW (9-char base) couldn't be created by embedded-sdmmc, and the final copy targeted the un-creatable STACKCHAN.RON.

embedded-sdmmc cannot create long-named files at all, but it can overwrite an existing file opened by its short name. So:

  • Stage to a valid 8.3 name (STKCFG.NEW) the firmware can create.
  • Resolve the existing STACKCHAN.RON short name via the shared lfn_short_name helper (factored out of the read path).
  • Truncate-write the rendered config onto it — which leaves the long-name directory entry intact, so the file stays readable as STACKCHAN.RON next boot.

Writeback updates an existing config (the realistic lifecycle — the file must already be present for Wi-Fi/auth to come up). If STACKCHAN.RON is absent, write_config returns FileNotFound with a clear log rather than silently writing a differently-named file.

Test plan

  • just clippy-firmware (-D warnings) — clean.
  • On-device (CoreS3, real STACKCHAN.RON on the card): a temporary idempotent self-test (rewrite the just-read config, then re-read) — removed before commit — logged:
    • dbg writeback: write_config OK
    • dbg writeback: re-read OK ssid=Interweb hostname=stackchan — round-trip intact, long name preserved.

Surfaced by config now loading (separate, not addressed here)

  • sidecar session: persist failed (Write) — a different persisted file; needs its own look.
  • wifi: start_async failed (InternalError(NoMem)) — Wi-Fi now actually starts (there's an SSID); a pre-existing init path that was never exercised while config never loaded.

Greptile: please review.

…rite

The config writeback was as broken as the read path: STAGING_FILE
"STACKCHAN.NEW" (9-char base) couldn't be created by embedded-sdmmc, and
the final copy targeted the un-creatable "STACKCHAN.RON". embedded-sdmmc
cannot create long-named files at all, but it CAN overwrite an existing
one opened by its short name. Stage to an 8.3 name (STKCFG.NEW), resolve
the existing STACKCHAN.RON short name via the shared LFN helper, and
truncate-write the rendered config onto it — which preserves the
long-name directory entry, so it stays readable as STACKCHAN.RON.
@andymai andymai merged commit ec7b458 into main May 29, 2026
12 of 13 checks passed
@andymai andymai deleted the fix/sd-config-writeback branch May 29, 2026 18:44
@release-kun release-kun Bot mentioned this pull request May 29, 2026
release-kun Bot added a commit that referenced this pull request May 29, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>stackchan-firmware: 0.113.4</summary>

##
[0.113.4](stackchan-firmware-v0.113.3...stackchan-firmware-v0.113.4)
(2026-05-29)


### Bug Fixes

* **firmware:** make STACKCHAN.RON writeback work via short-name
overwrite ([#579](#579))
([ec7b458](ec7b458))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-kun[bot] <276042328+release-kun[bot]@users.noreply.github.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR completes the SD config writeback feature by fixing the root cause that broke PUT /settings: embedded-sdmmc can't create files with long names, so the staging file STACKCHAN.NEW (9-char base) was unwritable. The fix stages to STKCFG.NEW (a valid 8.3 name), resolves STACKCHAN.RON's mangled short name via the factored-out lfn_short_name helper, and truncate-writes the new content in-place — preserving the LFN directory entry so the file stays accessible as STACKCHAN.RON on the next boot.

  • lfn_short_name is extracted from the read path and reused by both read_config and the new write_config logic, reducing duplication.
  • write_config now guards against the absent-file case with a clear defmt::warn log and returns FileNotFound rather than silently writing under a different name.
  • Two doc comments still reference the old staging name STACKCHAN.NEW instead of the renamed STKCFG.NEW.

Confidence Score: 4/5

Safe to merge — the core logic is well-reasoned and on-device tested; only two stale doc-comment references to the old staging filename remain.

The writeback mechanism is sound: staging to an 8.3-creatable name, resolving the LFN short name, and truncate-writing in place correctly preserves the long-name directory entry. The lfn_short_name refactor is clean. The only issues found are two doc comments that still name STACKCHAN.NEW.

No files require special attention beyond the two stale doc comments in storage.rs.

Important Files Changed

Filename Overview
crates/stackchan-firmware/src/storage.rs Fixes STACKCHAN.RON writeback by staging to a valid 8.3 name (STKCFG.NEW) and overwriting the existing file via its resolved FAT short name; also extracts lfn_short_name as a shared helper. Two stale doc comments refer to the old STACKCHAN.NEW name.

Comments Outside Diff (2)

  1. crates/stackchan-firmware/src/storage.rs, line 427-429 (link)

    P2 The write_config doc comment still names STACKCHAN.NEW and describes the old copy-then-delete dance — both are out of date after this change. Readers following the doc will be confused about how writeback actually works now.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: crates/stackchan-firmware/src/storage.rs
    Line: 427-429
    
    Comment:
    The `write_config` doc comment still names `STACKCHAN.NEW` and describes the old copy-then-delete dance — both are out of date after this change. Readers following the doc will be confused about how writeback actually works now.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code

  2. crates/stackchan-firmware/src/storage.rs, line 126-127 (link)

    P2 This comment still references STACKCHAN.NEW, the old staging name that was renamed to STKCFG.NEW in this PR. The reference is stale.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: crates/stackchan-firmware/src/storage.rs
    Line: 126-127
    
    Comment:
    This comment still references `STACKCHAN.NEW`, the old staging name that was renamed to `STKCFG.NEW` in this PR. The reference is stale.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
crates/stackchan-firmware/src/storage.rs:427-429
The `write_config` doc comment still names `STACKCHAN.NEW` and describes the old copy-then-delete dance — both are out of date after this change. Readers following the doc will be confused about how writeback actually works now.

```suggestion
    /// Atomically replace `/sd/STACKCHAN.RON` with the rendered RON
    /// of `config`. Stages to `STKCFG.NEW` first (an 8.3 name the
    /// firmware can create), then truncate-writes the rendered bytes
    /// onto the resolved short name of `STACKCHAN.RON`, and cleans
    /// up the staging file.
```

### Issue 2 of 2
crates/stackchan-firmware/src/storage.rs:126-127
This comment still references `STACKCHAN.NEW`, the old staging name that was renamed to `STKCFG.NEW` in this PR. The reference is stale.

```suggestion
/// Atomic-write staging name for the runtime store. Same dance as
/// `STKCFG.NEW`.
```

Reviews (1): Last reviewed commit: "fix(firmware): make STACKCHAN.RON writeb..." | Re-trigger Greptile

andymai added a commit that referenced this pull request May 29, 2026
… pool sizing (#581)

## Summary

Once a real `STACKCHAN.RON` loaded (after #575/#577), Wi-Fi never came
up — `start_async` failed with `InternalError(NoMem)`. This fixes the
bring-up end to end.

**Root cause (measured on-device):** only **~1.5 KiB** of internal SRAM
was free when the Wi-Fi MAC started. PSRAM (8 MiB free) can't back Wi-Fi
DMA buffers; the bootloader-reclaimed heap is hard-capped at **~72 KiB**
(already full); and the only other internal heap shares the DRAM segment
with the **stack** (growing it overflowed the stack in the BLE+Wi-Fi
coex path).

**Fix 1 — BLE/Wi-Fi mutual exclusion.** With a Wi-Fi SSID configured,
skip BLE bring-up entirely. Frees **~36 KiB** internal (1.5 KiB → 37
KiB) for the Wi-Fi stack and removes coex stack pressure. BLE (Hardware
Buddy) still runs when no SSID is set, so provisioning over BLE is
unaffected.

**Fix 2 — socket pool.** Wi-Fi connecting then exposed a second latent
bug: `STACK_SOCKETS` was 6, predating the 4-worker HTTP pool, so
`smoltcp` panicked (`adding a socket to a full SocketSet`) the instant
the link came up. Sized to real demand (`HTTP_WORKER_COUNT` + mDNS +
SNTP + DHCP/DNS + optional outbound clients).

Also reflows one `write_config` line that merged slightly un-formatted
in #579.

## Test plan

- `just clippy-firmware` (`-D warnings`) — clean.
- **On-device (CoreS3, `STACKCHAN.RON` with `ssid=Interweb`):** flashed
`--release`; defmt log shows:
- `ble: skipped — Wi-Fi SSID configured` and free internal **37 KiB**
before start (was 1.5 KiB).
- `wifi: connecting → wifi: connected`, HTTP workers listening, **DHCP
lease acquired**, and `sntp: synced via pool.ntp.org` — i.e. full
internet reachability.
- **Boots once, no reboot loop;** zero `NoMem`, stack-guard, or
`SocketSet` panics (all three were reproduced before the fix).

## Follow-ups (noted, out of scope)

- `coex` feature is now dead weight when an SSID is set (BLE never
co-runs); dropping it would reclaim more internal RAM and could be
revisited.
- `sidecar session: persist failed (Write)` (separate file) and the
BLE-only path's behavior are unchanged here.

Greptile: please review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant