Merge pull request #665 from r4d10n/esp_usb_jtag

esp_usb_jtag: support multiple boards (--busdev-num, --usb-serial-num)
This commit is contained in:
Gwenhael Goavec-Merou 2026-05-15 08:23:09 +02:00 committed by GitHub
commit 79aa75dd8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 92 additions and 26 deletions

View File

@ -70,7 +70,9 @@ openFPGALoader -- a program to flash FPGA
--cable-index arg probe index (FTDI and cmsisDAP)
--busdev-num arg select a probe by it bus and device number
(bus_num:device_addr)
--ftdi-serial arg FTDI chip serial number
--usb-serial-num arg USB iSerial (FTDI chip serial number or ESP32
iSerialNumber substring)
--ftdi-serial arg FTDI chip serial number (Deprecated)
--ftdi-channel arg FTDI chip channel number (channels 0-3 map to
A-D)
-d, --device arg device to use (/dev/ttyUSBx)

View File

@ -245,13 +245,17 @@ static uint16_t esp_usb_target_chip_id = 0; /* not applicable for FPGA, they hav
/* end copy from openocd */
esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid = ESPUSBJTAG_VID, int pid = ESPUSBJTAG_PID):
esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose,
int vid = ESPUSBJTAG_VID, int pid = ESPUSBJTAG_PID,
uint8_t bus_addr = 0, uint8_t dev_addr = 0,
const std::string &serial = ""):
_verbose(verbose > 1),
dev_handle(NULL), usb_ctx(NULL), _tdi(0), _tms(0),
/* Default for emard firmware. */
_esp_usb_jtag_caps(0x2000), _write_ep(0x02),
_vid(ESPUSBJTAG_VID), _pid(ESPUSBJTAG_PID)
{
libusb_device **devs = NULL;
int ret;
char mess[256];
@ -260,18 +264,61 @@ esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid = ESPUSBJTAG_
throw std::exception();
}
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
_vid, _pid);
if (!dev_handle) {
_esp_usb_jtag_caps = 0x030A;
_write_ep = 0x03;
_pid = 0x1002;
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
_vid, _pid);
ssize_t cnt = libusb_get_device_list(usb_ctx, &devs);
if (cnt < 0) {
std::cerr << "esp_usb_jtag: libusb_get_device_list failed: "
<< libusb_error_name(static_cast<int>(cnt)) << std::endl;
libusb_exit(usb_ctx);
throw std::exception();
}
for (ssize_t i = 0; i < cnt; i++) {
libusb_device *dev = devs[i];
struct libusb_device_descriptor desc;
if (libusb_get_device_descriptor(dev, &desc) < 0)
continue;
if (desc.idVendor != vid || desc.idProduct != pid)
continue;
/* bus/device filter (only when both are user-supplied) */
if (bus_addr != 0 && dev_addr != 0 &&
(libusb_get_bus_number(dev) != bus_addr ||
libusb_get_device_address(dev) != dev_addr))
continue;
/* serial filter */
if (!serial.empty()) {
libusb_device_handle *probe = NULL;
if (libusb_open(dev, &probe) < 0)
continue;
unsigned char raw[256] = {0};
int n = 0;
if (desc.iSerialNumber)
n = libusb_get_string_descriptor_ascii(probe,
desc.iSerialNumber, raw, sizeof(raw));
libusb_close(probe);
if (n <= 0)
continue;
const std::string found(reinterpret_cast<char *>(raw), n);
if (found.find(serial) == std::string::npos)
continue;
}
if (libusb_open(dev, &dev_handle) == 0)
break;
dev_handle = NULL;
}
libusb_free_device_list(devs, 1);
if (!dev_handle) {
snprintf(mess, 256, "fails to open esp_usb_jtag device");
printError(mess);
std::cerr << "fails to open esp_usb_jtag device vid:pid 0x"
<< std::hex << vid << ":0x" << pid;
if (bus_addr || dev_addr)
std::cerr << " bus:dev " << std::dec << static_cast<int>(bus_addr)
<< ":" << static_cast<int>(dev_addr);
if (!serial.empty())
std::cerr << " serial '" << serial << "'";
std::cerr << std::endl;
libusb_exit(usb_ctx);
throw std::exception();
}

View File

@ -12,6 +12,8 @@
#include <libusb.h>
#include <string>
#include "jtagInterface.hpp"
/*!
@ -23,7 +25,9 @@
class esp_usb_jtag : public JtagInterface {
public:
esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid);
esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid,
uint8_t bus_addr, uint8_t dev_addr,
const std::string &serial);
virtual ~esp_usb_jtag();
int setClkFreq(uint32_t clkHZ) override;

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();

View File

@ -79,7 +79,7 @@ struct arguments {
std::string secondary_bit_file;
std::string device;
std::string cable;
std::string ftdi_serial;
std::string usb_serial_num;
int ftdi_channel;
int status_pin;
uint32_t freq;
@ -264,13 +264,6 @@ int main(int argc, char **argv)
cable.config.interface = mapping[args.ftdi_channel];
}
if (!args.ftdi_serial.empty()) {
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG){
printError("Error: FTDI serial param is for FTDI cables.");
return EXIT_FAILURE;
}
}
if (args.status_pin != -1) {
if (cable.type != MODE_FTDI_SERIAL){
printError("Error: FTDI status pin is for FTDI MPSSE cables.");
@ -279,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;
@ -389,7 +390,7 @@ int main(int argc, char **argv)
Jtag *jtag;
try {
jtag = new Jtag(cable, &pins_config, args.device, args.ftdi_serial,
jtag = new Jtag(cable, &pins_config, args.device, args.usb_serial_num,
args.freq, args.verbose, args.ip_adr, args.port,
args.invert_read_edge, args.probe_firmware,
args.user_misc_devs);
@ -667,7 +668,7 @@ int run_xvc_server(const struct arguments &args, const cable_t &cable,
try {
XVC_server *xvc = NULL;
xvc = new XVC_server(args.port, cable, pins_config, args.device,
args.ftdi_serial, args.freq, args.verbose, args.ip_adr,
args.usb_serial_num, args.freq, args.verbose, args.ip_adr,
args.invert_read_edge, args.probe_firmware);
/* create connection */
xvc->open_connection();
@ -889,6 +890,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
jtag_pins_conf_t *pins_config)
{
std::string freqo;
std::string ftdi_serial;
std::vector<std::string> pins, bus_dev_num;
bool verbose = false, quiet = false;
int8_t verbose_level = -2;
@ -927,8 +929,10 @@ 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))
("ftdi-serial", "FTDI chip serial number",
cxxopts::value<std::string>(args->ftdi_serial))
("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))
("ftdi-channel",
"FTDI chip channel number (channels 0-3 map to A-D)",
cxxopts::value<int>(args->ftdi_channel))
@ -1134,6 +1138,14 @@ 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.");
return -1;
}
args->usb_serial_num = ftdi_serial;
}
if (result.count("busdev-num")) {
if (bus_dev_num.size() != 2) {
printError("Error: busdev-num must be xx:yy");