Skip to content

fx3_cmd → diagnostics tool: plan + Phase 1 (extract fx3_core)#162

Open
ringof wants to merge 6 commits into
mainfrom
claude/fx3-cmd-to-tool
Open

fx3_cmd → diagnostics tool: plan + Phase 1 (extract fx3_core)#162
ringof wants to merge 6 commits into
mainfrom
claude/fx3-cmd-to-tool

Conversation

@ringof

@ringof ringof commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Summary

Splits fx3_cmd into a reusable diagnostics core + the firmware regression/fuzz/soak harness, and re-points the harness at the shared core in the rx888_tools submodule so the two repos stop carrying parallel copies.

Commits

  1. docs: plan …docs/fx3_cmd-split-plan.md: the split plan (now updated to the verified, as-built state).
  2. tests: extract diagnostics core … (Phase 1) — behavior-preserving in-repo refactor into fx3_core.
  3. tests: backport --no-claim + GETSTATS length tolerance — keeps this repo's core convergent with rx888-tools (PR #26, merged) ahead of the cutover.
  4. tests: add hardware-free CLI smoke test …cli_smoke.sh (make check-cli, wired into CI) pins the --no-claim guard's exit codes; also corrects the guard/usage "read-only" wording (stack_check toggles debug mode but stays on EP0).
  5. docs: update fx3_cmd split plan … — re-baseline the plan to verified reality.
  6. tests: build harness against shared FX3 core from rx888_tools submodule (Phase 3) — the de-duplication.

