diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bf20e1..91a39a0 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() @@ -112,7 +114,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 ENABLE_USB_BLASTERII OR ENABLE_USB_SCAN) + OR ENABLE_ESP_USB OR ENABLE_JLINK OR ENABLE_GOWIN_GWU2X OR ENABLE_USB_BLASTERII + OR ENABLE_USB_SCAN OR ENABLE_CMSISDAP_V2) set(USE_LIBUSB ON) endif() @@ -216,7 +219,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) @@ -627,7 +630,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() @@ -694,18 +697,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..e35d7c4 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,83 @@ 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 { + initWithBulk(cable, verbose); + _backend = BACKEND_USBBULK; + } catch (std::runtime_error const& e) { + snprintf(t, sizeof(t), "try USB bulk init but failed with: %s", e.what()); + printInfo(t); + } +#endif +#ifdef ENABLE_CMSISDAP_V1 + try { + initWithHID(cable, index, verbose); + _backend = BACKEND_HID; + } catch (std::runtime_error const& e) { + snprintf(t, sizeof(t), "try HID init but failed with: %s", e.what()); + printInfo(t); + } +#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 +231,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 +282,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,33 +292,263 @@ 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() -{ - /* disconnect and close device - * and free context - */ - if (_is_connect) - dapDisconnect(); - if (_dev) - hid_close(_dev); - hid_exit(); - - if (_ll_buffer) - free(_ll_buffer); + printInfo("HID init successful"); } +#endif + +#ifdef ENABLE_CMSISDAP_V2 +void CmsisDAP::initWithBulk(const cable_t &cable, int8_t verbose){ + struct libusb_device **devs, *cur_dev; + + if (libusb_init(&_ctx) != 0){ + throw std::runtime_error("libusb init failed"); + } + + int devs_len = libusb_get_device_list(_ctx, &devs); + if (devs_len <= 0) { + libusb_exit(_ctx); + throw std::runtime_error("No device found"); + } + + std::vector devs_desc; + 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; + } + + if(dev_desc.idVendor == cable.vid && dev_desc.idProduct == cable.pid){ + devs_desc.push_back(&dev_desc); + cur_dev = dev; + break; + } + } + + if (devs_desc.size() <= 0) { + libusb_exit(_ctx); + throw std::runtime_error( + "Error: failed to find compatiable device from list"); + } + if (devs_desc.size() > 1) { + libusb_exit(_ctx); + throw std::runtime_error( + "Error: more than one device. Please provide VID/PID"); + } + + printInfo("Found " + std::to_string(devs_desc.size()) + " compatible device:"); + for (size_t i = 0; i < devs_desc.size(); i++) { + char val[256]; + snprintf(val, sizeof(val), "\t0x%04x 0x%04x", + devs_desc[i]->idVendor, + devs_desc[i]->idProduct); + // TODO: retrieve product and vendor strings right here, if possible + printInfo(val); + } + + libusb_device_descriptor *cur_desc = devs_desc[_device_idx]; + _vid = cur_desc->idVendor; + _pid = cur_desc->idProduct; + + /* open the device */ + int ret = libusb_open(cur_dev, &_usb_dev); + if (ret != 0 || !_usb_dev) { + char t[256]; + snprintf(t, sizeof(t), "Could not open device 0x%04x:0x%04x", _vid, _pid); + throw std::runtime_error(t); + } + + char serial[256] = {0}; + if(libusb_get_string_descriptor_ascii(_usb_dev, cur_desc->iSerialNumber, (uint8_t *) serial, sizeof(serial)) < 0){ + char t[256]; + snprintf(t, sizeof(t), "could not read serial number for device 0x%04x:0x%04x", _vid, _pid); + printWarn(t); + } else { + _serial_number = std::wstring(serial, serial + std::strlen(serial)); + } + + char vendor[256] = {0}; + if(libusb_get_string_descriptor_ascii(_usb_dev, cur_desc->iManufacturer, (uint8_t *) vendor, sizeof(vendor)) < 0){ + char t[256]; + snprintf(t, sizeof(t), "could not read serial number for device 0x%04x:0x%04x", _vid, _pid); + printWarn(t); + } else { + _vendor = std::wstring(vendor, vendor + std::strlen(vendor)); + } + + char product_string[256] = {0}; + if(libusb_get_string_descriptor_ascii(_usb_dev, cur_desc->iProduct, (uint8_t *) product_string, sizeof(product_string)) < 0){ + char t[256]; + snprintf(t, sizeof(t), "could not read product string for device 0x%04x:0x%04x", _vid, _pid); + printWarn(t); + } else { + _product_name = std::wstring(product_string, product_string + std::strlen(product_string)); + if (!std::strstr(product_string, "CMSIS-DAP")){ + // CMSIS-DAP spec mandates that the string "CMSIS-DAP" is present in the product string + char t[256]; + snprintf(t, sizeof(t), "device 0x%04x:0x%04x does not appear to be a CMSIS-DAP device", _vid, _pid); + throw std::runtime_error(t); + } + } + + for (int config = 0; config < cur_desc->bNumConfigurations; config++) { + struct libusb_config_descriptor *config_desc; + if (libusb_get_config_descriptor(cur_dev, config, &config_desc) != 0) { + char t[256]; + snprintf(t, sizeof(t), "could not get configuration descriptor %d for device 0x%04x:0x%04x", config, _vid, _pid); + printError(t); + continue; + } + + int config_num = config_desc->bConfigurationValue; + const struct libusb_interface_descriptor *intf_desc_found = NULL; + + for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) { + const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; + int interface_num = intf_desc->bInterfaceNumber; + + /* Search for "CMSIS-DAP" in the interface string */ + bool interface_str_valid = false; + if (intf_desc->iInterface != 0) { + char interface_str[256] = {0}; + if(libusb_get_string_descriptor_ascii(_usb_dev, intf_desc->iInterface, (uint8_t *)interface_str, sizeof(interface_str)) < 0){ + char t[256]; + snprintf(t, sizeof(t), "could not read interface string for device 0x%04x:0x%04x", _vid, _pid); + printWarn(t); + } else if (!std::strstr(interface_str, "CMSIS-DAP")){ + interface_str_valid = true; + } + } + + 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; + } + + if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || + intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) { + /* If the interface is reliably identified + * then we need not insist on setting USB class, subclass and protocol + * exactly as the specification requires. + * Just filter out the well known classes, mainly CDC and MSC. + * At least KitProg3 uses class 0 contrary to the specification */ + char t[256]; + if (interface_str_valid && + (intf_desc->bInterfaceClass == 0 || intf_desc->bInterfaceClass > 0x12)) { + snprintf(t, sizeof(t), "Using interface %d with wrong class %d, subclass %d or protocol %d", + interface_num, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); + printWarn(t); + } else { + continue; + } + } + intf_desc_found = intf_desc; + } + + if (!intf_desc_found) { + libusb_free_config_descriptor(config_desc); + char t[256]; + snprintf(t, sizeof(t), "could not find correct interface descriptor for device 0x%04x:0x%04x", _vid, _pid); + printError(t); + continue; + } + + int interface_num = intf_desc_found->bInterfaceNumber; + _packet_size = intf_desc_found->endpoint[0].wMaxPacketSize; + _ep_out = intf_desc_found->endpoint[0].bEndpointAddress; + _ep_in = intf_desc_found->endpoint[1].bEndpointAddress; + + libusb_free_device_list(devs, true); + libusb_free_config_descriptor(config_desc); + + int current_config; + if (libusb_get_configuration(_usb_dev, ¤t_config) != 0){ + throw std::runtime_error("could not find current configuration"); + } + + if (config_num != current_config) { + int ret = libusb_set_configuration(_usb_dev, config_desc->bConfigurationValue); + if(ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED){ + throw std::runtime_error("could not set current configuration"); + } + } + + if (libusb_claim_interface(_usb_dev, interface_num) != 0){ + throw std::runtime_error("could not claim interface"); + } + + if (!libusb_dev_mem_alloc(_usb_dev, _packet_size)){ + 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"); + } + + /* send connect */ + 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"); + return; + } + + libusb_free_device_list(devs, true); + libusb_exit(_ctx); + + throw std::runtime_error("failed to initialize USB bulk device"); +} +#endif /* send connect instruction (0x02) to switch * in JTAG mode (0x02) @@ -504,34 +810,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 +883,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 +979,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..55e3b55 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,13 @@ 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 + 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 +115,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 b5ed9a5..d286ec0 100644 --- a/src/jtag.cpp +++ b/src/jtag.cpp @@ -178,7 +178,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;