Skip to content

harden(rp2040): deploy robustness across host setups (hub chains, drive-scan stalls, timeout policy) #1082

Closed

Description

@zackees

Related: #1081 (hub-path BOOTSEL diagnostics), #1040 (stock-ROM first deploy), #1049 (deploy parity). Parent burn-down: FastLED/FastLED#3648.

Context

#1081's investigation identified the hub-vs-direct differential mechanisms (RP2040-E5 busy-bus reset erratum unpatchable in mask ROM, VBUS sag during QSPI program, TT bulk stalls escalating to port resets). A first hardening slice now exists locally (bounded UF2 transfer retries gated on a fresh ROM enumeration, plus managed-picotool fallback when the BOOTSEL volume never mounts) and was validated with two consecutive hub-path deploys on the reference board (2E8A:000A, serial 5303284720C4641C, COM12): full flash, CDC return, and firmware serial output observed (Hello from RP2040 Pico!). Notably, both runs logged a transient CDC error during the 1200-bps touch that the existing BOOTSEL-appeared signal rode through.

This issue inventories what still goes out of spec on other machines — deeper hub chains, different timings, enterprise policies, first-plug driver installs — and proposes a prioritized hardening plan. Datasheet references: FastLED/datasheets → raspberrypi/mcu/RP2040/SOURCES.md (RP2040 datasheet incl. erratum RP2040-E5; hardware-design-with-rp2040).

The deploy chain and its current budget

Every RP2040/RP2350 deploy walks this chain (crates/fbuild-deploy/src/rp2040.rs):

# Stage Current budget
1 USB profile cache check none (hard gate)
2 CDC port snapshot + selection one enumeration pass
3 1200-bps touch (9600 open → DTR pulse 100 ms → set 1200) 2 s serial timeout
4 BOOTSEL volume discovery (scan A:\–Z:\ for INFO_UF2.TXT) 10 s, 100 ms poll
5 UF2 write to NEW.UF2 no watchdog (3 attempts, fresh-enumeration gated)
6 Eject watch (marker disappears) 15 s
7 Runtime CDC reappears 15 s
8 picotool fallback (stage-5 failure, or stage-4 empty) 30 s subprocess

Failure-mode inventory on foreign setups

Stage 4 — volume discovery (most fragile on foreign machines)

  • Mapped network drives poison the A–Z scan. volume_roots() probes every letter with fs::read_to_string + read_dir; a disconnected SMB mapping can block each probe tens of seconds, eating the whole 10 s window before the real BOOTSEL letter is reached. Fix: GetDriveType() == DRIVE_REMOVABLE filter before touching a root.
  • No drive letter at all (GPO letter-hiding, exhaustion, mount-as-folder): volume mounts but never appears at a root. Fix: FindFirstVolume-style enumeration, or treat "PnP shows USB\VID_2E8A&PID_0003 present but no volume" as a distinct state → go straight to picotool.
  • First-plug driver install exceeds the window. Windows re-runs device install per hub-port instance path; "searching Windows Update" can add 10–60 s. Applies to stage 7's 15 s too. Fix: env-tunable timeouts and/or gate on PnP device arrival instead of a fixed window.
  • macOS 13+ accessory approval (Apple Silicon): first-seen USB device needs a user click before enumeration — guaranteed timeout with zero diagnostic. Fix: platform-specific hint in the timeout message.