Phase 3 — single shared core (this PR)

  • Submodule pin tests/rx888_tools 6191883 → fd01e67 (merged PR Enhancement: add debug-over-USB console subcommand to fx3_cmd #26 adds src/fx3_cmd/{fx3_core,fx3_usb,fx3_stats} + reconciled include/rx888.h).
  • Deleted the duplicated local fx3_core.{c,h}, fx3_usb.{c,h}, fx3_stats.{c,h}, fx3_proto.h (−1,056 lines net).
  • New tests/fx3_test_proto.h carries the only harness-only protocol bits (HANG*, EP1_IN, FX3_MAX_EP0LEN), kept out of the public rx888.h.
  • tests/Makefile compiles the core straight from the submodule (-Irx888_tools/src/fx3_cmd -Irx888_tools/include); local harness modules re-point "fx3_proto.h""rx888.h".
  • Verified equivalence: the cores were byte-identical except the include line, so this is a build-seam change with no behavior changefx3_cmd is the same size; make, check-health, check-cli all green; dispatch/usage identical.

Verification gate (Phase 0)

Post-#26 rx888.h matches the firmware source of truth (SDDC_FX3/protocol.h) on every shared symbol: AD8370_VGA, LED_BLUE bit 11, GETSTATS=0xB3, WDG_MAX_RECOV=14, USB IDs; the HANG* test codes are correctly absent from the public header.

Anti-drift rule (going forward)

Core edits land in rx888-tools first, then the firmware bumps the submodule pin — the firmware repo never re-forks the core or re-creates fx3_proto.h. (fx3_bulk stays firmware-local by design: rx888-tools streams via librx888/rx888_stream.)

Bench follow-up (needs hardware, not blocking)

Run tests/fw_test.sh / validate.sh once on a real RX888mk2 to confirm the harness scenarios pass post-cutover.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa

…rness

Draft plan documenting how to package fx3_cmd for quick diagnostics by
extracting a shared FX3 host core and diagnostics CLI into rx888-tools
while keeping the fuzz/soak/regression harness in this repo.

Documentation only; no code or build changes.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
Behavior-preserving split of the fx3_cmd monolith. Move the operator
-diagnostics primitives into a new shared translation unit so both the
firmware test harness (this repo) and the rx888-tools diagnostics CLI
can link the same core.

New tests/fx3_core.{c,h}: firmware upload (find_rx888_stream,
upload_firmware), the vendor-command primitives (do_test/gpio/adc/att/
vga/wdg_max/start/stop/i2cr/i2cw/reset/usbreset/reload/raw), and the
read-only status reads (do_test_stack_check/stats_pll/stats_shdn).
Functions gain external linkage and prototypes in fx3_core.h.

tests/fx3_cmd.c: include fx3_core.h, drop the moved bodies and their
redundant forward declarations; keep the regression/fuzz/soak harness,
the interactive debug console, and main()/dispatch. do_stats was
already shared in fx3_stats.c.

tests/Makefile: add fx3_core.o/fx3_core.h to the build.

Verified: clean -Wall -Wextra build; fx3_cmd usage and dispatch tokens
identical to pre-refactor; make check-health passes.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
@ringof ringof changed the title docs: plan to split fx3_cmd into a diagnostics tool + firmware harness fx3_cmd → diagnostics tool: plan + Phase 1 (extract fx3_core) Jun 8, 2026
Keep the shared diagnostics core convergent with rx888-tools (PR #26),
which evolved the same fx3_core/fx3_usb/fx3_stats files after the Phase 1
extraction. Ports the two robustness improvements; leaves out that repo's
rx888.h migration and command_lookup refactor (unrelated to these).

--no-claim read-only mode (fx3_usb.{c,h}, fx3_cmd.c):
  g_no_claim makes open_rx888 skip the interface claim / kernel-driver
  detach / EP1 ring restart, and close_rx888 skip the release. A new
  --no-claim CLI flag, restricted to the read-only EP0 commands
  (test/stats/stats_pll/stack_check), lets a host read counters without
  disturbing another process streaming with the interface claimed.

GETSTATS 26-byte tolerance (fx3_stats.{c,h}, fx3_core.c):
  read_stats accepts payloads >= GETSTATS_MIN_LEN (26) and records
  payload_len/has_gpio_state, reading gpio_state[26..29] only when the
  30-byte payload is present. do_stats prints gpio=n/a on legacy
  firmware; stats_shdn fails gracefully when gpio_state is absent.

On current 30-byte firmware has_gpio_state is always 1, so output is
unchanged. Verified: clean -Wall -Wextra build; --no-claim rejects
writes and allows reads; make check-health passes.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
@ringof ringof marked this pull request as ready for review June 8, 2026 18:17

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11eb732097

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/fx3_cmd.c
strcmp(cmd, "test") != 0 &&
strcmp(cmd, "stats") != 0 &&
strcmp(cmd, "stats_pll") != 0 &&
strcmp(cmd, "stack_check") != 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep --no-claim limited to passive reads

Allowing stack_check here breaks the new --no-claim safety contract for running alongside an active streamer: do_test_stack_check() is not a read-only status read, because it enables firmware debug mode with TESTFX3 wValue=1 and sends the stack command via READINFODEBUG before polling the response. In the fx3_cmd --no-claim stack_check scenario this can still mutate/debug-drive the firmware while another process owns the streaming interface, so it should be rejected like the other perturbing commands or documented/implemented as a claimed operation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on the classification — confirmed: do_test_stack_check() (tests/fx3_core.c:445) enables debug mode via TESTFX3 wValue=1 and drives the stack command over READINFODEBUG, so it is not a passive read like test/stats/stats_pll.

Decision: keeping stack_check in the --no-claim allow-list, but fixing the inaccurate "read-only" framing it was justified under. The actual contract --no-claim enforces is EP0 diagnostics that neither reconfigure the radio nor need the streaming interface — all four stay on EP0 and never claim interface 0 / restart the EP1 ring. stack_check toggles an internal firmware debug flag and reads RTOS stack info; it does not touch the RF/sample path (gain/atten/ADC-clock) that a concurrent streamer depends on, which is the perturbation the writes (gpio/att/vga/adc) are rejected to avoid.

Updated in 2af19d6: reworded the guard comment and --no-claim usage text to state this accurately (debug-mode toggle called out explicitly), and added a hardware-free CLI smoke test (make -C tests check-cli, wired into CI) pinning the guard's exit codes. The residual we accept is debug-console CPU contention on the FX3, not a stream-config mutation.


Generated by Claude Code

claude added 3 commits June 8, 2026 18:24
Pin the --no-claim allow-list (test/stats/stats_pll/stack_check) and the
usage exit codes via exit-code assertions that resolve before libusb
touches the device, so they run in CI without an RX888. Wire as
`make -C tests check-cli` and run it in the host-tools workflow job.

Also reword the guard comment and --no-claim usage text: they described
the allow-list as "read-only," but stack_check toggles firmware debug
mode (TESTFX3 wValue=1) and drives the debug console. The accurate
contract is EP0 diagnostics that neither reconfigure the radio nor need
the streaming interface; stack_check stays on EP0 and leaves the
RF/sample path untouched. No behavior change.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
…submodule)

Mark Phases 0-2 done: rx888-tools post-#26 rx888.h is reconciled to the
firmware protocol, and the firmware/tools cores are byte-identical except
the include line. Replace Phase 3 with the verified firmware-side steps and
the evidence-settled seam (share core/usb/stats from the submodule; keep
bulk/fuzz/lifecycle/cmd; carve harness-only codes into fx3_test_proto.h).
Add a single-source anti-drift rule as Phase 4.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
…le (Phase 3)

Delete the duplicated fx3_core/usb/stats + fx3_proto.h and compile the
core straight from the rx888_tools submodule (bumped to the post-#26 rev
fd01e67), so the firmware harness and rx888-tools no longer carry parallel
copies. Harness-only protocol codes (HANG*, EP1_IN, FX3_MAX_EP0LEN) move
to a new firmware-local fx3_test_proto.h; production constants come from
the submodule's rx888.h. Net -1,056 lines, no behavior change.

https://claude.ai/code/session_01YcMhE8u6WjetJosAT5dLPa
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.

2 participants