From b8036312cd63d0632872165ea9861c8e13043217 Mon Sep 17 00:00:00 2001 From: aisuneko icecat Date: Fri, 1 May 2026 23:20:49 +0800 Subject: [PATCH 1/6] cable: add Sipeed SLogic Combo 8 support --- doc/cable.yml | 15 +++++++++++---- src/cable.hpp | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/cable.yml b/doc/cable.yml index b513c85..dde9657 100644 --- a/doc/cable.yml +++ b/doc/cable.yml @@ -8,7 +8,7 @@ anlogicCable: arm-usb-ocd-h: - Name: Olimex ARM-USB-OCD-H adapter - Description: High-speed 3-IN-1 fast USB ARM JTAG, USB-to-RS232 virtual port and power supply 5VDC device + Description: High-speed 3-IN-1 fast USB ARM JTAG, USB-to-RS232 virtual port and power supply 5VDC device URL: https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/ @@ -57,10 +57,17 @@ ch552_jtag: cmsisdap: - Name: ARM CMSIS DAP protocol interface - Description: ARM CMSIS DAP protocol interface (hid only) + Description: ARM CMSIS DAP protocol interface URL: https://os.mbed.com/docs/mbed-os/v6.11/debug-test/daplink.html +sipeed_slogic_combo8: + + - Name: Sipeed SLogic Combo 8 + Description: The DAP-Link interface on Sipeed SLogic Combo 8 (usbbulk only) + URL: https://wiki.sipeed.com/hardware/en/logic_analyzer/combo8/index.html + + dfu: - Name: DFU interface @@ -70,13 +77,13 @@ dfu: digilent: - - Name: digilent cable + - Name: digilent cable Description: FT2232 JTAG / UART cable digilent_b: - - Name: digilent cable + - Name: digilent cable Description: digilent FT2232 JTAG / UART cable (interface B) diff --git a/src/cable.hpp b/src/cable.hpp index c7790e4..3482fd1 100644 --- a/src/cable.hpp +++ b/src/cable.hpp @@ -130,6 +130,7 @@ static std::map cable_list = { {"numato-neso", FTDI_SER(0x2a19, 0x1005, FTDI_INTF_B, 0x08, 0x4b, 0x00, 0x00)}, {"orbtrace", CMSIS_CL(0x1209, 0x3443 )}, {"papilio", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0x08, 0x0B, 0x09, 0x0B)}, + {"sipeed_slogic_combo8", CMSIS_CL(0xd6e7, 0x3507 )}, {"steppenprobe", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0x58, 0xFB, 0x00, 0x99)}, {"tigard", FTDI_SER(0x0403, 0x6010, FTDI_INTF_B, 0x08, 0x3B, 0x00, 0x00)}, {"usb-blaster", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6001 )}, From 53180a83f2974c5bb8c44bdc13eda67811ba6f91 Mon Sep 17 00:00:00 2001 From: aisuneko icecat Date: Fri, 1 May 2026 23:18:26 +0800 Subject: [PATCH 2/6] cmsisdap: add support for USB Bulk backend --- CMakeLists.txt | 41 +++- src/cmsisDAP.cpp | 510 +++++++++++++++++++++++++++++++++++++++++------ src/cmsisDAP.hpp | 50 ++++- src/jtag.cpp | 2 +- 4 files changed, 527 insertions(+), 76 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45b3d56..25f0dad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,9 @@ option(ENABLE_ANLOGIC_CABLE "enable Anlogic cable (requires libUSB)" ${ option(ENABLE_CH347 "enable CH347 cable (requires libUSB)" ${ENABLE_CABLE_ALL}) # CMSIS-DAP requires hidapi which is complex to cross-compile, disable by default for cross-compilation if (NOT WINDOWS_CROSSCOMPILE) - option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" ${ENABLE_CABLE_ALL}) + option(ENABLE_CMSISDAP "enable cmsis DAP interface (v1 and v2)" ${ENABLE_CABLE_ALL}) + option(ENABLE_CMSISDAP_V1 "enable cmsis DAP interface v1 (requires hidapi)" ${ENABLE_CMSISDAP}) + option(ENABLE_CMSISDAP_V2 "enable cmsis DAP interface v2 (requires libusb)" ${ENABLE_CMSISDAP}) else() option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" OFF) endif() @@ -120,7 +122,8 @@ endif(ENABLE_FTDI_BASED_CABLE OR ENABLE_USB_BLASTERI OR ENABLE_XILINX_VIRTUAL_CA # Only adds libusb as dependency when a cable need this library if (ENABLE_DFU OR ENABLE_ANLOGIC_CABLE OR ENABLE_CH347 OR ENABLE_DIRTYJTAG - OR ENABLE_ESP_USB OR ENABLE_JLINK OR ENABLE_GOWIN_GWU2X OR USE_FX2_LL OR ENABLE_USB_SCAN) + OR ENABLE_ESP_USB OR ENABLE_JLINK OR ENABLE_GOWIN_GWU2X OR USE_FX2_LL OR ENABLE_USB_SCAN + OR ENABLE_CMSISDAP_V2) set(USE_LIBUSB ON) endif() @@ -213,7 +216,7 @@ if (USE_PKGCONFIG) set(LIBUSB_LIBRARIES "") endif(USE_LIBUSB) - if(ENABLE_CMSISDAP) + if(ENABLE_CMSISDAP_V1) pkg_check_modules(HIDAPI hidapi-libusb) # if libusb not found try with hidraw if (NOT HIDAPI_FOUND) @@ -630,7 +633,7 @@ if (ENABLE_LIBGPIOD) link_directories(${LIBGPIOD_LIBRARY_DIRS}) endif() -if (ENABLE_CMSISDAP AND HIDAPI_FOUND) +if (ENABLE_CMSISDAP_V1 AND HIDAPI_FOUND) link_directories(${HIDAPI_LIBRARY_DIRS}) endif() @@ -697,18 +700,34 @@ else() message("CH347 support disabled") endif() -if (ENABLE_CMSISDAP) +# CMSIS DAP +if (ENABLE_CMSISDAP_V1) if (HIDAPI_FOUND) include_directories(${HIDAPI_INCLUDE_DIRS}) target_link_libraries(openFPGALoader ${HIDAPI_LIBRARIES}) - add_definitions(-DENABLE_CMSISDAP=1) - target_sources(openFPGALoader PRIVATE src/cmsisDAP.cpp) - list (APPEND OPENFPGALOADER_HEADERS src/cmsisDAP.hpp) - message("cmsis_dap support enabled") + add_definitions(-DENABLE_CMSISDAP_V1=1) + message("cmsis_dap v1 support enabled") else() - message("hidapi-libusb not found: cmsis_dap support disabled") + set(ENABLE_CMSISDAP_V1 OFF) + message("hidapi-libusb not found: cmsis_dap v1 support disabled") endif() -endif(ENABLE_CMSISDAP) +endif(ENABLE_CMSISDAP_V1) +if (NOT ENABLE_CMSISDAP_V1) + message("cmsis_dap v1 support disabled") +endif() + +if (ENABLE_CMSISDAP_V2) + add_definitions(-DENABLE_CMSISDAP_V2=1) + message("cmsis_dap v2 support enabled") +else() + message("cmsis_dap v2 support disabled") +endif (ENABLE_CMSISDAP_V2) + +if (ENABLE_CMSISDAP OR ENABLE_CMSISDAP_V1 OR ENABLE_CMSISDAP_V2) + add_definitions(-DENABLE_CMSISDAP=1) + target_sources(openFPGALoader PRIVATE src/cmsisDAP.cpp) + list (APPEND OPENFPGALOADER_HEADERS src/cmsisDAP.hpp) +endif() # DFU if (ENABLE_DFU) diff --git a/src/cmsisDAP.cpp b/src/cmsisDAP.cpp index e627ac6..fdab721 100644 --- a/src/cmsisDAP.cpp +++ b/src/cmsisDAP.cpp @@ -3,8 +3,14 @@ * Copyright (c) 2021 Gwenhael Goavec-Merou */ +#include +#include +#ifdef ENABLE_CMSISDAP_V1 #include +#endif +#ifdef ENABLE_CMSISDAP_V2 #include +#endif #include #include #include @@ -87,15 +93,87 @@ enum cmsisdap_status { DAP_ERROR = 0xff }; -CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(verbose>0), - _device_idx(0), _vid(cable.vid), _pid(cable.pid), - _serial_number(L""), _dev(NULL), _num_tms(0), _is_connect(false) +enum cmsisdap_backend_type { + BACKEND_NONE = -1, + BACKEND_HID = 0, + BACKEND_USBBULK = 1, +}; + +CmsisDAP::CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbose):_verbose(verbose>0), + _device_idx(0), _vid(cable.vid), _pid(cable.pid), _serial_number(L""), +#ifdef ENABLE_CMSISDAP_V1 + _hid_dev(NULL), +#endif +#ifdef ENABLE_CMSISDAP_V2 + _usb_dev(NULL), _ctx(NULL), +#endif + _packet_size(0), + _ep_in(0), _ep_out(0), _num_tms(0), _is_connect(false), _backend(BACKEND_NONE) { - std::vector dev_found; - _ll_buffer = (unsigned char *)malloc(sizeof(unsigned char) * 65); + _ll_buffer = (unsigned char *)malloc(sizeof(unsigned char) * 1024); if (!_ll_buffer) throw std::runtime_error("internal buffer allocation failed"); _buffer = _ll_buffer+2; + char t[256]; +#ifdef ENABLE_CMSISDAP_V2 + try { + _backend = BACKEND_USBBULK; + initWithBulk(cable, verbose); + } catch (std::runtime_error const& e) { + snprintf(t, sizeof(t), "try USB bulk init but failed with: %s", e.what()); + printInfo(t); + _backend = BACKEND_NONE; + } +#endif +#ifdef ENABLE_CMSISDAP_V1 + if (_backend == BACKEND_NONE) { + try { + _backend = BACKEND_HID; + initWithHID(cable, index, verbose); + } catch (std::runtime_error const& e) { + snprintf(t, sizeof(t), "try HID init but failed with: %s", e.what()); + printInfo(t); + _backend = BACKEND_NONE; + } + } +#endif + if (_backend == BACKEND_NONE) + throw std::runtime_error("Error: no USB backend available"); + if (clkHZ > 0) + setClkFreq(clkHZ); +} + +CmsisDAP::~CmsisDAP() +{ + /* disconnect and close device + * and free context + */ + switch(_backend){ +#ifdef ENABLE_CMSISDAP_V1 + case BACKEND_HID: + if (_is_connect) + dapDisconnect(); + if (_hid_dev) + hid_close(_hid_dev); + hid_exit(); + break; +#endif +#ifdef ENABLE_CMSISDAP_V2 + case BACKEND_USBBULK: + libusb_close(_usb_dev); + libusb_exit(_ctx); + break; +#endif + default: + break; + } + if (_ll_buffer) + free(_ll_buffer); +} + +#ifdef ENABLE_CMSISDAP_V1 +void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ + std::vector dev_found; /* only hid support */ struct hid_device_info *devs, *cur_dev; @@ -157,11 +235,13 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(ver /* store params about device to use */ _vid = dev_found[_device_idx]->vendor_id; _pid = dev_found[_device_idx]->product_id; + _vendor = dev_found[_device_idx]->manufacturer_string; + _product_name = dev_found[_device_idx]->product_string; if (dev_found[_device_idx]->serial_number != NULL) _serial_number = std::wstring(dev_found[_device_idx]->serial_number); /* open the device */ - _dev = hid_open_path(dev_found[_device_idx]->path); - if (!_dev) { + _hid_dev = hid_open_path(dev_found[_device_idx]->path); + if (!_hid_dev) { throw std::runtime_error( std::string("Couldn't open device. Check permissions for ") + dev_found[_device_idx]->path); } @@ -206,7 +286,7 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(ver memset(_buffer, 0, 63); int res = read_info(INFO_ID_HWCAP, _buffer, 63); if (res < 0) { - hid_close(_dev); + hid_close(_hid_dev); hid_exit(); char t[256]; snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); @@ -216,34 +296,265 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(ver if (verbose) printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]); if (!(_buffer[2] & (1 << 1))) { - hid_close(_dev); + hid_close(_hid_dev); hid_exit(); throw std::runtime_error("JTAG is not supported by the probe"); } /* send connect */ if (dapConnect() != 1) { - hid_close(_dev); + hid_close(_hid_dev); hid_exit(); throw std::runtime_error("DAP connection in JTAG mode failed"); } -} -CmsisDAP::~CmsisDAP() + printInfo("HID init successful"); +} +#endif + +#ifdef ENABLE_CMSISDAP_V2 +void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) { - /* disconnect and close device - * and free context - */ - if (_is_connect) - dapDisconnect(); - if (_dev) - hid_close(_dev); - hid_exit(); + if (libusb_init(&_ctx) != 0) + throw std::runtime_error("libusb init failed"); - if (_ll_buffer) - free(_ll_buffer); + std::vector devices = findCmsisDapDevices(cable.vid, cable.pid); + + /* Check if one and only device is found + * otherwise fails when no devices found or more than one present + */ + if (devices.empty()) { + libusb_exit(_ctx); + throw std::runtime_error("Error: failed to find compatible CMSIS-DAP device"); + } + if (devices.size() > 1) { + for (auto &d : devices) + libusb_close(d.handle); + libusb_exit(_ctx); + throw std::runtime_error( + "Error: more than one device. Please provide VID/PID"); + } + + cmsis_dap_v2_dev_t &dev = devices[0]; + _usb_dev = dev.handle; + _vid = dev.vid; + _pid = dev.pid; + _serial_number = dev.serial; + _vendor = dev.vendor; + _product_name = dev.product; + + printInfo("Found 1 compatible device:"); + char val[256]; + snprintf(val, sizeof(val), "\t0x%04x 0x%04x", _vid, _pid); + printInfo(val); + + int current_config; + if (libusb_get_configuration(_usb_dev, ¤t_config) != 0) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("could not find current configuration"); + } + + if (dev.config_num != current_config) { + int ret = libusb_set_configuration(_usb_dev, dev.config_num); + if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("could not set current configuration"); + } + } + + if (libusb_claim_interface(_usb_dev, dev.interface_num) != 0) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("could not claim interface"); + } + + _packet_size = dev.packet_size; + _ep_out = dev.ep_out; + _ep_in = dev.ep_in; + + if (!libusb_dev_mem_alloc(_usb_dev, _packet_size)) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("failed to alloc DMA memory for device"); + } + + if (verbose) { + display_info(INFO_ID_VID , DAPLINK_INFO_STRING); + display_info(INFO_ID_PID , DAPLINK_INFO_STRING); + display_info(INFO_ID_SERNUM , DAPLINK_INFO_STRING); + display_info(INFO_ID_FWVERS , DAPLINK_INFO_STRING); + display_info(INFO_ID_TARGET_DEV_VENDOR , DAPLINK_INFO_STRING); + display_info(INFO_ID_TARGET_DEV_NAME , DAPLINK_INFO_STRING); + display_info(INFO_ID_HWCAP , DAPLINK_INFO_BYTE); + display_info(INFO_ID_SWO_TRACE_BUF_SIZE, DAPLINK_INFO_WORD); + display_info(INFO_ID_MAX_PKT_CNT , DAPLINK_INFO_BYTE); + display_info(INFO_ID_MAX_PKT_SZ , DAPLINK_INFO_SHORT); + } + + memset(_buffer, 0, 63); + int res = read_info(INFO_ID_HWCAP, _buffer, 63); + if (res < 0) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + char t[256]; + snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); + throw std::runtime_error(t); + } + + if (verbose) + printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]); + + if (!(_buffer[2] & (1 << 1))) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("JTAG is not supported by the probe"); + } + + if (dapConnect() != 1) { + libusb_close(_usb_dev); + libusb_exit(_ctx); + throw std::runtime_error("DAP connection in JTAG mode failed"); + } + + printInfo("USB bulk init successful"); } +/* Enumerate all USB devices and return those that expose a CMSIS-DAP v2 + * bulk interface. + * Enumerate may be filtered when vid and pid are non-zero. + * Each returned entry carries an already-open libusb handle; the caller + * is responsible for closing handles it does not use. + */ +std::vector +CmsisDAP::findCmsisDapDevices(uint16_t vid, uint16_t pid) +{ + std::vector result; + struct libusb_device **devs; + + int devs_len = libusb_get_device_list(_ctx, &devs); + if (devs_len <= 0) + return result; + + for (int i = 0; i < devs_len; i++) { + struct libusb_device *dev = devs[i]; + struct libusb_device_descriptor dev_desc; + + if (libusb_get_device_descriptor(dev, &dev_desc) != 0) { + printWarn("could not get device descriptor for device " + std::to_string(i)); + continue; + } + + /* optional VID/PID filter: if either is non-zero, both must match */ + if ((vid != 0 || pid != 0) && + (dev_desc.idVendor != vid || dev_desc.idProduct != pid)) + continue; + + libusb_device_handle *handle = NULL; + if (libusb_open(dev, &handle) != 0 || !handle) + continue; + + cmsis_dap_v2_dev_t candidate = {}; + candidate.handle = handle; + candidate.vid = dev_desc.idVendor; + candidate.pid = dev_desc.idProduct; + + char str[256]; + + memset(str, 0, sizeof(str)); + if (libusb_get_string_descriptor_ascii(handle, dev_desc.iSerialNumber, + (uint8_t *)str, sizeof(str)) >= 0) + candidate.serial = std::wstring(str, str + std::strlen(str)); + + memset(str, 0, sizeof(str)); + if (libusb_get_string_descriptor_ascii(handle, dev_desc.iManufacturer, + (uint8_t *)str, sizeof(str)) >= 0) + candidate.vendor = std::wstring(str, str + std::strlen(str)); + + memset(str, 0, sizeof(str)); + if (libusb_get_string_descriptor_ascii(handle, dev_desc.iProduct, + (uint8_t *)str, sizeof(str)) >= 0) + candidate.product = std::wstring(str, str + std::strlen(str)); + + bool intf_found = false; + for (int cfg = 0; cfg < dev_desc.bNumConfigurations && !intf_found; cfg++) { + struct libusb_config_descriptor *cfg_desc; + if (libusb_get_config_descriptor(dev, cfg, &cfg_desc) != 0) { + char t[256]; + snprintf(t, sizeof(t), "could not get configuration descriptor %d " + "for device 0x%04x:0x%04x", cfg, candidate.vid, candidate.pid); + printError(t); + continue; + } + + for (int intf = 0; intf < cfg_desc->bNumInterfaces && !intf_found; intf++) { + const struct libusb_interface_descriptor *intf_desc = + &cfg_desc->interface[intf].altsetting[0]; + + /* require two bulk endpoints: [0] OUT, [1] IN */ + if (intf_desc->bNumEndpoints < 2 || + (intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT || + (intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) + continue; + + /* check whether the interface string contains "CMSIS-DAP" */ + bool intf_str_valid = false; + if (intf_desc->iInterface != 0) { + char intf_str[256] = {0}; + if (libusb_get_string_descriptor_ascii(handle, intf_desc->iInterface, + (uint8_t *)intf_str, sizeof(intf_str)) >= 0 && + std::strstr(intf_str, "CMSIS-DAP")) + intf_str_valid = true; + } + + /* CMSIS-DAP v2 spec requires vendor-specific class/subclass/protocol. + * Accept deviations (e.g. KitProg3 uses class 0) only when the + * interface string reliably identifies the interface as CMSIS-DAP + * and the class is not a well-known one (CDC, MSC …). */ + if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || + intf_desc->bInterfaceSubClass != 0 || + intf_desc->bInterfaceProtocol != 0) { + if (intf_str_valid && + (intf_desc->bInterfaceClass == 0 || + intf_desc->bInterfaceClass > 0x12)) { + char t[256]; + snprintf(t, sizeof(t), "Using interface %d with wrong class %d, " + "subclass %d or protocol %d", + intf_desc->bInterfaceNumber, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); + printWarn(t); + } else { + continue; + } + } + + candidate.interface_num = intf_desc->bInterfaceNumber; + candidate.config_num = cfg_desc->bConfigurationValue; + candidate.ep_out = intf_desc->endpoint[0].bEndpointAddress; + candidate.ep_in = intf_desc->endpoint[1].bEndpointAddress; + candidate.packet_size = intf_desc->endpoint[0].wMaxPacketSize; + intf_found = true; + } + + libusb_free_config_descriptor(cfg_desc); + } + + if (intf_found) + result.push_back(candidate); + else + libusb_close(handle); + } + + libusb_free_device_list(devs, true); + return result; +} +#endif + /* send connect instruction (0x02) to switch * in JTAG mode (0x02) */ @@ -504,34 +815,70 @@ int CmsisDAP::flush() int CmsisDAP::xfer(uint8_t instruction, int tx_len, uint8_t *rx_buff, int rx_len) { - (void)tx_len; - + int ret = -1, bulk_len = 0; _ll_buffer[0] = 0; _ll_buffer[1] = instruction; - int ret = hid_write(_dev, _ll_buffer, 65); - if (ret == -1) { - printf("Error\n"); - return ret; + switch(_backend){ +#ifdef ENABLE_CMSISDAP_V1 + case BACKEND_HID: + ret = hid_write(_hid_dev, _ll_buffer, 65); + if (ret == -1) { + printError("Error: HID write failed\n"); + return ret; + } + ret = hid_read_timeout(_hid_dev, _ll_buffer, 65, 1000); + if (ret <= 0) { + if (ret == 0) + printError("Error: HID read timeout\n"); + else if (ret == -1) + printError("Error: HID comm failed\n"); + return ret; + } + break; +#endif +#ifdef ENABLE_CMSISDAP_V2 + case BACKEND_USBBULK: + memset(&_ll_buffer[1 + tx_len + 1], 0, 64 - (tx_len + 1)); + ret = libusb_bulk_transfer(_usb_dev, _ep_out, &_ll_buffer[1], 64, &bulk_len, 1000); + if (ret != 0) { + printError("Error: Bulk write failed\n"); + return ret; + } + memset(&_ll_buffer[0], 0, 1024); + ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _packet_size, &bulk_len, 1000); + // sleep for 1ms to ensure that polling behavior aligns with HID backend + usleep(1000); + if (ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) { + printError("Error: Bulk read failed\n"); + return ret; + } + if(bulk_len == 0){ + printError("Error: Bulk timeout\n"); + return -1; + } + // if (rx_buff && bulk_len < rx_len + 2) { + // printf("bulk short read: expected %d, got %d\n", rx_len + 2, bulk_len); + // } + ret = bulk_len; + break; +#endif + default: + printError("Error: unknown USB backend\n"); + break; } - ret = hid_read_timeout(_dev, _ll_buffer, 65, 1000); - if (ret <= 0) { - if (ret == 0) - printError("Error timeout\n"); - else if (ret == -1) - printError("Error comm\n"); - return ret; - } - if (_ll_buffer[0] != instruction && _ll_buffer[1] != DAP_OK) { - printf("Error: command error"); + if (_ll_buffer[0] != instruction) { + printError("Error: command error\n"); + return -1; + } + if (_ll_buffer[1] != DAP_OK) { + printError("Error: DAP status error\n"); return -1; } - if (rx_buff) { memcpy(rx_buff, _buffer, rx_len); } - return ret; } @@ -541,28 +888,61 @@ int CmsisDAP::xfer(uint8_t instruction, int tx_len, */ int CmsisDAP::xfer(int tx_len, uint8_t *rx_buff, int rx_len) { - (void)tx_len; - + int ret = -1, bulk_len = 0; _ll_buffer[0] = 0; - int ret = hid_write(_dev, _ll_buffer, 65); - if (ret == -1) { - printf("Error\n"); - return ret; + switch(_backend){ +#ifdef ENABLE_CMSISDAP_V1 + case BACKEND_HID: + ret = hid_write(_hid_dev, _ll_buffer, 65); + if (ret == -1) { + printError("Error: HID write failed\n"); + return ret; + } + ret = hid_read_timeout(_hid_dev, _ll_buffer, 65, 1000); + if (ret <= 0) { + if (ret == 0) + printError("Error: HID read timeout\n"); + else if (ret == -1) + printError("Error: HID comm failed\n"); + return ret; + } + break; +#endif +#ifdef ENABLE_CMSISDAP_V2 + case BACKEND_USBBULK: + memset(&_ll_buffer[1 + tx_len + 1], 0, 64 - (tx_len + 1)); + ret = libusb_bulk_transfer(_usb_dev, _ep_out, &_ll_buffer[1], 64, &bulk_len, 1000); + if (ret != 0) { + printError("Error: Bulk write failed\n"); + return ret; + } + memset(&_ll_buffer[0], 0, 1024); + ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _packet_size, &bulk_len, 1000); + // sleep for 1ms to ensure that polling behavior aligns with HID backend + usleep(1000); + if (ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) { + printError("Error: Bulk read failed\n"); + return ret; + } + if(bulk_len == 0){ + printError("Error: Bulk timeout\n"); + return -1; + } + // if (rx_buff && bulk_len < rx_len + 2) { + // printf("bulk short read: expected %d, got %d\n", rx_len + 2, bulk_len); + // } + ret = bulk_len; + break; +#endif + default: + printError("Error: unknown USB backend\n"); + break; } - ret = hid_read_timeout(_dev, _ll_buffer, 65, 1000); - if (ret <= 0) { - if (ret == 0) - printf("Error timeout\n"); - else if (ret == -1) - printf("Error comm\n"); - return ret; - } if (rx_len) memmove(rx_buff, _ll_buffer, rx_len); - return ret; } @@ -604,10 +984,22 @@ void CmsisDAP::display_info(uint8_t info, uint8_t type) printError("\t" + cmsisdap_info_id_str[info] + " : NA"); return; } - } else if (info == INFO_ID_TARGET_DEV_NAME || \ - info == INFO_ID_TARGET_DEV_VENDOR) { - /* nothing */ - return; + } else if (info == INFO_ID_TARGET_DEV_NAME) { + if (!_product_name.empty()){ + snprintf(val, sizeof(val), "\t%s: %ls", + cmsisdap_info_id_str[info].c_str(), _product_name.c_str()); + } else { + printError("\t" + cmsisdap_info_id_str[info] + " : NA"); + return; + } + } else if (info == INFO_ID_TARGET_DEV_VENDOR) { + if (!_vendor.empty()){ + snprintf(val, sizeof(val), "\t%s: %ls", + cmsisdap_info_id_str[info].c_str(), _vendor.c_str()); + } else { + printError("\t" + cmsisdap_info_id_str[info] + " : NA"); + return; + } } else { printError("\t" + cmsisdap_info_id_str[info] + " : NA"); return; diff --git a/src/cmsisDAP.hpp b/src/cmsisDAP.hpp index 59933d7..5cdfac7 100644 --- a/src/cmsisDAP.hpp +++ b/src/cmsisDAP.hpp @@ -6,8 +6,12 @@ #ifndef SRC_CMSISDAP_HPP_ #define SRC_CMSISDAP_HPP_ +#ifdef ENABLE_CMSISDAP_V1 #include +#endif +#ifdef ENABLE_CMSISDAP_V2 #include +#endif #include #include @@ -23,9 +27,10 @@ class CmsisDAP: public JtagInterface { * \param[in] vid: vendor id * \param[in] pid: product id * \param[in] index: interface number - * \param[in] verbose: verbose level 0 normal, 1 verbose + * \param[in] clkHZ: clock frequency + * \param[in] verbose: verbose level (0 normal, 1 verbose) */ - CmsisDAP(const cable_t &cable, int index, int8_t verbose); + CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbose); ~CmsisDAP(); @@ -48,7 +53,7 @@ class CmsisDAP: public JtagInterface { /*! * \brief write and read len bits with optional tms set to 1 if end - * \param[in] tx: serie of tdi state to send + * \param[in] tx: serie of tdi state to send * \param[out] rx: buffer to store tdo bits from device * \param[in] len: number of bit to read/write * \param[in] end: if true tms is set to one with the last tdi bit @@ -89,6 +94,28 @@ class CmsisDAP: public JtagInterface { */ int dapDisconnect(); int dapResetTarget(); + +#ifdef ENABLE_CMSISDAP_V1 + void initWithHID(const cable_t &cable, int index, int8_t verbose); +#endif +#ifdef ENABLE_CMSISDAP_V2 + struct cmsis_dap_v2_dev_t { + libusb_device_handle *handle; + uint16_t vid; + uint16_t pid; + std::wstring serial; + std::wstring vendor; + std::wstring product; + int interface_num; + int config_num; + uint8_t ep_in; + uint8_t ep_out; + int packet_size; + }; + + std::vector findCmsisDapDevices(uint16_t vid, uint16_t pid); + void initWithBulk(const cable_t &cable, int8_t verbose); +#endif int read_info(uint8_t info, uint8_t *rd_info, int max_len); int xfer(int tx_len, uint8_t *rx_buff, int rx_len); int xfer(uint8_t instruction, int tx_len, @@ -103,13 +130,26 @@ class CmsisDAP: public JtagInterface { uint16_t _vid; /**< device Vendor ID */ uint16_t _pid; /**< device Product ID */ std::wstring _serial_number; /**< device serial number */ + std::wstring _vendor; /**< device manufacturer */ + std::wstring _product_name; /**< device product name */ - hid_device *_dev; /**< hid device used to communicate */ - +#ifdef ENABLE_CMSISDAP_V1 + hid_device *_hid_dev; /**< hid device used to communicate */ +#endif +#ifdef ENABLE_CMSISDAP_V2 + libusb_device_handle *_usb_dev; /**< libusb device used to communicate */ + libusb_context *_ctx; /**< libusb context */ +#endif unsigned char *_ll_buffer; /**< message buffer */ unsigned char *_buffer; /**< subset of _ll_buffer */ +#ifdef ENABLE_CMSISDAP_V2 + int _packet_size; /**< USB bulk packet size */ + int _ep_in; /**< USB bulk in endpoint */ + int _ep_out; /**< USB bulk out endpoint */ +#endif int _num_tms; /**< current tms length */ int _is_connect; /**< device status ((dis)connected) */ + int _backend; /**< type of USB backend */ }; #endif // SRC_CMSISDAP_HPP_ diff --git a/src/jtag.cpp b/src/jtag.cpp index bad8814..2b528c7 100644 --- a/src/jtag.cpp +++ b/src/jtag.cpp @@ -182,7 +182,7 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf, #endif case MODE_CMSISDAP: #ifdef ENABLE_CMSISDAP - _jtag = new CmsisDAP(cable, cable.config.index, verbose); + _jtag = new CmsisDAP(cable, cable.config.index, clkHZ, verbose); break; #else std::cerr << "Jtag: support for cmsisdap was not enabled at compile time" << std::endl; From dfcc540daa438b7cc36b6b6fa71c3ce8e5c47db3 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 23 May 2026 16:35:42 +0200 Subject: [PATCH 3/6] cmsisDAP: only throw exception in CTOR method --- src/cmsisDAP.cpp | 101 ++++++++++++++++++++++++++++++----------------- src/cmsisDAP.hpp | 4 +- 2 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/cmsisDAP.cpp b/src/cmsisDAP.cpp index fdab721..c163e52 100644 --- a/src/cmsisDAP.cpp +++ b/src/cmsisDAP.cpp @@ -116,23 +116,22 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbo _buffer = _ll_buffer+2; char t[256]; #ifdef ENABLE_CMSISDAP_V2 - try { - _backend = BACKEND_USBBULK; - initWithBulk(cable, verbose); - } catch (std::runtime_error const& e) { - snprintf(t, sizeof(t), "try USB bulk init but failed with: %s", e.what()); - printInfo(t); +#ifdef ENABLE_CMSISDAP_V1 + const bool err_as_info = true; +#else + const bool err_as_info = false; +#endif + _backend = BACKEND_USBBULK; + if (!initWithBulk(cable, verbose, err_as_info)) { + printInfo("cmsisDAP v2: try USB bulk init but failed"); _backend = BACKEND_NONE; } #endif #ifdef ENABLE_CMSISDAP_V1 if (_backend == BACKEND_NONE) { - try { - _backend = BACKEND_HID; - initWithHID(cable, index, verbose); - } catch (std::runtime_error const& e) { - snprintf(t, sizeof(t), "try HID init but failed with: %s", e.what()); - printInfo(t); + _backend = BACKEND_HID; + if (!initWithHID(cable, index, verbose)) { + printInfo("cmsisDAP v1: try HID init but failed"); _backend = BACKEND_NONE; } } @@ -172,14 +171,15 @@ CmsisDAP::~CmsisDAP() } #ifdef ENABLE_CMSISDAP_V1 -void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ +bool CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ std::vector dev_found; /* only hid support */ struct hid_device_info *devs, *cur_dev; if (hid_init() != 0) { - throw std::runtime_error("hidapi init failed"); + printError("hidapi init failed"); + return false; } /* search for HID compatible devices @@ -195,13 +195,15 @@ void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ /* no devices: stop */ if (dev_found.empty()) { hid_exit(); - throw std::runtime_error("No device found"); + printError("cmsisDAP: No CMSIS-DAP v1 device found"); + return false; } /* more than one device: can't continue without more information */ if (dev_found.size() > 1 && index == -1) { hid_exit(); - throw std::runtime_error( - "Error: more than one device. Please provides VID/PID or cable-index"); + printError( + "cmsisDAP: more than one CMSIS-DAP v1 device. Please provides VID/PID or cable-index"); + return false; } /* if index check for if interface exist */ @@ -216,8 +218,9 @@ void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ } if (!found) { hid_exit(); - throw std::runtime_error( - "Error: no compatible interface with index " + std::to_string(_device_idx)); + printError( + "CmsisDAP: no compatible interface with index " + std::to_string(_device_idx)); + return false; } } @@ -242,8 +245,9 @@ void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ /* open the device */ _hid_dev = hid_open_path(dev_found[_device_idx]->path); if (!_hid_dev) { - throw std::runtime_error( - std::string("Couldn't open device. Check permissions for ") + dev_found[_device_idx]->path); + printError( + std::string("Couldn't open device. Check permissions for ") + dev_found[_device_idx]->path); + return false; } /* cleanup enumeration */ hid_free_enumeration(devs); @@ -290,7 +294,8 @@ void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ hid_exit(); char t[256]; snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); - throw std::runtime_error(t); + printError(t); + return false; } if (verbose) @@ -298,25 +303,38 @@ void CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ if (!(_buffer[2] & (1 << 1))) { hid_close(_hid_dev); hid_exit(); - throw std::runtime_error("JTAG is not supported by the probe"); + printError("JTAG is not supported by the probe"); + return false; } /* send connect */ if (dapConnect() != 1) { hid_close(_hid_dev); hid_exit(); - throw std::runtime_error("DAP connection in JTAG mode failed"); + printError("DAP connection in JTAG mode failed"); + return false; } printInfo("HID init successful"); + return true; } #endif #ifdef ENABLE_CMSISDAP_V2 -void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) +void disp_error_info(const std::string &mess, bool disp_as_info) { - if (libusb_init(&_ctx) != 0) - throw std::runtime_error("libusb init failed"); + if (disp_as_info) + printInfo(mess); + else + printError(mess); +} + +bool CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose, bool err_as_info) +{ + if (libusb_init(&_ctx) != 0) { + disp_error_info("cmsisDAP v2: libusb init failed", err_as_info); + return false; + } std::vector devices = findCmsisDapDevices(cable.vid, cable.pid); @@ -325,14 +343,15 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) */ if (devices.empty()) { libusb_exit(_ctx); - throw std::runtime_error("Error: failed to find compatible CMSIS-DAP device"); + disp_error_info("cmsisDAP: failed to find compatible CMSIS-DAP v2 device", err_as_info); + return false; } if (devices.size() > 1) { for (auto &d : devices) libusb_close(d.handle); libusb_exit(_ctx); - throw std::runtime_error( - "Error: more than one device. Please provide VID/PID"); + disp_error_info("Error: more than one CMSIS-DAP v2 device. Please provide VID/PID", err_as_info); + return false; } cmsis_dap_v2_dev_t &dev = devices[0]; @@ -352,7 +371,8 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) if (libusb_get_configuration(_usb_dev, ¤t_config) != 0) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("could not find current configuration"); + disp_error_info("cmsisDAP: could not find current configuration", err_as_info); + return false; } if (dev.config_num != current_config) { @@ -360,14 +380,16 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("could not set current configuration"); + disp_error_info("cmsisDAP: could not set current configuration", err_as_info); + return false; } } if (libusb_claim_interface(_usb_dev, dev.interface_num) != 0) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("could not claim interface"); + disp_error_info("cmsisDAP: could not claim interface", err_as_info); + return false; } _packet_size = dev.packet_size; @@ -377,7 +399,8 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) if (!libusb_dev_mem_alloc(_usb_dev, _packet_size)) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("failed to alloc DMA memory for device"); + disp_error_info("cmsisDAP: failed to alloc DMA memory for device", err_as_info); + return false; } if (verbose) { @@ -400,7 +423,8 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) libusb_exit(_ctx); char t[256]; snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); - throw std::runtime_error(t); + disp_error_info(t, err_as_info); + return false; } if (verbose) @@ -409,16 +433,19 @@ void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose) if (!(_buffer[2] & (1 << 1))) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("JTAG is not supported by the probe"); + disp_error_info("JTAG is not supported by the probe", err_as_info); + return false; } if (dapConnect() != 1) { libusb_close(_usb_dev); libusb_exit(_ctx); - throw std::runtime_error("DAP connection in JTAG mode failed"); + disp_error_info("DAP connection in JTAG mode failed", err_as_info); + return false; } printInfo("USB bulk init successful"); + return true; } /* Enumerate all USB devices and return those that expose a CMSIS-DAP v2 diff --git a/src/cmsisDAP.hpp b/src/cmsisDAP.hpp index 5cdfac7..42b3e00 100644 --- a/src/cmsisDAP.hpp +++ b/src/cmsisDAP.hpp @@ -96,7 +96,7 @@ class CmsisDAP: public JtagInterface { int dapResetTarget(); #ifdef ENABLE_CMSISDAP_V1 - void initWithHID(const cable_t &cable, int index, int8_t verbose); + bool initWithHID(const cable_t &cable, int index, int8_t verbose); #endif #ifdef ENABLE_CMSISDAP_V2 struct cmsis_dap_v2_dev_t { @@ -114,7 +114,7 @@ class CmsisDAP: public JtagInterface { }; std::vector findCmsisDapDevices(uint16_t vid, uint16_t pid); - void initWithBulk(const cable_t &cable, int8_t verbose); + bool initWithBulk(const cable_t &cable, int8_t verbose, bool err_as_info); #endif int read_info(uint8_t info, uint8_t *rd_info, int max_len); int xfer(int tx_len, uint8_t *rx_buff, int rx_len); From 58aadf8c3a3e4f1a98a0c83a47722ddecaac04bc Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sat, 23 May 2026 16:48:05 +0200 Subject: [PATCH 4/6] cmsisDAP: move init/dapConnect at CTOR level to avoid dupplicate --- src/cmsisDAP.cpp | 182 ++++++++++++++++++++--------------------------- 1 file changed, 76 insertions(+), 106 deletions(-) diff --git a/src/cmsisDAP.cpp b/src/cmsisDAP.cpp index c163e52..8351345 100644 --- a/src/cmsisDAP.cpp +++ b/src/cmsisDAP.cpp @@ -138,6 +138,82 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbo #endif if (_backend == BACKEND_NONE) throw std::runtime_error("Error: no USB backend available"); + + if (verbose) { + display_info(INFO_ID_VID , DAPLINK_INFO_STRING); + display_info(INFO_ID_PID , DAPLINK_INFO_STRING); + display_info(INFO_ID_SERNUM , DAPLINK_INFO_STRING); + display_info(INFO_ID_FWVERS , DAPLINK_INFO_STRING); + display_info(INFO_ID_TARGET_DEV_VENDOR , DAPLINK_INFO_STRING); + display_info(INFO_ID_TARGET_DEV_NAME , DAPLINK_INFO_STRING); + display_info(INFO_ID_HWCAP , DAPLINK_INFO_BYTE); + display_info(INFO_ID_SWO_TRACE_BUF_SIZE, DAPLINK_INFO_WORD); + display_info(INFO_ID_MAX_PKT_CNT , DAPLINK_INFO_BYTE); + display_info(INFO_ID_MAX_PKT_SZ , DAPLINK_INFO_SHORT); + } + + /* read device capabilities -> check if it's JTAG compatible + * 0 -> info + * 1 -> len (1: info0, 2: info0, info1) + * Available transfer protocols to target: + Info0 - Bit 0: 1 = SWD Serial Wire Debug communication is implemented + 0 = SWD Commands not implemented + Info0 - Bit 1: 1 = JTAG communication is implemented + 0 = JTAG Commands not implemented + Serial Wire Trace (SWO) support: + Info0 - Bit 2: 1 = SWO UART - UART Serial Wire Output is implemented + 0 = not implemented + Info0 - Bit 3: 1 = SWO Manchester - Manchester Serial Wire Output is implemented + 0 = not implemented + Command extensions for transfer protocol: + Info0 - Bit 4: 1 = Atomic Commands - Atomic Commands support is implemented + 0 = Atomic Commands not implemented + Time synchronisation via Test Domain Timer: + Info0 - Bit 5: 1 = Test Domain Timer - debug unit support for Test Domain Timer is implemented + 0 = not implemented + SWO Streaming Trace support: + Info0 - Bit 6: 1 = SWO Streaming Trace is implemented (0 = not implemented). + */ + bool is_error = false; + memset(_buffer, 0, 63); + int res = read_info(INFO_ID_HWCAP, _buffer, 63); + if (res < 0) { + is_error = true; + char t[256]; + snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); + printError(t); + } + + if (verbose) + printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]); + + if ((!is_error) && (!(_buffer[2] & (1 << 1)))) { + is_error = true; + printError("JTAG is not supported by the probe"); + } + + /* send connect */ + if (!is_error && dapConnect() != 1) { + is_error = true; + printError("DAP connection in JTAG mode failed"); + } + + if (is_error) { + if (BACKEND_HID) { + hid_close(_hid_dev); + hid_exit(); + } else { + libusb_close(_usb_dev); + libusb_exit(_ctx); + } + throw std::runtime_error("cmsisDAP: init Failed"); + } else { + if (BACKEND_HID) { + printInfo("HID init successful"); + } else { + printInfo("USB bulk init successful"); + } + } if (clkHZ > 0) setClkFreq(clkHZ); } @@ -252,70 +328,6 @@ bool CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ /* cleanup enumeration */ hid_free_enumeration(devs); - if (verbose) { - display_info(INFO_ID_VID , DAPLINK_INFO_STRING); - display_info(INFO_ID_PID , DAPLINK_INFO_STRING); - display_info(INFO_ID_SERNUM , DAPLINK_INFO_STRING); - display_info(INFO_ID_FWVERS , DAPLINK_INFO_STRING); - display_info(INFO_ID_TARGET_DEV_VENDOR , DAPLINK_INFO_STRING); - display_info(INFO_ID_TARGET_DEV_NAME , DAPLINK_INFO_STRING); - display_info(INFO_ID_HWCAP , DAPLINK_INFO_BYTE); - display_info(INFO_ID_SWO_TRACE_BUF_SIZE, DAPLINK_INFO_WORD); - display_info(INFO_ID_MAX_PKT_CNT , DAPLINK_INFO_BYTE); - display_info(INFO_ID_MAX_PKT_SZ , DAPLINK_INFO_SHORT); - } - - /* read device capabilities -> check if it's JTAG compatible - * 0 -> info - * 1 -> len (1: info0, 2: info0, info1) - * Available transfer protocols to target: - Info0 - Bit 0: 1 = SWD Serial Wire Debug communication is implemented - 0 = SWD Commands not implemented - Info0 - Bit 1: 1 = JTAG communication is implemented - 0 = JTAG Commands not implemented - Serial Wire Trace (SWO) support: - Info0 - Bit 2: 1 = SWO UART - UART Serial Wire Output is implemented - 0 = not implemented - Info0 - Bit 3: 1 = SWO Manchester - Manchester Serial Wire Output is implemented - 0 = not implemented - Command extensions for transfer protocol: - Info0 - Bit 4: 1 = Atomic Commands - Atomic Commands support is implemented - 0 = Atomic Commands not implemented - Time synchronisation via Test Domain Timer: - Info0 - Bit 5: 1 = Test Domain Timer - debug unit support for Test Domain Timer is implemented - 0 = not implemented - SWO Streaming Trace support: - Info0 - Bit 6: 1 = SWO Streaming Trace is implemented (0 = not implemented). - */ - memset(_buffer, 0, 63); - int res = read_info(INFO_ID_HWCAP, _buffer, 63); - if (res < 0) { - hid_close(_hid_dev); - hid_exit(); - char t[256]; - snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); - printError(t); - return false; - } - - if (verbose) - printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]); - if (!(_buffer[2] & (1 << 1))) { - hid_close(_hid_dev); - hid_exit(); - printError("JTAG is not supported by the probe"); - return false; - } - - /* send connect */ - if (dapConnect() != 1) { - hid_close(_hid_dev); - hid_exit(); - printError("DAP connection in JTAG mode failed"); - return false; - } - - printInfo("HID init successful"); return true; } #endif @@ -403,48 +415,6 @@ bool CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose, bool err_as_in return false; } - if (verbose) { - display_info(INFO_ID_VID , DAPLINK_INFO_STRING); - display_info(INFO_ID_PID , DAPLINK_INFO_STRING); - display_info(INFO_ID_SERNUM , DAPLINK_INFO_STRING); - display_info(INFO_ID_FWVERS , DAPLINK_INFO_STRING); - display_info(INFO_ID_TARGET_DEV_VENDOR , DAPLINK_INFO_STRING); - display_info(INFO_ID_TARGET_DEV_NAME , DAPLINK_INFO_STRING); - display_info(INFO_ID_HWCAP , DAPLINK_INFO_BYTE); - display_info(INFO_ID_SWO_TRACE_BUF_SIZE, DAPLINK_INFO_WORD); - display_info(INFO_ID_MAX_PKT_CNT , DAPLINK_INFO_BYTE); - display_info(INFO_ID_MAX_PKT_SZ , DAPLINK_INFO_SHORT); - } - - memset(_buffer, 0, 63); - int res = read_info(INFO_ID_HWCAP, _buffer, 63); - if (res < 0) { - libusb_close(_usb_dev); - libusb_exit(_ctx); - char t[256]; - snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP); - disp_error_info(t, err_as_info); - return false; - } - - if (verbose) - printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]); - - if (!(_buffer[2] & (1 << 1))) { - libusb_close(_usb_dev); - libusb_exit(_ctx); - disp_error_info("JTAG is not supported by the probe", err_as_info); - return false; - } - - if (dapConnect() != 1) { - libusb_close(_usb_dev); - libusb_exit(_ctx); - disp_error_info("DAP connection in JTAG mode failed", err_as_info); - return false; - } - - printInfo("USB bulk init successful"); return true; } From 468f787fdf28139d4c3625e921cc0aa5004caf02 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 24 May 2026 08:52:04 +0200 Subject: [PATCH 5/6] cmsisDAP: initWithHID: displays index not device_idx (not updated when not found) --- src/cmsisDAP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmsisDAP.cpp b/src/cmsisDAP.cpp index 8351345..4ade615 100644 --- a/src/cmsisDAP.cpp +++ b/src/cmsisDAP.cpp @@ -295,7 +295,7 @@ bool CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ if (!found) { hid_exit(); printError( - "CmsisDAP: no compatible interface with index " + std::to_string(_device_idx)); + "CmsisDAP: no compatible interface with index " + std::to_string(index)); return false; } } From bba86d8be34a5a0d6b1c993129eec525c441fbb8 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 24 May 2026 09:16:30 +0200 Subject: [PATCH 6/6] cmsisDAP: v1: uses INFO_ID_MAX_PKT_SZ to fix xfer length --- src/cmsisDAP.cpp | 40 +++++++++++++++++++++++++++++----------- src/cmsisDAP.hpp | 2 +- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/cmsisDAP.cpp b/src/cmsisDAP.cpp index 4ade615..5401e79 100644 --- a/src/cmsisDAP.cpp +++ b/src/cmsisDAP.cpp @@ -107,7 +107,7 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbo #ifdef ENABLE_CMSISDAP_V2 _usb_dev(NULL), _ctx(NULL), #endif - _packet_size(0), + _pkt_sz(0), _ep_in(0), _ep_out(0), _num_tms(0), _is_connect(false), _backend(BACKEND_NONE) { _ll_buffer = (unsigned char *)malloc(sizeof(unsigned char) * 1024); @@ -129,6 +129,7 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, uint32_t clkHZ, int8_t verbo #endif #ifdef ENABLE_CMSISDAP_V1 if (_backend == BACKEND_NONE) { + _pkt_sz = 64; _backend = BACKEND_HID; if (!initWithHID(cable, index, verbose)) { printInfo("cmsisDAP v1: try HID init but failed"); @@ -328,6 +329,23 @@ bool CmsisDAP::initWithHID(const cable_t &cable, int index, int8_t verbose){ /* cleanup enumeration */ hid_free_enumeration(devs); + /* query actual HID packet size and grow buffer if needed */ + uint8_t buf[65]; + memset(buf, 0, 65); + if (read_info(INFO_ID_MAX_PKT_SZ, buf, 64) == 2) { + const uint16_t sz = (static_cast(buf[3]) << 8) | buf[2]; + if (sz > 64) { + _pkt_sz = sz; + if (sz > 1024) { + unsigned char *tmp = (unsigned char *)realloc(_ll_buffer, _pkt_sz + 1); + if (!tmp) + throw std::runtime_error("internal buffer reallocation failed"); + _ll_buffer = tmp; + _buffer = _ll_buffer + 2; + } + } + } + return true; } #endif @@ -404,11 +422,11 @@ bool CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose, bool err_as_in return false; } - _packet_size = dev.packet_size; + _pkt_sz = dev.packet_size; _ep_out = dev.ep_out; _ep_in = dev.ep_in; - if (!libusb_dev_mem_alloc(_usb_dev, _packet_size)) { + if (!libusb_dev_mem_alloc(_usb_dev, _pkt_sz)) { libusb_close(_usb_dev); libusb_exit(_ctx); disp_error_info("cmsisDAP: failed to alloc DMA memory for device", err_as_info); @@ -697,8 +715,8 @@ int CmsisDAP::writeJtagSequence(uint8_t tms, const uint8_t *tx, uint8_t *rx, * => one sequence == 9Bytes and 9*7 == 63 * then we have 6 * 8 fully filled sequence + one up to 56bits */ - if (xfer_byte_len + 1 + pos > 63) { - xfer_byte_len = 63 - pos - 1; // number of free bytes + if (xfer_byte_len + 1 + pos > _pkt_sz - 1) { + xfer_byte_len = _pkt_sz - pos - 2; // number of free bytes xfer_bit_len = xfer_byte_len * 8; } @@ -819,12 +837,12 @@ int CmsisDAP::xfer(uint8_t instruction, int tx_len, switch(_backend){ #ifdef ENABLE_CMSISDAP_V1 case BACKEND_HID: - ret = hid_write(_hid_dev, _ll_buffer, 65); + ret = hid_write(_hid_dev, _ll_buffer, _pkt_sz + 1); if (ret == -1) { printError("Error: HID write failed\n"); return ret; } - ret = hid_read_timeout(_hid_dev, _ll_buffer, 65, 1000); + ret = hid_read_timeout(_hid_dev, _ll_buffer, _pkt_sz + 1, 1000); if (ret <= 0) { if (ret == 0) printError("Error: HID read timeout\n"); @@ -843,7 +861,7 @@ int CmsisDAP::xfer(uint8_t instruction, int tx_len, return ret; } memset(&_ll_buffer[0], 0, 1024); - ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _packet_size, &bulk_len, 1000); + ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _pkt_sz, &bulk_len, 1000); // sleep for 1ms to ensure that polling behavior aligns with HID backend usleep(1000); if (ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) { @@ -891,12 +909,12 @@ int CmsisDAP::xfer(int tx_len, uint8_t *rx_buff, int rx_len) switch(_backend){ #ifdef ENABLE_CMSISDAP_V1 case BACKEND_HID: - ret = hid_write(_hid_dev, _ll_buffer, 65); + ret = hid_write(_hid_dev, _ll_buffer, _pkt_sz + 1); if (ret == -1) { printError("Error: HID write failed\n"); return ret; } - ret = hid_read_timeout(_hid_dev, _ll_buffer, 65, 1000); + ret = hid_read_timeout(_hid_dev, _ll_buffer, _pkt_sz + 1, 1000); if (ret <= 0) { if (ret == 0) printError("Error: HID read timeout\n"); @@ -915,7 +933,7 @@ int CmsisDAP::xfer(int tx_len, uint8_t *rx_buff, int rx_len) return ret; } memset(&_ll_buffer[0], 0, 1024); - ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _packet_size, &bulk_len, 1000); + ret = libusb_bulk_transfer(_usb_dev, _ep_in, &_ll_buffer[0], _pkt_sz, &bulk_len, 1000); // sleep for 1ms to ensure that polling behavior aligns with HID backend usleep(1000); if (ret != 0 && ret != LIBUSB_ERROR_TIMEOUT) { diff --git a/src/cmsisDAP.hpp b/src/cmsisDAP.hpp index 42b3e00..47403e9 100644 --- a/src/cmsisDAP.hpp +++ b/src/cmsisDAP.hpp @@ -143,7 +143,7 @@ class CmsisDAP: public JtagInterface { unsigned char *_ll_buffer; /**< message buffer */ unsigned char *_buffer; /**< subset of _ll_buffer */ #ifdef ENABLE_CMSISDAP_V2 - int _packet_size; /**< USB bulk packet size */ + int _pkt_sz; /**< USB bulk packet size */ int _ep_in; /**< USB bulk in endpoint */ int _ep_out; /**< USB bulk out endpoint */ #endif