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
+11 -3
View File
@@ -272,6 +272,14 @@ int main(int argc, char **argv)
}
#endif
if (!args.usb_serial_num.empty()) {
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG &&
cable.type != MODE_ESP){
printError("Error: usb-serial-num param is for FTDI and esp32s3 cables.");
return EXIT_FAILURE;
}
}
if (args.vid != 0) {
printInfo("Cable VID overridden");
cable.vid = args.vid;
@@ -921,7 +929,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
("busdev-num",
"select a probe by it bus and device number (bus_num:device_addr)",
cxxopts::value<std::vector<std::string>>(bus_dev_num))
("usb-serial-num", "USB iSerial (FTDI chip serial number)",
("usb-serial-num", "USB iSerial (FTDI chip serial number or ESP32 iSerialNumber substring)",
cxxopts::value<std::string>(args->usb_serial_num))
("ftdi-serial", "FTDI chip serial number (Deprecated)",
cxxopts::value<std::string>(ftdi_serial))
@@ -1131,8 +1139,8 @@ int parse_opt(int argc, char **argv, struct arguments *args,
}
if (result.count("ftdi-serial")) {
if (result.count("usb_serial_num")) {
printError("Error: ftdi_serial and usb_serial_num can't be used at the same time.");
if (result.count("usb-serial-num")) {
printError("Error: ftdi-serial and usb-serial-num can't be used at the same time.");
return -1;
}
args->usb_serial_num = ftdi_serial;