esp_usb_jtag: disambiguate multiple boards via --busdev-num and --usb-serial-num

libusb_open_device_with_vid_pid() returns the first VID:PID match, so
with two ESP32-S3 cables connected, every invocation programmed the
same board. Replace it with a libusb_get_device_list() iteration that
also honours cable.bus_addr/device_addr (already exposed as
--busdev-num) and --usb-serial-num flag that matches the device
iSerialNumber by substring (useful with MAC-derived serials).

The -d /dev/ttyACM* path could not help: that's the CDC-ACM interface
(iface 0), while JTAG is on the vendor iface 2 reached via libusb;
ttyACM numbering and libusb enumeration order are independent.

Constraint: must keep existing single-board invocations working without flag changes
Confidence: high
Scope-risk: narrow
Directive: arguments struct uses positional aggregate init at main.cpp:120; new fields must add a matching slot
Not-tested: simultaneous two-board programming on real hardware (single-board path verified to build)

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
r4d10n
2026-05-14 18:28:31 +02:00
committed by Gwenhael Goavec-Merou
co-authored by Claude Opus 4.7
parent 4000496abc
commit 9e548983f9
5 changed files with 79 additions and 17 deletions
+2 -1
View File
@@ -165,7 +165,8 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
break;
case MODE_ESP:
#ifdef ENABLE_ESP_USB
_jtag = new esp_usb_jtag(clkHZ, verbose, 0x303a, 0x1001);
_jtag = new esp_usb_jtag(clkHZ, verbose, 0x303a, 0x1001,
cable.bus_addr, cable.device_addr, serial);
#else
std::cerr << "Jtag: support for esp32s3 cable was not enabled at compile time" << std::endl;
throw std::exception();