| Age | Commit message (Collapse) | Author |
|
hil, ci: scope HIL builds and tests to the boards a PR affects
Add test/hil/hil_select.py, a stdlib-only selector that maps a PR diff to the
rig boards, tests and BSP families a change can affect, and wire it into CI so
pull requests build and run only those. A port change picks its families' boards,
a class change picks the examples enabling that class, and device/host changes
prune the other role. Anything unclassified — infra, an unmapped port, a selector
error — falls back to the full matrix, and push/schedule runs are untouched.
Move the shared example lists to hil_examples.py; 54 hardware-free tests cover
the rules.
|
|
probes (#3794)
test/hil: add board-pool health check, split hil_test into focused modules (#3794)
Add test/hil/hil_pool_check.py: per-board rig health scan — probe presence,
light-example flash (dfu_runtime; device_info + serial check for host-only
boards), uid re-enumeration, safe recovery (probe authorized-toggle, board
reset), verified board_test re-park, USB topology report, and a markdown
summary table. Missing firmware is built on the spot (tools/build.py, idf.py
for espressif, one get_deps retry); row statuses: ok, flash-failed, failed,
locked. Board locks are always respected, never bypassed.
Refactor hil_test.py into hil_lock.py (flock protocol, controller permits,
hold/release/status CLI; replaces board_lock.py) and hil_flash.py (flashers,
find_firmware, run_cmd). Update WCH probe uids and the board roster in
tinyusb.json; add the hil-pool-check skill.
|
|
(#3789)
test/hil: replace PCI reset with root-port VBUS cycle for D-state recovery
pci-reset was documented as an FLR, but no controller on either rig has FLR, so
it issued a PCIe secondary bus reset on a live, driver-bound xHCI -- halting the
card until the PVE host was power-cycled, and returning success so the caller
could not tell. It destroyed the ci controller twice.
Replace it with root-cycle, which cuts VBUS at the xHCI root port and touches
only the root hub, so it never takes the per-device lock the wedged ioctl holds.
uhubctl needs -S, or its sysfs backend disconnects the child before cutting
power and blocks on that same lock. Success is proven by the device's sysfs
directory inode changing: node existence proves nothing, and devnum is reused
once the per-bus map wraps.
usbtest.py's hang path invokes it, then confirms via /proc that nothing still
holds the device node. Skill scripts now run from the repo; the drifted
/usr/local/sbin copies are deleted.
|
|
Coverage rows now resolve the de-collided module-qualified key introduced
for same-named statics. RA boards: document that --attach requires a
debugger-booted target - the C_DEBUGEN gate exists because an unguarded
TRCKCR write bricks standalone boots (hardware-proven), so the limitation
is documented rather than the guard weakened; a debugger-side TRCKCR hook
can lift it later once re-verified on hardware. The stm32n6 board-gating
suggestion is not taken: N6 trace pins are AF0-fixed chip-level, the same
family-wide pattern as stm32h7.
|
|
The board-specific PHY-reset nets move behind a board.h opt-in
(TRACE_ETM_QUIET_ENET_PHY on same70_xplained and mimxrt1170_evkb) so other
boards of those families cannot inherit a foreign GPIO write; the
chip-level trace pin muxes stay family-wide by design (same pattern as
stm32h7). same70 reference: width 1 is the validated default until the
J403.16 rework, and the hooks now wait (bounded) for PCKRDY3 before Ozone
arms trace. ra8m1 reference caches the boot ROM in AfterTargetConnect so
--attach sessions decode ROM execution too. etm_capture rejects an
unexpanded CMake JLINK_DEVICE with a clear error; PIO-USB + TRACE_ETM on
RP2350 is now a compile error (48 MHz trace clock is too slow for PIO-USB
and a runtime switch would desync the stream); etm_profile keeps
same-named statics from different modules as distinct rows.
Build-verified: same70_xplained, mimxrt1170_evkb, raspberry_pi_pico2.
|
|
Bot findings (Copilot/Codex): no-op board_trace_pinmux stubs for
lpcxpresso18s37/43s67 (TRACE_ETM otherwise broke their build), SAME70
ID_PIOD clock enable, capture-script duplicate BeforeTargetConnect on the
RA references, profile-script support for --no-timestamps itraces.
Deep review (whole branch): same70_xplained board row + caveat restored,
stale pico2 72 MHz claim corrected to the shipped 48, explicit
SetTracePortWidth(4) in the three references that relied on Ozone's
default, coverage-cell guard, median-based SysTick calibration, dead
session flag removed, stale RA8M1 divider comment fixed (0x02 = /4 is the
validated chip max) and the debugger guard indented.
EVKB bench findings: only R1884/D3 remains open (D1/D2 meter-verified);
RT1176 trace width is 1 or 4 only - J-Link arms the CSSYS TPIU and its
own sampler at 4-bit for any width>=2 request; a powered MCU-Link USB
breaks the external probe even with JP4 shorted.
|
|
Fresh bring-up pass on mimxrt1170_evkb: holding the 100M RTL8201 in reset
(ENET_RST_B = GPIO_LPSR_04) stops its RMII lines driving against the
shared trace pads and doubles the clean trace-pin rate to 50 MHz
(100 MHz CSTRACE root; 133 MHz root is marginal, stock 132 corrupts).
Validated 3x 8 s TinyUSB captures at 11.46M fetches. D1-D3 remain silent
in every configuration - the welded R1882-R1884 are electrically open;
reflow is the remaining step to width 4. Board notes gain JP4 (must be
shorted for an external probe on J58).
|
|
Fifth capture view alongside usbmon/kernel/target/wire: exact execution
history via J-Trace, existing only where the trace header is wired -
confirm with the user before reaching for it.
|
|
Instruction-level trace outranks PC-sampling when samples cannot resolve a
mechanism, but the J-Trace is exclusive per-board hardware: the agent uses
it only when its prompt says the board is trace-wired or the user asked,
and otherwise proposes it in notes - mirroring the lock-force consent rule.
|
|
target-debug replaced usb-target-debug in the debug-skill overhaul; update
the cross-skill table and PC-sampling pointer. Add the consent gate: the
J-Trace is a single probe moved between boards, so captures on a board the
user did not just ask about need explicit confirmation that it is wired.
|
|
Headless instruction-trace capture on any TRACE_ETM-capable board via
Ozone's automation socket (port 19201, xvfb): etm_capture.py generates a
throwaway project from the board's committed ozone reference (device, TIF,
width, timing, hooks, JLinkScript inheritance), drives the session, and
exports profile/coverage; etm_profile.py renders hot functions, coverage,
per-line/instruction counters and ISR timing from the itrace stream.
SKILL.md carries rig discipline, capture recipes, a new-board bring-up
ladder and troubleshooting; boards.md is the per-board reference (config
table + caveats) for all validated boards.
|
|
- target-debug: fault frame lives on PSP when EXC_RETURN bit2 set (FreeRTOS
tasks) — decode LR before choosing $msp/$psp (Codex; valid, our verify
happened to fault on MSP)
- esp-target-debug: show the Xtensa gdb for S3 in the attach recipe; clarify
adapter serial = USB-SJ iSerial (colon MAC, hardware-verified) vs the
CP2102N flasher uids in tinyusb.json (Codex; second half of the finding
had the identifiers inverted)
- esp plan: align serial form with the verified command; record the real
console-gate outcome (UART0, USB-SJ console untested) (Copilot)
- target-debug plan: Task 4 now consistently $JB/ARMv7-M matching the
executed JLinkExe path (Copilot)
- drop IDE-local .idea files swept in by the rename commit (Copilot)
|
|
by board family
- esp-target-debug: de-narrated (~1000 -> 847 words) — session-diary phrasing
('this unit', dates, 'we measured') replaced with durable reference facts;
restructured per-board (P4 vs S3 notes); new Scripted-session gotchas
section consolidates telnet-halt pattern, ESP_ONLYCPU, and ROM-frame
guidance; UART-reset recipe stated once
- target-debug: fix run-on seam from the -singlerun insertion
- target-debugger agent: charter now resolves the board family FIRST and
routes Espressif boards to esp-target-debug as primary playbook; skills
table re-aligned
- retrieval regression: 4/4 (agent routing, S3 keep-alive quirk, OpenOCD RTT
on ST-Link, ROM-frame guidance)
|
|
rig-verified
P4 (hand-wired USB-SJ breakout, GPIO24/25 from header J1):
- COEXISTENCE verified: 303a:1001 + cafe:4008 enumerated simultaneously;
gdb attach/halt/bt during live CDC traffic; symbolized app backtrace
(tud_task_ext <- usb_device_task <- vPortTaskWrapper)
- set ESP_RTOS FreeRTOS before board cfg -> full dual-core task list;
without it, bare 'Remote target'
- attach-may-reset nuance flagged (post-mortem autopsy caution)
- console = UART0 (CP2102 flasher tty) on stock builds; D+/D- swap symptom
documented (low-speed + error -71 vs full-speed)
S3 (same-port PHY swap):
- boundary captured live in dmesg: same hub port flips 303a:1001 ->
cafe:4008 as the app boots; openocd 'esp_usb_jtag: could not find or open
device!' verbatim
- attach/halt/symbol resolution verified via board_test (usb_new_phy absent
from ELF when CFG_TUD/TUH=0); app-context keep-alive quirk (~4 s
unattended drop, -71 half-dead, UART esptool reset recovers); cpu1
OCD_ID=0 -> ESP_ONLYCPU=1; telnet-halt + gdb-read scripted pattern;
RTC_CNTL PHY-mux reference (0x60008120) + esptool read_mem/write_mem
- target-debug pointer + target-debugger agent table row
|
|
to table; SWO enable chain
- DWT data trace: FUNCTION 0b0011 (ARMv7-M ARM Table C1-21) streams value +
accessor-PC packets per access, no halt, no code. Verified on
stm32f407disco (J-Link SWORead: 451 KB, value = uptime ms, PC =
tusb_time_millis_api) and stm32h743nucleo (OpenOCD/ST-Link tpiu capture:
607 KB, same decode). Caveat recorded: R/W-only trace floods on polled
variables.
- SWO enable chain documented: tools own TRCENA/ITM/TPIU; vendor part bites
— H7 needs DBGMCU trace clocks, PB3 manually muxed to AF0, native
stlink-dap (hla tpiu silently no-ops), the cfg's stm32h7x.swo object (the
.tpiu object is the parallel port), traceclk = c_ck 400 MHz (wrong guesses:
ratio-garbage or silence).
- Sections reordered to match the intrusiveness table (least->most
intrusive); cross-references fixed; table gains the data-trace row.
|
|
aligned columns
- target-debugger: skill list is now a table referencing skills by name only
(path pattern stated once).
- target-debug: probe-mapping run-on paragraph split into bullets; drop the
GDB Ninth-Edition caveat (calibre now holds the Tenth-Edition PDF, id 2264).
- Align markdown table columns across target-debug, usb-sniffer, usbmon, hil,
usbtest and the agent (7 tables); tables with paragraph-length cells left
unpadded (usbmon symptom map, usbtest case map).
|
|
table integration
- Vector catch + Cortex-M fault autopsy, verified with a deliberate bad-load
on stm32f407disco: CFSR=0x8200 (BFARVALID|PRECISERR), BFAR = exact bad
address, stacked pc addr2lined to the faulting line; gotchas recorded
(stale FPB comparators fire phantom SIGTRAPs — scrub first; arm DEMCR
after reset; loads precise / stores imprecise; ARMv6-M has no CFSR/BFAR)
- SWO exception trace + hw PC sampling gate PASSED on F407: 680 KB of
packets in 3 s (0x17 PC samples in flash range, 0x0E SysTick enter/exit);
JLinkSWOViewerCL decodes stimulus only — raw SWORead is the recipe;
SWOStart needs an explicit speed headless
- verifybin 'Verify successful.'; FreeRTOS -rtos plugin lists all 6
cdc_msc_freertos tasks after a run->stop cycle (plain attach = 0xDEAD
placeholder); semihosting anti-note; monitor-mode pointer (untested)
- Intrusiveness table gains the new rows; agent playbook bullet updated;
retrieval gate 5/5 with a fresh reader; executed plan committed
|
|
- Link J-Link UM08001, OpenOCD and GDB (Tenth Ed.) manuals
- bp/wp depth with halt-per-hit cost model. Verified on stm32f407disco
(J-Link) + raspberry_pi_pico (OpenOCD): FPB/DWT budget reads (M4 6 bp/4 wp,
M0+ 4/2 exact), 'Hardware watchpoint' confirmation rule (software fallback
single-steps = USB death), OpenOCD data-VALUE watchpoints, dprintf +
breakpoint command lists exercised on hardware; JLinkGDBServer -singlerun
lifecycle gotcha
- RTT is not J-Link-only: OpenOCD rtt setup/start/server verified on pico
(control block found at the nm address, LOG=2 boot banner captured over nc)
|
|
Rename usb-target-debug -> target-debug, usb-debug -> usb-kernel-debug,
usb-recover -> usb-kernel-recover (script filenames unchanged), and make all
debug skills/agents decide tool applicability by which end of the link runs
Linux: TinyUSB may run the device or host stack, and its peer may be a Linux
PC, another TinyUSB board, or a Linux gadget (e.g. Raspberry Pi UDC).
- usbmon: exists only when a Linux PC is the link's host
- usb-kernel-debug: either Linux end; allowlist gains dwc3/libcomposite/udc_core
for the gadget side of a Linux peer
- usb-sniffer: the only full-visibility capture when TinyUSB is the host
- target-debug: covers dcd_* and hcd_*/tuh_ debugging; channel choice by topology
- update target-debugger/hil-operator agents, pre-pr, hil-validate.js, and the
USB_RECOVER path constant in test/hil/usbtest.py
- CLAUDE.md: fold the dcd/hcd datasheet cross-check rule into the read-doc line
|
|
* docs: add read-doc skill for on-demand datasheet lookup
Search and read MCU datasheets, reference manuals, errata, and the USB
spec from a local Calibre library ($HOME/Documents/calibre-library)
instead of answering register/bitfield/pinout questions from model
memory. Gated on the library's existence, so it no-ops for contributors
who don't have it.
* docs: reference read-doc skill and tighten CLAUDE.md
Point the datasheet/reference entry at the new read-doc skill, and trim
sections that only duplicate a skill already owning the detail:
PVS-Studio and Code Size collapse to pointers; GDB/Build/Flash command
blocks condensed to essentials. 213 -> 129 lines; behavioral guidelines
and the validation checklist unchanged.
* docs: tighten skill redundancy; rename AGENTS.md refs to CLAUDE.md
code-size: fold the step list into a sentence and drop invocation
examples the argument tables already cover. hil: merge the duplicated
self-lock bullets and compress the hifiphile note. usbmon: compress the
group-membership setup paragraph. All commands, flags, lock rules, and
report paths preserved. usb-target-debug and the pvs script only get
stale AGENTS.md references renamed to CLAUDE.md (now the real file);
run_pvs.sh no longer cites a --dump-files mention that CLAUDE.md dropped.
* docs: fix review findings — restore Espressif cd step, ELF placeholder, code-size comment
Codex/Copilot/Claude review of #3778: the condensed Espressif bullet
lost its cd (idf.py resolves the project from CWD, so the command failed
from repo root); the GDB example now uses the build/your_app.elf
placeholder that docs/troubleshooting.rst established; the code-size
invocation comment no longer references --combined, which the shown
command doesn't use.
|
|
- Drop the dated/host-specific tap topology; confirm the cabling each
session instead (the tap gets re-cabled often), and read the DUT link
speed from sysfs to pick --speed.
- Genericize the hub-upstream reset-visibility note.
- Rewrite "one-time setup" as a copy-paste shell block (udev + binary +
Wireshark extcap symlink), keeping only the firmware-command caution.
|
|
Fourth view in the USB debugging toolset (usbmon = host URBs, usb-debug =
host reasoning, usb-target-debug = device firmware, usb-sniffer = what
actually crossed D+/D-). Covers the ataradov/usb-sniffer analyzer:
headless pcapng capture (--speed ls/fs/hs, --fold, --limit self-exit),
Wireshark/tshark analysis recipes, and the wire realities that bite:
downstream broadcast, sniffer self-capture noise, xHCI devnum != wire
address, tap-point-dependent reset visibility (hub choreography anchors),
FS-behind-HS-hub splits. Every recipe hardware-validated on the rig,
including the capture-window floor (a 3 s window provably misses the
enumeration ladder; 3M packets minimum).
Two udev files with distinct audiences, not one:
- examples/device/99-tinyusb-examples.rules (renamed from 99-tinyusb.rules):
the user-facing rules the examples need — cafe VID access, hidraw, the
ModemManager blacklist, a couple of board probes. getting_started.rst,
the webusb_serial README and its source comment point here.
- tools/88-tinyusb.rules: the HIL rig's private probe/analyzer allowlist,
now with the sniffer (6666:6620 + blank FX2LP 04b4:8613). Installed on
the rig only; the usb-sniffer skill references it.
|
|
Opus-tier agent charter for backgrounding a long hardware debug session:
instrument -> build -> flash under one held board lock -> dual-side
capture -> correlate -> refine, strictly one instance, skills as source
of truth (usb-target-debug, usbmon, usb-debug, usb-sniffer, usb-recover,
hil). The charter encodes what dogfooding established:
- diagnosis standard: evidence must show the mechanism, or a fix must
flip the ORIGINAL failing case on hardware; stop after two
evidence-free cycles and hand back a partial diagnosis
- lock cadence: hold for the whole session, release around hil_test.py
runs (it self-locks per board)
- revert semantics: "fix stays, probe goes, re-verify clean" —
instrumentation reverted, candidate fix left uncommitted and
re-verified on a clean build, pristine firmware reflashed before
lock release
Returns a machine-parseable diagnosis report including ruledOut[] —
disproven hypotheses are deliverables. Spec roster updated (opus/xhigh,
effort requested per agent() call).
|
|
Completes the debugging toolset (usbmon = what the host exchanged,
usb-debug = why the host acted, usb-sniffer = what crossed the wire):
TU_LOG/RTT capture, per-probe GDB autopsy without reset, RAM ring-buffer
event trace, J-Link DWT_PCSR PC-sampling, dual-side capture posture, and
board-lock rig discipline. Includes the implementation plan it executes.
Hard-won warnings baked in from real bring-up sessions: volatile ring
buffers vs -Os dead-store elimination, RTT NO_BLOCK_SKIP post-mortem
limits (no overwrite mode exists), DHCSR validity anchors for register
snapshots, release-lock-before-hil_test, and that a marginal just-recabled
link can fake a deterministic firmware bug.
Also ignore .claude/worktrees/.
|
|
incompatible
The MosChip MCS9990 card is physically removed from the rig: delete its
cases-11/25 SKIP workaround (and the now-orphaned SKIP accounting) from
usbtest.py and refuse to run outright if a DUT ever sits behind one again.
usb_recover.sh gains `hub-cycle <busport>`: uhubctl VBUS cycle of the port
feeding the device, walking upstream (parent hub -> root port) until it
re-enumerates. Verified on the rig: leaf-level recovery (13-4.4 usbtest
device) and full walk to the root port on a dead branch. SKILL.md updated
for the action and the two-Renesas topology (root-port ppps is real; leaf
1a40:0201 hubs fake their "ganged" switching).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WxUeX4Yn26KibfjvDg2pN9
|
|
- dcd_edpt_stall flushes the primed buffer (ENDPTFLUSH), but the aborted
transfer's dQH overlay can be left ACTIVE with mid-transfer state; the
next prime after clear-halt then resumes the stale overlay instead of
loading the fresh qtd, so post-halt IN reads return mid-buffer data
(usbtest case 13 'buf[32] = 56 (not 0)', with case 18 failing
downstream of the same corruption in the full battery). qhd_start_xfer
now clears overlay.active alongside overlay.halted before linking the
new qtd.
- test/hil(hfp): drop lpcxpresso43s67's device/usbtest skip - the
historical first-case wedge no longer reproduces on this branch, and
with the overlay fix the board runs 30/30 on its Fresco xHCI host
(previously 28/30 with deterministic case 13/18 failures).
mimxrt1064_evk (imxrt dcache path) 30/30 regression-clean.
- docs(hil skill): document the external hifiphile rig - pool
test/hil/hfp.json, SSH-reachable from htpc/ci with no outbound SSH,
exercised by the CI hil-tinyusb (hfp.json) job; never run HIL against
it during development unless the user explicitly asks.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017TQZrFfU3K4Y198aLsUpBC
|
|
# Conflicts:
# .claude/skills/hil/SKILL.md
# test/hil/hil_test.py
|
|
Pool/config:
- record real uids (ra8m1_ek), enable usbtest for espressif s3/p4, then
park ra6m5_ek and ra8m1_ek in boards-skip (ra6m5's usbtest/MSC traffic
can kill the uPD720201 host on its ROM firmware; ra8m1 USBHS bring-up
pending); max32666/nrf54lm20 stay enabled - their MosChip flakiness
never wedges
- re-enable device/usbtest on HS boards (mimxrt1064, ch32v307) now that
uPD720201 firmware 2.0.2.6 fixes the command-ring death; mimxrt1015
stays skipped - its HS battery killed the controller on both ROM and
2.0.2.6 firmware (board-specific); match the moved host-test bundles
(f723 <-> rt1064); skip never-passing tests on the new
nrf5340dk/nrf54lm20dk boards and the detached pico host bundle, each
documented with a comment
Host-controller quirk gating in usbtest.py (auto-skip, self-heals on a
healthy xHCI):
- MosChip MCS9990 EHCI: case 25 (int-OUT never scheduled, FRINDEX bug)
and case 11 (unlinked reads complete short/EREMOTEIO)
- Renesas uPD720201 xHCI: firmware-gated. The card must run firmware
>= 2.0.2.6 (RAM-uploaded - it reverts to ROM on every power cycle):
on older firmware the command ring dies under unlink stress (a
Configure Endpoint command stops completing; the hub worker deadlocks
holding the device lock; only a host power cycle recovers; three
boards reproduced it). usbtest.py reads the FW version register (PCI
config 0x6c) and refuses to run at all on older firmware - hil_test
surfaces that as a failed test with the reason. On current firmware
the full 30-case battery runs (validated FS+HS: metro_m4, f723,
f723-DMA all 30/30).
Scheduling (hil_test.py):
- Shuffle each (board, variant)'s test order with a seeded RNG
(HIL_SHUFFLE_SEED to replay) so usbtest batteries and flash churn spread
across the timeline instead of convoying on one controller.
- Per-controller usbtest + flash semaphores: HIL_USBTEST_PARALLEL
(default 4) concurrent usbtest batteries and HIL_FLASH_PARALLEL
(default 8) concurrent flashes per host controller. Profiled on
uPD720201 firmware 2.0.2.6 across 8/1..12/8: wall time falls
22.2/14.3/12.5/10.8 min at usbtest width 1/2/3/4 and plateaus there;
zero controller errors everywhere; first battery case failures
(leaf-hub bandwidth stretch) appear at 12/8, and flash width 12 only
amplifies flasher-hub contention flakes - so 8/4 is the optimum. A
separate battery-window flash throttle was profiled and dropped.
- Give every example a unique hardcoded USB PID (0x4001-0x4022, usbtest
keeps 0x4010) instead of the PID_MAP interface bitmap: different
examples now always re-enumerate back-to-back, even on boards whose
CPU reset does not drop D+ (WCH CH58x), so the EXAMPLE_PID table and
same-PID adjacency reordering in hil_test.py are gone; only the
variant-boundary same-example repeat needs a swap.
- Report matrix: stable columns with the metric-bearing tests pinned
first (usbtest, cdc_msc_throughput, msc_file_explorer[_freertos]),
the rest alphabetical.
Fail fast:
- enum wait budget 8 s on the first attempt, 4 s on retries; dfu waits
are deadline-based so dfu-util's own runtime counts against the
budget.
A device-absent failure now costs ~3-5x a passing test (20-30 s)
instead of 10-30x (47-150 s).
- CI runs hil_test with --retry 1 and no in-run second pass: a broken
fixture fails the job fast instead of holding the self-hosted runner
for hours and blocking other PRs' HIL jobs. hil_test still writes the
.skip sidecar, so a manual re-run attempt only retests what failed.
Review fixes (multi-agent adversarial review of this commit):
- tinyusb_win_usbser.inf: the PID rework moved five CDC examples onto
even PIDs the INF's odd-only DeviceList never matched (legacy-Windows
usbser binding) - appended 0x4006/4008/400a/4020/4022 to both lists.
- usbtest example: USBTEST_TIER is now overridable and the descriptors
and pumps are tier-conditional, so a board whose DCD cannot serve a
tier lowers it instead of skipping the whole example - RA2A1 (RUSB2
with no isochronous pipe) builds at tier 3 via its BOARD_ define; the
host battery follows the tier advertised in bcdDevice. Tier-4 output
verified byte-identical after the refactor.
- dynamic_configuration's second config derived USB_PID + 11 = 0x4018,
colliding with net_lwip_webserver - now USB_PID + 0x0100, outside the
per-example space. tools/check_example_pids.py (pre-commit hook)
enforces PID uniqueness incl. derived and literal idProduct values.
- usbtest.py firmware gate: matched by device ID (uPD720201/720202,
both use the 0x6c FW register), and an unreadable version (setpci
missing/denied) now refuses with its own message instead of
masquerading as "firmware 0x00000000"; noted the gate is necessary
but not sufficient (board-specific kills stay per-board skips).
- hil_test: deadline waits use time.monotonic(); multiprocessing
context pinned to fork (raw semaphores in Pool initargs); flash and
usbtest permits unified into one fail-closed, exception-safe
ctrl_permit (unknown controller takes every slot and logs a warning
instead of silently borrowing slot 0); an all-skipped battery
reports as skip, not "0/0" failure; slow-body polls (mtp, printer,
disk read) go through a shared deadline-based wait_until so their
bodies count against the enum budget; throughput's FS detection
compares serials case-insensitively like every other walk; a missing
MSC read-speed line now fails the host msc_file_explorer test
instead of passing with an empty metric.
Hardening:
- fail fast (15 s) when a driver-registry sysfs write blocks: a wedged
device otherwise turns every subsequent battery into an unkillable
D-state writer and silently hangs the whole run
- usb-recover skill: a VM reboot is not a reliable cure (MosChip hubs
latch up across the PCIe reset); full host power cycle is
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
Confirmed by a 10-finder / 28-verifier adversarial review pass:
board_lock.py — the flock is now the sole authority: drop cmd_hold's
pid-liveness pre-gate (a live hil_test.py pool worker's stale record no
longer blocks a genuinely free board); cmd_release probes the flock and
only signals a verified holder, refuses to kill hil_test.py holders
(CI mid-test), handles PermissionError; the holder daemon truncates its
lock records on SIGTERM and keeps the success pipe clear of fds 0-2
(closed-stdio hold used to leave an orphan holder while reporting
failure); --config default resolves beside the script.
hil_test.py — truncate the lock record on per-board release (pool
workers outlive their flocks); warn instead of silently failing open
when the lock dir is unusable; error out on -b names absent from the
config (was a silent zero-test exit 0, readable as a green HIL run);
drop an emptied board row in accumulate_report (variant boards left a
blank ghost row).
workflows — remove the stray positional arg that made the validate size
stage exit 2 on every run; wrap JSON.parse(args) in all six scripts;
factor pr-babysit's drifted reply recipe into postReplyRecipe and dedup
refutation replies across cycles; validate args.pr and maxCycles;
driver-review rejects an empty dimensions list; hil-validate drops a
dead guard clause and retries diagnostics with -v -r 1.
agents/docs — port-dev scopes git clang-format to its own files
(concurrent workers reformatted each other in shared checkouts);
hil-operator/hil skill wording matches actual fail-fast output; the
implementation plan is now a DO-NOT-EXECUTE historical record (banner +
checked boxes) so plan-executing agents cannot revert shipped files.
Verified: lock storm 1-winner-in-10, stale-record hold, closed-stdio
hold, dead-pid cleanup, CI-holder refusal, ghost-row 4-scenario merge,
unknown-board exit 1, py_compile + check.sh on all six workflows,
pre-commit clean.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Upj4hta5TNoAbidqeC1zZ6
|
|
Review-fix batch (owner-confirmed) on the multi-agent harness:
- board_lock: detach holder stdio so a captured `hold` cannot hang on the
daemon's inherited pipe; probe locks by holder-pid liveness instead of a
momentary flock, which could spuriously fail a concurrent acquirer
(storm-tested: 1 winner in 10, 0/15 acquire failures under probe storm)
- hil_test: locked board renders a visible board-locked fail row so the
report matches the exit code; stale marker cleared on a real re-run
- pr-babysit: autoPush now opt-in (default dry run); resolve recipe
paginates reviewThreads; post-push resolve gets issue-comment fallback
- validate: size stage honors non-default base via --base-branch; pvs
stage delegated to the new agent
- new static-analyzer agent (sonnet): PVS-Studio SAST+MISRA for one
board, structured findings gated on files changed vs base
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Rn1AN5DsTdFhRwhugfgKZi
|
|
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
Add worker agents (builder, port-dev, driver-reviewer, hil-operator,
pr-monitor), deterministic workflows (validate, fanout-dev, driver-review,
hil-validate, full-check, pr-babysit) and a /pre-pr gate skill, so sessions
can fan build/test/review/PR-triage work out to tiered subagents. pr-babysit
drives a PR to green: triage CI + bot reviews, fix validated findings, verify,
push, and reply-to + resolve each inline review thread (fixed or refuted).
Replace the stop-the-runner HIL discipline with per-board flock locks:
test/hil/board_lock.py plus a fail-open guard in hil_test.py let CI and dev
sessions share the rig per board (locked boards fail fast and re-run;
HIL_NO_BOARD_LOCK=1 is a user-authorized bypass). The actions-runner is
never stopped.
Design spec, implementation plan, and real-rig smoke evidence under
docs/superpowers/.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Rn1AN5DsTdFhRwhugfgKZi
|
|
* docs: convert changelog release notes from RST to Markdown
|
|
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Relocate docs/info/changelog/ -> docs/changelog/ (docs/info held only the
changelog) and update all references: the toctree, README + MAINTAINERS links,
make_release.py, and the make-release skill.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
backfill note
- ci_preferred_boards: rp2040 -> raspberry_pi_pico, raspberry_pi_pico2 so the
one-board CI/metrics build uses a Pico (the first-alphabetical board failed).
- make-release skill: the metrics backfill was a one-time 0.20.0 task, not a
recurring release step; keep only the CI auto-compare note.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
CI auto-uploads metrics.json + a compare to each release on the release event
(needs the previous release's metrics.json); plus the procedure to backfill a
missing baseline by building the old tag's own tree and post-processing its
linker maps (current tooling can't build old source — co-evolved tree).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- changelog: fix 3 silent RST mis-renders carried over from the old monolith
— Markdown link in 0.7.0, mismatched/single backticks in 0.18.0 / 0.20.0
- make-release skill contributors one-liner: parallelize the gh fetch, anchor
the bot filter (was a substring that dropped handles like "abbott"), and join
with ", " (paste -sd cycles the delimiter -> "@a,@b @c"); finalize now stages
only the reviewed set (git add -A -- ':!.idea'); drop the obsolete CRLF gotcha
- make_release.py: emit LF not CRLF in the repository.yml insertion (fixes the
gotcha at the source)
- docs sidebar: drop the hardcoded furo component list; override brand.html to
include furo's own template + the sponsor button (decoupled from furo
internals, no upper-bound pin needed); move sponsor styles into custom.css
- .pre-commit-config.yaml: drop stale end-of-file-fixer excludes for the
deleted contributors/CoC include shims
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- make-release skill: stage new files with git add -A in finalize, use
unprefixed release tags (X.Y.Z), and run validate build steps in subshells
so the cwd doesn't leak between commands
- docs/requirements.txt: require furo>=2025.12.19 so the sidebar component
list in conf.py (incl. variant-selector.html) is always available
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- README: restore the separate CH32V103 / CH583,CH582 rows in the Supported
CPUs table — the merged row wrongly applied "ISO data loss [2]" to CH583/2
- Fix typos in historical changelog entries (santiy, Venndor, dynamnic, bagde,
masstorage, techinical, walkaround, "Update Update") flagged by Copilot
- Replace the AGENTS.md Release section with a pointer to the make-release
skill; add a Finalize step (maintainer commit/tag/push + GitHub release) to
the skill so nothing is lost
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Release:
- Bump version to 0.21.0 and regenerate tusb_option.h, library.json,
repository.yml, sonar-project.properties, boards.rst, dependencies.rst
- Add 0.21.0 release notes and split the changelog into per-release files
under docs/info/changelog/ (date out of title, driver/class groups as
sub-headings, DCD & HCD section after Device/Host stacks)
Contributors:
- Credit each release's PR authors in a Contributors section
- Drop the curated contributors page; add MAINTAINERS.rst
Docs:
- Update Code of Conduct to Contributor Covenant 3.0 (keep it in the repo,
remove it from the built docs)
- Sidebar: add a home entry, rename the group to "Documentation", move
Changelog into it, add a GitHub Sponsor button, merge external links,
rename FAQ; hide the inline toctree on the landing page
- Add the make-release skill and update the AGENTS.md release process
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- Order CFG_TUH_DEVICE_MAX before CFG_TUH_HID in the host config snippets
(cdc_msc_hid, hid_controller) so the documented snippet has no forward
macro reference when copied into tusb_config.h.
- Fix stale `examples.rst` references: the generator now writes per-group
`docs/examples/<group>/index.rst` pages, so update the conf.py comment and
the build-doc SKILL.md accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Documentation tooling:
- Add the `build-doc` skill and `tools/build_doc.py` wrapper for local
Sphinx builds (clean / -W / open).
- Enable Markdown (MyST) in conf.py and auto-collect
examples/{device,host,dual}/*/README.md into a 3-level Examples nav
(Examples > Device/Host/Dual > example), noting each page's source
location and normalizing headings to a single H1.
- Remove the stale `.claude/commands/build-doc.md`; point the AGENTS.md
Documentation section at the skill.
Example docs:
- Add a README.md for every device/host/dual example: what it does, USB
interface table, notable tusb_config.h settings, generic CMake + Make
build steps, and how to try it.
- Fold each *_freertos variant into its base README, noting the FreeRTOS
source path and any RTOS-specific behavior.
Generated docs/examples/ output is git-ignored. Builds clean with
`sphinx-build -W`.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Adds a Claude Code skill that wraps usbmon + tshark to capture host-side
URBs into a Wireshark pcapng and decode them, for debugging TinyUSB device
enumeration/transfer issues on real Linux hardware. Includes a usbcap.sh
capture helper (bus / VID:PID / auto) plus filter, errno, and
symptom->check reference tables.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- Parse PVS_STUDIO_CREDENTIALS into two quoted fields (no glob/word-split).
- AGENTS.md: examples build sets CMAKE_EXPORT_COMPILE_COMMANDS ON already.
Addresses Copilot review on #3695.
|
|
- Add --security-related-issues to run_pvs.sh and AGENTS.md analyze commands
so local runs reproduce the CI SAST classification (static_analysis.yml).
- Ignore *.sarif so a successful run leaves the worktree clean.
Addresses Codex review on #3695.
|
|
The AGENTS.md '-S src/foo.c' example was inaccurate: -S takes a plaintext
file listing source paths, not paths directly. Drop --dump-files from the
documented commands (it scatters .PVS-Studio.i/.cfg dumps across the tree;
FP-debugging only) and reference the new pvs skill.
https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
|
|
Bundle a run_pvs.sh helper (takes BOARD as its first argument) that
follows the PVS-Studio static-analysis flow from AGENTS.md: build all
examples with an exported compile_commands.json, run pvs-studio-analyzer
against .PVS-Studio/.pvsconfig, then emit errorfile + SARIF reports.
https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
|
|
- claude.yml: drop the issues "assigned" trigger; its author_association
gate keys on the issue author, not the assigner, so a maintainer
assigning an outside contributor's issue would be wrongly skipped.
- claude-code-review.yml: issues: read -> write so use_sticky_comment can
create/update its PR comment via the issues API.
- hil SKILL.md: make local/remote command blocks copy-pasteable (drop
[-b BOARD_NAME] notation for concrete examples) and fix timeout
(600000 ms is 10 min; use 1200000 ms for the stated 20 min).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
- claude.yml: gate @claude on author_association (OWNER/MEMBER/COLLABORATOR)
so the write-scoped token and OAuth secret are never issued for an
untrusted commenter on this public repo (defense-in-depth).
- claude-code-review.yml: skip fork PRs in the job condition
(head.repo.full_name == github.repository) since forks get no secrets
and would only fail noisily; fix the misleading token comment; pass
additional_permissions: actions: read so actions: read is effective.
- hil SKILL.md: reword hostname guidance, use full test/hil/* paths, and
show an explicit CONFIG= assignment so the local command is runnable.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|