| Age | Commit message (Collapse) | Author |
|
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019MRGjBT2NBkCoWwyDT4LaE
|
|
The CH569 USBSS ctrl_out flakiness (cases 14/21, host -EPROTO) is a
silicon erratum, not a driver bug: EP0 OUT data stages whose wLength
% 4 == 1 are intermittently dropped at 5 Gbps. Proven by A/B against
WCH's own binary USB3 stack (SimulateCDC EVT demo patched to accept
the gadget-zero 0x5b/0x5c requests), which fails identically on the
same board — independent of host LPM (persists with U1/U2 disabled)
and sysclk (80 vs 120 MHz). Bulk OUT at the same lengths is clean.
Document the erratum in the dcd and drop the ineffective zeroed-BOS
workaround.
Rather than letting known-impossible cases flake the battery, the
firmware now advertises quirk flags in bcdDevice bits 4-7 (tier stays
in bits 0-3): 0x10 skips ctrl_out 14/21, 0x20 skips ep-halt 13 (the
previously proven single-STALL limitation). usbtest.py skips flagged
cases visibly at SuperSpeed only (explicit --tests still runs them)
and reports them in the summary/JSON.
Also fix the CH56x USB3 dcd leaving an endpoint halted across
reconfiguration: clear the stalled flag in dcd_edpt_open/close/
close_all (USB 2.0 9.4.5) so a SET_CONFIGURATION recovery of a
halted-then-reopened endpoint does not STALL forever.
Validated on hydrausb3_v1 at 5000M: tier-4 battery x3 = 27/27 passed
+ 3 skipped, full HIL device suite 12/12 green (MSC 160/134 MB/s).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019MRGjBT2NBkCoWwyDT4LaE
|
|
Running the Linux kernel usbtest/testusb battery against the CH569 for
the first time. Results: 30/30 at high speed (4 consecutive reflash
cycles), 25/26 at SuperSpeed.
DCD fixes found by the battery:
- dcd_ch56x_usbhs: clear-halt on an armed bulk-OUT pipe reset the toggle
but dropped the queued receive, NAKing forever (usbtest case 29 - the
same defect previously found on rp2040/fsdev/ch32_usbhs/rusb2)
- dcd_ch56x_usb30: endpoint halt is now latched; the endpoint event
handler used to clear the response field on every completion, wiping a
just-set STALL while the peer streamed, and clear-halt now re-arms a
still-armed transfer with the fresh packet sequence (cases 13/29)
usbtest example gains SuperSpeed support: tier 3 on SS builds, a
4-endpoint SS descriptor set with companions, EP0 512 config and
1024-byte receive buffers.
test/hil/usbtest.py gains SuperSpeed-aware case parameters: bulk sizes
and vary steps must be 1024-multiples at SS or the device's whole-packet
source overruns the host request (case 4 EOVERFLOW).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019MRGjBT2NBkCoWwyDT4LaE
|
|
Brings the usbtest device example (gadget-zero source/sink peer for the
kernel's usbtest.ko/testusb), the test/hil/usbtest.py battery runner and
the extended vendor class driver (interrupt/isochronous endpoints, alt
settings) into the CH569 SuperSpeed branch, enabling the battery to run
against both CH56x dcds.
Conflict resolution: test/hil/tinyusb.json keeps this branch's
hydrausb3_v1 fixture entry and adds the usbtest branch's
ch32v307v_r1_1v0 entry.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019MRGjBT2NBkCoWwyDT4LaE
|
|
- CFG_TUD_WCH_USB30_FALLBACK (on by default for SPEED=super): the USB3
dcd owns both controllers on rhport 0. TMR0 times out SuperSpeed link
training (2x 0.5 s: shut USB3 down, then bring USB2 up); an LTSSM
disabled event (SS rejected by the port) switches immediately. The
active controller is dispatched at each dcd entry point; IRQ pendings
are cleared on switch and dcd_int_enable is mode-aware (a stale LINK
pending otherwise refires on every usbd queue unlock)
- Bounded link busy-waits (LINK_STATUS busy can stick once the link is
torn down)
- board_get_unique_id from the factory ID in read-only info flash
(0x77FE4), so the USB serial identifies the chip (HIL requirement)
- HIL: replace ch582m_evt (probe moved) with hydrausb3_v1
- Regenerate boards.rst, dependencies.rst, BoardPresets.json
Verified on HydraUSB3 v1 (ci rig): SuperSpeed still trains at 5000M
with fallback armed (3x replug); with SS terminations disabled the
device falls back and enumerates fully at 480M. Full HIL run passes
10/10 device tests including cdc_msc at SuperSpeed and
cdc_msc_throughput (MSC 22.1/14.1 MBps read/write at NUMP=1);
non-SuperSpeed-aware examples recover onto USB2 via the fallback.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
Groundwork for TinyUSB's first SuperSpeed port (WCH CH569):
- TUSB_SPEED_SUPER, OPT_MODE_SUPER_SPEED, TUD_OPT_SUPER_SPEED and
TUP_RHPORT_SUPERSPEED capability plumbing
- Allow CFG_TUD_ENDPOINT0_SIZE 512 on SS builds; EP0 control transfers
chunk at the runtime link speed (512 at SS, 64 on USB2 fallback)
- Handle SET_SEL, SET_ISOCH_DELAY and U1/U2_ENABLE feature requests
- Tolerate SS endpoint companion descriptors in usbd_open_edpt_pair,
cdcd_open and mscd_open interface parsing
- SS descriptor types/structs and template macros: endpoint companion,
BOS USB2-extension + SuperSpeed capability, SS config and
CDC/MSC/vendor SS variants (bulk fixed at 1024)
- cdc_msc example: SS device/config/BOS descriptors, speed-aware sizes
- Unit tests: SS endpoint validation, companion-tolerant endpoint pair
open, SET_SEL, SET_ISOCH_DELAY
All SS paths compile out when disabled: verified 0-byte code-size delta
on stm32f407disco (MinSizeRel) vs master; 65/65 unit tests pass.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
Copilot review:
- tud_vendor_int_tx_cb/iso_tx_cb submitted sizeof(chunk) (the HS-capacity buffer)
instead of the negotiated-speed mps, diverging from usbtest_pump() on an
HS-capable build enumerated at full speed. Factor the length into shared
usbtest_int_len()/usbtest_iso_len() helpers used by the pump and both callbacks.
- Reword the usb_descriptors.h comment that still called the plain mps macro
'live operating speed' — it is the compile-time capability maximum.
Claude review (test/hil/tinyusb-sudoer): drop the two grants that bypassed the
file's root-owned-helper boundary and gave uid 1000 passwordless root:
- /sbin/debugfs (unused; permits '!/bin/sh' shell escape + raw root-disk write).
- /home/*/actions-runner/svc.sh (user-writable script). Replace with a root-owned,
argument-restricted 'systemctl stop/start actions.runner.*' grant. Also tighten
the dmesg/uhubctl runas from (ALL) to (root).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
- dcd(rusb2): pipe_zlp_in()'s CURPIPE deselect wait gets the same spin bound as
the other FIFO waits — it runs with the USB IRQ masked, where any stuck spin
freezes the stack.
- test/hil: quote the board uid interpolated into the shell=True usbtest
invocation.
Verified: ra4m1_ek 30/30 through the HIL battery.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
- dcd(nrf5x): dcd_edpt_iso_activate drops a stale armed transfer (started/
data_received/iso_in_transfer_ready) — there is no dcd close on this port, so
a transfer armed before SET_INTERFACE would trip TU_ASSERT(!xfer->started) on
the class's next arm after usbd reset the endpoint's claim state.
- class(vendor): tud_vendor_n_mounted() counts the interrupt endpoints, so an
interrupt-only vendor interface (bulk absent) reports mounted.
- example(usbtest): int/iso write lengths follow the negotiated speed
(tud_speed_get), not the compile-time capability — a high-speed build
enumerated at full speed serves the FS descriptor (mps 64/128) and must not
submit HS-sized packets.
- test/hil: test_example() return annotation matches the (err, status, metric)
3-tuple it returns.
Verified: feather_nrf52840_express and raspberry_pi_pico 30/30 through the HIL
battery; pico/feather/ch32v307-usbhs builds clean.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
Its board and WCH-Link failed to re-enumerate after the rig reboot and need a
physical replug; skip so HIL runs stay green until then.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
- dcd(rp2040): rewind IN staging before the clear-halt re-issue. Staging advances
user_buf/remaining_len when packets are copied into DPRAM, before the host has
consumed them; aborting and re-issuing from the advanced pointer silently
skipped the staged-but-unsent bytes.
- dcd(ip3511): dcd_edpt_iso_activate aborts a transfer still armed from the
previous altsetting (clear Active on both buffer slots) so the hardware can't
keep servicing the old descriptor against the class's fresh queueing.
- dcd(rusb2): reuse an endpoint's existing pipe in dcd_edpt_open. usbd_edpt_close
is a no-op on ISO_ALLOC ports, so a class's close/open across SET_INTERFACE
would allocate a second pipe with the same EPNUM and leak pipes.
- class(vendor): the buffered-mode free-slot check also tests the interrupt
endpoints, so an interrupt-only vendor interface isn't clobbered as "free".
- bsp(ch32v30x): board_get_unique_id respects max_len and copies bytes
(alignment-safe) instead of writing 12 bytes through a uint32_t cast.
- test/hil/usbtest.py: treat same-serial multi-matches as ambiguous and retry
until the dual-port stale node drops (nanoch32v203/ch32v307 variants); reprobe
a binding that predates the dynamic-id re-registration so a stale capability
profile can't survive; skip the remove_id/unbind cleanup after an unrecovered
kernel-side hang (it would join the D-state convoy and deadlock the bus).
- usbtest skip.txt: add the families whose DCD refuses dcd_edpt_iso_alloc
(CXD56, FT90X, LPC175X_6X, LPC40XX, NUC100/120/505, PIC32MZ, SAMG, SAMX7X,
VALENTYUSB_EPTRI) — tier 4 cannot enumerate there.
- test/hil/tinyusb-sudoer: note that '#1000' is a sudoers UID specifier, not a
comment (the review misread the grants as commented out).
Refuted in review threads: nrf5x ISOSPLIT keeps reserve-max per-configuration
allocation semantics (iso_alloc is per-config, not per-alt); the LPC EP-number
claim (default descriptor uses EP1-3; lpcxpresso11u37 passes 30/30 on HW); the
vendor alt-0 "abort" concern (host cannot address endpoints outside the active
altsetting; usbd_edpt_iso_activate resets state on re-entry).
Verified on hardware: raspberry_pi_pico, lpcxpresso11u37, ra4m1_ek all 30/30
through the HIL battery after the changes; builds clean incl. buffered-mode
vendor (webusb_serial).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
hil_test.py tests boards in a multiprocessing Pool, so the full-fleet run had
many usbtest batteries running concurrently — each saturates the host
controller with bulk-perf, iso streams and unlink storms, and together they
hard-froze the CI rig mid-run (fatal PCIe error on the VFIO-passed xHCI; the
machine rebooted). Single-board runs and the earlier sequential sweep never hit
this.
Add a pool-wide lock so only one battery runs at a time while other boards'
ordinary tests keep going in parallel (the baseline load the rig has always
handled), and raise the default pool timeout to 70 min for the serialized tail.
Verified: 3-board pool run (lpcxpresso11u37, ra4m1_ek, ch32v307 usbhs+usbfs)
all report ✅ 30/30 with batteries serialized, 160 s total.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
overflow
Four PR-CI failures, each with a distinct root cause:
- class/vendor: mark the shared non-buffered transfer helpers TU_ATTR_UNUSED.
In buffered mode with the int/iso endpoint gates off none is referenced, and
clang (-Wunused-function -Werror) and IAR (Error[Pe177]) reject an unused
static — gcc does not, which is why only the clang/IAR matrix failed.
- bsp/ch32v20x: keep dcd_int_handler alive under LTO. The `call` sits inside
naked asm where LTO cannot see it, so -flto make builds internalized the
symbol and every ch32v20x device example failed to link (cmake has no LTO,
which masked it). A TU_ATTR_USED function-pointer reference pins it.
- usbtest: LPC11/13 (ip3511 FS) keep endpoint buffers in a dedicated 2 KB USB
RAM; the 2048 B bulk epbuf overflowed it (RamUsb2 150%) in make builds. Use
512 B (= 8 FS packets) on those parts; lpcxpresso11u37 still passes 30/30.
- test/hil: skip device/usbtest on lpcxpresso43s67 (hfp rig) — its ip3511 HS
port wedges from the first control case (1/30) and needs on-rig debugging.
Verified: make builds link for nanoch32v203 (dfu_runtime + usbtest),
lpcxpresso11u37 and lpcxpresso1347 (RamUsb2 75%); buffered-mode webusb_serial
builds; 61/61 unit tests; lpcxpresso11u37 usbtest 30/30 on hardware with the
smaller epbuf.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
# Conflicts:
# lib/rt-thread/port/msc_device_port.c
# src/device/usbd.c
|
|
Add device/usbtest to the device test battery. test_device_usbtest() waits for
the cafe:4010 device to enumerate, runs usbtest.py --json against it, and shows
the pass count in the report cell — "✅ 30/30" on a clean run or "❌ 29/30" on a
partial, instead of a bare ✅/❌.
To carry the count onto a failing cell, a test may raise TestFail(msg, metric=…);
test_example() captures that metric on the final failed attempt. The report tally
is now icon-aware so an icon-prefixed metric ("❌ 29/30") is counted as a failure
(and "✅ …" as a pass), keeping the passed/failed/skipped totals correct.
Verified end-to-end: ra4m1_ek reports "✅ 30/30"; the partial path renders
"❌ N/M" and tallies as failed.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
The CH32V307 exposes two device controllers: the full-speed USBFS (dcd_ch32_usbfs,
selected with -DSPEED=full) and the high-speed USBHS (dcd_ch32_usbhs, the default).
Both now pass the Linux testusb tier-4 battery 30/30 (3 reflash cycles each) on
ch32v307v_r1_1v0.
- dcd(ch32_usbhs): fix clear-stall on an armed OUT endpoint. It set the pipe to
NAK unconditionally, so a receive the class still considers submitted NAKed
forever after CLEAR_FEATURE(HALT) and usbtest toggle test 29 timed out. Re-queue
the pending receive (ACK/NYET) instead. This is the first usbtest coverage of the
ch32_usbhs driver.
- bsp(ch32v30x): implement board_get_unique_id from the ESIG UID (0x1FFFF7E8);
the port previously fell back to the placeholder serial.
- usbtest: the CH32V307 usbfs port caps iso at 64 B like the other WCH USBFS parts,
so add it to the FS iso-64 descriptor branch (its usbhs port uses the HS sizes).
- test/hil: register ch32v307v_r1_1v0 (usbhs + usbfs variants, WCH-Link BC5DA47360D0)
and move nrf54lm20dk to boards-skip.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
Passes usbtest tier-4 30/30 at high speed. J-Link OB S/N 1051856258.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
bound ndp16 wLength against received ntb in recv_validate_datagram
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
Signed-off-by: HiFiPhile <[email protected]>
|
|
usb_recover.sh: add `pci-bind <addr> [drv]` to re-attach a driver to a controller
left driverless (e.g. after a pci-rebind whose re-bind hung on an unkillable
D-state URB); auto-tries xhci-pci-renesas then xhci_hcd.
usb-recover skill: document the Renesas uPD720201 pci-reset ENOTTY (no FLR), the
pci-rebind-strands-driverless footgun, and reboot as the last-resort D-state cure
with an @reboot one-shot session auto-resume. Recovery reboot uses
`systemctl reboot --force` -- a graceful reboot stalls in shutdown waiting for the
wedged D-state process to exit; --force reboots immediately.
tinyusb-sudoer: grant `systemctl reboot --force` (and plain reboot), the actions-
runner svc.sh stop/start around manual HW runs, and testusb; grants stay generic-
by-UID (#1000). usb-debug skill: sync the deploy one-liner.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
folds the reproducer for the recv_validate_datagram bound into a small
self-contained fuzz target. it feeds a raw ntb straight into the validator
(the driver is pulled in so the static function is reachable) and ships the
crafted 64-byte ntb as a seed. the seed trips an asan heap-buffer-overflow
against the unpatched driver and is rejected cleanly with the wLength bound
in place.
|
|
Add the actions-runner/svc.sh NOPASSWD grant to test/hil/tinyusb-sudoer and
correct the hil skill: svc.sh must be invoked from ~/actions-runner (cd first)
or it errors 'Must run from runner root'.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
usbd:
- usbd_edpt_clear_stall keeps the long-standing unconditional STALLED|BUSY
clear (audio's set-interface relies on it to drop a leftover BUSY bit)
and only gates the new CLAIMED release on the endpoint having been
stalled — fixes the halt-test starvation without the double-arm race and
without regressing audio on ports where nothing else zeros ep_status.
- GET_STATUS direction guard + checked return factored into a shared
process_get_status() and applied to all three recipients (device,
interface, endpoint); previously only the interface case was hardened,
leaving the endpoint/device siblings able to hand usbd a stack buffer for
a malformed OUT request.
vendor:
- vendord_open commits p_itf_desc only after the descriptor parse succeeds,
so a mid-parse failure no longer marks the interface slot permanently
occupied (find_vendor_itf keys on p_itf_desc under ALT_SETTINGS).
- vendord_set_alt is a single pass again: the current endpoints are dropped
only once the target altsetting is confirmed present, dropping the
redundant vendord_has_alt pre-scan while keeping the invalid-alt rollback.
- CLOSE_API iso re-activation now closes+reopens the endpoint (zeroing
ep_status) instead of a no-op, so a re-selected altsetting on ip3511/rusb2
can't starve on stale BUSY/CLAIMED.
test/hil/usbtest.py:
- re-resolve on the concrete serial (never retarget a different device),
best-effort cleanup that can't mask the original error, set_pattern
catches PermissionError too, --tier choices derive from TIER_CASES,
--tests uses isdecimal.
Full 30-case battery passes on all four dwc2 boards; all three GET_STATUS
recipients + invalid SET_INTERFACE + EP0 halt verified via raw usbfs
control transfers; usbtest builds for ip3511/rusb2 (CLOSE_API iso path).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
- example: interrupt/iso endpoint buffers track the per-speed max packet
size instead of a fixed 512, saving ~1.6 KB of USB DMA RAM on FS builds.
- test/hil/usbtest.py: re-resolve the device node after a mid-battery
re-enumeration (stale node was misreported as NOTRUN); reject an
out-of-range tier (a tier-0 device would run an empty battery and read
green); validate --tests case numbers; run cleanup in a try/finally so a
crash can't leave the dynamic id registered to hijack the next device;
guard set_pattern and the pci-reset placeholder; report a sudo-password
failure on the testusb fallback instead of a misleading NOTRUN.
- tinyusb-sudoer: allow the foreign-driver unbind path and the testusb
fallback used by the runner.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
- test/hil/tinyusb-sudoer: consolidated sudoers grants (deploys to
/etc/sudoers.d/tinyusb-sudoer), documenting what each grant is for
- usb-recover skill: version usb_recover.sh under scripts/, deploy section
- new usb-debug skill: usb_dyndbg.sh (allowlisted kernel dynamic-debug
toggle for USB host modules) + workflow and deploy instructions
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
A wedged control/bulk pipe leaves testusb in uninterruptible sleep;
FLR is the only lock-free recovery, and it must run before the cleanup
unbind writes or they deadlock the bus (see .claude/skills/usb-recover).
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
ordering rule
The runner no longer waits on an unkillable child stuck in a usbfs ioctl:
it marks the case HUNG, aborts the battery, and prints the pci-reset
recovery command. Skill now documents the new usb_recover.sh pci-reset
(FLR) mode and the hard-won ordering rule: on a D-state hang FLR must come
before any rebind attempt, because a blocked rebind holds the PCI device
lock that FLR needs — after that only a reboot recovers.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
Binds the device to the usbtest driver (dynamic id; Gadget-Zero profile
ref-trick for tier>=2), runs the tier-appropriate cases with explicit
packet-aligned parameters, and parses testusb stdout: its exit code is
always 0 and profile-gated cases print nothing, so a missing result line
is reported as a failure rather than a silent pass.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01HeF2gZ1M7GWkz6Av4BpKPg
|
|
The board was added to the CI HIL pool with device/cdc_msc_throughput
skipped, so the test had never run on it. Remove the skip to include it
in the device test set.
Verified passing on the ci rig (USBFS, full-speed):
CDC read 639 / write 544 kBps, MSC read 845 / write 575 kBps.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Prefix each rig's hil_report.md matrix with a one-line tally
(passed / failed / skipped) so the number of failed tests is visible at a
glance in the PR comment without scanning the table. A metric-string cell
(e.g. throughput) counts as a pass; blank/not-run cells are excluded.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
|
|
Fold in the CH58x BSP review fixes:
- family.mk: drop stray trailing backslashes on the last LDFLAGS/SRC_C entries
(harmless -- GNU Make ends the list at the blank line -- but misleading).
- debug_uart.c: uart_write() spun on a full ring buffer with nothing to drain it
(only uart_sync() advances tx_consume), so a burst larger than the buffer
deadlocked. Drain the FIFO while waiting, like uart_sync() does.
- wch-riscv.cfg: move the OpenOCD work area from 0x80000000 (unmapped) to the
0x20000000 SRAM, sized to 32 KB, matching ch32v20x/wch-riscv.cfg.
- family.c: implement board_get_unique_id() from the factory MAC. CH58x is a BLE
part, so a unique 6-byte MAC lives in FlashROM at ROM_CFG_MAC_ADDR; GetMACAddress()
reads it via FLASH_EEPROM_CMD (in libISP583.a), so no extra source file is needed.
The read buffer is TU_ATTR_ALIGNED(4) and 8 bytes, per the SDK's documented
4-byte-aligned, word-granular buffer contract (CH58x_flash.c).
- test/hil/tinyusb.json: key ch582m_evt off this board's actual MAC (D443627B5450)
instead of the fixed placeholder, like every other board.
Verified on ci.lan HIL: ch582m_evt enumerates with serial D443627B5450 and all
device examples pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Add the device-only CH582M-EVT (WCH USBFS via the shared dcd_ch32_usbfs.c),
riscv-gcc, flashed by openocd_wch probe 7FD88F0604B5, to tinyusb.json.
Also reorder device_tests to keep examples sharing a VID:PID non-adjacent:
cdc_msc and cdc_msc_throughput both use cafe:4003, and on boards whose
CPU-reset does not drop D+ (e.g. WCH CH58x via openocd) back-to-back same-PID
firmware leaves the host on the previous example's cached descriptors, so the
new example's CDC never enumerates and the test fails. Moving dfu (cafe:4000)
between them changes the PID and forces the host to re-enumerate.
Remote HIL on ci.lan: all device examples pass, including cdc_msc_throughput
(no skip needed).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Enabling the audio test fleet-wide surfaced failures on esp32-p4/s3 and
metro_m4_express: the UAC mic enumerates but arecord fails the iso IN read
with EIO, while 18 other boards pass strict=1.000.
esp32: root cause is the FreeRTOS tick rate. ESP-IDF defaults
CONFIG_FREERTOS_HZ to 100, so the audio task wakes only every 10 ms and
can't service the 1 ms UAC iso frames -> underrun -> arecord EIO. (The same
dwc2 driver passes on STM32, whose FreeRTOSConfig is 1000 Hz.) Set
CONFIG_FREERTOS_HZ=1000 in the example sdkconfig.defaults; the example
defaults are honored in the generated sdkconfig alongside the BSP's, so this
takes effect.
metro_m4_express (samd51): not tick-rate -- its FreeRTOSConfig is already
1000 Hz like the passing boards -- so it's a separate iso-IN issue, skipped
for now.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
arecord (alsa-utils) is a documented HIL host requirement, like
mtools/libmtp9/iperf — none of which have a skip-if-missing guard. The
audio test was the exception: it silently returned 'skipped' when arecord
was absent, masking host misconfiguration. The ci.lan rig had been
silently skipping device/audio_test_freertos on every board because
alsa-utils was never installed.
Remove the shutil.which('arecord') guard so a missing package surfaces as
a failure, consistent with the other tool-dependent tests, and drop the
now-unused shutil import. Note in the host-setup comment that these
packages are required (a missing tool fails its test rather than skipping).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Now that CH32V103 USB device works, add the board to the active HIL pool.
It is a WCH RISC-V USBFS part, so it builds under the riscv-gcc bucket;
single config (USBFS only, no fsdev variant).
cdc_msc_throughput is skipped for this board: its device->host CDC bulk-IN
read hard-fails here (a known, pre-existing dcd_ch32_usbfs throughput
limitation, not specific to CH32V103). All other device tests pass on
ci.lan (verified green, 0 failures).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
dcd/musb: defer EP0 SETUP during DATA_IN/STATUS race
|
|
* hil: enable nanoch32v203 in CI with fsdev + usbfs variants
nanoch32v203 was parked in boards-skip; move it into the active pool now
that the board is wired to the ci.lan rig. Cover both USB device IPs as
build variants:
- nanoch32v203-fsdev: RHPORT_DEVICE=0 (USBD / stm32 FSDev IP)
- nanoch32v203-usbfs: RHPORT_DEVICE=1 (WCH USBFS IP)
|
|
* device: clamp EP0 OUT data copy to the control transfer buffer
usbd_control_xfer_cb() copied xferred_bytes from the EP0 bounce buffer
into the requester's buffer with no bound. A non-compliant host that
sends an OUT data packet larger than the control transfer's data_len
(= min(len, wLength), the buffer capacity) would overflow that buffer
and over-count total_xferred. Clamp xferred_bytes to the remaining
buffer space before the memcpy and accounting.
|
|
pyserial's posix write() raises SerialTimeoutException after partial
progress with the byte count lost, so the retry loop re-sent from the
same offset and could duplicate bytes on the wire — surfacing as bogus
data-mismatch failures that look like device firmware bugs.
write_timeout is already a total per-call deadline, so the loop added
duplication risk without extending the budget: write once and treat a
timeout as fatal. Default bumped 2 -> 10 s to keep the old overall
bound; HIL_SERIAL_WRITE_DEADLINE removed.
The per-character CLI loops keep their existing pacing (the 2 ms sleep
between single-byte writes already spaces them on the wire); no
unbounded ser.flush()/tcdrain is added.
Review follow-up for #3643 (hil_test.py l.257/264 findings).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
|
# Conflicts:
# test/hil/hil_test.py
|
|
* test/hil: replace build.flags_on with named variant schema
Boards declare build variants as `variant: [{name, flags}]` instead of
`build.flags_on`. The variant `name` is the build dir (cmake-build-<name>) and
the HIL report row; `flags` is the raw CFLAGS string (-D...=1) injected via
CFLAGS_CLI. No `variant` => a single build named after the board.
- build.py: --build-name <name> (dir) + --cflag=<token> (raw CFLAGS, repeatable,
=form survives the matrix's shell word-splitting); drop -f1/CFLAGS wrapping.
- hil_ci_set_matrix.py: emit one build arg per variant.
- hil_test.py: iterate variants; report row + build dir = variant name.
- hil_ci.sh: copy all cmake-build-<board>* dirs for -b runs.
- get_deps.py: accept (ignore) --build-name/--cflag from matrix args.
- tinyusb.json: migrate all 6 flags_on boards to variant.
* board_test: park CI build with busy spin instead of wfe
|
|
hil: park boards with idle board_test instead of erasing flash
|
|
Teardown: instead of flashing device/board_test (a USB-less blink loop that
keeps the MCU busy-looping), erase the first flash sector (vector table) so the
board faults to idle after its tests — no USB, lower power, faster. Per-flasher
erase_<name>: openocd/openocd_adi `flash erase_sector 0 0 0`; stlink `--erase
0`; jlink erases the sector at the flash origin read from the ELF (pure-Python,
new elf_flash_origin); esptool `erase_region 0x0 0x4000`; lm4flash writes a 4 KB
all-0xFF blank image (lm4flash erases before programming, so the first sector
ends up blank). device/board_test flash remains a fallback for flashers with no
erase_ function. The teardown is no longer a report column (it's cleanup).
Report: cdc_msc_throughput and msc_file_explorer[_freertos] now return a compact
read/write speed shown in their report cell instead of the pass tick (e.g.
"C 652k/422k M 1.1M/783k", "rd 1.2MB/s"). test_example returns an optional
metric; render_matrix shows it verbatim. Firmware lookup factored into
find_firmware (reused by the erase teardown).
Verified on the rig (stm32f723disco, jlink): erase disables the board in 0.8 s
and it disappears from the bus; the throughput cell shows live speeds.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Neutral white circle for skipped, giving a ✅/❌/⚪ pass/fail/skip set.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Colored emoji render green/red in the GitHub PR comment, far more visible than
the monochrome ✔/✖ dingbats. Skip stays ➖.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
The report sidecar lives in a persistent dir (it survives the CI workspace
clean so accumulation works across run attempts). A full run is "fresh" and
must not merge prior state, but previously fresh only avoided *loading* the
json at merge time — if a fresh run crashed before writing the report, the
stale json/md from an earlier run lingered and a retry (fresh=False) could
merge it, or the always() upload could post it. Delete hil_report.json/.md at
the start of a fresh run so prior results can never leak.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
hil_test.py persists results in a hil_report.json sidecar and regenerates
hil_report.md from it. A full run starts fresh; a re-run (--skip-board / -bt,
i.e. the .skip file) merges into the existing report so already-passed
boards/tests are preserved while only re-run cells update. The report dir is
configurable via HIL_REPORT_DIR.
build.yml: each HIL rig writes the report to a workspace-sibling dir that
survives the per-attempt workspace clean, and uploads it as an artifact. A new
hil-report job merges the rigs' reports into one sticky PR comment (marocchino)
with one table per rig.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
|
Per review (HiFiPhile): Ninja Multi-Config is needed for IAR, otherwise the
optimization level can't be lowered to none for debug. Revert gen_presets.py
back to Ninja Multi-Config (keeping only the cmake-build-<board> binaryDir
change), and instead teach hil_test.py to locate <ex>.elf whether it sits
directly in the example dir (single-config) or under a per-config subdir like
RelWithDebInfo/ (multi-config).
Verified: stm32u083nucleo passes 13/13 remote HIL with a multi-config preset
build (rsync preserves the RelWithDebInfo/ subdir; the resolver finds it).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|