Stages 3–5 — hub topology and timing

  • Hubs-on-hubs multiply enumeration latency. Up to 5 external tiers; ≥100 ms attach debounce per tier plus host retry cycles, and the deploy does two full re-enumerations (runtime → BOOTSEL → runtime). A flaky 2-tier chain can blow either window even when the device eventually arrives.
  • FS hub segments / chained single-TT hubs enlarge the RP2040-E5 blast radius. B0/B1 silicon needs 800 µs of idle bus after reset; on a broadcast FS segment a polled sibling (keyboard, serial dongle at 30–50 µs intervals) can make BOOTSEL enumeration never succeed; the boot ROM cannot be patched. Retries only help if re-enumeration eventually wins the race. Fix: topology capture (CfgMgr32 parent walk) so failures can say "board is 2 hubs deep with 3 siblings — move to a direct port" (investigate(rp2040): harden hub-path BOOTSEL mass-storage diagnostics #1081's diagnostic slice).
  • Cascaded bus-powered hubs are out of power spec. QSPI erase/program current spikes brown out marginal VBUS mid-copy, possibly repeatably (retry won't converge). Same topology capture can flag "bus-powered hub chain" preemptively.
  • KVM switches and monitor/dock hubs (DisplayLink and friends) re-enumerate children unpredictably; a KVM focus switch mid-transfer is a guaranteed kill. Only diagnosable via topology strings.

Stage 5 — the write itself

  • No watchdog on the copy. A storport retry storm behind a sick hub can block write_all for minutes with no output; the daemon just hangs. Fix: per-attempt watchdog (~60 s) that abandons the blocked thread and routes to the retry/fallback path.
  • GPO/BitLocker removable-write-deny returns error 5 (ACCESS_DENIED) — currently the generic message. Fix: typed guidance like the existing 121/1006/1392 branches.

Stage 7 — the false-failure trap

  • After a confirmed eject (ROM accepted the image), a CDC timeout still fails the whole deploy even though the flash succeeded and the sketch runs. On slow-driver-install machines this makes CI re-flash a healthy board in a loop. Fix: distinct outcome ("flashed, CDC unconfirmed") instead of a hard error.

Stages 1 & 8 — environment dependencies

  • Fresh/offline machine: ensure_verified_usb_profiles refuses to deploy if the FastLED/boards USB profile cache was never populated — a network dependency before the board is touched.
  • picotool fallback needs WinUSB bound to the RP2 Boot interface on RP2040 (RP2350's ROM ships MS OS 2.0 descriptors; RP2040's does not) — on machines that never ran Zadig/pico-setup the fallback fails cleanly but uselessly. Windows-ARM64 availability of the managed picotool package is unverified.
  • Multi-board rigs: two boards in BOOTSEL → select_single_uf2_volume hard-errors. Fix: snapshot volumes before the touch and attribute the one that appeared.

Prioritized hardening plan

P0

P1

  • Per-attempt write watchdog (~60 s) feeding the existing retry/fallback path.
  • Env-tunable stage-4/stage-7 timeouts; consider PnP-arrival gating for stage 4.
  • "Flashed, CDC unconfirmed" outcome after confirmed eject instead of deploy failure.

P2

  • Appeared-volume attribution for multi-board rigs (pre/post-touch volume diff).
  • Typed error-5 (removable write-deny policy) guidance.
  • macOS accessory-approval hint on stage-4 timeout.
  • Verify managed picotool availability on Windows ARM64; document the RP2040 WinUSB binding caveat in the fallback error.

Acceptance criteria

  • A machine with a dead mapped network drive completes stage 4 inside the normal window.
  • A stage-4/5 failure behind a hub reports hub depth, power mode, and sibling count when Windows can supply them, and labels unavailable topology explicitly (no guessing).
  • A blocked UF2 write terminates within the watchdog budget and produces an actionable typed error.
  • A deploy whose eject was observed never reports hard failure solely because the runtime CDC missed the window.
  • Focused deterministic tests cover the new branches (drive filter decision, watchdog expiry, CDC-unconfirmed outcome, multi-volume attribution), consistent with the existing injected-closure test style in rp2040.rs.
  • No PlatformIO, raw serial, or direct flashing-tool invocation is introduced (fbuild remains the only deploy interface).

Open questions

  • Should stage-4 discovery switch entirely to volume enumeration + PnP arrival (removing the drive-letter scan), or keep the scan with the removable filter as the conservative first step?
  • Is abandoning a blocked writer thread acceptable in the daemon's threading model, or does the watchdog need a helper-process write?
  • Where should the topology facts live so both the deploy error path and fbuild device introspection can render them (fbuild-serial vs fbuild-deploy)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions