Merge pull request #659 from aisuneko/cmsisdap_backend
Add USB Bulk backend support for cmsisDAP
This commit is contained in:
commit
6633700665
|
|
@ -40,7 +40,9 @@ option(ENABLE_ANLOGIC_CABLE "enable Anlogic cable (requires libUSB)" ${
|
||||||
option(ENABLE_CH347 "enable CH347 cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
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
|
# CMSIS-DAP requires hidapi which is complex to cross-compile, disable by default for cross-compilation
|
||||||
if (NOT WINDOWS_CROSSCOMPILE)
|
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()
|
else()
|
||||||
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" OFF)
|
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" OFF)
|
||||||
endif()
|
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
|
# Only adds libusb as dependency when a cable need this library
|
||||||
if (ENABLE_DFU OR ENABLE_ANLOGIC_CABLE OR ENABLE_CH347 OR ENABLE_DIRTYJTAG
|
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)
|
set(USE_LIBUSB ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -213,7 +216,7 @@ if (USE_PKGCONFIG)
|
||||||
set(LIBUSB_LIBRARIES "")
|
set(LIBUSB_LIBRARIES "")
|
||||||
endif(USE_LIBUSB)
|
endif(USE_LIBUSB)
|
||||||
|
|
||||||
if(ENABLE_CMSISDAP)
|
if(ENABLE_CMSISDAP_V1)
|
||||||
pkg_check_modules(HIDAPI hidapi-libusb)
|
pkg_check_modules(HIDAPI hidapi-libusb)
|
||||||
# if libusb not found try with hidraw
|
# if libusb not found try with hidraw
|
||||||
if (NOT HIDAPI_FOUND)
|
if (NOT HIDAPI_FOUND)
|
||||||
|
|
@ -630,7 +633,7 @@ if (ENABLE_LIBGPIOD)
|
||||||
link_directories(${LIBGPIOD_LIBRARY_DIRS})
|
link_directories(${LIBGPIOD_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_CMSISDAP AND HIDAPI_FOUND)
|
if (ENABLE_CMSISDAP_V1 AND HIDAPI_FOUND)
|
||||||
link_directories(${HIDAPI_LIBRARY_DIRS})
|
link_directories(${HIDAPI_LIBRARY_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -697,18 +700,34 @@ else()
|
||||||
message("CH347 support disabled")
|
message("CH347 support disabled")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_CMSISDAP)
|
# CMSIS DAP
|
||||||
|
if (ENABLE_CMSISDAP_V1)
|
||||||
if (HIDAPI_FOUND)
|
if (HIDAPI_FOUND)
|
||||||
include_directories(${HIDAPI_INCLUDE_DIRS})
|
include_directories(${HIDAPI_INCLUDE_DIRS})
|
||||||
target_link_libraries(openFPGALoader ${HIDAPI_LIBRARIES})
|
target_link_libraries(openFPGALoader ${HIDAPI_LIBRARIES})
|
||||||
add_definitions(-DENABLE_CMSISDAP=1)
|
add_definitions(-DENABLE_CMSISDAP_V1=1)
|
||||||
target_sources(openFPGALoader PRIVATE src/cmsisDAP.cpp)
|
message("cmsis_dap v1 support enabled")
|
||||||
list (APPEND OPENFPGALOADER_HEADERS src/cmsisDAP.hpp)
|
|
||||||
message("cmsis_dap support enabled")
|
|
||||||
else()
|
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()
|
||||||
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
|
# DFU
|
||||||
if (ENABLE_DFU)
|
if (ENABLE_DFU)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ anlogicCable:
|
||||||
arm-usb-ocd-h:
|
arm-usb-ocd-h:
|
||||||
|
|
||||||
- Name: Olimex ARM-USB-OCD-H adapter
|
- 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/
|
URL: https://www.olimex.com/Products/ARM/JTAG/ARM-USB-OCD-H/
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -57,10 +57,17 @@ ch552_jtag:
|
||||||
cmsisdap:
|
cmsisdap:
|
||||||
|
|
||||||
- Name: ARM CMSIS DAP protocol interface
|
- 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
|
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:
|
dfu:
|
||||||
|
|
||||||
- Name: DFU interface
|
- Name: DFU interface
|
||||||
|
|
@ -70,13 +77,13 @@ dfu:
|
||||||
|
|
||||||
digilent:
|
digilent:
|
||||||
|
|
||||||
- Name: digilent cable
|
- Name: digilent cable
|
||||||
Description: FT2232 JTAG / UART cable
|
Description: FT2232 JTAG / UART cable
|
||||||
|
|
||||||
|
|
||||||
digilent_b:
|
digilent_b:
|
||||||
|
|
||||||
- Name: digilent cable
|
- Name: digilent cable
|
||||||
Description: digilent FT2232 JTAG / UART cable (interface B)
|
Description: digilent FT2232 JTAG / UART cable (interface B)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ static std::map <std::string, cable_t> cable_list = {
|
||||||
{"numato-neso", FTDI_SER(0x2a19, 0x1005, FTDI_INTF_B, 0x08, 0x4b, 0x00, 0x00)},
|
{"numato-neso", FTDI_SER(0x2a19, 0x1005, FTDI_INTF_B, 0x08, 0x4b, 0x00, 0x00)},
|
||||||
{"orbtrace", CMSIS_CL(0x1209, 0x3443 )},
|
{"orbtrace", CMSIS_CL(0x1209, 0x3443 )},
|
||||||
{"papilio", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0x08, 0x0B, 0x09, 0x0B)},
|
{"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)},
|
{"steppenprobe", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0x58, 0xFB, 0x00, 0x99)},
|
||||||
{"tigard", FTDI_SER(0x0403, 0x6010, FTDI_INTF_B, 0x08, 0x3B, 0x00, 0x00)},
|
{"tigard", FTDI_SER(0x0403, 0x6010, FTDI_INTF_B, 0x08, 0x3B, 0x00, 0x00)},
|
||||||
{"usb-blaster", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6001 )},
|
{"usb-blaster", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6001 )},
|
||||||
|
|
|
||||||
665
src/cmsisDAP.cpp
665
src/cmsisDAP.cpp
|
|
@ -3,8 +3,14 @@
|
||||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
#include <hidapi.h>
|
#include <hidapi.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_CMSISDAP_V2
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
@ -87,86 +93,52 @@ enum cmsisdap_status {
|
||||||
DAP_ERROR = 0xff
|
DAP_ERROR = 0xff
|
||||||
};
|
};
|
||||||
|
|
||||||
CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(verbose>0),
|
enum cmsisdap_backend_type {
|
||||||
_device_idx(0), _vid(cable.vid), _pid(cable.pid),
|
BACKEND_NONE = -1,
|
||||||
_serial_number(L""), _dev(NULL), _num_tms(0), _is_connect(false)
|
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
|
||||||
|
_pkt_sz(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) * 1024);
|
||||||
_ll_buffer = (unsigned char *)malloc(sizeof(unsigned char) * 65);
|
|
||||||
if (!_ll_buffer)
|
if (!_ll_buffer)
|
||||||
throw std::runtime_error("internal buffer allocation failed");
|
throw std::runtime_error("internal buffer allocation failed");
|
||||||
_buffer = _ll_buffer+2;
|
_buffer = _ll_buffer+2;
|
||||||
|
char t[256];
|
||||||
/* only hid support */
|
#ifdef ENABLE_CMSISDAP_V2
|
||||||
struct hid_device_info *devs, *cur_dev;
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
|
const bool err_as_info = true;
|
||||||
if (hid_init() != 0) {
|
#else
|
||||||
throw std::runtime_error("hidapi init failed");
|
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
|
||||||
/* search for HID compatible devices
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
* if vid/pid are 0 this function return all;
|
if (_backend == BACKEND_NONE) {
|
||||||
* if vid/pid are >0 only one (or 0) device returned
|
_pkt_sz = 64;
|
||||||
*/
|
_backend = BACKEND_HID;
|
||||||
devs = hid_enumerate(cable.vid, cable.pid);
|
if (!initWithHID(cable, index, verbose)) {
|
||||||
|
printInfo("cmsisDAP v1: try HID init but failed");
|
||||||
for (cur_dev = devs; NULL != cur_dev; cur_dev = cur_dev->next) {
|
_backend = BACKEND_NONE;
|
||||||
dev_found.push_back(cur_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* no devices: stop */
|
|
||||||
if (dev_found.empty()) {
|
|
||||||
hid_exit();
|
|
||||||
throw std::runtime_error("No device found");
|
|
||||||
}
|
|
||||||
/* 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if index check for if interface exist */
|
|
||||||
if (index != -1) {
|
|
||||||
bool found = false;
|
|
||||||
for (size_t i = 0; i < dev_found.size(); i++) {
|
|
||||||
if (dev_found[i]->interface_number == index) {
|
|
||||||
found = true;
|
|
||||||
_device_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
hid_exit();
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Error: no compatible interface with index " + std::to_string(_device_idx));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
printInfo("Found " + std::to_string(dev_found.size()) + " compatible device:");
|
if (_backend == BACKEND_NONE)
|
||||||
for (size_t i = 0; i < dev_found.size(); i++) {
|
throw std::runtime_error("Error: no USB backend available");
|
||||||
char val[256];
|
|
||||||
snprintf(val, sizeof(val), "\t0x%04x 0x%04x 0x%d %ls",
|
|
||||||
dev_found[i]->vendor_id,
|
|
||||||
dev_found[i]->product_id,
|
|
||||||
dev_found[i]->interface_number,
|
|
||||||
dev_found[i]->product_string);
|
|
||||||
printInfo(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* store params about device to use */
|
|
||||||
_vid = dev_found[_device_idx]->vendor_id;
|
|
||||||
_pid = dev_found[_device_idx]->product_id;
|
|
||||||
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) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string("Couldn't open device. Check permissions for ") + dev_found[_device_idx]->path);
|
|
||||||
}
|
|
||||||
/* cleanup enumeration */
|
|
||||||
hid_free_enumeration(devs);
|
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
display_info(INFO_ID_VID , DAPLINK_INFO_STRING);
|
display_info(INFO_ID_VID , DAPLINK_INFO_STRING);
|
||||||
|
|
@ -203,30 +175,48 @@ CmsisDAP::CmsisDAP(const cable_t &cable, int index, int8_t verbose):_verbose(ver
|
||||||
SWO Streaming Trace support:
|
SWO Streaming Trace support:
|
||||||
Info0 - Bit 6: 1 = SWO Streaming Trace is implemented (0 = not implemented).
|
Info0 - Bit 6: 1 = SWO Streaming Trace is implemented (0 = not implemented).
|
||||||
*/
|
*/
|
||||||
|
bool is_error = false;
|
||||||
memset(_buffer, 0, 63);
|
memset(_buffer, 0, 63);
|
||||||
int res = read_info(INFO_ID_HWCAP, _buffer, 63);
|
int res = read_info(INFO_ID_HWCAP, _buffer, 63);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
hid_close(_dev);
|
is_error = true;
|
||||||
hid_exit();
|
|
||||||
char t[256];
|
char t[256];
|
||||||
snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP);
|
snprintf(t, sizeof(t), "Error %d for command %d\n", res, INFO_ID_HWCAP);
|
||||||
throw std::runtime_error(t);
|
printError(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]);
|
printf("Hardware cap %02x %02x %02x\n", _buffer[0], _buffer[1], _buffer[2]);
|
||||||
if (!(_buffer[2] & (1 << 1))) {
|
|
||||||
hid_close(_dev);
|
if ((!is_error) && (!(_buffer[2] & (1 << 1)))) {
|
||||||
hid_exit();
|
is_error = true;
|
||||||
throw std::runtime_error("JTAG is not supported by the probe");
|
printError("JTAG is not supported by the probe");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send connect */
|
/* send connect */
|
||||||
if (dapConnect() != 1) {
|
if (!is_error && dapConnect() != 1) {
|
||||||
hid_close(_dev);
|
is_error = true;
|
||||||
hid_exit();
|
printError("DAP connection in JTAG mode failed");
|
||||||
throw std::runtime_error("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);
|
||||||
}
|
}
|
||||||
|
|
||||||
CmsisDAP::~CmsisDAP()
|
CmsisDAP::~CmsisDAP()
|
||||||
|
|
@ -234,16 +224,352 @@ CmsisDAP::~CmsisDAP()
|
||||||
/* disconnect and close device
|
/* disconnect and close device
|
||||||
* and free context
|
* and free context
|
||||||
*/
|
*/
|
||||||
if (_is_connect)
|
switch(_backend){
|
||||||
dapDisconnect();
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
if (_dev)
|
case BACKEND_HID:
|
||||||
hid_close(_dev);
|
if (_is_connect)
|
||||||
hid_exit();
|
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)
|
if (_ll_buffer)
|
||||||
free(_ll_buffer);
|
free(_ll_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
|
bool 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;
|
||||||
|
|
||||||
|
if (hid_init() != 0) {
|
||||||
|
printError("hidapi init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search for HID compatible devices
|
||||||
|
* if vid/pid are 0 this function return all;
|
||||||
|
* if vid/pid are >0 only one (or 0) device returned
|
||||||
|
*/
|
||||||
|
devs = hid_enumerate(cable.vid, cable.pid);
|
||||||
|
|
||||||
|
for (cur_dev = devs; NULL != cur_dev; cur_dev = cur_dev->next) {
|
||||||
|
dev_found.push_back(cur_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no devices: stop */
|
||||||
|
if (dev_found.empty()) {
|
||||||
|
hid_exit();
|
||||||
|
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();
|
||||||
|
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 */
|
||||||
|
if (index != -1) {
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < dev_found.size(); i++) {
|
||||||
|
if (dev_found[i]->interface_number == index) {
|
||||||
|
found = true;
|
||||||
|
_device_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
hid_exit();
|
||||||
|
printError(
|
||||||
|
"CmsisDAP: no compatible interface with index " + std::to_string(index));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printInfo("Found " + std::to_string(dev_found.size()) + " compatible device:");
|
||||||
|
for (size_t i = 0; i < dev_found.size(); i++) {
|
||||||
|
char val[256];
|
||||||
|
snprintf(val, sizeof(val), "\t0x%04x 0x%04x 0x%d %ls",
|
||||||
|
dev_found[i]->vendor_id,
|
||||||
|
dev_found[i]->product_id,
|
||||||
|
dev_found[i]->interface_number,
|
||||||
|
dev_found[i]->product_string);
|
||||||
|
printInfo(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
_hid_dev = hid_open_path(dev_found[_device_idx]->path);
|
||||||
|
if (!_hid_dev) {
|
||||||
|
printError(
|
||||||
|
std::string("Couldn't open device. Check permissions for ") + dev_found[_device_idx]->path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* 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<uint16_t>(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
|
||||||
|
|
||||||
|
#ifdef ENABLE_CMSISDAP_V2
|
||||||
|
void disp_error_info(const std::string &mess, bool disp_as_info)
|
||||||
|
{
|
||||||
|
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<cmsis_dap_v2_dev_t> 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);
|
||||||
|
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);
|
||||||
|
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];
|
||||||
|
_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);
|
||||||
|
disp_error_info("cmsisDAP: could not find current configuration", err_as_info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
disp_error_info("cmsisDAP: could not claim interface", err_as_info);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pkt_sz = dev.packet_size;
|
||||||
|
_ep_out = dev.ep_out;
|
||||||
|
_ep_in = dev.ep_in;
|
||||||
|
|
||||||
|
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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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::cmsis_dap_v2_dev_t>
|
||||||
|
CmsisDAP::findCmsisDapDevices(uint16_t vid, uint16_t pid)
|
||||||
|
{
|
||||||
|
std::vector<cmsis_dap_v2_dev_t> 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
|
/* send connect instruction (0x02) to switch
|
||||||
* in JTAG mode (0x02)
|
* in JTAG mode (0x02)
|
||||||
*/
|
*/
|
||||||
|
|
@ -389,8 +715,8 @@ int CmsisDAP::writeJtagSequence(uint8_t tms, const uint8_t *tx, uint8_t *rx,
|
||||||
* => one sequence == 9Bytes and 9*7 == 63
|
* => one sequence == 9Bytes and 9*7 == 63
|
||||||
* then we have 6 * 8 fully filled sequence + one up to 56bits
|
* then we have 6 * 8 fully filled sequence + one up to 56bits
|
||||||
*/
|
*/
|
||||||
if (xfer_byte_len + 1 + pos > 63) {
|
if (xfer_byte_len + 1 + pos > _pkt_sz - 1) {
|
||||||
xfer_byte_len = 63 - pos - 1; // number of free bytes
|
xfer_byte_len = _pkt_sz - pos - 2; // number of free bytes
|
||||||
xfer_bit_len = xfer_byte_len * 8;
|
xfer_bit_len = xfer_byte_len * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -504,34 +830,70 @@ int CmsisDAP::flush()
|
||||||
int CmsisDAP::xfer(uint8_t instruction, int tx_len,
|
int CmsisDAP::xfer(uint8_t instruction, int tx_len,
|
||||||
uint8_t *rx_buff, int rx_len)
|
uint8_t *rx_buff, int rx_len)
|
||||||
{
|
{
|
||||||
(void)tx_len;
|
int ret = -1, bulk_len = 0;
|
||||||
|
|
||||||
_ll_buffer[0] = 0;
|
_ll_buffer[0] = 0;
|
||||||
_ll_buffer[1] = instruction;
|
_ll_buffer[1] = instruction;
|
||||||
|
|
||||||
int ret = hid_write(_dev, _ll_buffer, 65);
|
switch(_backend){
|
||||||
if (ret == -1) {
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
printf("Error\n");
|
case BACKEND_HID:
|
||||||
return ret;
|
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, _pkt_sz + 1, 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], _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) {
|
||||||
|
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 (_ll_buffer[0] != instruction) {
|
||||||
if (ret <= 0) {
|
printError("Error: command error\n");
|
||||||
if (ret == 0)
|
return -1;
|
||||||
printError("Error timeout\n");
|
}
|
||||||
else if (ret == -1)
|
if (_ll_buffer[1] != DAP_OK) {
|
||||||
printError("Error comm\n");
|
printError("Error: DAP status error\n");
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (_ll_buffer[0] != instruction && _ll_buffer[1] != DAP_OK) {
|
|
||||||
printf("Error: command error");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx_buff) {
|
if (rx_buff) {
|
||||||
memcpy(rx_buff, _buffer, rx_len);
|
memcpy(rx_buff, _buffer, rx_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -541,28 +903,61 @@ int CmsisDAP::xfer(uint8_t instruction, int tx_len,
|
||||||
*/
|
*/
|
||||||
int CmsisDAP::xfer(int tx_len, uint8_t *rx_buff, int rx_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;
|
_ll_buffer[0] = 0;
|
||||||
|
|
||||||
int ret = hid_write(_dev, _ll_buffer, 65);
|
switch(_backend){
|
||||||
if (ret == -1) {
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
printf("Error\n");
|
case BACKEND_HID:
|
||||||
return ret;
|
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, _pkt_sz + 1, 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], _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) {
|
||||||
|
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)
|
if (rx_len)
|
||||||
memmove(rx_buff, _ll_buffer, rx_len);
|
memmove(rx_buff, _ll_buffer, rx_len);
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -604,10 +999,22 @@ void CmsisDAP::display_info(uint8_t info, uint8_t type)
|
||||||
printError("\t" + cmsisdap_info_id_str[info] + " : NA");
|
printError("\t" + cmsisdap_info_id_str[info] + " : NA");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (info == INFO_ID_TARGET_DEV_NAME || \
|
} else if (info == INFO_ID_TARGET_DEV_NAME) {
|
||||||
info == INFO_ID_TARGET_DEV_VENDOR) {
|
if (!_product_name.empty()){
|
||||||
/* nothing */
|
snprintf(val, sizeof(val), "\t%s: %ls",
|
||||||
return;
|
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 {
|
} else {
|
||||||
printError("\t" + cmsisdap_info_id_str[info] + " : NA");
|
printError("\t" + cmsisdap_info_id_str[info] + " : NA");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,12 @@
|
||||||
#ifndef SRC_CMSISDAP_HPP_
|
#ifndef SRC_CMSISDAP_HPP_
|
||||||
#define SRC_CMSISDAP_HPP_
|
#define SRC_CMSISDAP_HPP_
|
||||||
|
|
||||||
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
#include <hidapi.h>
|
#include <hidapi.h>
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_CMSISDAP_V2
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -23,9 +27,10 @@ class CmsisDAP: public JtagInterface {
|
||||||
* \param[in] vid: vendor id
|
* \param[in] vid: vendor id
|
||||||
* \param[in] pid: product id
|
* \param[in] pid: product id
|
||||||
* \param[in] index: interface number
|
* \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();
|
~CmsisDAP();
|
||||||
|
|
||||||
|
|
@ -48,7 +53,7 @@ class CmsisDAP: public JtagInterface {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief write and read len bits with optional tms set to 1 if end
|
* \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[out] rx: buffer to store tdo bits from device
|
||||||
* \param[in] len: number of bit to read/write
|
* \param[in] len: number of bit to read/write
|
||||||
* \param[in] end: if true tms is set to one with the last tdi bit
|
* \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 dapDisconnect();
|
||||||
int dapResetTarget();
|
int dapResetTarget();
|
||||||
|
|
||||||
|
#ifdef ENABLE_CMSISDAP_V1
|
||||||
|
bool 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<cmsis_dap_v2_dev_t> findCmsisDapDevices(uint16_t vid, uint16_t pid);
|
||||||
|
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 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(int tx_len, uint8_t *rx_buff, int rx_len);
|
||||||
int xfer(uint8_t instruction, int tx_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 _vid; /**< device Vendor ID */
|
||||||
uint16_t _pid; /**< device Product ID */
|
uint16_t _pid; /**< device Product ID */
|
||||||
std::wstring _serial_number; /**< device serial number */
|
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 *_ll_buffer; /**< message buffer */
|
||||||
unsigned char *_buffer; /**< subset of _ll_buffer */
|
unsigned char *_buffer; /**< subset of _ll_buffer */
|
||||||
|
#ifdef ENABLE_CMSISDAP_V2
|
||||||
|
int _pkt_sz; /**< 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 _num_tms; /**< current tms length */
|
||||||
int _is_connect; /**< device status ((dis)connected) */
|
int _is_connect; /**< device status ((dis)connected) */
|
||||||
|
int _backend; /**< type of USB backend */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SRC_CMSISDAP_HPP_
|
#endif // SRC_CMSISDAP_HPP_
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
|
||||||
#endif
|
#endif
|
||||||
case MODE_CMSISDAP:
|
case MODE_CMSISDAP:
|
||||||
#ifdef ENABLE_CMSISDAP
|
#ifdef ENABLE_CMSISDAP
|
||||||
_jtag = new CmsisDAP(cable, cable.config.index, verbose);
|
_jtag = new CmsisDAP(cable, cable.config.index, clkHZ, verbose);
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
std::cerr << "Jtag: support for cmsisdap was not enabled at compile time" << std::endl;
|
std::cerr << "Jtag: support for cmsisdap was not enabled at compile time" << std::endl;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue