diff --git a/README.md b/README.md index 7e48627..b9e767b 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/src/esp_usb_jtag.cpp b/src/esp_usb_jtag.cpp index 1649586..4d4bfe8 100644 --- a/src/esp_usb_jtag.cpp +++ b/src/esp_usb_jtag.cpp @@ -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(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(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(bus_addr) + << ":" << static_cast(dev_addr); + if (!serial.empty()) + std::cerr << " serial '" << serial << "'"; + std::cerr << std::endl; libusb_exit(usb_ctx); throw std::exception(); } diff --git a/src/esp_usb_jtag.hpp b/src/esp_usb_jtag.hpp index da0fb8f..65357b2 100644 --- a/src/esp_usb_jtag.hpp +++ b/src/esp_usb_jtag.hpp @@ -12,6 +12,8 @@ #include +#include + #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; diff --git a/src/jtag.cpp b/src/jtag.cpp index d084bd8..2b99023 100644 --- a/src/jtag.cpp +++ b/src/jtag.cpp @@ -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(); diff --git a/src/main.cpp b/src/main.cpp index 9ca2940..4c779e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 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>(bus_dev_num)) - ("ftdi-serial", "FTDI chip serial number", - cxxopts::value(args->ftdi_serial)) + ("usb-serial-num", "USB iSerial (FTDI chip serial number or ESP32 iSerialNumber substring)", + cxxopts::value(args->usb_serial_num)) + ("ftdi-serial", "FTDI chip serial number (Deprecated)", + cxxopts::value(ftdi_serial)) ("ftdi-channel", "FTDI chip channel number (channels 0-3 map to A-D)", cxxopts::value(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");