cmsisdap: add support for USB Bulk backend
This commit is contained in:
parent
afff175806
commit
6a743a35e9
|
|
@ -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)
|
||||
|
|
|
|||
509
src/cmsisDAP.cpp
509
src/cmsisDAP.cpp
|
|
@ -3,8 +3,14 @@
|
|||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#ifdef ENABLE_CMSISDAP_V1
|
||||
#include <hidapi.h>
|
||||
#endif
|
||||
#ifdef ENABLE_CMSISDAP_V2
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
|
@ -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<struct hid_device_info *> 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<struct hid_device_info *> 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<struct libusb_device_descriptor *> 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;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@
|
|||
#ifndef SRC_CMSISDAP_HPP_
|
||||
#define SRC_CMSISDAP_HPP_
|
||||
|
||||
#ifdef ENABLE_CMSISDAP_V1
|
||||
#include <hidapi.h>
|
||||
#endif
|
||||
#ifdef ENABLE_CMSISDAP_V2
|
||||
#include <libusb.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue