Skip to content

feat(rp2350w): complete pin-free AutoResearch and ESP32-C6 peer-network bring-up #3832

Open

Description

@zackees

Context Complete the pin-free bring-up of the attached Pico 2 W-compatible RP2350 through AutoResearch. This includes safe deployment, serial JSON-RPC, runtime/platform validation, watchdog recovery, and real network communication with the attached ESP32-C6. Current hardware: - RP2350W DUT: COM17, VID:PID 2E8A:F00F, serial 2DCB876B587EA334 - ESP32-C6 network fixture: COM9, VID:PID 303A:1001, serial 8C:BF:EA:CF:87:B4 - The shared USB fingerprint is displayed as WEMOS LOLIN S3, but prior live chip evidence in #3587 identifies this device as ESP32-C6. The ESP32-C6 should provide a deterministic WPA2 SoftAP and peer server/client so RP2350W networking can be proven without changing the host computer's Wi-Fi connection or depending on external infrastructure. ### Hardware status update (2026-08-05) The required RP2350W pins are now soldered. External GPIO, PIO, SPI, UART, and LED-driver hardware validation is unblocked and should proceed with live-board evidence. ### Current gaps - FastLED maps rp2350 to non-W rpipico2; there is no board-correct rp2350w -> rpipico2w target. - The repository used to request fbuild 2.5.6, but the released 2.5.7 dependency is now merged and verified. - RP2350 application-port fingerprints disagree with the observed 2E8A:F00F. - AutoResearch deployment, post-deploy scanning, watchdog recovery, and RPC-smoke labels contain RP2040-specific assumptions. - AutoResearch omits RP2350 from its example filter and reports it as Unknown platform. - RP2350 mutex/semaphore dispatch is guarded only for FL_IS_RP2040. - --perf-wave2d incorrectly enters the GPIO-dependent path. - fl::net::wifi, AutoResearch HTTP networking, OTA, and BLE currently have real implementations only on ESP32; RP2350 receives stubs. - Existing network modes orchestrate one MCU plus the host, not two attached MCUs. - Existing JSON-RPC validation is serial-only; network-carried JSON-RPC is not proven on RP2350W. ## Proposal ### 1. Establish a correct and safe RP2350W target - Synchronize the repository on released fbuild 2.5.7. - Add canonical rp2350w -> rpipico2w board support while preserving rp2350 -> rpipico2. - Require the Pico 2 W/CYW43 compile identity. - Reconcile runtime USB identities from a single authoritative board source. - Generalize RP2xxx deployment and watchdog re-enumeration around the active environment and fbuild-returned port. - Add tests proving COM17 cannot be confused with another attached RP or Espressif device. ### 2. Complete serial JSON-RPC bring-up Add RP2350W support to the existing pin-free smoke path and require: - Correct chip/board identity - rpc.discover and structured help - Required method presence - Monotonic ping - Exact nested debugTest payload echo - status, drivers, and testNoSerial - Structured unknown-method handling - A distinction between RPC readiness and the intentionally unavailable LED RX channel Canonical gate: bash bash autoresearch rp2350w --rpc-smoke --upload-port COM17 --timeout 120s ### 3. Validate pin-free platform functionality - IEEE-754 correctness - SIMD correctness and benchmarks - Watchdog acknowledgement, reset, CDC reacquisition, uptime reset, and post-reset RPC - Wave2D benchmarks after fixing their GPIO-mode classification - RP2350 mutex/semaphore dispatch and real concurrency behavior - Coroutine support only if backed by a real RP implementation; a null backend is not a pass - Repeated deploy/RPC and cold-reconnect soak ### 4. Add an ESP32-C6 peer-network AutoResearch mode Add a dual-device command similar to: bash bash autoresearch rp2350w --net-peer --upload-port COM17 --peer-environment esp32c6 --peer-upload-port COM9 --timeout 120s The host orchestrator should maintain two independent fbuild-backed serial RpcClient connections and use serial only as the control/diagnostic plane. Network sequence: 1. Confirm live chip identity on both ports. 2. ESP32-C6 starts the existing WPA2 AP and HTTP fixture at 192.168.4.1. 3. RP2350W joins through a new CYW43-backed fl::net::wifi implementation. 4. Poll until RP2350W reports a nonempty DHCP lease. 5. RP2350W calls the C6 /ping, /status, and echo endpoints. 6. RP2350W exposes equivalent endpoints; C6 calls them using runNetClientTest. 7. Exercise a deterministic payload of at least 4 KiB and verify its exact hash. 8. Carry JSON-RPC over the network transport and validate discovery, ping, nested payload echo, status, and unknown-method handling between the two MCUs. 9. Tear down both sides and prove both serial RPC channels remain responsive. This should reuse the existing C6 network RPCs and HTTP fixture rather than create one-off sketches or host-Wi-Fi workarounds. ### 5. Complete wireless lifecycle coverage After peer networking is stable: - Prove disconnect/reconnect and DHCP recovery. - Run ten network setup, bidirectional exchange, teardown, and serial-health cycles. - Add RP2350W OTA using the C6 as the isolated AP/artifact peer; require a post-reboot build marker and restored serial/network RPC. - Audit RP2350W Bluetooth support in the selected Arduino-Pico/core stack. Track BLE JSON-RPC as a child phase if a real backend is available; otherwise document the precise upstream capability boundary rather than accepting stub behavior. ## Acceptance criteria - [x] uv run fbuild --version reports 2.5.10. - [x] rp2350w generates the rpipico2w board configuration. - [ ] Deploying to COM17 never touches COM9 or another attached board. - [ ] Serial RPC smoke ends with its decisive PASS result on the RP2350W. - [ ] IEEE-754, SIMD, watchdog, concurrency, and Wave2D pin-free gates pass or report an explicit unsupported implementation gap. - [ ] The C6 is firmware-confirmed as ESP32-C6 before use; the generic USB label is not treated as proof. - [ ] RP2350W joins the C6 AP and receives a valid lease. - [ ] RP2350W -> C6 and C6 -> RP2350W HTTP checks pass. - [ ] Network JSON-RPC discovery, ping, payload echo, status, and error handling pass between the boards. - [ ] A deterministic >=4 KiB payload is transferred without corruption. - [ ] Ten reconnect/teardown cycles pass without RPC timeout, watchdog reset, stale port, or wrong-device selection. - [ ] Both boards answer serial ping after every network test and after cleanup. - [ ] RP2350W OTA proves the expected build after reboot and recovers both control paths. - [ ] All closeout evidence records both ports, VID:PIDs, serial identities, exact commands, and decisive REMOTE:/RESULT: lines. - [ ] No raw flasher, raw pyserial, one-off sketch, external AP dependency, or host Wi-Fi switching is introduced. - [ ] PIO/GPIO/SPI/UART LED-driver hardware validation is performed against the soldered RP2350W and recorded with decisive live-board evidence. ## Related issues - #1673 - original RP2350/Pico 2 support - #3576 - existing dual-device Wi-Fi robustness work - #3587 - prior live ESP32-C6 COM9 STA/HTTP validation - #3648 - RP2040 pin-free AutoResearch bring-up precedent - FastLED/fbuild#1233 - deployment proof for this attached Pico 2 W-compatible target

