moved DAP code away from main

This commit is contained in:
Hardy Griech
2023-08-25 07:48:52 +02:00
parent 2b7f5e1c8f
commit cc1b8f9df8
8 changed files with 449 additions and 325 deletions

View File

@@ -138,7 +138,6 @@ endif()
add_executable(${PROJECT}
src/dap_util.c
src/get_config.c
src/led.c
src/main.c
@@ -148,6 +147,8 @@ add_executable(${PROJECT}
src/sw_dp_pio.c
src/sw_lock.c
src/usb_descriptors.c
src/cmsis-dap/dap_server.c
src/cmsis-dap/dap_util.c
)
target_sources(${PROJECT} PRIVATE

6
src/cmsis-dap/README.adoc Executable file
View File

@@ -0,0 +1,6 @@
:imagesdir: doc/png
:source-highlighter: rouge
:toc:
:toclevels: 5
# CMSIS-DAP Server

380
src/cmsis-dap/dap_server.c Executable file
View File

@@ -0,0 +1,380 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <pico/stdlib.h>
#include "FreeRTOS.h"
#include "event_groups.h"
#include "task.h"
#include "tusb.h"
#include "picoprobe_config.h"
#include "dap_server.h"
#include "dap_util.h"
#include "DAP_config.h"
#include "DAP.h"
#include "led.h"
#include "sw_lock.h"
#if OPT_CMSIS_DAPV2
static TaskHandle_t dap_taskhandle = NULL;
static EventGroupHandle_t dap_events;
#endif
/*
* The following is part of a hack to make DAP_PACKET_COUNT a variable.
* CMSIS-DAPv2 has better performance with 2 packets while
* CMSIS-DAPv1 only works with one packet, at least with openocd which throws a
* "CMSIS-DAP transfer count mismatch: expected 12, got 8" on flashing.
* The correct packet count has to be set on connection.
*
* More notes: pyocd works with large packets only, if the packet count is one.
* Additionally pyocd is instable if packet count > 1. Valid for pyocd 0.34.3.
*/
//#define _DAP_PACKET_COUNT_OPENOCD 2
//#define _DAP_PACKET_SIZE_OPENOCD CFG_TUD_VENDOR_RX_BUFSIZE
#define _DAP_PACKET_COUNT_OPENOCD 1 // TODO check optimizations
#define _DAP_PACKET_SIZE_OPENOCD 256
#define _DAP_PACKET_COUNT_PYOCD 1
#define _DAP_PACKET_SIZE_PYOCD 1024 // pyocd does not like packets > 128 if COUNT != 1
#define _DAP_PACKET_COUNT_UNKNOWN 1
#define _DAP_PACKET_SIZE_UNKNOWN 64
#define _DAP_PACKET_COUNT_HID 1
#define _DAP_PACKET_SIZE_HID 64
uint8_t dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
uint16_t dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
#if OPT_CMSIS_DAPV1 || OPT_CMSIS_DAPV2
static uint8_t TxDataBuffer[_DAP_PACKET_COUNT_OPENOCD * CFG_TUD_VENDOR_RX_BUFSIZE]; // maximum required size
#endif
#if OPT_CMSIS_DAPV2
static uint8_t RxDataBuffer[_DAP_PACKET_COUNT_OPENOCD * CFG_TUD_VENDOR_RX_BUFSIZE]; // maximum required size
#endif
#if OPT_CMSIS_DAPV2
void tud_vendor_rx_cb(uint8_t itf)
{
if (itf == 0) {
xEventGroupSetBits(dap_events, 0x01);
}
} // tud_vendor_rx_cb
#endif
#if OPT_CMSIS_DAPV2
/**
* CMSIS-DAP task.
* Receive DAP requests, execute them via DAP_ExecuteCommand() and transmit the response.
*
* Problem zones:
* - connect / disconnect: pyOCD does not send permanently requests if in gdbserver mode, OpenOCD does.
* As a consequence "disconnect" has to be detected via the command stream. If the tool on host side
* fails without a disconnect, the SWD connection is not freed (for MSC or RTT). To recover from this
* situation either reset the probe or issue something like "pyocd reset -t rp2040"
* - fingerprinting the host tool: this is for optimization of the OpenOCD connection, because OpenOCD
* can handle big DAP packets and thus transfer is faster.
* - ID_DAP_Disconnect / ID_DAP_Info / ID_DAP_HostStatus leads to an SWD disconnect if there is no other
* command following within 1s. This is required, because "pyocd list" leads to tool detection without
* connect/disconnect and thus otherwise tool detection would be stuck to "pyocd" for the next connection.
*/
void dap_task(void *ptr)
{
bool swd_connected = false;
bool swd_disconnect_requested = false;
uint32_t last_request_us = 0;
uint32_t rx_len = 0;
daptool_t tool = E_DAPTOOL_UNKNOWN;
dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
for (;;) {
// disconnect after 1s without data
if (swd_disconnect_requested && time_us_32() - last_request_us > 1000000) {
if (swd_connected) {
swd_connected = false;
picoprobe_info("=================================== DAPv2 disconnect target\n");
led_state(LS_DAPV2_DISCONNECTED);
sw_unlock("DAPv2");
}
swd_disconnect_requested = false;
dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
tool = DAP_FingerprintTool(NULL, 0);
}
xEventGroupWaitBits(dap_events, 0x01, pdTRUE, pdFALSE, pdMS_TO_TICKS(100)); // TODO "pyocd reset -f 500000" does otherwise not disconnect
if (tud_vendor_available())
{
rx_len += tud_vendor_read(RxDataBuffer + rx_len, sizeof(RxDataBuffer));
if (rx_len != 0)
{
uint32_t request_len;
request_len = DAP_GetCommandLength(RxDataBuffer, rx_len);
if (rx_len >= request_len)
{
last_request_us = time_us_32();
// picoprobe_info("<<<(%lx) %d %d\n", request_len, RxDataBuffer[0], RxDataBuffer[1]);
//
// try to find out which tool is connecting
//
if (tool == E_DAPTOOL_UNKNOWN) {
tool = DAP_FingerprintTool(RxDataBuffer, request_len);
if (tool == E_DAPTOOL_OPENOCD) {
dap_packet_count = _DAP_PACKET_COUNT_OPENOCD;
dap_packet_size = _DAP_PACKET_SIZE_OPENOCD;
}
else if (tool == E_DAPTOOL_PYOCD) {
dap_packet_count = _DAP_PACKET_COUNT_PYOCD;
dap_packet_size = _DAP_PACKET_SIZE_PYOCD;
}
}
//
// initiate SWD connect / disconnect
//
if ( !swd_connected && RxDataBuffer[0] != ID_DAP_Info) {
if (sw_lock("DAPv2", true)) {
swd_connected = true;
picoprobe_info("=================================== DAPv2 connect target, host %s\n",
(tool == E_DAPTOOL_OPENOCD) ? "OpenOCD with two big buffers" :
((tool == E_DAPTOOL_PYOCD) ? "pyOCD with single big buffer" : "UNKNOWN"));
led_state(LS_DAPV2_CONNECTED);
}
}
if (RxDataBuffer[0] == ID_DAP_Disconnect || RxDataBuffer[0] == ID_DAP_Info || RxDataBuffer[0] == ID_DAP_HostStatus) {
swd_disconnect_requested = true;
}
else {
swd_disconnect_requested = false;
}
//
// execute request and send back response
//
if (swd_connected || DAP_OfflineCommand(RxDataBuffer))
{
uint32_t resp_len;
resp_len = DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
// picoprobe_info(">>>(%lx) %d %d %d %d\n", resp_len, TxDataBuffer[0], TxDataBuffer[1], TxDataBuffer[2], TxDataBuffer[3]);
tud_vendor_write(TxDataBuffer, resp_len & 0xffff);
tud_vendor_flush();
if (request_len != (resp_len >> 16))
{
// there is a bug in CMSIS-DAP, see https://github.com/ARM-software/CMSIS_5/pull/1503
// but we trust our own length calculation
picoprobe_error(" !!!!!!!! request (%u) and executed length (%u) differ\n",
(unsigned)request_len, (unsigned)(resp_len >> 16));
}
if (rx_len == request_len)
{
rx_len = 0;
}
else
{
memmove(RxDataBuffer, RxDataBuffer + request_len, rx_len - request_len);
rx_len -= request_len;
}
}
}
}
}
}
} // dap_task
#endif
#if OPT_CMSIS_DAPV2
extern uint8_t const desc_ms_os_20[];
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case 1:
if (request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, desc_ms_os_20 + 8, 2);
return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len);
}
else {
return false;
}
default:
break;
}
break;
default:
break;
}
// stall unknown request
return false;
} // tud_vendor_control_xfer_cb
#endif
#if OPT_CMSIS_DAPV1
static bool hid_swd_connected;
static bool hid_swd_disconnect_requested;
static TimerHandle_t timer_hid_disconnect = NULL;
static void *timer_hid_disconnect_id;
static void hid_disconnect(TimerHandle_t xTimer)
{
if (hid_swd_disconnect_requested && hid_swd_connected) {
hid_swd_connected = false;
picoprobe_info("=================================== DAPv1 disconnect target\n");
led_state(LS_DAPV1_DISCONNECTED);
sw_unlock("DAPv1");
}
} // hid_disconnect
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
return 0;
}
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* RxDataBuffer, uint16_t bufsize)
{
uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize);
// This doesn't use multiple report and report ID
(void) itf;
(void) report_id;
(void) report_type;
if (timer_hid_disconnect == NULL) {
timer_hid_disconnect = xTimerCreate("timer_hid_disconnect", pdMS_TO_TICKS(1000), pdFALSE, timer_hid_disconnect_id,
hid_disconnect);
if (timer_hid_disconnect == NULL) {
picoprobe_error("tud_hid_set_report_cb: cannot create timer_hid_disconnect\n");
}
}
else {
xTimerReset(timer_hid_disconnect, pdMS_TO_TICKS(1000));
}
//
// initiate SWD connect / disconnect
//
if ( !hid_swd_connected && RxDataBuffer[0] != ID_DAP_Info) {
if (sw_lock("DAPv1", true)) {
hid_swd_connected = true;
picoprobe_info("=================================== DAPv1 connect target\n");
led_state(LS_DAPV1_CONNECTED);
}
}
if (RxDataBuffer[0] == ID_DAP_Disconnect || RxDataBuffer[0] == ID_DAP_Info || RxDataBuffer[0] == ID_DAP_HostStatus) {
hid_swd_disconnect_requested = true;
// this is the minimum version which should always work
dap_packet_count = _DAP_PACKET_COUNT_HID;
dap_packet_size = _DAP_PACKET_SIZE_HID;
}
else {
hid_swd_disconnect_requested = false;
}
//
// execute request and send back response
//
if (hid_swd_connected || DAP_OfflineCommand(RxDataBuffer)) {
#if 0
// heavy debug output, set dap_packet_count=2 to stumble into the bug
uint32_t request_len = DAP_GetCommandLength(RxDataBuffer, bufsize);
picoprobe_info("< ");
for (int i = 0; i < bufsize; ++i) {
picoprobe_info_out(" %02x", RxDataBuffer[i]);
if (i == request_len - 1) {
picoprobe_info_out(" !!!!");
}
}
picoprobe_info_out("\n");
vTaskDelay(pdMS_TO_TICKS(30));
uint32_t res = DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
picoprobe_info("> %lu %lu\n", res >> 16, res & 0xffff);
#else
DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
#endif
tud_hid_report(0, TxDataBuffer, response_size);
}
} // tud_hid_set_report_cb
#endif
void dap_server_init(uint32_t task_prio)
{
picoprobe_debug("dap_server_init(%u)\n", (unsigned)task_prio);
#if OPT_CMSIS_DAPV2
dap_events = xEventGroupCreate();
xTaskCreate(dap_task, "CMSIS-DAPv2", configMINIMAL_STACK_SIZE, NULL, task_prio, &dap_taskhandle);
#endif
} // rtt_console_init

