| 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.
|
|
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.
|
|
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
|
|
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]>
|
|
Update the hil skill so config selection is per-host: run `hostname`
first, then htpc uses local.json and ci uses tinyusb.json. ci can now
run HIL on its own large board pool locally instead of only via SSH
from htpc. Remote (SSH) mode is htpc-only since ci cannot reach htpc.
Also compact the skill for brevity.
|
|
- run() now catches subprocess.TimeoutExpired (only triggered by `cmake --build`'s
timeout=600) and returns CompletedProcess(rc=124) so the caller falls through to
error reporting and worktree cleanup instead of crashing with a traceback.
- code-size SKILL.md: document the actual default filter (per-side absolute
<checkout>/src/ path, not the old `tinyusb/src` substring) and adjust the
reporting guidance to match what the report rows actually contain.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
|
|