diff --git a/CMakeLists.txt b/CMakeLists.txt index fc7476e..4e9f8a4 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/cmsis-dap/README.adoc b/src/cmsis-dap/README.adoc new file mode 100755 index 0000000..f8463c5 --- /dev/null +++ b/src/cmsis-dap/README.adoc @@ -0,0 +1,6 @@ +:imagesdir: doc/png +:source-highlighter: rouge +:toc: +:toclevels: 5 + +# CMSIS-DAP Server diff --git a/src/cmsis-dap/dap_server.c b/src/cmsis-dap/dap_server.c new file mode 100755 index 0000000..df99153 --- /dev/null +++ b/src/cmsis-dap/dap_server.c @@ -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 +#include +#include + +#include + +#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 diff --git a/src/cmsis-dap/dap_server.h b/src/cmsis-dap/dap_server.h new file mode 100755 index 0000000..d9edcaf --- /dev/null +++ b/src/cmsis-dap/dap_server.h @@ -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 + + +#ifdef __cplusplus + extern "C" { +#endif + + +void dap_server_init(uint32_t task_prio); + + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/src/dap_util.c b/src/cmsis-dap/dap_util.c similarity index 100% rename from src/dap_util.c rename to src/cmsis-dap/dap_util.c diff --git a/src/dap_util.h b/src/cmsis-dap/dap_util.h similarity index 100% rename from src/dap_util.h rename to src/cmsis-dap/dap_util.h diff --git a/src/daplink-pico/README.adoc b/src/daplink-pico/README.adoc new file mode 100755 index 0000000..b255d37 --- /dev/null +++ b/src/daplink-pico/README.adoc @@ -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. diff --git a/src/main.c b/src/main.c index 9ca5505..a121e28 100644 --- a/src/main.c +++ b/src/main.c @@ -29,7 +29,6 @@ #include "timers.h" #include "event_groups.h" -#include #ifdef TARGET_BOARD_PICO_W #include #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"); }