45
src/cmsis-dap/dap_server.h Executable file
View File

@@ -0,0 +1,45 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef DAP_SERVER_H
#define DAP_SERVER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void dap_server_init(uint32_t task_prio);
#ifdef __cplusplus
}
#endif
#endif

8
src/daplink-pico/README.adoc Executable file
View File

@@ -0,0 +1,8 @@
:imagesdir: doc/png
:source-highlighter: rouge
:toc:
:toclevels: 5
# DAPLink adoptions for the probe
These modules fit the probe into the DAPLink infrastructure.

View File

@@ -29,7 +29,6 @@
#include "timers.h"
#include "event_groups.h"
#include <pico/stdlib.h>
#ifdef TARGET_BOARD_PICO_W
#include <pico/cyw43_arch.h>
#endif
@@ -61,12 +60,15 @@
#if OPT_CDC_SYSVIEW
#include "cdc/cdc_sysview.h"
#endif
#include "dap_util.h"
#if OPT_CMSIS_DAPV2
#include "cmsis-dap/dap_server.h"
#endif
#include "get_config.h"
#include "led.h"
#include "sw_lock.h"
#include "DAP_config.h"
#include "DAP.h"
#include "sw_lock.h"
#include "target_board.h" // DAPLink
@@ -116,34 +118,6 @@
// maximum number of expected FreeRTOS task (used for uxTaskGetSystemState())
#define TASK_MAX_CNT 15
/*
* The following is part of a hack to make DAP_PACKET_COUNT a variable.
* CMSIS-DAPv2 has better performance with 2 packets while
* CMSIS-DAPv1 only works with one packet, at least with openocd which throws a
* "CMSIS-DAP transfer count mismatch: expected 12, got 8" on flashing.
* The correct packet count has to be set on connection.
*
* More notes: pyocd works with large packets only, if the packet count is one.
* Additionally pyocd is instable if packet count > 1. Valid for pyocd 0.34.3.
*/
#define _DAP_PACKET_COUNT_OPENOCD 2
#define _DAP_PACKET_SIZE_OPENOCD CFG_TUD_VENDOR_RX_BUFSIZE
#define _DAP_PACKET_COUNT_PYOCD 1
#define _DAP_PACKET_SIZE_PYOCD 1024 // pyocd does not like packets > 128 if COUNT != 1
#define _DAP_PACKET_COUNT_UNKNOWN 1
#define _DAP_PACKET_SIZE_UNKNOWN 64
#define _DAP_PACKET_COUNT_HID 1
#define _DAP_PACKET_SIZE_HID 64
uint8_t dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
uint16_t dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
#if OPT_CMSIS_DAPV1 || OPT_CMSIS_DAPV2
static uint8_t TxDataBuffer[_DAP_PACKET_COUNT_OPENOCD * CFG_TUD_VENDOR_RX_BUFSIZE]; // maximum required size
static uint8_t RxDataBuffer[_DAP_PACKET_COUNT_OPENOCD * CFG_TUD_VENDOR_RX_BUFSIZE]; // maximum required size
#endif
// prios are critical and determine throughput
#define LED_TASK_PRIO (tskIDLE_PRIORITY + 30) // simple task which may interrupt everything else for periodic blinking
#define TUD_TASK_PRIO (tskIDLE_PRIORITY + 28) // high prio for TinyUSB
@@ -158,10 +132,6 @@ uint16_t dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
#define RTT_CONSOLE_TASK_PRIO (tskIDLE_PRIORITY + 1) // target -> host via RTT, ATTENTION: this task can fully load the CPU depending on target RTT output
static TaskHandle_t tud_taskhandle;
#if OPT_CMSIS_DAPV2
static TaskHandle_t dap_taskhandle;
#endif
static EventGroupHandle_t dap_events;
@@ -256,148 +226,6 @@ void tud_cdc_tx_complete_cb(uint8_t itf)
#if OPT_CMSIS_DAPV2
void tud_vendor_rx_cb(uint8_t itf)
{
if (itf == 0) {
xEventGroupSetBits(dap_events, 0x01);
}
} // tud_vendor_rx_cb
#endif
#if OPT_CMSIS_DAPV2
/**
* CMSIS-DAP task.
* Receive DAP requests, execute them via DAP_ExecuteCommand() and transmit the response.
*
* Problem zones:
* - connect / disconnect: pyOCD does not send permanently requests if in gdbserver mode, OpenOCD does.
* As a consequence "disconnect" has to be detected via the command stream. If the tool on host side
* fails without a disconnect, the SWD connection is not freed (for MSC or RTT). To recover from this
* situation either reset the probe or issue something like "pyocd reset -t rp2040"
* - fingerprinting the host tool: this is for optimization of the OpenOCD connection, because OpenOCD
* can handle big DAP packets and thus transfer is faster.
* - ID_DAP_Disconnect / ID_DAP_Info / ID_DAP_HostStatus leads to an SWD disconnect if there is no other
* command following within 1s. This is required, because "pyocd list" leads to tool detection without
* connect/disconnect and thus otherwise tool detection would be stuck to "pyocd" for the next connection.
*/
void dap_task(void *ptr)
{
bool swd_connected = false;
bool swd_disconnect_requested = false;
uint32_t last_request_us = 0;
uint32_t rx_len = 0;
daptool_t tool = E_DAPTOOL_UNKNOWN;
dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
for (;;) {
// disconnect after 1s without data
if (swd_disconnect_requested && time_us_32() - last_request_us > 1000000) {
if (swd_connected) {
swd_connected = false;
picoprobe_info("=================================== DAPv2 disconnect target\n");
led_state(LS_DAPV2_DISCONNECTED);
sw_unlock("DAPv2");
}
swd_disconnect_requested = false;
dap_packet_count = _DAP_PACKET_COUNT_UNKNOWN;
dap_packet_size = _DAP_PACKET_SIZE_UNKNOWN;
tool = DAP_FingerprintTool(NULL, 0);
}
xEventGroupWaitBits(dap_events, 0x01, pdTRUE, pdFALSE, pdMS_TO_TICKS(100)); // TODO "pyocd reset -f 500000" does otherwise not disconnect
if (tud_vendor_available())
{
rx_len += tud_vendor_read(RxDataBuffer + rx_len, sizeof(RxDataBuffer));
if (rx_len != 0)
{
uint32_t request_len;
request_len = DAP_GetCommandLength(RxDataBuffer, rx_len);
if (rx_len >= request_len)
{
last_request_us = time_us_32();
// picoprobe_info("<<<(%lx) %d %d\n", request_len, RxDataBuffer[0], RxDataBuffer[1]);
//
// try to find out which tool is connecting
//
if (tool == E_DAPTOOL_UNKNOWN) {
tool = DAP_FingerprintTool(RxDataBuffer, request_len);
if (tool == E_DAPTOOL_OPENOCD) {
dap_packet_count = _DAP_PACKET_COUNT_OPENOCD;
dap_packet_size = _DAP_PACKET_SIZE_OPENOCD;
}
else if (tool == E_DAPTOOL_PYOCD) {
dap_packet_count = _DAP_PACKET_COUNT_PYOCD;
dap_packet_size = _DAP_PACKET_SIZE_PYOCD;
}
}
//
// initiate SWD connect / disconnect
//
if ( !swd_connected && RxDataBuffer[0] != ID_DAP_Info) {
if (sw_lock("DAPv2", true)) {
swd_connected = true;
picoprobe_info("=================================== DAPv2 connect target, host %s\n",
(tool == E_DAPTOOL_OPENOCD) ? "OpenOCD with two big buffers" :
((tool == E_DAPTOOL_PYOCD) ? "pyOCD with single big buffer" : "UNKNOWN"));
led_state(LS_DAPV2_CONNECTED);
}
}
if (RxDataBuffer[0] == ID_DAP_Disconnect || RxDataBuffer[0] == ID_DAP_Info || RxDataBuffer[0] == ID_DAP_HostStatus) {
swd_disconnect_requested = true;
}
else {
swd_disconnect_requested = false;
}
//
// execute request and send back response
//
if (swd_connected || DAP_OfflineCommand(RxDataBuffer))
{
uint32_t resp_len;
resp_len = DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
// picoprobe_info(">>>(%lx) %d %d %d %d\n", resp_len, TxDataBuffer[0], TxDataBuffer[1], TxDataBuffer[2], TxDataBuffer[3]);
tud_vendor_write(TxDataBuffer, resp_len & 0xffff);
tud_vendor_flush();
if (request_len != (resp_len >> 16))
{
// there is a bug in CMSIS-DAP, see https://github.com/ARM-software/CMSIS_5/pull/1503
// but we trust our own length calculation
picoprobe_error(" !!!!!!!! request (%u) and executed length (%u) differ\n",
(unsigned)request_len, (unsigned)(resp_len >> 16));
}
if (rx_len == request_len)
{
rx_len = 0;
}
else
{
memmove(RxDataBuffer, RxDataBuffer + request_len, rx_len - request_len);
rx_len -= request_len;
}
}
}
}
}
}
} // dap_task
#endif
#if configGENERATE_RUN_TIME_STATS
static uint32_t tusb_count;
static TimerHandle_t timer_task_stat;
@@ -585,7 +413,7 @@ void usb_thread(void *ptr)
#endif
#if OPT_CMSIS_DAPV2
xTaskCreate(dap_task, "CMSIS-DAPv2", configMINIMAL_STACK_SIZE, NULL, DAPV2_TASK_PRIO, &dap_taskhandle);
dap_server_init(DAPV2_TASK_PRIO);
#endif
#if configGENERATE_RUN_TIME_STATS
@@ -704,8 +532,6 @@ int main(void)
#endif
picoprobe_info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
dap_events = xEventGroupCreate();
// it seems that TinyUSB does not like affinity setting in its thread, so the affinity of the USB thread is corrected in the task itself
xTaskCreate(usb_thread, "TinyUSB Main", 4096, NULL, TUD_TASK_PRIO, &tud_taskhandle);
vTaskStartScheduler();
@@ -715,148 +541,6 @@ int main(void)
#if OPT_CMSIS_DAPV1
static bool hid_swd_connected;
static bool hid_swd_disconnect_requested;
static TimerHandle_t timer_hid_disconnect = NULL;
static void *timer_hid_disconnect_id;
static void hid_disconnect(TimerHandle_t xTimer)
{
if (hid_swd_disconnect_requested && hid_swd_connected) {
hid_swd_connected = false;
picoprobe_info("=================================== DAPv1 disconnect target\n");
led_state(LS_DAPV1_DISCONNECTED);
sw_unlock("DAPv1");
}
} // hid_disconnect
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
{
// TODO not Implemented
(void) itf;
(void) report_id;
(void) report_type;
(void) buffer;
(void) reqlen;
return 0;
}
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* RxDataBuffer, uint16_t bufsize)
{
uint32_t response_size = TU_MIN(CFG_TUD_HID_EP_BUFSIZE, bufsize);
// This doesn't use multiple report and report ID
(void) itf;
(void) report_id;
(void) report_type;
if (timer_hid_disconnect == NULL) {
timer_hid_disconnect = xTimerCreate("timer_hid_disconnect", pdMS_TO_TICKS(1000), pdFALSE, timer_hid_disconnect_id,
hid_disconnect);
if (timer_hid_disconnect == NULL) {
picoprobe_error("tud_hid_set_report_cb: cannot create timer_hid_disconnect\n");
}
}
else {
xTimerReset(timer_hid_disconnect, pdMS_TO_TICKS(1000));
}
//
// initiate SWD connect / disconnect
//
if ( !hid_swd_connected && RxDataBuffer[0] != ID_DAP_Info) {
if (sw_lock("DAPv1", true)) {
hid_swd_connected = true;
picoprobe_info("=================================== DAPv1 connect target\n");
led_state(LS_DAPV1_CONNECTED);
}
}
if (RxDataBuffer[0] == ID_DAP_Disconnect || RxDataBuffer[0] == ID_DAP_Info || RxDataBuffer[0] == ID_DAP_HostStatus) {
hid_swd_disconnect_requested = true;
// this is the minimum version which should always work
dap_packet_count = _DAP_PACKET_COUNT_HID;
dap_packet_size = _DAP_PACKET_SIZE_HID;
}
else {
hid_swd_disconnect_requested = false;
}
//
// execute request and send back response
//
if (hid_swd_connected || DAP_OfflineCommand(RxDataBuffer)) {
#if 0
// heavy debug output, set dap_packet_count=2 to stumble into the bug
uint32_t request_len = DAP_GetCommandLength(RxDataBuffer, bufsize);
picoprobe_info("< ");
for (int i = 0; i < bufsize; ++i) {
picoprobe_info_out(" %02x", RxDataBuffer[i]);
if (i == request_len - 1) {
picoprobe_info_out(" !!!!");
}
}
picoprobe_info_out("\n");
vTaskDelay(pdMS_TO_TICKS(30));
uint32_t res = DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
picoprobe_info("> %lu %lu\n", res >> 16, res & 0xffff);
#else
DAP_ExecuteCommand(RxDataBuffer, TxDataBuffer);
#endif
tud_hid_report(0, TxDataBuffer, response_size);
}
} // tud_hid_set_report_cb
#endif
#if OPT_CMSIS_DAPV2
extern uint8_t const desc_ms_os_20[];
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
// nothing to with DATA & ACK stage
if (stage != CONTROL_STAGE_SETUP)
return true;
switch (request->bmRequestType_bit.type) {
case TUSB_REQ_TYPE_VENDOR:
switch (request->bRequest) {
case 1:
if (request->wIndex == 7) {
// Get Microsoft OS 2.0 compatible descriptor
uint16_t total_len;
memcpy(&total_len, desc_ms_os_20 + 8, 2);
return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len);
}
else {
return false;
}
default:
break;
}
break;
default:
break;
}
// stall unknown request
return false;
} // tud_vendor_control_xfer_cb
#endif
void vApplicationTickHook (void)
{
}
@@ -865,12 +549,12 @@ void vApplicationTickHook (void)
void vApplicationStackOverflowHook(TaskHandle_t Task, char *pcTaskName)
{
panic("stack overflow (not the helpful kind) for %s\n", *pcTaskName);
panic("stack overflow (not the helpful kind) for %s\n", *pcTaskName);
}
void vApplicationMallocFailedHook(void)
{
panic("Malloc Failed\n");
panic("Malloc Failed\n");
}