Activity

  1. zackees commented on Aug 2, 2026

    @zackees
    MemberAuthor

    Phase 1 complete.

    • feat(rp2350w): add board and transport foundation #3834 merged: rp2350w -> rpipico2w, Arduino-Pico 4.5.3, RP2xxx deploy/watchdog generalization, board-exact USB identities, serial-number-safe CDC reacquisition, RP2350 AutoResearch filtering/platform identity, and regression coverage.
    • fix(rp2040): use Pico W USB identity #3835 merged: corrected rpipicow to its Arduino-Pico application identity 2E8A:F00A and proved it cannot select a non-W 2E8A:000A port.
    • Local validation on merged master: uv run pytest ci/tests/test_autoresearch_phases.py -k "rpipicow or rp2350w" -q -> 12 passed.
    • Foundation validation before merge: bash lint passed; bash test --cpp passed (279/279 unit tests; 83/83 examples); bash compile rp2350w --examples AutoResearch produced the Raspberry Pi Pico 2 W / RP2350 build.

    Continuing with serial JSON-RPC and pin-free platform validation.

  2. zackees commented on Aug 2, 2026

    @zackees
    MemberAuthor

    Phase 2 implementation is ready in #3837, but hardware merge proof is correctly blocked on the exact RP2350W being absent.

    Completed:

    Current fbuild scan:

    • COM17 / 2E8A:F00F / serial 2DCB876B587EA334: phantom, selectable=no.
    • COM9 / 303A:1001 / serial 8C:BF:EA:CF:87:B4: healthy.
    • The live BOOTSEL device previously seen at G: was proven to be the unrelated RP2040 formerly on COM12, so it was not flashed again.

    Required next action: physically reconnect the exact RP2350W so COM17 (or its serial-number-matched replacement port) becomes healthy. Then #3837 will run the serial RPC, IEEE-754, SIMD, watchdog, Wave2D, concurrency, repeated-deploy, and reconnect gates before merge.

  3. zackees commented on Aug 5, 2026

    @zackees
    MemberAuthor

    PIO Channels bring-up is now merged.

    • chore(deps): bump fbuild to 2.5.7 #3840 merged: FastLED now pins released fbuild 2.5.7; local validation reports uv run fbuild --version = 2.5.7.
    • fix(rp2350): expose independent PIO channels #3841 merged: RP PIO Channels now register as distinct PIO0/PIO1 drivers, RP2350 exposes PIO2, and AutoResearch can select PIO2 while retaining the portable Bus::FLEX_IO abstraction.
    • Validation passed: focused PIO mock/manager test, focused AutoResearch parser tests, full lint, and bash compile rp2350w --examples AutoResearch.

    Live LED-driver evidence remains blocked by the host state, not the soldered pins: COM17 (2E8A:F00F, serial 2DCB876B587EA334) is still reported by Windows/fbuild as a phantom, non-selectable devnode. The issue also does not record the actual soldered GPIO mapping, so no PIO LED/loopback test was attempted with guessed pins.

  4. zackees commented on Aug 5, 2026

    @zackees
    MemberAuthor

    Hardware wiring clarification: GPIO0 (TX) is bridged to GPIO1 (RX) on the RP2350W.

    Attempted the concrete PIO2 Channels gate:

    bash autoresearch rp2350w --flex-io --rp-pio-index 2 --tx-pin 0 --rx-pin 1 --upload-port COM17 --timeout 120s
    

    The RP2350W PIO2 build and C++ lint completed. fbuild then refused COM17 safely because the exact serial-matched device (USB\\VID_2E8A&PID_F00F\\2DCB876B587EA334) is a Windows phantom devnode. A direct fbuild deploy with --admin was also attempted; it refused without side effects because this automation session is non-interactive and cannot perform UAC-gated PnP recovery. COM9 was never selected.

    Required external action: reconnect the RP2350W (or hold BOOT and tap RESET) until fbuild port scan reports its serial as healthy/selectable; then rerun the command above. The documented GPIO0↔GPIO1 bridge is ready for the live PIO evidence.

  5. zackees commented on Aug 5, 2026

    @zackees
    MemberAuthor

    CYW43 Wi-Fi support is now merged in #3842 (merge commit 99bd0584436f06c24ffdfd0ee1bf31dcbdc5d553). fl::net::wifi now selects the Arduino-Pico CYW43 backend for RP2350W builds, using the core's non-blocking WiFi.beginNoBlock association path plus AP/status/IP support. Focused RP2350W contract coverage, C++ lint, and bash compile rp2350w --examples AutoResearch all passed (1,118,548-byte flash image).

    The broader ESP32-C6 peer HTTP/JSON-RPC and OTA orchestration remains unimplemented: AutoResearch's current server/client/OTA code is ESP-IDF-specific, so it is not falsely claimed as validated on RP2350W.

    Current live scan after merge: COM17 / 2E8A:F00F / serial 2DCB876B587EA334 is still a phantom/non-selectable RP2350 endpoint; COM9 / 303A:1001 / serial 8C:BF:EA:CF:87:B4 is healthy. Windows also reports USB problem code 43 at a root port. Once the RP2350 endpoint becomes healthy (reconnect or BOOT+RESET), rerun the GPIO0 TX <-> GPIO1 RX PIO2 gate and the serial/network on-device gates; no raw flasher or raw serial path was used.

  6. zackees commented on Aug 6, 2026

    @zackees
    MemberAuthor

    Source bring-up update:

    Hardware remains blocked only by the physical device: the user-confirmed loopback is GPIO0 TX ↔ GPIO1 RX, but fbuild port scan reports the RP2350W COM17 USB device as a non-selectable Windows problem-code-43 phantom. Once it re-enumerates as a healthy selectable port, rerun the exact fbuild AutoResearch PIO2 loopback command; no direct flasher/serial path was used.

  7. zackees commented on Aug 6, 2026

    @zackees
    MemberAuthor

    Watchdog recovery hardening is merged in #3846 (commit 2992532): AutoResearch now reports the previous reset cause in ping, --watchdog-soak requires both lastResetWasWatchdog=true and restarted uptime, and its host watchdog is cancelled only after full runner cleanup. RP2350W AutoResearch builds successfully (1.12 MB flash, 124.26 KB RAM) and targeted tests/lint pass. Hardware execution remains blocked only by the current Windows USB state: fbuild port scan identifies the intended board as COM17 / 2E8A:F00F / serial 2DCB876B587EA334 but reports health=phantom, selectable=no, alongside problem code 43. I did not flash a nonselectable target. Once COM17 is healthy/selectable, run bash autoresearch rp2350w --watchdog-soak --upload-port COM17 --timeout 120s before the GPIO0↔GPIO1 PIO loopback.

  8. zackees commented on Aug 6, 2026

    @zackees
    MemberAuthor

    Watchdog reset-loop hardening shipped in #3847. Root cause: the RP implementation kept consecutiveCrashCount() only in RAM, so a watchdog reset erased the count and isInSafeMode() could never trip. The fix reserves two RP watchdog scratch bytes for the count, retains it across soft reset, and makes AutoResearch enter a test-only CDC-safe recovery loop before PIO/RX/RPC/Wi-Fi/driver initialization after repeated watchdog resets.\n\nValidation: �ash test watchdog, �ash compile rp2350w --examples AutoResearch, and �ash lint --cpp passed. Live deployment was not attempted because COM17 remains health=phantom selectable=no with Windows root-hub Code 43; that host USB-enumeration condition cannot be reset by firmware WDT.

  9. zackees commented on Aug 6, 2026

    @zackees
    MemberAuthor

    Follow-up hardening is merged in #3849 (af97829b9ec535a2d8778fed394752eb683319fd).

    • Bus::FLEX_IO maps PIO0/PIO1 on RP2040 and PIO0/PIO1/PIO2 on RP2350; all expose both clockless and arbitrary-pin SPI through the Channels engine.
    • Bus::SPI remains the RP hardware SPI0/SPI1 path; Bus::UART remains UART0/UART1 clockless. AUTO dispatches among those, while BIT_BANG is the fallback; DUAL_SPI, QUAD_SPI, OCTAL_SPI, and RMT do not have RP Channels specializations.
    • Replaced raw function-local bus-holder state with header-safe fl::SingletonShared holders; this is the header-safe singleton variant required by the project rules. Added reusable TX/SPI peripheral mocks with per-test state and converted the PIO lifecycle tests to use them.
    • FastLED now pins fbuild 2.5.14. Its First led of WS2812B is glitching with NodeMCU #1260 deployment fix binds picotool to the selected board and rejects Windows Code 43 devices instead of permitting an unscoped flash attempt.

    Verification: focused PIO unit test, strict C++ lint on all touched files, and bash compile rp2350w AutoResearch --no-interactive are green. The remaining live acceptance gates cannot run until COM17 stops enumerating as Windows Code 43 / phantom; no deployment was attempted against it.

  10. zackees commented on Aug 6, 2026

    @zackees
    MemberAuthor

    Merged #3851 (419d0ce) to add a strict fbuild-only dual-board AutoResearch path:

    bash autoresearch rp2350w --net-peer --upload-port COM17 --peer-environment esp32c6 --peer-upload-port COM9 --timeout 120s

    It requires both explicit ports, deploys both boards through fbuild only, never switches host Wi-Fi, validates RP2350W <-> C6 HTTP in both directions for 10 teardown/reconnect cycles, and pings serial JSON-RPC after each RP teardown. Host verification: 180 targeted tests plus file-targeted lint passed.

    Live execution is intentionally still blocked: fbuild currently identifies COM17 as RP2350 serial 2DCB876B587EA334 but marks it health=phantom selectable=no; Windows reports a direct-root USB Code 43 node. No deploy was attempted. This is source/test coverage only, not hardware acceptance evidence.

  11. 37 remaining items

  12. zackees commented on Sep 10, 2026

    @zackees
    MemberAuthor

    The coroutine criterion was passing vacuously — #4308

    Re-ran the pin-free criteria on the attached RP2350. The coroutine one needs flagging, because it has been contributing a PASS to this issue's acceptance matrix without running anything:

    $ bash autoresearch rp2350 --coroutine
    RESULT: COROUTINE UNSUPPORTED (backend=null): RP2xxx currently selects the generic Arduino null coroutine backend
    rc=0
    

    RP2xxx selects the generic Arduino null coroutine backend, so the device answers supported=False and executes zero coroutine tests — and _run_coroutine_tests returned 0 for that case. An existing test asserted rc == 0, so the behaviour was pinned in place rather than accidental.

    The sharper problem is not the bookkeeping. If a real backend ever lands here and then regresses to supported=False, the output and the exit status would be byte-identical to today's. The criterion cannot distinguish "not implemented yet" from "implemented and broken", which is the one distinction it exists to make.

    #4308 splits the outcomes into three codes (0 passed / 1 failed / 2 unsupported) and leaves the criterion honest: --coroutine on RP2xxx now exits 2 and says why, until a real backend lands.

    This does not move the issue forward — it removes a false positive from it. Worth re-reading any matrix entry recorded from a --coroutine run before this, since a green there meant only that the RPC round-tripped.

    Status of the rest, same board, same session

    criterion result
    --simd 85/85 pass, and the s16x16x4 15x penalty is gone since #4299 (verified on device, numbers in #4216)
    --coroutine unsupported, backend=null — no RP2xxx implementation exists
    SPI / UART loopback still blocked on the GPIO3→GPIO0 and GPIO11→GPIO8 jumpers, which I cannot fit unattended

    So the remaining work here is genuinely blocked on two things I cannot supply from this bench: a coroutine backend for RP2xxx, and someone to fit two jumpers.

  13. zackees commented on Sep 10, 2026

    @zackees
    MemberAuthor

    Parent matrix update — twelve of the fifteen acceptance criteria now have live evidence

    #3899 asks that the final matrix land here. All of the following ran this session against the attached pair — RP2350W 2DCB876B587EA334 on /dev/ttyACM0, ESP32-C6 8C:BF:EA:CF:87:B4 on /dev/ttyACM2 — on a Linux bench rather than the Windows one the issue body describes, so the ports are /dev/ttyACM* and not COM17/COM9.

    criterion status evidence
    fbuild version ✅ 2.5.23
    rp2350w → rpipico2w ✅ builds and deploys
    Deploying to one board never touches the other ✅ every run used explicit --upload-port / --peer-upload-port; both boards answered afterwards
    Serial RPC smoke ends with decisive PASS ✅ RESULT: RPC smoke PASS (discovery, help, ping, payload, status, drivers, testNoSerial, RP concurrency, RP PIO contention, RP PIO0+PIO1 resources, error handling)
    IEEE-754 ✅ IEEE754 CODEC TEST PASSED (35 checks)
    SIMD ✅ SIMD TEST PASSED (85 tests) — and the s16x16x4 15x penalty is gone since #4299 (device numbers in #4216)
    Watchdog ✅ RESULT: watchdog soak PASS (ack, disconnect, CDC recovery, ping, RPC smoke), with lastResetCause: WATCHDOG confirming a real reset
    Concurrency ✅ RP concurrency, RP PIO contention and PIO0+PIO1 resources all inside the smoke PASS above
    Wave2D ✅ 64×64: 668.6 / 653.6 / 654.0 fps, one variant at 101.3
    C6 firmware-confirmed before use ✅ --net-peer asserts esp32-c6 in the peer's status.platform; the shared USB label is not used as proof
    RP2350W joins the C6 AP with a valid lease ✅ RP2350W joined in 5.8s (attempt 1) -> 192.168.4.2
    HTTP both directions ✅ tests_passed=12 tests_failed=0 in both directions, every cycle
    Network JSON-RPC discovery/ping/echo/status/errors ✅ the 12 per-direction tests above
    ≥4 KiB deterministic payload, exact hash ✅ POST /echo 4096-byte FNV-1a bytes=4096 passed=True, both directions
    Ten reconnect/teardown cycles ✅ NET PEER AUTORESEARCH PASSED (10 reconnect cycles)
    Both boards answer serial ping after every test ✅ each of the 10 cycles re-runs serial RPC on both boards
    PIO/GPIO/SPI/UART LED-driver validation ✅ (with unreachable paths listed) full matrix in #3899

    Canonical command for the peer leg, since the issue body's 120 s budget is not enough:

    bash autoresearch rp2350w --net-peer --upload-port /dev/ttyACM0 \
      --peer-upload-port /dev/ttyACM2 --peer-environment esp32c6 --timeout 1200
    

    --timeout is the entire run budget, not a per-call timeout. At 120 s the join leg was left with 1.0 s and failed with RP2350W did not join the ESP32-C6 AP after 1.0s across 4 attempt(s) — a budget artifact that reads like a WiFi fault. Worth correcting in the issue body.

    The three that are not satisfied

    Coroutine — no RP2xxx backend. This issue already says "a null backend is not a pass". It was nonetheless being scored as one: bash autoresearch rp2350 --coroutine printed COROUTINE UNSUPPORTED (backend=null) and exited 0, and an existing test asserted that exit code. So the criterion has been contributing a green result on the strength of zero tests having run. #4308 splits the outcomes (0 passed / 1 failed / 2 unsupported); it now exits 2 and says why. That does not implement a backend — it stops the matrix claiming one exists.

    OTA — four defects deep, three fixed. RP2350W OTA proves the expected build after reboot is not met. #3956 was closed this morning after root-causing the 512-byte chunk limit; that was premature, and clearing it exposed a control-socket collision, a fixture filesystem too small to hold two artifacts, an RP fetch failure logged to a deliberately-closed serial link, and an OTA staging region half the size of the image. #4318 fixes what I could verify. I have reopened #3956.

    BLE — blocked on the bench host, not on FastLED. --ble fails with org.freedesktop.DBus.Error.ServiceUnknown. The adapter exists (hci0) but bluetooth.service does not — BlueZ userspace is absent, so bleak has no org.bluez to reach. Nothing about #3861/#3955 can be evaluated here regardless of firmware state; recorded as a provisioning gap on #3714. Enabling it needs root and is not something to do unattended.

    Also worth recording against this issue's "safe deployment" goal

    fbuild's environment-based port selection refuses to deploy when the board's running firmware advertises a different USB identity than the target environment — and on RP the identity comes from the firmware, so flashing rp2350 silently removes the ability to flash rp2350w, and vice versa. I hit both directions. Filed as FastLED/fbuild#1430; the bench workaround is to always pass -p <port> explicitly.

  14. zackees commented on Sep 11, 2026

    @zackees
    MemberAuthor

    Coroutine: the "null backend" claim is now tested — and five RPCs wedge an RP board until the watchdog fires

    testCoroutineAll does not test anything on RP. AutoResearchRemoteAsyncMethods.cpp:455 short-circuits it:

    #if defined(FL_IS_RP)
        r.set("supported", false);
        r.set("backend", "null");
        r.set("reason", "RP2xxx currently selects the generic Arduino null coroutine backend");
        r.set("passed", 0); r.set("failed", 0); r.set("total", 0);
        return r;
    #else

    That is an assertion, not a measurement. But the eight individual tests are bound unconditionally (lines 60–383), so they are callable on RP over serial RPC. I called them on RP2350W 2DCB876B587EA334.

    Three run, and confirm the claim with evidence

    testCoroutineBasic:      {"success": false, "taskRan": false,   "taskCompleted": false, "durationMs": 0}
    testCoroutineStop:       {"success": false, "taskStarted": false, "wasRunning": false,  "durationMs": 2000}
    testCoroutineConcurrent: {"success": false, "completedCount": 0, "allCompleted": false, "durationMs": 3000}
    

    Tasks are created and never execute. So the null-backend conclusion is correct — it just had no evidence behind it until now.

    Five hang the device

    testCoroutineAwait, testCoroutineAwaitError, testCoroutinePromiseCallbacks, testCoroutinePromiseCatchCallback, testCoroutineChainedAwait all return null — no response. And the device is gone afterwards, not merely slow:

    testCoroutineAwait: null
    ping:               null      <- device no longer answering at all
    status:             null
    

    It recovers on its own. The board re-enumerated and came back with:

    {"message": "pong", "success": true, "uptimeMs": 78827,
     "lastResetCause": "WATCHDOG", "lastResetWasWatchdog": true}
    

    --rpc-smoke passes afterwards. So the watchdog escape does its job — but the sketch does hang, because these five call fl::task::await(), which with a null backend blocks forever rather than returning.

    The actionable defect

    The guard is in the wrong place. #if defined(FL_IS_RP) protects only the aggregate; the five hanging methods stay exposed on the RPC surface and are advertised through rpc.discover, so the interface invites exactly the call that wedges the board. Anyone driving the RPC API directly on an RP board — an agent enumerating methods, a bench script, this issue's own "pin-free" premise — hits it.

    Either the individual binds should carry the same FL_IS_RP decline, or fl::task::await() should fail fast on a null backend instead of blocking. The second is better: it fixes the class rather than the symptom, and a null backend blocking forever is a hazard wherever await() is reachable, not only in these tests.

    Criterion status

    This issue requires "coroutine support only if backed by a real RP implementation; a null backend is not a pass" — that remains unmet, now demonstrated rather than asserted. Related: the criterion was also scoring as a pass until #4308, since the mode exited 0.

    Board healthy throughout; the wedge was self-recovering and never needed intervention.

  15. zackees commented on Sep 11, 2026

    @zackees
    MemberAuthor

    The ten-cycle criterion was passing intermittently, not reliably — #4372

    When I reported this issue's peer-network criteria as met, the evidence was a single passing run. Running the gate repeatedly for an unrelated regression control showed it fails about two runs in five:

    runs result
    master 3 2 pass, 1 fail (cycle 7)
    unrelated branch 2 1 pass, 1 fail (cycle 5)

    Always the same failure — the RP's HTTP server takes complete headers and then none of a 4096-byte body, 408 at lastTimeoutElapsedMs: 2006 against a 2000 ms budget. Six milliseconds over.

    Cause is an asymmetry left behind by #4231: kRpHttpClientStallMs was raised to 6000 after five legitimate requests at 2706-3586 ms were measured, while kRpPeerStallMs stayed at 2000. The budget is a property of the peer — the C6 blocks up to 5000 ms servicing from its sketch main loop — so those gaps occur in both directions. #4372 matches them.

    After: 6 runs, 6 passes, zero stalls.

    So "Ten reconnect/teardown cycles pass without RPC timeout" is satisfied more solidly than when I first reported it, and my original report overstated the confidence — one passing run of an intermittent gate is not the same as the gate passing. Worth applying to the rest of this matrix: several entries above rest on a single run each, and I have not re-run them enough to know which are similarly marginal.

  16. zackees commented on Sep 11, 2026

    @zackees
    MemberAuthor

    Stability of the pin-free gates — from accumulated runs, not new ones

    I flagged that most entries in this matrix rest on a single run each, which the ten-cycle gate showed is not the same as passing. Rather than generate fresh runs, the session has already accumulated enough repeats to answer most of it:

    gate logs with PASS logs with FAIL
    PIO0 / PIO1 / PIO2 loopback 6 0
    --simd 14 0
    --watchdog-soak 6 0
    --rpc-smoke 58 5

    So most of these are better supported than "one run" — --simd and --watchdog-soak in particular, the latter being the one that exercises CDC disconnect and reacquisition.

    The five --rpc-smoke failures are one sub-test

    All five are the same thing, and it is not a transport or timing flake:

    RESULT: RPC smoke FAIL: testRpPioParallelResources returned unsuccessful response:
      {'pinA': 2, 'pinB': 4, 'bound': {'freeDma': 15, 'freeS...
    

    They sit in logs from an earlier segment of this session (pio1471*, pio3899*), and I cannot now establish which branch or firmware each was run against, so I am not claiming testRpPioParallelResources fails on master — only that it has failed five times under conditions I can no longer reconstruct. Worth someone re-running deliberately, since --rpc-smoke is the gate this issue treats as decisive and that sub-test is inside it.

    Caveat on the counts

    These are log counts, not controlled trials — different branches, different firmware, across a long session. They establish that these gates are not frequently flaky; they do not establish a failure rate. The ten-cycle gate failed 2 runs in 5 and would have looked fine under this kind of tally if I had happened to capture only its passes.

    I also could not complete the deliberate 3-runs-per-gate check I intended: the bench started killing device runs intermittently regardless of size — a single run died 156 lines in with 33 GB free — so repeated sampling is not currently reliable here.

  17. zackees commented on Sep 11, 2026

    @zackees
    MemberAuthor

    Closing out the testRpPioParallelResources concern — it does not fail on current master

    In the comment above I flagged five --rpc-smoke failures on that sub-test and said I could not reconstruct their context. Timestamps settle it:

    • the five failing logs are dated 09-07
    • every --rpc-smoke run from today (09-11) passes, and names that sub-test explicitly in the pass list:
    RESULT: RPC smoke PASS (discovery, help, ping, payload, status, drivers, testNoSerial,
                            RP concurrency, RP PIO contention, RP PIO0+PIO1 resources,
                            error handling)
    

    Four days and a lot of merged work separate them. So testRpPioParallelResources is not a live concern for this issue's decisive gate, and the 58/5 split in my table is not a current failure rate — it is today's passes mixed with a four-day-old snapshot.

    That is a flaw in how I built that tally worth naming: I counted matches across every log in the scratch directory without regard to when they were produced or against which tree. It happened to be conservative here — it surfaced a concern that turned out stale rather than hiding a real one — but the same method could as easily have buried a current failure under a pile of older passes, or reported a fixed bug as live. Log-grep archaeology needs the timestamps read alongside the matches, which I did only after the fact.

    Corrected stability picture for the pin-free gates, restricted to today's runs against current master: PIO0/1/2, --simd, --watchdog-soak and --rpc-smoke all pass repeatedly with no failures. The one gate with a demonstrated failure rate remains the ten-cycle peer-network run, at 2 in 5 before #4372.

  18. zackees commented on Sep 12, 2026

    @zackees
    MemberAuthor

    Fresh hardware pass on current master (731fb6f8ad), both boards attached. Recording it against the acceptance list so the remaining work is precise.

    Fixture

    role port VID:PID serial firmware-confirmed identity
    RP2350W DUT /dev/ttyACM0 2E8A:F00F 2DCB876B587EA334 status.platform → "Raspberry Pi Pico 2 W (RP2350)"
    ESP32-C6 peer /dev/ttyACM2 303A:1001 8C:BF:EA:CF:87:B4 esptool → Chip type: ESP32-C6FH4 (QFN32) (revision v0.1)

    Host: NixOS 6.18.48, fbuild 2.5.23. Ports are the current enumeration, not the COM17/COM9 in the issue body.


    1. Peer network — ten cycles, clean

    bash autoresearch rp2350w --net-peer \
      --upload-port /dev/ttyACM0 --peer-upload-port /dev/ttyACM2 --timeout 600
    --- Peer network cycle 1/10 ---
      RP2350W joined in 5.7s (attempt 1) -> 192.168.4.2
      RP2350W -> ESP32-C6: tests_passed=12 tests_failed=0
        RP2350W -> ESP32-C6 payload: test='POST /echo 4096-byte FNV-1a' bytes=4096 passed=True
      ESP32-C6 -> RP2350W: tests_passed=12 tests_failed=0
        ESP32-C6 -> RP2350W payload: test='POST /echo 4096-byte FNV-1a' bytes=4096 passed=True
      RP2350W serial RPC ping: PASS
    ...
    --- Peer network cycle 10/10 ---
      RP2350W joined in 5.9s (attempt 1) -> 192.168.4.2
      RP2350W -> ESP32-C6: tests_passed=12 tests_failed=0
      ESP32-C6 -> RP2350W: tests_passed=12 tests_failed=0
      RP2350W serial RPC ping: PASS
      ESP32-C6 serial RPC ping: PASS
    
    NET PEER AUTORESEARCH PASSED (10 reconnect cycles)
    

    Exit 0. Join time 5.7–5.9 s, attempt 1 on all ten cycles, same lease every time. No cycle failed, and the log carries none of the ID-timeout signature #4173 produced at cycle 7 — that regression does not reproduce on master.

    The 12 per-direction tests are not 12 pings; they are GET /ping, GET /status, GET /leds, GET /rpc/{discover,ping,status,unknown}, POST /rpc with the same four methods, and the 4 KiB echo. So network-carried JSON-RPC discovery, ping, status and -32601 error handling are each exercised in both GET and POST form, in both directions, ten times.

    2. Serial RPC smoke

    bash autoresearch rp2350w --rpc-smoke --upload-port /dev/ttyACM0 --timeout 240
    RESULT: RPC smoke PASS (discovery, help, ping, payload, status, drivers,
    testNoSerial, RP concurrency, RP PIO contention, RP PIO0+PIO1 resources,
    error handling)
    

    Decisive lines behind it:

    REMOTE: help -> 39 methods
    REMOTE: status -> {'platform': 'Raspberry Pi Pico 2 W (RP2350)', 'rpcReady': True, 'ledRxAvailable': False}
    REMOTE: debugTest -> {'received': {'text': 'rp2350w-rpc-smoke', 'nested': {'ok': True, 'values': [1,2,3]}, 'number': 2350}}
    REMOTE: missing-method structured error -> code=-32601, message='Method not found: __autoresearch_missing_method__'
    

    rpcReady: True alongside ledRxAvailable: False is the RPC-readiness vs LED-RX distinction the issue asks for, reported explicitly rather than inferred.

    3. Concurrency and the RP mutex dispatch gap

    REMOTE: testRpConcurrency -> {'actual': 200, 'expected': 200, 'success': True,
      'backend': 'pico-sdk-mutex+arduino-core1', 'supported': True,
      'core0Completed': 100, 'core1Completed': 100, 'recursiveMutexReady': True,
      'core1LoopCountBefore': 8077, 'core1LoopCountAfter': 8079}
    

    Real dual-core work — core1's loop counter advances across the test, so the second core is genuinely running rather than stubbed. That closes the listed gap "RP2350 mutex/semaphore dispatch is guarded only for FL_IS_RP2040" with live evidence.

    Also from the same run, both PIO resource gates: testRpPioContention (noTheft, noLeak, 11 SMs free before and after) and testRpPioParallelResources (PIO0+PIO1 concurrent, collisionFree, noResidueBetweenFrames, DMA free 15 → 15).

    4. SIMD

    bash autoresearch rp2350w --simd --upload-port /dev/ttyACM0 --timeout 240
    Results: 85/85 passed
    SIMD TEST PASSED (85 tests)
    

    Plus testSimdBenchmark returning real figures (simd_us 571 / 898 / 568).


    Against the acceptance list

    Satisfied by the above:

    • Serial RPC smoke ends with its decisive PASS result
    • The C6 is firmware-confirmed as ESP32-C6 before use
    • RP2350W joins the C6 AP and receives a valid lease
    • RP2350W → C6 and C6 → RP2350W HTTP checks pass
    • Network JSON-RPC discovery, ping, payload echo, status and error handling pass between the boards
    • A deterministic ≥4 KiB payload is transferred without corruption
    • Ten reconnect/teardown cycles pass without RPC timeout, watchdog reset, stale port or wrong-device selection
    • Both boards answer serial ping after every network test and after cleanup
    • Closeout evidence records both ports, VID:PIDs, serial identities, exact commands and decisive REMOTE:/RESULT: lines
    • No raw flasher, raw pyserial, one-off sketch, external AP, or host Wi-Fi switching — every deploy went through fbuild deploy with an explicit -p, and the host's own Wi-Fi was untouched

    Partly satisfied — being explicit rather than ticking it:

    • IEEE-754, SIMD, watchdog, concurrency and Wave2D gates. SIMD (85/85) and concurrency (200/200) are proven above. IEEE-754, the watchdog reset/CDC-reacquisition cycle, and Wave2D were not run in this pass and are not claimed.

    Still open, with the reason:

  19. zackees commented on Sep 12, 2026

    @zackees
    MemberAuthor

    One more item off the current-gaps list, with live evidence.

    --perf-wave2d incorrectly enters the GPIO-dependent path.

    It does not any more:

    $ bash autoresearch rp2350w --perf-wave2d 32x32 --upload-port /dev/ttyACM0
    📌 Wave2D mode: skipping pin discovery and GPIO pre-test
    

    Same shape as --simd — the mode is recognised as pin-free and skips discovery and the GPIO pre-test entirely, so the Wave2D gate no longer depends on a bridge it never needed.

    The run is clean on the attached Pico 2 W (2E8A:F00F, 2DCB876B587EA334), sanity probes included:

    perfProbeMemcpy (4096 bytes x 1000 iters)... 194.5 MB/s
    perfProbeNop    (100k iters)............... 0.0410 us/iter
    perfProbeRepeat (32x32, 50 iters x 8 rep).. 0.23% (stable)
    
    wave2dPerf:
      FivePoint          (compute)     0.3750 us/cell   2602 fps
      FivePoint          (loads_only)  0.3760 us/cell   2600 fps
      NinePointIsotropic (compute)     2.4570 us/cell    397 fps
      NinePointIsotropic (loads_only)  0.3760 us/cell   2598 fps
    
    "untrusted": false, "untrusted_reasons": []
    

    Along with it, two more of the "IEEE-754, SIMD, watchdog, concurrency and Wave2D" gates I could only partly claim in my earlier comment:

    • IEEE-754: ieee754CodecTest → {"tests_run": 35, "tests_failed": 0}
    • Timing drift: 2954 shows, show_min_us: 109 / show_max_us: 200, every iteration after warm-up at 2495 ms

    That leaves watchdog as the only unclaimed member of that bullet. I have deliberately not tripped it: this bench runs unattended, and a deliberate hang is the one action whose recovery I would not be present to confirm. The recovery half is evidenced by every deploy in this session (fresh uptime, lastResetCause: "SOFTWARE", RPC live immediately after), and a real lastResetCause: "WATCHDOG" with self-recovery is already on record in #4173.

    Full gate table and the driver matrix are on #3899.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ciGitHub Actions, fbuild, toolchainsdeferredTriage pass could not resolve this; skipped by ci/oldest_issue.pyplatform: rp2040Raspberry Pi Picostatus: blockedBlocked by external dependency or issuetype: featureNew capability or enhancement

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions