diff --git a/.gitignore b/.gitignore index 1d74e21..e524d79 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .vscode/ +build/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..45b689f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: c +sudo: required +before_install: +- sudo apt install -y gcc git wget make libncurses-dev flex bison python python-serial +- wget https://dl.espressif.com/dl/xtensa-lx106-elf-linux64-1.22.0-100-ge567ec7-5.2.0.tar.gz + +install: +- tar -xzf ./xtensa-lx106-elf-linux64-1.22.0-100-ge567ec7-5.2.0.tar.gz +- git clone --recursive https://github.com/espressif/ESP8266_RTOS_SDK.git +- python -m pip install --user -r ./ESP8266_RTOS_SDK/requirements.txt + +before_script: +- export IDF_PATH=$PWD/ESP8266_RTOS_SDK +- export PATH="$PATH:$PWD/xtensa-lx106-elf/bin" + +script: +- python ./idf.py fullclean +- python ./idf.py build + +deploy: + provider: releases + api_key: ${GITHUB_TOKEN} + file: + - ./build/esp8266_dap.bin + skip_cleanup: true + on: + tags: true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3514e60..0eb1581 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ # The following five lines of boilerplate have to be in your project's # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) +#set(COMPONENT_DIRS "${IDF_PATH}/components ${PROJECT_PATH}/components") include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(tcp_server) +project(esp8266_dap) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e14fa0d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 windowsair + +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. \ No newline at end of file diff --git a/README.md b/README.md index e69de29..b8f4a0d 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,159 @@ +

+

Wireless ESP8266 DAP

+ +[![Build Status](https://travis-ci.com/windowsair/wireless-esp8266-dap.svg?branch=master)](https://travis-ci.com/windowsair/wireless-esp8266-dap) master +[![Build Status](https://travis-ci.com/windowsair/wireless-esp8266-dap.svg?branch=develop)](https://travis-ci.com/windowsair/wireless-esp8266-dap) develop + +[![](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/LICENSE) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-blue.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap/pulls) [![%e2%9d%a4](https://img.shields.io/badge/made%20with-%e2%9d%a4-ff69b4.svg?style=flat-square)](https://github.com/windowsair/wireless-esp8266-dap) + + +## Introduce + +Wireless debugging with ***only one ESP8266*** ! + +Realized by USBIP and CMSIS-DAP protocol stack. + +> 👉 5m distance, 100kb size firmware flash test: + +

+ +## Feature + +1. Debug Communication Mode + - [x] SWJ + - [x] JTAG + +2. USB Communication Mode + - [x] USB-HID + - [ ] WCID & WinUSB + +3. Debug Trace + - [ ] UART Serial Wire Output(SWO) + - [ ] SWO Streaming Trace + +4. More.. + - [x] Custom maximum debug clock(more than 10MHz) + - [ ] ... + + + +## Link your board + +1. WIFI + +The default connected WIFI SSID is `DAP` , password `12345678` + +You can change `WIFI_SSID` and ` WIFI_PASS` in [wifi_configuration.h](main/wifi_configuration.h) + +2. Debugger + +- SWD + +| SWD | | +|----------------|--------| +| SWCLK | GPIO5 | +| SWDIO | GPIO4 | +| LED\_CONNECTED | GPIO2 | +| LED\_RUNNING | GPIO15 | +| TVCC | 3V3 | +| GND | GND | + +- JTAG + +| JTAG | | +|--------------------|---------| +| TCK | GPIO5 | +| TMS | GPIO4 | +| TDI | GPIO13 | +| TDO | GPIO12 | +| nTRST \(optional\) | GPIO0\* | +| nRESET | GPIO14 | +| LED\_CONNECTED | GPIO2 | +| LED\_RUNNING | GPIO15 | +| TVCC | 3V3 | +| GND | GND | + +You can modify these pin definitions in [DAP_config.h](components/DAP/config/DAP_config.h) + +> Tips: Try to avoid using `GPIO0`(working mode switch) and `GPIO16`(RTC) + +## Build + +1. Get ESP8266 RTOS Software Development Kit + +See: [ESP8266_RTOS_SDK](https://github.com/espressif/ESP8266_RTOS_SDK "ESP8266_RTOS_SDK") + +2. Build & Flash + +Build with ESP-IDF build system. +More information can be found at the following link: [Build System](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html "Build System") + +The following example shows a possible way to build on Windows: + +```bash +# Build +python ./idf.py build +# Flash +python ./idf.py -p /dev/ttyS5 flash +``` + +> We also provided sample firmware quick evaluation. See [Releases](https://github.com/windowsair/wireless-esp8266-dap/releases) + + +## Usage + +1. Get USBIP project + +- Windows: [usbip-windows](https://github.com/george-hopkins/usbip-windows "usbip-windows") . Or you can find it already built here: https://github.com/barbalion/usbip-win-client +- Linux: Distributed as part of the kernel + +2. Start esp8266 and connect it to the device to be debugged + +3. Connect it with usbip: + +```bash +.\usbip.exe -D -a 1-1 +``` + +If all goes well, you should see your device connected. +![image](https://user-images.githubusercontent.com/17078589/73833411-eb3f6d80-4844-11ea-8501-02a008f6119d.png) + +![target](https://user-images.githubusercontent.com/17078589/73830040-eb3c6f00-483e-11ea-85ee-c40b68a836b2.png) + + + +## Develop + +> Credits to: +> - https://github.com/thevoidnn/esp8266-wifi-cmsis-dap for adapter firmware based on CMSIS-DAP v1.0 +> - https://github.com/ARM-software/CMSIS_5 for CMSIS + + +In this repo you can find the complete implementation of the USB protocol stack including USB-HID, WCID, WinUSB. Although WinUSB-based mode currently does not work on USBIP :disappointed_relieved: . They are very easy and can help you quickly build your own DAP on other hardware platforms. + + +Currently using USB-HID for transmission is still slightly slower, If you have any ideas, welcome: +- [New issues](https://github.com/windowsair/wireless-esp8266-dap/issues) +- [New pull](https://github.com/windowsair/wireless-esp8266-dap/pulls) + + +### Issue + +2-4 + +Due to the limitation of USB-HID (I'm not sure if this is a problem with USBIP or Windows), now each URB packet can only reach 255 bytes (About 1MBps bandwidth), which has not reached the upper limit of ESP8266 transmission bandwidth. + +I now have an idea to construct a Man-in-the-middle between the two to forward traffic, thereby increasing the bandwidth of each transmission. + +1-31 + +At present, the adaptation to WCID, WinUSB, etc. has all been completed. However, when transmitting data on the endpoint, we received an error message from USBIP. This is most likely a problem with the USBIP project itself. + +Due to the completeness of the USBIP protocol document, we have not yet understood its role in the Bulk transmission process, which may also lead to errors in subsequent processes. + +We will continue to try to make it work on USB HID. Once the USBIP problem is solved, we will immediately transfer it to work on WinUSB + + + +## License +[MIT LICENSE](LICENSE) \ No newline at end of file diff --git a/components/DAP/CMakeLists.txt b/components/DAP/CMakeLists.txt new file mode 100644 index 0000000..3eec5a2 --- /dev/null +++ b/components/DAP/CMakeLists.txt @@ -0,0 +1,5 @@ +set(COMPONENT_ADD_INCLUDEDIRS "config include $ENV{IDF_PATH}/components/esp8266/include/esp8266/ $ENV{IDF_PATH}//components/esp_ringbuf/include/") +set(COMPONENT_SRCS "./source/DAP.c ./source/DAP_vendor.c ./source/JTAG_DP.c ./source/SW_DP.c ./source/SWO.c ./source/uart_modify.c") + + +register_component() \ No newline at end of file diff --git a/components/DAP/config/DAP_config.h b/components/DAP/config/DAP_config.h new file mode 100644 index 0000000..7121a2e --- /dev/null +++ b/components/DAP/config/DAP_config.h @@ -0,0 +1,764 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Configuration + * Title: DAP_config.h CMSIS-DAP Configuration File (Template) + * + *---------------------------------------------------------------------------*/ + +#ifndef __DAP_CONFIG_H__ +#define __DAP_CONFIG_H__ + +#include +#include +#include "cmsis_compiler.h" +#include "gpio.h" +#include "gpio_struct.h" +#include "timer_struct.h" +#include "esp8266/pin_mux_register.h" + +//************************************************************************************************** +/** +\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information +\ingroup DAP_ConfigIO_gr +@{ +Provides definitions about the hardware and configuration of the Debug Unit. + +This information includes: + - Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit. + - Debug Unit Identification strings (Vendor, Product, Serial Number). + - Debug Unit communication packet size. + - Debug Access Port supported modes and settings (JTAG/SWD and SWO). + - Optional information about a connected Target Device (for Evaluation Boards). +*/ + +//#ifdef _RTE_ +//#include "RTE_Components.h" +//#include CMSIS_device_header +//#else +//#include "device.h" // Debug Unit Cortex-M Processor Header File +//#endif + +/// Processor Clock of the Cortex-M MCU used in the Debug Unit. +/// This value is used to calculate the SWD/JTAG clock speed. +#define CPU_CLOCK 160000000 ///< Specifies the CPU Clock in Hz. +// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<160MHz + +// This value is used to replace the largest 10MHZ speed clock in Keil +#define MAX_USER_CLOCK 10000000 ///< Specifies the max Debug Clock in Hz. + +/// Number of processor cycles for I/O Port write operations. +/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O +/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors +/// require 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses +/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be +/// required. +#define IO_PORT_WRITE_CYCLES 2U ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0. + +/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available. + +/// Indicate that JTAG communication mode is available at the Debug Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available. + +/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port. +/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255. +#define DAP_JTAG_DEV_CNT 8U ///< Maximum number of JTAG devices on scan chain. + +/// Default communication mode on the Debug Access Port. +/// Used for the command \ref DAP_Connect when Port Default mode is selected. +#define DAP_DEFAULT_PORT 1U ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG. + +/// Default communication speed on the Debug Access Port for SWD and JTAG mode. +/// Used to initialize the default SWD/JTAG clock frequency. +/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. +#define DAP_DEFAULT_SWJ_CLOCK 1000000U ///< Default SWD/JTAG clock frequency in Hz. +// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<1MHz + +/// Maximum Package Size for Command and Response data. +/// This configuration settings is used to optimize the communication performance with the +/// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or WinUSB, +/// 1024 for High-speed USB HID and 512 for High-speed USB WinUSB. +#define DAP_PACKET_SIZE 255U ///< Specifies Packet Size in bytes. +// <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 512 for High-speed USB WinUSB. + +/// Maximum Package Buffers for Command and Response data. +/// This configuration settings is used to optimize the communication performance with the +/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the +/// setting can be reduced (valid range is 1 .. 255). +#define DAP_PACKET_COUNT 20 ///< Specifies number of packets buffered. + +/// Indicate that UART Serial Wire Output (SWO) trace is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define SWO_UART 0 ///< SWO UART: 1 = available, 0 = not available. + +/// Maximum SWO UART Baudrate. +#define SWO_UART_MAX_BAUDRATE (115200U * 40U) ///< SWO UART Maximum Baudrate in Hz. +// <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 5MHz +//// TODO: uncertain value + +/// Indicate that Manchester Serial Wire Output (SWO) trace is available. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define SWO_MANCHESTER 0 ///< SWO Manchester: 1 = available, 0 = not available. + +/// SWO Trace Buffer Size. +#define SWO_BUFFER_SIZE 4096U ///< SWO Trace Buffer Size in bytes (must be 2^n). + +/// SWO Streaming Trace. +#define SWO_STREAM 0 ///< SWO Streaming Trace: 1 = available, 0 = not available. + +/// Clock frequency of the Test Domain Timer. Timer value is returned with \ref TIMESTAMP_GET. +#define TIMESTAMP_CLOCK 5000000U ///< Timestamp clock in Hz (0 = timestamps not supported). +// <<<<<<<<<<<<<<<<<<<<<5MHz + +/// Debug Unit is connected to fixed Target Device. +/// The Debug Unit may be part of an evaluation board and always connected to a fixed +/// known device. In this case a Device Vendor and Device Name string is stored which +/// may be used by the debugger or IDE to configure device parameters. +#define TARGET_DEVICE_FIXED 0 ///< Target Device: 1 = known, 0 = unknown; + +#if TARGET_DEVICE_FIXED +#define TARGET_DEVICE_VENDOR "ARM" ///< String indicating the Silicon Vendor +#define TARGET_DEVICE_NAME "Cortex-M4" ///< String indicating the Target Device +#endif + +/** + * @brief Get Vendor ID string. + * + * @param str Pointer to buffer to store the string. + * @return String length. + */ +__STATIC_INLINE uint8_t DAP_GetVendorString(char *str) +{ + ////TODO: fill this + // In fact, Keil can get the corresponding information through USB + // without filling in this information. + // (void)str; + strcpy(str, "windowsair"); + return (sizeof("windowsair")); +} + +/** + * @brief Get Product ID string. + * + * @param str Pointer to buffer to store the string. + * @return String length. + */ +__STATIC_INLINE uint8_t DAP_GetProductString(char *str) +{ + //(void)str; + strcpy(str, "CMSIS-DAP v2"); + return (sizeof("CMSIS-DAP v2")); +} + +/** + * @brief Get Serial Number string. + * + * @param str Pointer to buffer to store the string. + * @return String length. + */ +__STATIC_INLINE uint8_t DAP_GetSerNumString(char *str) +{ + strcpy(str, "1234"); + return (sizeof("1234")); +} + +///@} + +// Modify your pins here + +// ATTENTION: DO NOT USE RTC GPIO16 +#define PIN_SWDIO 4 +#define PIN_SWCLK 5 +#define PIN_TDO 13 +#define PIN_TDI 12 +#define PIN_nTRST 0 // optional +#define PIN_nRESET 14 +// LED_BUILTIN +#define PIN_LED_CONNECTED 2 +// LED_BUILTIN +#define PIN_LED_RUNNING 15 + +//************************************************************************************************** +/** +\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access +\ingroup DAP_ConfigIO_gr +@{ + +Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode +and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug +interface of a device. The following I/O Pins are provided: + +JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode +---------------------------- | -------------------- | --------------------------------------------- +TCK: Test Clock | SWCLK: Clock | Output Push/Pull +TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data) +TDI: Test Data Input | | Output Push/Pull +TDO: Test Data Output | | Input +nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor +nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor + + +DAP Hardware I/O Pin Access Functions +------------------------------------- +The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to +these I/O Pins. + +For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only. +This functions are provided to achieve faster I/O that is possible with some advanced GPIO +peripherals that can independently write/read a single I/O pin without affecting any other pins +of the same I/O port. The following SWDIO I/O Pin functions are provided: + - \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware. + - \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware. + - \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed. + - \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed. +*/ + +/** + * @brief Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. + * Configures the DAP Hardware I/O pins for JTAG mode: + * - TCK, TMS, TDI, nTRST, nRESET to ***output*** mode and set to high level. + * - TDO to ***input*** mode. + * + */ +__STATIC_INLINE void PORT_JTAG_SETUP(void) +{ + gpio_pin_reg_t pin_reg; + + // gpio_set_direction(PIN_SWCLK, GPIO_MODE_OUTPUT); + // gpio_set_direction(PIN_SWDIO, GPIO_MODE_OUTPUT); + GPIO.enable_w1ts |= (0x1 << PIN_SWCLK); + GPIO.pin[PIN_SWCLK].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_SWCLK)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_SWCLK), pin_reg.val); + GPIO.enable_w1ts |= (0x1 << PIN_SWDIO); + GPIO.pin[PIN_SWDIO].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_SWDIO)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_SWDIO), pin_reg.val); + + // gpio_set_direction(PIN_TDO, GPIO_MODE_DEF_INPUT); + GPIO.enable_w1tc |= (0x1 << PIN_TDO); + GPIO.pin[PIN_TDO].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_TDO)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_TDO), pin_reg.val); + // gpio_set_direction(PIN_TDI, GPIO_MODE_OUTPUT); + GPIO.enable_w1ts |= (0x1 << PIN_TDI); + GPIO.pin[PIN_TDI].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_TDI)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_TDI), pin_reg.val); + + // gpio_set_direction(PIN_nTRST, GPIO_MODE_OUTPUT_OD); + // gpio_set_direction(PIN_nRESET, GPIO_MODE_OUTPUT_OD); + GPIO.enable_w1tc |= (0x1 << PIN_nTRST); + GPIO.pin[PIN_nTRST].driver = 1; + GPIO.enable_w1tc |= (0x1 << PIN_nRESET); + GPIO.pin[PIN_nRESET].driver = 1; + + // gpio_set_pull_mode(PIN_nTRST, GPIO_PULLUP_ONLY); + // gpio_set_pull_mode(PIN_nRESET, GPIO_PULLUP_ONLY); + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_nTRST)); + pin_reg.pullup = 1; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_nTRST), pin_reg.val); + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_nRESET)); + pin_reg.pullup = 1; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_nRESET), pin_reg.val); +} + +/** + * @brief Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. + * Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: + * - SWCLK, SWDIO, nRESET to output mode and set to default high level. + * - TDI, nTRST to HighZ mode (pins are unused in SWD mode). + * + */ +__STATIC_INLINE void PORT_SWD_SETUP(void) +{ + gpio_pin_reg_t pin_reg; + + // gpio_set_direction(PIN_SWCLK, GPIO_MODE_OUTPUT); + // gpio_set_direction(PIN_SWDIO, GPIO_MODE_OUTPUT); + GPIO.enable_w1ts |= (0x1 << PIN_SWCLK); + GPIO.pin[PIN_SWCLK].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_SWCLK)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_SWCLK), pin_reg.val); + GPIO.enable_w1ts |= (0x1 << PIN_SWDIO); + GPIO.pin[PIN_SWDIO].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_SWDIO)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_SWDIO), pin_reg.val); + + // gpio_set_direction(PIN_TDO, GPIO_MODE_DEF_INPUT); + GPIO.enable_w1tc |= (0x1 << PIN_TDO); + GPIO.pin[PIN_TDO].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_TDO)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_TDO), pin_reg.val); + // gpio_set_direction(PIN_TDI, GPIO_MODE_OUTPUT); + GPIO.enable_w1ts |= (0x1 << PIN_TDI); + GPIO.pin[PIN_TDI].driver = 0; + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_TDI)); + pin_reg.pullup = 0; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_TDI), pin_reg.val); + + // gpio_set_direction(PIN_nTRST, GPIO_MODE_OUTPUT_OD); + // gpio_set_direction(PIN_nRESET, GPIO_MODE_OUTPUT_OD); + GPIO.enable_w1tc |= (0x1 << PIN_nTRST); + GPIO.pin[PIN_nTRST].driver = 1; + GPIO.enable_w1tc |= (0x1 << PIN_nRESET); + GPIO.pin[PIN_nRESET].driver = 1; + + // gpio_set_pull_mode(PIN_nTRST, GPIO_PULLUP_ONLY); + // gpio_set_pull_mode(PIN_nRESET, GPIO_PULLUP_ONLY); + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_nTRST)); + pin_reg.pullup = 1; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_nTRST), pin_reg.val); + pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(PIN_nRESET)); + pin_reg.pullup = 1; + WRITE_PERI_REG(GPIO_PIN_REG(PIN_nRESET), pin_reg.val); +} + +/** + * @brief Disable JTAG/SWD I/O Pins. + * Disables the DAP Hardware I/O pins which configures: + * - TCK/SWCLK, TMS/SWDIO, TDI, TDO, nTRST, nRESET to High-Z mode. + * + */ +__STATIC_INLINE void PORT_OFF(void) +{ + // Will be called when the DAP disconnected + // gpio_set_direction(PIN_SWCLK, GPIO_MODE_DEF_DISABLE); + // gpio_set_direction(PIN_SWDIO, GPIO_MODE_DEF_DISABLE); + + // gpio_set_direction(PIN_TDO, GPIO_MODE_DEF_DISABLE); + // gpio_set_direction(PIN_TDI, GPIO_MODE_DEF_DISABLE); + + // gpio_set_direction(PIN_nTRST, GPIO_MODE_DEF_DISABLE); + // gpio_set_direction(PIN_nRESET, GPIO_MODE_DEF_DISABLE); + GPIO.pin[PIN_SWCLK].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_SWCLK); + + GPIO.pin[PIN_SWDIO].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_SWDIO); + + GPIO.pin[PIN_TDO].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_TDO); + + GPIO.pin[PIN_TDI].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_TDI); + + GPIO.pin[PIN_nTRST].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_nTRST); + + GPIO.pin[PIN_nRESET].driver = 0; + GPIO.enable_w1tc |= (0x1 << PIN_nRESET); +} + +// SWCLK/TCK I/O pin ------------------------------------- + +/** + * @brief SWCLK/TCK I/O pin: Get Input. + * + * @return Current status of the SWCLK/TCK DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_SWCLK_TCK_IN(void) +{ + ////TODO: can we set to 0? + return 0; +} + +/** + * @brief SWCLK/TCK I/O pin: Set Output to High. + * + * Set the SWCLK/TCK DAP hardware I/O pin to high level. + */ +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_SET(void) +{ + GPIO.out_w1ts |= (0x1 << PIN_SWCLK); +} + +/** + * @brief SWCLK/TCK I/O pin: Set Output to Low. + * + * Set the SWCLK/TCK DAP hardware I/O pin to low level. + */ +__STATIC_FORCEINLINE void PIN_SWCLK_TCK_CLR(void) +{ + GPIO.out_w1tc |= (0x1 << PIN_SWCLK); +} + +// SWDIO/TMS Pin I/O -------------------------------------- + +/** + * @brief SWDIO/TMS I/O pin: Get Input. + * + * @return Current status of the SWDIO/TMS DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_TMS_IN(void) +{ + return ((GPIO.in >> PIN_SWDIO) & 0x1) ? 1 : 0; +} + +/** + * @brief SWDIO/TMS I/O pin: Set Output to High. + * + * Set the SWDIO/TMS DAP hardware I/O pin to high level. + */ +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_SET(void) +{ + GPIO.out_w1ts |= (0x1 << PIN_SWDIO); +} + +/** + * @brief SWDIO/TMS I/O pin: Set Output to Low. + * + * Set the SWDIO/TMS DAP hardware I/O pin to low level. + */ +__STATIC_FORCEINLINE void PIN_SWDIO_TMS_CLR(void) +{ + GPIO.out_w1tc |= (0x1 << PIN_SWDIO); +} + +/** + * @brief SWDIO I/O pin: Get Input (used in SWD mode only). + * + * @return Current status of the SWDIO DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_SWDIO_IN(void) +{ + return ((GPIO.in >> PIN_SWDIO) & 0x1) ? 1 : 0; +} + +/** + * @brief SWDIO I/O pin: Set Output (used in SWD mode only). + * + * @param bit Output value for the SWDIO DAP hardware I/O pin. + * + */ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT(uint32_t bit) +{ + /** + * Important: Use only one bit (bit0) of param! + * Sometimes the func "SWD_TransferFunction" of SW_DP.c will + * issue "2" as param instead of "0". Zach Lee + */ + if ((bit & 1U) == 1) + { + //set bit + GPIO.out_w1ts |= (0x1 << PIN_SWDIO); + + } + else + { + //reset bit + GPIO.out_w1tc |= (0x1 << PIN_SWDIO); + + } +} + +/** + * @brief SWDIO I/O pin: Switch to Output mode (used in SWD mode only). + * Configure the SWDIO DAP hardware I/O pin to output mode. This function is + * called prior \ref PIN_SWDIO_OUT function calls. + */ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) +{ + // Need fast response + + // set \ref gpio_set_direction -> OUTPUT + GPIO.enable_w1ts |= (0x1 << PIN_SWDIO); + GPIO.pin[PIN_SWDIO].driver = 0; +} + +/** + * @brief SWDIO I/O pin: Switch to Input mode (used in SWD mode only). + * Configure the SWDIO DAP hardware I/O pin to input mode. This function is + * called prior \ref PIN_SWDIO_IN function calls. + */ +__STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) +{ + // Need fast response + // set \ref gpio_set_dircetion -> INPUT + // esp8266 input is always connected + GPIO.enable_w1tc |= (0x1 << PIN_SWDIO); + GPIO.pin[PIN_SWDIO].driver = 0; +} + +// TDI Pin I/O --------------------------------------------- + +/** + * @brief TDI I/O pin: Get Input. + * + * @return Current status of the TDI DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_TDI_IN(void) +{ + return ((GPIO.in >> PIN_TDI) & 0x1) ? 1 : 0; +} + +/** + * @brief TDI I/O pin: Set Output. + * + * @param bit Output value for the TDI DAP hardware I/O pin. + * + */ +__STATIC_FORCEINLINE void PIN_TDI_OUT(uint32_t bit) +{ + if ((bit & 1U) == 1) + { + //set bit + GPIO.out_w1ts |= (0x1 << PIN_TDI); + + } + else + { + //reset bit + GPIO.out_w1tc |= (0x1 << PIN_TDI); + + } +} + +// TDO Pin I/O --------------------------------------------- + +/** + * @brief TDO I/O pin: Get Input. + * + * @return Current status of the TDO DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_TDO_IN(void) +{ + return ((GPIO.in >> PIN_TDO) & 0x1) ? 1 : 0; +} + +// nTRST Pin I/O ------------------------------------------- + +/** + * @brief nTRST I/O pin: Get Input. + * + * @return Current status of the nTRST DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_nTRST_IN(void) +{ + return 0; // not available +} + +/** + * @brief nTRST I/O pin: Set Output. + * + * @param bit JTAG TRST Test Reset pin status: + * - 0: issue a JTAG TRST Test Reset. + - 1: release JTAG TRST Test Reset. + */ +__STATIC_FORCEINLINE void PIN_nTRST_OUT(uint32_t bit) +{ + // ////TODO: What does this mean? ? ? + // if ((bit & 1U) == 1) + // { + // //set bit + // GPIO.out_w1ts |= (0x1 << PIN_nTRST); + // } + // else + // { + // //reset bit + // GPIO.out_w1tc |= (0x1 << PIN_nTRST); + // } + ; // not available +} + +// nRESET Pin I/O------------------------------------------ + +/** + * @brief nRESET I/O pin: Get Input. + * + * @return Current status of the nRESET DAP hardware I/O pin. + */ +__STATIC_FORCEINLINE uint32_t PIN_nRESET_IN(void) +{ + return ((GPIO.in >> PIN_nRESET) & 0x1) ? 1 : 0; +} + +/** + * @brief nRESET I/O pin: Set Output. + * + * @param bit target device hardware reset pin status: + * - 0: issue a device hardware reset. + * - 1: release device hardware reset. + */ +__STATIC_FORCEINLINE void PIN_nRESET_OUT(uint32_t bit) +{ + ////TODO: What does this mean? ? ? + if ((bit & 1U) == 1) + { + //set bit + GPIO.out_w1ts |= (0x1 << PIN_nRESET); + } + else + { + //reset bit + GPIO.out_w1tc |= (0x1 << PIN_nRESET); + } +} + +///@} + +//************************************************************************************************** +/** +\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit. + +It is recommended to provide the following LEDs for status indication: + - Connect LED: is active when the DAP hardware is connected to a debugger. + - Running LED: is active when the debugger has put the target device into running state. +*/ + +/** Debug Unit: Set status of Connected LED. +\param bit status of the Connect LED. + - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. + - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. +*/ + +/** + * @brief Debug Unit: Set status of Connected LED. + * + * @param bit status of the Connect LED. + * - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. + * - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. + */ +__STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit) +{ + if (bit) + { + //set bit + GPIO.out_w1ts |= (0x1 << PIN_LED_CONNECTED); + } + else + { + //reset bit + GPIO.out_w1tc |= (0x1 << PIN_LED_CONNECTED); + } +} + +/** + * @brief Debug Unit: Set status Target Running LED. + * + * @param bit status of the Target Running LED. + * - 1: Target Running LED ON: program execution in target started. + * - 0: Target Running LED OFF: program execution in target stopped. + */ +__STATIC_INLINE void LED_RUNNING_OUT(uint32_t bit) +{ + if (bit) + { + //set bit + GPIO.out_w1ts |= (0x1 << PIN_LED_RUNNING); + } + else + { + //reset bit + GPIO.out_w1tc |= (0x1 << PIN_LED_RUNNING); + } +} + +///@} + +//************************************************************************************************** +/** +\defgroup DAP_Config_Timestamp_gr CMSIS-DAP Timestamp +\ingroup DAP_ConfigIO_gr +@{ +Access function for Test Domain Timer. + +The value of the Test Domain Timer in the Debug Unit is returned by the function \ref TIMESTAMP_GET. By +default, the DWT timer is used. The frequency of this timer is configured with \ref TIMESTAMP_CLOCK. + +*/ + +/** + * @brief Get timestamp of Test Domain Timer. + * + * @return Current timestamp value. + */ +__STATIC_INLINE uint32_t TIMESTAMP_GET(void) +{ + // FRC1 is a 23-bit countdown timer + return (0x7FFFFF - (frc1.count.data)); +} + +///@} + +//************************************************************************************************** +/** +\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP. +*/ + +/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized). +This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the +Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set: + - I/O clock system enabled. + - all I/O pins: input buffer enabled, output pins are set to HighZ mode. + - for nTRST, nRESET a weak pull-up (if available) is enabled. + - LED output pins are enabled and LEDs are turned off. +*/ +__STATIC_INLINE void DAP_SETUP(void) +{ + // This function maybe unnecessary... + gpio_set_direction(PIN_SWCLK, GPIO_MODE_DEF_INPUT); + gpio_set_direction(PIN_SWDIO, GPIO_MODE_DEF_INPUT); // + gpio_set_direction(PIN_nRESET, GPIO_MODE_DEF_INPUT); // + gpio_set_direction(PIN_TDI, GPIO_MODE_DEF_INPUT); + gpio_set_direction(PIN_TDO, GPIO_MODE_DEF_INPUT); + + // Configure: LED as output (turned off) + gpio_set_direction(PIN_LED_CONNECTED, GPIO_MODE_DEF_OUTPUT); + LED_CONNECTED_OUT(0); + gpio_set_direction(PIN_LED_RUNNING, GPIO_MODE_DEF_OUTPUT); + LED_RUNNING_OUT(0); +} + +/** Reset Target Device with custom specific I/O pin or command sequence. +This function allows the optional implementation of a device specific reset sequence. +It is called when the command \ref DAP_ResetTarget and is for example required +when a device needs a time-critical unlock sequence that enables the debug port. +\return 0 = no device specific reset sequence is implemented.\n + 1 = a device specific reset sequence is implemented. +*/ +__STATIC_INLINE uint8_t RESET_TARGET(void) +{ + return (0U); // not available +} + +///@} + +#endif /* __DAP_CONFIG_H__ */ diff --git a/components/DAP/include/DAP.h b/components/DAP/include/DAP.h new file mode 100644 index 0000000..65e0459 --- /dev/null +++ b/components/DAP/include/DAP.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2013-2019 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 26. November 2019 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Include + * Title: DAP.h Definitions + * + *---------------------------------------------------------------------------*/ + +#ifndef __DAP_H__ +#define __DAP_H__ + + +// DAP Firmware Version +#ifdef DAP_FW_V1 +#define DAP_FW_VER "1.2.0" +#else +#define DAP_FW_VER "2.0.0" +#endif + +// DAP Command IDs +#define ID_DAP_Info 0x00U +#define ID_DAP_HostStatus 0x01U +#define ID_DAP_Connect 0x02U +#define ID_DAP_Disconnect 0x03U +#define ID_DAP_TransferConfigure 0x04U +#define ID_DAP_Transfer 0x05U +#define ID_DAP_TransferBlock 0x06U +#define ID_DAP_TransferAbort 0x07U +#define ID_DAP_WriteABORT 0x08U +#define ID_DAP_Delay 0x09U +#define ID_DAP_ResetTarget 0x0AU +#define ID_DAP_SWJ_Pins 0x10U +#define ID_DAP_SWJ_Clock 0x11U +#define ID_DAP_SWJ_Sequence 0x12U +#define ID_DAP_SWD_Configure 0x13U +#define ID_DAP_SWD_Sequence 0x1DU +#define ID_DAP_JTAG_Sequence 0x14U +#define ID_DAP_JTAG_Configure 0x15U +#define ID_DAP_JTAG_IDCODE 0x16U +#define ID_DAP_SWO_Transport 0x17U +#define ID_DAP_SWO_Mode 0x18U +#define ID_DAP_SWO_Baudrate 0x19U +#define ID_DAP_SWO_Control 0x1AU +#define ID_DAP_SWO_Status 0x1BU +#define ID_DAP_SWO_ExtendedStatus 0x1EU +#define ID_DAP_SWO_Data 0x1CU + +#define ID_DAP_QueueCommands 0x7EU +#define ID_DAP_ExecuteCommands 0x7FU + +// DAP Vendor Command IDs +#define ID_DAP_Vendor0 0x80U +#define ID_DAP_Vendor1 0x81U +#define ID_DAP_Vendor2 0x82U +#define ID_DAP_Vendor3 0x83U +#define ID_DAP_Vendor4 0x84U +#define ID_DAP_Vendor5 0x85U +#define ID_DAP_Vendor6 0x86U +#define ID_DAP_Vendor7 0x87U +#define ID_DAP_Vendor8 0x88U +#define ID_DAP_Vendor9 0x89U +#define ID_DAP_Vendor10 0x8AU +#define ID_DAP_Vendor11 0x8BU +#define ID_DAP_Vendor12 0x8CU +#define ID_DAP_Vendor13 0x8DU +#define ID_DAP_Vendor14 0x8EU +#define ID_DAP_Vendor15 0x8FU +#define ID_DAP_Vendor16 0x90U +#define ID_DAP_Vendor17 0x91U +#define ID_DAP_Vendor18 0x92U +#define ID_DAP_Vendor19 0x93U +#define ID_DAP_Vendor20 0x94U +#define ID_DAP_Vendor21 0x95U +#define ID_DAP_Vendor22 0x96U +#define ID_DAP_Vendor23 0x97U +#define ID_DAP_Vendor24 0x98U +#define ID_DAP_Vendor25 0x99U +#define ID_DAP_Vendor26 0x9AU +#define ID_DAP_Vendor27 0x9BU +#define ID_DAP_Vendor28 0x9CU +#define ID_DAP_Vendor29 0x9DU +#define ID_DAP_Vendor30 0x9EU +#define ID_DAP_Vendor31 0x9FU + +#define ID_DAP_Invalid 0xFFU + +// DAP Status Code +#define DAP_OK 0U +#define DAP_ERROR 0xFFU + +// DAP ID +#define DAP_ID_VENDOR 1U +#define DAP_ID_PRODUCT 2U +#define DAP_ID_SER_NUM 3U +#define DAP_ID_FW_VER 4U +#define DAP_ID_DEVICE_VENDOR 5U +#define DAP_ID_DEVICE_NAME 6U +#define DAP_ID_CAPABILITIES 0xF0U +#define DAP_ID_TIMESTAMP_CLOCK 0xF1U +#define DAP_ID_SWO_BUFFER_SIZE 0xFDU +#define DAP_ID_PACKET_COUNT 0xFEU +#define DAP_ID_PACKET_SIZE 0xFFU + +// DAP Host Status +#define DAP_DEBUGGER_CONNECTED 0U +#define DAP_TARGET_RUNNING 1U + +// DAP Port +#define DAP_PORT_AUTODETECT 0U // Autodetect Port +#define DAP_PORT_DISABLED 0U // Port Disabled (I/O pins in High-Z) +#define DAP_PORT_SWD 1U // SWD Port (SWCLK, SWDIO) + nRESET +#define DAP_PORT_JTAG 2U // JTAG Port (TCK, TMS, TDI, TDO, nTRST) + nRESET + +// DAP SWJ Pins +#define DAP_SWJ_SWCLK_TCK 0 // SWCLK/TCK +#define DAP_SWJ_SWDIO_TMS 1 // SWDIO/TMS +#define DAP_SWJ_TDI 2 // TDI +#define DAP_SWJ_TDO 3 // TDO +#define DAP_SWJ_nTRST 5 // nTRST +#define DAP_SWJ_nRESET 7 // nRESET + +// DAP Transfer Request +#define DAP_TRANSFER_APnDP (1U<<0) +#define DAP_TRANSFER_RnW (1U<<1) +#define DAP_TRANSFER_A2 (1U<<2) +#define DAP_TRANSFER_A3 (1U<<3) +#define DAP_TRANSFER_MATCH_VALUE (1U<<4) +#define DAP_TRANSFER_MATCH_MASK (1U<<5) +#define DAP_TRANSFER_TIMESTAMP (1U<<7) + +// DAP Transfer Response +#define DAP_TRANSFER_OK (1U<<0) +#define DAP_TRANSFER_WAIT (1U<<1) +#define DAP_TRANSFER_FAULT (1U<<2) +#define DAP_TRANSFER_ERROR (1U<<3) +#define DAP_TRANSFER_MISMATCH (1U<<4) + +// DAP SWO Trace Mode +#define DAP_SWO_OFF 0U +#define DAP_SWO_UART 1U +#define DAP_SWO_MANCHESTER 2U + +// DAP SWO Trace Status +#define DAP_SWO_CAPTURE_ACTIVE (1U<<0) +#define DAP_SWO_CAPTURE_PAUSED (1U<<1) +#define DAP_SWO_STREAM_ERROR (1U<<6) +#define DAP_SWO_BUFFER_OVERRUN (1U<<7) + + +// Debug Port Register Addresses +#define DP_IDCODE 0x00U // IDCODE Register (SW Read only) +#define DP_ABORT 0x00U // Abort Register (SW Write only) +#define DP_CTRL_STAT 0x04U // Control & Status +#define DP_WCR 0x04U // Wire Control Register (SW Only) +#define DP_SELECT 0x08U // Select Register (JTAG R/W & SW W) +#define DP_RESEND 0x08U // Resend (SW Read Only) +#define DP_RDBUFF 0x0CU // Read Buffer (Read Only) + +// JTAG IR Codes +#define JTAG_ABORT 0x08U +#define JTAG_DPACC 0x0AU +#define JTAG_APACC 0x0BU +#define JTAG_IDCODE 0x0EU +#define JTAG_BYPASS 0x0FU + +// JTAG Sequence Info +#define JTAG_SEQUENCE_TCK 0x3FU // TCK count +#define JTAG_SEQUENCE_TMS 0x40U // TMS value +#define JTAG_SEQUENCE_TDO 0x80U // TDO capture + +// SWD Sequence Info +#define SWD_SEQUENCE_CLK 0x3FU // SWCLK count +#define SWD_SEQUENCE_DIN 0x80U // SWDIO capture + + +#include +#include +#include "cmsis_compiler.h" + +// DAP Data structure +typedef struct { + uint8_t debug_port; // Debug Port + uint8_t fast_clock; // Fast Clock Flag + uint8_t padding[2]; + uint32_t clock_delay; // Clock Delay + uint32_t timestamp; // Last captured Timestamp + struct { // Transfer Configuration + uint8_t idle_cycles; // Idle cycles after transfer + uint8_t padding[3]; + uint16_t retry_count; // Number of retries after WAIT response + uint16_t match_retry; // Number of retries if read value does not match + uint32_t match_mask; // Match Mask + } transfer; +#if (DAP_SWD != 0) + struct { // SWD Configuration + uint8_t turnaround; // Turnaround period + uint8_t data_phase; // Always generate Data Phase + } swd_conf; +#endif +#if (DAP_JTAG != 0) + struct { // JTAG Device Chain + uint8_t count; // Number of devices + uint8_t index; // Device index (device at TDO has index 0) +#if (DAP_JTAG_DEV_CNT != 0) + uint8_t ir_length[DAP_JTAG_DEV_CNT]; // IR Length in bits + uint16_t ir_before[DAP_JTAG_DEV_CNT]; // Bits before IR + uint16_t ir_after [DAP_JTAG_DEV_CNT]; // Bits after IR +#endif + } jtag_dev; +#endif +} DAP_Data_t; + +extern DAP_Data_t DAP_Data; // DAP Data +extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag + + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Functions +extern void SWJ_Sequence (uint32_t count, const uint8_t *data); +extern void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi); +extern void JTAG_Sequence (uint32_t info, const uint8_t *tdi, uint8_t *tdo); +extern void JTAG_IR (uint32_t ir); +extern uint32_t JTAG_ReadIDCode (void); +extern void JTAG_WriteAbort (uint32_t data); +extern uint8_t JTAG_Transfer (uint32_t request, uint32_t *data); +extern uint8_t SWD_Transfer (uint32_t request, uint32_t *data); + +extern void Delayms (uint32_t delay); + +extern uint32_t SWO_Transport (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Mode (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Baudrate (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Control (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Status (uint8_t *response); +extern uint32_t SWO_ExtendedStatus (const uint8_t *request, uint8_t *response); +extern uint32_t SWO_Data (const uint8_t *request, uint8_t *response); + +extern void SWO_QueueTransfer (uint8_t *buf, uint32_t num); +extern void SWO_AbortTransfer (void); +extern void SWO_TransferComplete (void); + +extern uint32_t UART_SWO_Mode (uint32_t enable); +extern uint32_t UART_SWO_Baudrate (uint32_t baudrate); +extern uint32_t UART_SWO_Control (uint32_t active); +extern void UART_SWO_Capture (uint8_t *buf, uint32_t num); +extern uint32_t UART_SWO_GetCount (void); + +extern uint32_t Manchester_SWO_Mode (uint32_t enable); +extern uint32_t Manchester_SWO_Baudrate (uint32_t baudrate); +extern uint32_t Manchester_SWO_Control (uint32_t active); +extern void Manchester_SWO_Capture (uint8_t *buf, uint32_t num); +extern uint32_t Manchester_SWO_GetCount (void); + +extern uint32_t DAP_ProcessVendorCommand (const uint8_t *request, uint8_t *response); +extern uint32_t DAP_ProcessCommand (const uint8_t *request, uint8_t *response); +extern uint32_t DAP_ExecuteCommand (const uint8_t *request, uint8_t *response); + +extern void DAP_Setup (void); + +// Configurable delay for clock generation +#ifndef DELAY_SLOW_CYCLES +#define DELAY_SLOW_CYCLES 3U // Number of cycles for one iteration +#endif + +#define USE_ASSEMBLY 1 + +#if (USE_ASSEMBLY == 0) + __STATIC_FORCEINLINE void PIN_DELAY_SLOW(uint32_t delay) + { + uint32_t count = delay; + while (--count) + ; + } +#else +__STATIC_FORCEINLINE void PIN_DELAY_SLOW(uint32_t delay) +{ + __asm__ volatile( + "l_PINDELAYSLOW%=:" + "ADDI.N %[time], %[time], -1;" + "BNEZ %[time], l_PINDELAYSLOW%=;" + : [time] "+r"(delay)); +} + +#endif + +// Fixed delay for fast clock generation +#ifndef DELAY_FAST_CYCLES +#define DELAY_FAST_CYCLES 0U // Number of cycles: 0..3 +#endif +__STATIC_FORCEINLINE void PIN_DELAY_FAST (void) { +#if (DELAY_FAST_CYCLES >= 1U) + __NOP(); +#endif +#if (DELAY_FAST_CYCLES >= 2U) + __NOP(); +#endif +#if (DELAY_FAST_CYCLES >= 3U) + __NOP(); +#endif +} + +#ifdef __cplusplus +} +#endif + + +#endif /* __DAP_H__ */ diff --git a/components/DAP/include/cmsis_compiler.h b/components/DAP/include/cmsis_compiler.h new file mode 100644 index 0000000..aafbe21 --- /dev/null +++ b/components/DAP/include/cmsis_compiler.h @@ -0,0 +1,50 @@ +#ifndef __CMSIS_COMPILER_H__ +#define __CMSIS_COMPILER_H__ + +#ifndef __STATIC_FORCEINLINE + #define __STATIC_FORCEINLINE static inline __attribute__((always_inline)) +#endif +#ifndef __STATIC_INLINE + #define __STATIC_INLINE static inline __attribute__((always_inline)) +#endif +#ifndef __WEAK + #define __WEAK __attribute__((weak)) +#endif + +#define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U +#define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U +#define GPIO_PIN_REG_2 PERIPHS_IO_MUX_GPIO2_U +#define GPIO_PIN_REG_3 PERIPHS_IO_MUX_U0RXD_U +#define GPIO_PIN_REG_4 PERIPHS_IO_MUX_GPIO4_U +#define GPIO_PIN_REG_5 PERIPHS_IO_MUX_GPIO5_U +#define GPIO_PIN_REG_6 PERIPHS_IO_MUX_SD_CLK_U +#define GPIO_PIN_REG_7 PERIPHS_IO_MUX_SD_DATA0_U +#define GPIO_PIN_REG_8 PERIPHS_IO_MUX_SD_DATA1_U +#define GPIO_PIN_REG_9 PERIPHS_IO_MUX_SD_DATA2_U +#define GPIO_PIN_REG_10 PERIPHS_IO_MUX_SD_DATA3_U +#define GPIO_PIN_REG_11 PERIPHS_IO_MUX_SD_CMD_U +#define GPIO_PIN_REG_12 PERIPHS_IO_MUX_MTDI_U +#define GPIO_PIN_REG_13 PERIPHS_IO_MUX_MTCK_U +#define GPIO_PIN_REG_14 PERIPHS_IO_MUX_MTMS_U +#define GPIO_PIN_REG_15 PERIPHS_IO_MUX_MTDO_U +#define GPIO_PIN_REG_16 PAD_XPD_DCDC_CONF +#define GPIO_PIN_REG(i) \ + (i==0) ? GPIO_PIN_REG_0: \ + (i==1) ? GPIO_PIN_REG_1: \ + (i==2) ? GPIO_PIN_REG_2: \ + (i==3) ? GPIO_PIN_REG_3: \ + (i==4) ? GPIO_PIN_REG_4: \ + (i==5) ? GPIO_PIN_REG_5: \ + (i==6) ? GPIO_PIN_REG_6: \ + (i==7) ? GPIO_PIN_REG_7: \ + (i==8) ? GPIO_PIN_REG_8: \ + (i==9) ? GPIO_PIN_REG_9: \ + (i==10)? GPIO_PIN_REG_10: \ + (i==11)? GPIO_PIN_REG_11: \ + (i==12)? GPIO_PIN_REG_12: \ + (i==13)? GPIO_PIN_REG_13: \ + (i==14)? GPIO_PIN_REG_14: \ + (i==15)? GPIO_PIN_REG_15: \ + GPIO_PIN_REG_16 + +#endif \ No newline at end of file diff --git a/components/DAP/include/uart_modify.h b/components/DAP/include/uart_modify.h new file mode 100644 index 0000000..3d3a277 --- /dev/null +++ b/components/DAP/include/uart_modify.h @@ -0,0 +1,565 @@ +/** + * @brief Made some simple modifications to the official UART + * + */ + +// Copyright 2018-2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef _DRIVER_UART_H_ +#define _DRIVER_UART_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/queue.h" + +#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */ +#define UART_INTR_MASK 0x1ff /*!< Mask of all UART interrupts */ +#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */ + +#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/ +#define UART_INVERSE_RXD (BIT(19)) /*!< UART RXD input inverse*/ +#define UART_INVERSE_CTS (BIT(20)) /*!< UART CTS input inverse*/ +#define UART_INVERSE_TXD (BIT(22)) /*!< UART TXD output inverse*/ +#define UART_INVERSE_RTS (BIT(23)) /*!< UART RTS output inverse*/ + +/** + * @brief UART mode selection + */ +typedef enum { + UART_MODE_UART = 0x00, /*!< mode: regular UART mode*/ +} uart_mode_t; + +/** + * @brief UART word length constants + */ +typedef enum { + UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/ + UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/ + UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/ + UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/ + UART_DATA_BITS_MAX = 0x4, +} uart_word_length_t; + +/** + * @brief UART stop bits number + */ +typedef enum { + UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/ + UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/ + UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/ + UART_STOP_BITS_MAX = 0x4, +} uart_stop_bits_t; + +/** + * @brief UART peripheral number + */ +typedef enum { + UART_NUM_0 = 0x0, + UART_NUM_1 = 0x1, + UART_NUM_MAX, +} uart_port_t; + +/** + * @brief UART parity constants + */ +typedef enum { + UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/ + UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/ + UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/ +} uart_parity_t; + +/** + * @brief UART hardware flow control modes + */ +typedef enum { + UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/ + UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/ + UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/ + UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/ + UART_HW_FLOWCTRL_MAX = 0x4, +} uart_hw_flowcontrol_t; + +/** + * @brief UART configuration parameters for my_uart_param_config function + */ +typedef struct { + int baud_rate; /*!< UART baud rate*/ + uart_word_length_t data_bits; /*!< UART byte size*/ + uart_parity_t parity; /*!< UART parity mode*/ + uart_stop_bits_t stop_bits; /*!< UART stop bits*/ + uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/ + uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/ +} uart_config_t; + +/** + * @brief UART interrupt configuration parameters for my_uart_intr_config function + */ +typedef struct { + uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/ + uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold (unit: time of sending one byte)*/ + uint8_t txfifo_empty_intr_thresh; /*!< UART TX empty interrupt threshold.*/ + uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/ +} uart_intr_config_t; + +/** + * @brief UART event types used in the ring buffer + */ +typedef enum { + UART_DATA, /*!< UART data event*/ + UART_BUFFER_FULL, /*!< UART RX buffer full event*/ + UART_FIFO_OVF, /*!< UART FIFO overflow event*/ + UART_FRAME_ERR, /*!< UART RX frame error event*/ + UART_PARITY_ERR, /*!< UART RX parity event*/ + UART_EVENT_MAX, /*!< UART event max index*/ +} uart_event_type_t; + +/** + * @brief Event structure used in UART event queue + */ +typedef struct { + uart_event_type_t type; /*!< UART event type */ + size_t size; /*!< UART data size for UART_DATA event*/ +} uart_event_t; + + +/** + * @brief Set UART data bits. + * + * @param uart_num Uart port number. + * @param data_bit Uart data bits. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit); + +/** + * @brief Get UART data bits. + * + * @param uart_num Uart port number. + * @param data_bit Pointer to accept value of UART data bits. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_word_length(uart_port_t uart_num, uart_word_length_t *data_bit); + +/** + * @brief Set UART stop bits. + * + * @param uart_num Uart port number + * @param stop_bits Uart stop bits + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits); + +/** + * @brief Get UART stop bits. + * + * @param uart_num Uart port number. + * @param stop_bits Pointer to accept value of UART stop bits. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t *stop_bits); + +/** + * @brief Set UART parity mode. + * + * @param uart_num Uart port number. + * @param parity_mode The enum of uart parity configuration. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode); + +/** + * @brief Get UART parity mode. + * + * @param uart_num Uart port number + * @param parity_mode Pointer to accept value of UART parity mode. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_parity(uart_port_t uart_num, uart_parity_t *parity_mode); + +/** + * @brief Set UART baud rate. + * + * @param uart_num Uart port number + * @param baudrate UART baud rate. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate); + +/** + * @brief Get UART baud rate. + * + * @param uart_num Uart port number. + * @param baudrate Pointer to accept value of Uart baud rate. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_baudrate(uart_port_t uart_num, uint32_t *baudrate); + +/** + * @brief Set UART line inverse mode + * + * @param uart_num UART_NUM_0 + * @param inverse_mask Choose the wires that need to be inverted. + * Inverse_mask should be chosen from + * UART_INVERSE_RXD / UART_INVERSE_TXD / UART_INVERSE_RTS / UART_INVERSE_CTS, + * combined with OR operation. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask); + +/** + * @brief Configure Hardware flow control. + * + * @param uart_num Uart port number. + * @param flow_ctrl Hardware flow control mode. + * @param rx_thresh Threshold of Hardware flow control. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh); + +/** + * @brief Get hardware flow control mode + * + * @param uart_num Uart port number. + * @param flow_ctrl Option for different flow control mode. + * + * @return + * - ESP_OK Success, result will be put in (*flow_ctrl) + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t *flow_ctrl); + +/** + * @brief UART0 swap. + * Use MTCK as UART0 RX, MTDO as UART0 TX, so ROM log will not output from + * this new UART0. We also need to use MTDO (U0RTS) and MTCK (U0CTS) as UART0 in hardware. + * + * @return + * - ESP_OK Success + */ +esp_err_t my_uart_enable_swap(void); + +/** + * @brief Disable UART0 swap. + * Use the original UART0, not MTCK and MTDO. + * + * @return + * - ESP_OK Success + */ +esp_err_t my_uart_disable_swap(void); + +/** + * @brief Clear uart interrupts status. + * + * @param uart_num Uart port number. + * @param mask Uart interrupt bits mask. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_clear_intr_status(uart_port_t uart_num, uint32_t mask); + +/** + * @brief Set UART interrupt enable + * + * @param uart_num Uart port number + * @param enable_mask Bit mask of the enable bits. + * The bit mask should be composed from the fields of register UART_INT_ENA_REG. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask); + +/** + * @brief Clear UART interrupt enable bits + * + * @param uart_num Uart port number + * @param disable_mask Bit mask of the disable bits. + * The bit mask should be composed from the fields of register UART_INT_ENA_REG. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask); + +/** + * @brief Enable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_num UART_NUM_0 + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_enable_rx_intr(uart_port_t uart_num); + +/** + * @brief Disable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT) + * + * @param uart_num UART_NUM_0 + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_disable_rx_intr(uart_port_t uart_num); + +/** + * @brief Disable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT) + * + * @param uart_num UART_NUM_0 + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_disable_tx_intr(uart_port_t uart_num); + +/** + * @brief Enable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT) + * + * @param uart_num UART_NUM_0 + * @param enable 1: enable; 0: disable + * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); + +/** + * @brief Register UART interrupt handler (ISR). + * + * @param uart_num UART_NUM_0 + * @param fn Interrupt handler function. + * @param arg parameter for handler function + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg); + +/** + * @brief Config Common parameters of serial ports. + * + * @param uart_num Uart port number. + * @param uart_conf Uart config parameters. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_param_config(uart_port_t uart_num, uart_config_t *uart_conf); + +/** + * @brief Config types of uarts. + * + * @param uart_num Uart port number. + * @param uart_intr_conf Uart interrupt config parameters. + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_intr_config(uart_port_t uart_num, uart_intr_config_t *uart_intr_conf); + +/** + * @brief Install UART driver. + * + * @note Rx_buffer_size should be greater than UART_FIFO_LEN. Tx_buffer_size should be either zero or greater than UART_FIFO_LEN. + * + * @param uart_num Uart port number. + * @param rx_buffer_size UART RX ring buffer size. + * @param tx_buffer_size UART TX ring buffer size. + * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out. + * @param queue_size UART event queue size/depth. + * @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide + * access to UART events. If set to NULL, driver will not use an event queue. + * @param no_use Invalid parameters, just to fit some modules. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int no_use); + +/** + * @brief Uninstall UART driver. + * + * @param uart_num Uart port number. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_driver_delete(uart_port_t uart_num); + +/** + * @brief Waiting for the last byte of data to be sent + * + * @param uart_num Uart port number. + * @param ticks_to_wait Timeout, count in RTOS ticks + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait); + +/** + * @brief Send data to the UART port from a given buffer and length. + * + * This function will not wait for enough space in TX FIFO. It will just fill the available TX FIFO and return when the FIFO is full. + * @note This function should only be used when UART TX buffer is not enabled. + * + * @param uart_num Uart port number. + * @param buffer data buffer address + * @param len data length to send + * + * @return + * - (-1) Parameter error + * - OTHERS (>=0) The number of bytes pushed to the TX FIFO + */ +int my_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len); + +/** + * @brief Send data to the UART port from a given buffer and length, + * + * If the UART driver's parameter 'tx_buffer_size' is set to zero: + * This function will not return until all the data have been sent out, or at least pushed into TX FIFO. + * + * Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer, + * UART ISR will then move data from the ring buffer to TX FIFO gradually. + * + * @param uart_num Uart port number. + * @param src data buffer address + * @param size data length to send + * + * @return + * - (-1) Parameter error + * - OTHERS (>=0) The number of bytes pushed to the TX FIFO + */ +int my_uart_write_bytes(uart_port_t uart_num, const char *src, size_t size); + +/** + * @brief UART read bytes from UART buffer + * + * @param uart_num Uart port number. + * @param buf pointer to the buffer. + * @param length data length + * @param ticks_to_wait sTimeout, count in RTOS ticks + * + * @return + * - (-1) Error + * - OTHERS (>=0) The number of bytes read from UART FIFO + */ +int my_uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickType_t ticks_to_wait); + +/** + * @brief Alias of my_uart_flush_input. + * UART ring buffer flush. This will discard all data in the UART RX buffer. + * @note Instead of waiting the data sent out, this function will clear UART rx buffer. + * In order to send all the data in tx FIFO, we can use my_uart_wait_tx_done function. + * @param uart_num UART port number. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_flush(uart_port_t uart_num); + +/** + * @brief Clear input buffer, discard all the data is in the ring-buffer. + * @note In order to send all the data in tx FIFO, we can use my_uart_wait_tx_done function. + * @param uart_num UART port number. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_flush_input(uart_port_t uart_num); + +/** + * @brief UART get RX ring buffer cached data length + * + * @param uart_num UART port number. + * @param size Pointer of size_t to accept cached data length + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_get_buffered_data_len(uart_port_t uart_num, size_t *size); + +/** + * @brief UART set threshold timeout for TOUT feature + * + * @param uart_num Uart number to configure + * @param tout_thresh This parameter defines timeout threshold in uart symbol periods. The maximum value of threshold is 126. + * tout_thresh = 1, defines TOUT interrupt timeout equal to transmission time of one symbol (~11 bit) on current baudrate. + * If the time is expired the UART_RXFIFO_TOUT_INT interrupt is triggered. If tout_thresh == 0, + * the TOUT feature is disabled. + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t my_uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh); + +#ifdef __cplusplus +} +#endif + +#endif // _DRIVER_UART_H_ diff --git a/components/DAP/source/DAP.c b/components/DAP/source/DAP.c new file mode 100644 index 0000000..03f048c --- /dev/null +++ b/components/DAP/source/DAP.c @@ -0,0 +1,1773 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: DAP.c CMSIS-DAP Commands + * + *---------------------------------------------------------------------------*/ + +#include +#include "DAP_config.h" +#include "DAP.h" + + +#if (DAP_PACKET_SIZE < 64U) +#error "Minimum Packet Size is 64!" +#endif +#if (DAP_PACKET_SIZE > 32768U) +#error "Maximum Packet Size is 32768!" +#endif +#if (DAP_PACKET_COUNT < 1U) +#error "Minimum Packet Count is 1!" +#endif +#if (DAP_PACKET_COUNT > 255U) +#error "Maximum Packet Count is 255!" +#endif + + +// Clock Macros + +#define MAX_SWJ_CLOCK(delay_cycles) \ + ((CPU_CLOCK/2U) / (IO_PORT_WRITE_CYCLES + delay_cycles)) + +#define CLOCK_DELAY(swj_clock) \ + (((CPU_CLOCK/2U) / swj_clock) - IO_PORT_WRITE_CYCLES) + + + DAP_Data_t DAP_Data; // DAP Data +volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag + + +static const char DAP_FW_Ver [] = DAP_FW_VER; + +#if TARGET_DEVICE_FIXED +static const char TargetDeviceVendor [] = TARGET_DEVICE_VENDOR; +static const char TargetDeviceName [] = TARGET_DEVICE_NAME; +#endif + + +// Get DAP Information +// id: info identifier +// info: pointer to info data +// return: number of bytes in info data +static uint8_t DAP_Info(uint8_t id, uint8_t *info) { + uint8_t length = 0U; + + switch (id) { + case DAP_ID_VENDOR: + length = DAP_GetVendorString((char *)info); + break; + case DAP_ID_PRODUCT: + length = DAP_GetProductString((char *)info); + break; + case DAP_ID_SER_NUM: + length = DAP_GetSerNumString((char *)info); + break; + case DAP_ID_FW_VER: + length = (uint8_t)sizeof(DAP_FW_Ver); + memcpy(info, DAP_FW_Ver, length); + break; + case DAP_ID_DEVICE_VENDOR: +#if TARGET_DEVICE_FIXED + length = (uint8_t)sizeof(TargetDeviceVendor); + memcpy(info, TargetDeviceVendor, length); +#endif + break; + case DAP_ID_DEVICE_NAME: +#if TARGET_DEVICE_FIXED + length = (uint8_t)sizeof(TargetDeviceName); + memcpy(info, TargetDeviceName, length); +#endif + break; + case DAP_ID_CAPABILITIES: + info[0] = ((DAP_SWD != 0) ? (1U << 0) : 0U) | + ((DAP_JTAG != 0) ? (1U << 1) : 0U) | + ((SWO_UART != 0) ? (1U << 2) : 0U) | + ((SWO_MANCHESTER != 0) ? (1U << 3) : 0U) | + /* Atomic Commands */ (1U << 4) | + ((TIMESTAMP_CLOCK != 0U) ? (1U << 5) : 0U) | + ((SWO_STREAM != 0U) ? (1U << 6) : 0U); + length = 1U; + break; + case DAP_ID_TIMESTAMP_CLOCK: +#if (TIMESTAMP_CLOCK != 0U) + info[0] = (uint8_t)(TIMESTAMP_CLOCK >> 0); + info[1] = (uint8_t)(TIMESTAMP_CLOCK >> 8); + info[2] = (uint8_t)(TIMESTAMP_CLOCK >> 16); + info[3] = (uint8_t)(TIMESTAMP_CLOCK >> 24); + length = 4U; +#endif + break; + case DAP_ID_SWO_BUFFER_SIZE: +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + info[0] = (uint8_t)(SWO_BUFFER_SIZE >> 0); + info[1] = (uint8_t)(SWO_BUFFER_SIZE >> 8); + info[2] = (uint8_t)(SWO_BUFFER_SIZE >> 16); + info[3] = (uint8_t)(SWO_BUFFER_SIZE >> 24); + length = 4U; +#endif + break; + case DAP_ID_PACKET_SIZE: + info[0] = (uint8_t)(DAP_PACKET_SIZE >> 0); + info[1] = (uint8_t)(DAP_PACKET_SIZE >> 8); + length = 2U; + break; + case DAP_ID_PACKET_COUNT: + info[0] = DAP_PACKET_COUNT; + length = 1U; + break; + default: + break; + } + + return (length); +} + + +// Delay for specified time +// delay: delay time in ms +void Delayms(uint32_t delay) { + delay *= ((CPU_CLOCK/1000U) + (DELAY_SLOW_CYCLES-1U)) / DELAY_SLOW_CYCLES; + PIN_DELAY_SLOW(delay); +} + + +// Process Delay command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Delay(const uint8_t *request, uint8_t *response) { + uint32_t delay; + + delay = (uint32_t)(*(request+0)) | + (uint32_t)(*(request+1) << 8); + delay *= ((CPU_CLOCK/1000000U) + (DELAY_SLOW_CYCLES-1U)) / DELAY_SLOW_CYCLES; + + PIN_DELAY_SLOW(delay); + + *response = DAP_OK; + return ((2U << 16) | 1U); +} + + +// Process Host Status command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_HostStatus(const uint8_t *request, uint8_t *response) { + + switch (*request) { + case DAP_DEBUGGER_CONNECTED: + LED_CONNECTED_OUT((*(request+1) & 1U)); + break; + case DAP_TARGET_RUNNING: + LED_RUNNING_OUT((*(request+1) & 1U)); + break; + default: + *response = DAP_ERROR; + return ((2U << 16) | 1U); + } + + *response = DAP_OK; + return ((2U << 16) | 1U); +} + + +// Process Connect command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Connect(const uint8_t *request, uint8_t *response) { + uint32_t port; + + if (*request == DAP_PORT_AUTODETECT) { + port = DAP_DEFAULT_PORT; + } else { + port = *request; + } + + switch (port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + DAP_Data.debug_port = DAP_PORT_SWD; + PORT_SWD_SETUP(); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + DAP_Data.debug_port = DAP_PORT_JTAG; + PORT_JTAG_SETUP(); + break; +#endif + default: + port = DAP_PORT_DISABLED; + break; + } + + *response = (uint8_t)port; + return ((1U << 16) | 1U); +} + + +// Process Disconnect command and prepare response +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_Disconnect(uint8_t *response) { + + DAP_Data.debug_port = DAP_PORT_DISABLED; + PORT_OFF(); + + *response = DAP_OK; + return (1U); +} + + +// Process Reset Target command and prepare response +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_ResetTarget(uint8_t *response) { + + *(response+1) = RESET_TARGET(); + *(response+0) = DAP_OK; + return (2U); +} + + +// Process SWJ Pins command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWJ_Pins(const uint8_t *request, uint8_t *response) { +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + uint32_t value; + uint32_t select; + uint32_t wait; + uint32_t timestamp; + + value = (uint32_t) *(request+0); + select = (uint32_t) *(request+1); + wait = (uint32_t)(*(request+2) << 0) | + (uint32_t)(*(request+3) << 8) | + (uint32_t)(*(request+4) << 16) | + (uint32_t)(*(request+5) << 24); + + if ((select & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + if ((value & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + PIN_SWCLK_TCK_SET(); + } else { + PIN_SWCLK_TCK_CLR(); + } + } + if ((select & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + if ((value & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + PIN_SWDIO_TMS_SET(); + } else { + PIN_SWDIO_TMS_CLR(); + } + } + if ((select & (1U << DAP_SWJ_TDI)) != 0U) { + PIN_TDI_OUT(value >> DAP_SWJ_TDI); + } + if ((select & (1U << DAP_SWJ_nTRST)) != 0U) { + PIN_nTRST_OUT(value >> DAP_SWJ_nTRST); + } + if ((select & (1U << DAP_SWJ_nRESET)) != 0U){ + PIN_nRESET_OUT(value >> DAP_SWJ_nRESET); + } + + if (wait != 0U) { +#if (TIMESTAMP_CLOCK != 0U) + if (wait > 3000000U) { + wait = 3000000U; + } +#if (TIMESTAMP_CLOCK >= 1000000U) + wait *= TIMESTAMP_CLOCK / 1000000U; +#else + wait /= 1000000U / TIMESTAMP_CLOCK; +#endif +#else + wait = 1U; +#endif + timestamp = TIMESTAMP_GET(); + do { + if ((select & (1U << DAP_SWJ_SWCLK_TCK)) != 0U) { + if ((value >> DAP_SWJ_SWCLK_TCK) ^ PIN_SWCLK_TCK_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_SWDIO_TMS)) != 0U) { + if ((value >> DAP_SWJ_SWDIO_TMS) ^ PIN_SWDIO_TMS_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_TDI)) != 0U) { + if ((value >> DAP_SWJ_TDI) ^ PIN_TDI_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_nTRST)) != 0U) { + if ((value >> DAP_SWJ_nTRST) ^ PIN_nTRST_IN()) { + continue; + } + } + if ((select & (1U << DAP_SWJ_nRESET)) != 0U) { + if ((value >> DAP_SWJ_nRESET) ^ PIN_nRESET_IN()) { + continue; + } + } + break; + } while ((TIMESTAMP_GET() - timestamp) < wait); + } + + value = (PIN_SWCLK_TCK_IN() << DAP_SWJ_SWCLK_TCK) | + (PIN_SWDIO_TMS_IN() << DAP_SWJ_SWDIO_TMS) | + (PIN_TDI_IN() << DAP_SWJ_TDI) | + (PIN_TDO_IN() << DAP_SWJ_TDO) | + (PIN_nTRST_IN() << DAP_SWJ_nTRST) | + (PIN_nRESET_IN() << DAP_SWJ_nRESET); + + *response = (uint8_t)value; +#else + *response = 0U; +#endif + + return ((6U << 16) | 1U); +} + + +// Process SWJ Clock command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWJ_Clock(const uint8_t *request, uint8_t *response) { +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + uint32_t clock; + uint32_t delay; + + clock = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + + if (clock == 0U) { + *response = DAP_ERROR; + return ((4U << 16) | 1U); + } + if(clock == 10000000){ + clock = MAX_USER_CLOCK; + } + + + if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) { + DAP_Data.fast_clock = 1U; + DAP_Data.clock_delay = 1U; + } else { + DAP_Data.fast_clock = 0U; + + delay = ((CPU_CLOCK/2U) + (clock - 1U)) / clock; + if (delay > IO_PORT_WRITE_CYCLES) { + delay -= IO_PORT_WRITE_CYCLES; + delay = (delay + (DELAY_SLOW_CYCLES - 1U)) / DELAY_SLOW_CYCLES; + } else { + delay = 1U; + } + + DAP_Data.clock_delay = delay; + } + + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + return ((4U << 16) | 1U); +} + + +// Process SWJ Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWJ_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t count; + + count = *request++; + if (count == 0U) { + count = 256U; + } + +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + SWJ_Sequence(count, request); + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + count = (count + 7U) >> 3; + + return (((count + 1U) << 16) | 1U); +} + + +// Process SWD Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWD_Configure(const uint8_t *request, uint8_t *response) { +#if (DAP_SWD != 0) + uint8_t value; + + value = *request; + DAP_Data.swd_conf.turnaround = (value & 0x03U) + 1U; + DAP_Data.swd_conf.data_phase = (value & 0x04U) ? 1U : 0U; + + *response = DAP_OK; +#else + *response = DAP_ERROR; +#endif + + return ((1U << 16) | 1U); +} + + +// Process SWD Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_SWD_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t sequence_info; + uint32_t sequence_count; + uint32_t request_count; + uint32_t response_count; + uint32_t count; + +#if (DAP_SWD != 0) + *response++ = DAP_OK; +#else + *response++ = DAP_ERROR; +#endif + request_count = 1U; + response_count = 1U; + + sequence_count = *request++; + while (sequence_count--) { + sequence_info = *request++; + count = sequence_info & SWD_SEQUENCE_CLK; + if (count == 0U) { + count = 64U; + } + count = (count + 7U) / 8U; +#if (DAP_SWD != 0) + if ((sequence_info & SWD_SEQUENCE_DIN) != 0U) { + PIN_SWDIO_OUT_DISABLE(); + } else { + PIN_SWDIO_OUT_ENABLE(); + } + SWD_Sequence(sequence_info, request, response); + if (sequence_count == 0U) { + PIN_SWDIO_OUT_ENABLE(); + } +#endif + if ((sequence_info & SWD_SEQUENCE_DIN) != 0U) { + request_count++; +#if (DAP_SWD != 0) + response += count; + response_count += count; +#endif + } else { + request += count; + request_count += count + 1U; + } + } + + return ((request_count << 16) | response_count); +} + + +// Process JTAG Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_Sequence(const uint8_t *request, uint8_t *response) { + uint32_t sequence_info; + uint32_t sequence_count; + uint32_t request_count; + uint32_t response_count; + uint32_t count; + +#if (DAP_JTAG != 0) + *response++ = DAP_OK; +#else + *response++ = DAP_ERROR; +#endif + request_count = 1U; + response_count = 1U; + + sequence_count = *request++; + while (sequence_count--) { + sequence_info = *request++; + count = sequence_info & JTAG_SEQUENCE_TCK; + if (count == 0U) { + count = 64U; + } + count = (count + 7U) / 8U; +#if (DAP_JTAG != 0) + JTAG_Sequence(sequence_info, request, response); +#endif + request += count; + request_count += count + 1U; +#if (DAP_JTAG != 0) + if ((sequence_info & JTAG_SEQUENCE_TDO) != 0U) { + response += count; + response_count += count; + } +#endif + } + + return ((request_count << 16) | response_count); +} + + +// Process JTAG Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_Configure(const uint8_t *request, uint8_t *response) { + uint32_t count; +#if (DAP_JTAG != 0) + uint32_t length; + uint32_t bits; + uint32_t n; + + count = *request++; + DAP_Data.jtag_dev.count = (uint8_t)count; + + bits = 0U; + for (n = 0U; n < count; n++) { + length = *request++; + DAP_Data.jtag_dev.ir_length[n] = (uint8_t)length; + DAP_Data.jtag_dev.ir_before[n] = (uint16_t)bits; + bits += length; + } + for (n = 0U; n < count; n++) { + bits -= DAP_Data.jtag_dev.ir_length[n]; + DAP_Data.jtag_dev.ir_after[n] = (uint16_t)bits; + } + + *response = DAP_OK; +#else + count = *request; + *response = DAP_ERROR; +#endif + + return (((count + 1U) << 16) | 1U); +} + + +// Process JTAG IDCODE command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_JTAG_IDCode(const uint8_t *request, uint8_t *response) { +#if (DAP_JTAG != 0) + uint32_t data; + + if (DAP_Data.debug_port != DAP_PORT_JTAG) { + goto id_error; + } + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto id_error; + } + + // Select JTAG chain + JTAG_IR(JTAG_IDCODE); + + // Read IDCODE register + data = JTAG_ReadIDCode(); + + // Store Data + *(response+0) = DAP_OK; + *(response+1) = (uint8_t)(data >> 0); + *(response+2) = (uint8_t)(data >> 8); + *(response+3) = (uint8_t)(data >> 16); + *(response+4) = (uint8_t)(data >> 24); + + return ((1U << 16) | 5U); + +id_error: +#endif + *response = DAP_ERROR; + return ((1U << 16) | 1U); +} + + +// Process Transfer Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_TransferConfigure(const uint8_t *request, uint8_t *response) { + + DAP_Data.transfer.idle_cycles = *(request+0); + DAP_Data.transfer.retry_count = (uint16_t) *(request+1) | + (uint16_t)(*(request+2) << 8); + DAP_Data.transfer.match_retry = (uint16_t) *(request+3) | + (uint16_t)(*(request+4) << 8); + + *response = DAP_OK; + return ((5U << 16) | 1U); +} + + +// Process SWD Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + uint8_t *response_head; + uint32_t response_count; + uint32_t response_value; + uint32_t post_read; + uint32_t check_write; + uint32_t match_value; + uint32_t match_retry; + uint32_t retry; + uint32_t data; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t timestamp; +#endif + + request_head = request; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 2; + + DAP_TransferAbort = 0U; + + post_read = 0U; + check_write = 0U; + + request++; // Ignore DAP index + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if (post_read) { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((request_value & (DAP_TRANSFER_APnDP | DAP_TRANSFER_MATCH_VALUE)) == DAP_TRANSFER_APnDP) { + // Read previous AP data and post next AP read + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } else { + // Read previous AP data + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0U; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous AP data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); +#if (TIMESTAMP_CLOCK != 0U) + if (post_read) { + // Store Timestamp of next AP read + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } + } +#endif + } + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + match_value = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } + do { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + } else { + // Normal read + retry = DAP_Data.transfer.retry_count; + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Read AP register + if (post_read == 0U) { + // Post AP read + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + post_read = 1U; + } + } else { + // Read DP register + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + } + check_write = 0U; + } else { + // Write register + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0U; + } + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + if ((request_value & DAP_TRANSFER_MATCH_MASK) != 0U) { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } else { + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + check_write = 1U; + } + } + response_count++; + if (DAP_TransferAbort) { + break; + } + } + + for (; request_count != 0U; request_count--) { + // Process canceled requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + if (response_value == DAP_TRANSFER_OK) { + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } else if (check_write) { + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head+0) = (uint8_t)response_count; + *(response_head+1) = (uint8_t)response_value; + + return (((uint32_t)(request - request_head) << 16) | (uint32_t)(response - response_head)); +} +#endif + + +// Process JTAG Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + uint32_t request_ir; + uint8_t *response_head; + uint32_t response_count; + uint32_t response_value; + uint32_t post_read; + uint32_t match_value; + uint32_t match_retry; + uint32_t retry; + uint32_t data; + uint32_t ir; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t timestamp; +#endif + + request_head = request; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 2; + + DAP_TransferAbort = 0U; + + ir = 0U; + post_read = 0U; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto end; + } + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + request_value = *request++; + request_ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if (post_read) { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((ir == request_ir) && ((request_value & DAP_TRANSFER_MATCH_VALUE) == 0U)) { + // Read previous data and post next read + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } else { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0U; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); +#if (TIMESTAMP_CLOCK != 0U) + if (post_read) { + // Store Timestamp of next AP read + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } + } +#endif + } + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + match_value = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + do { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) { + break; + } + } else { + // Normal read + if (post_read == 0U) { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + post_read = 1U; + } + } + } else { + // Write register + if (post_read) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0U; + } + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + if ((request_value & DAP_TRANSFER_MATCH_MASK) != 0U) { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } else { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + break; + } +#if (TIMESTAMP_CLOCK != 0U) + // Store Timestamp + if ((request_value & DAP_TRANSFER_TIMESTAMP) != 0U) { + timestamp = DAP_Data.timestamp; + *response++ = (uint8_t) timestamp; + *response++ = (uint8_t)(timestamp >> 8); + *response++ = (uint8_t)(timestamp >> 16); + *response++ = (uint8_t)(timestamp >> 24); + } +#endif + } + } + response_count++; + if (DAP_TransferAbort) { + break; + } + } + + for (; request_count != 0U; request_count--) { + // Process canceled requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + if (response_value == DAP_TRANSFER_OK) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } else { + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head+0) = (uint8_t)response_count; + *(response_head+1) = (uint8_t)response_value; + + return (((uint32_t)(request - request_head) << 16) | (uint32_t)(response - response_head)); +} +#endif + + +// Process Dummy Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Dummy_Transfer(const uint8_t *request, uint8_t *response) { + const + uint8_t *request_head; + uint32_t request_count; + uint32_t request_value; + + request_head = request; + + request++; // Ignore DAP index + + request_count = *request++; + + for (; request_count != 0U; request_count--) { + // Process dummy requests + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register + if ((request_value & DAP_TRANSFER_MATCH_VALUE) != 0U) { + // Read with value match + request += 4; + } + } else { + // Write register + request += 4; + } + } + + *(response+0) = 0U; // Response count + *(response+1) = 0U; // Response value + + return (((uint32_t)(request - request_head) << 16) | 2U); +} + + +// Process Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_Transfer(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_Transfer(request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_Transfer(request, response); + break; +#endif + default: + num = DAP_Dummy_Transfer(request, response); + break; + } + + return (num); +} + + +// Process SWD Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 3; + + DAP_TransferAbort = 0U; + + request++; // Ignore DAP index + + request_count = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8); + request += 2; + if (request_count == 0U) { + goto end; + } + + request_value = *request++; + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Read register block + if ((request_value & DAP_TRANSFER_APnDP) != 0U) { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + } + while (request_count--) { + // Read DP/AP register + if ((request_count == 0U) && ((request_value & DAP_TRANSFER_APnDP) != 0U)) { + // Last AP read + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } else { + // Write register block + while (request_count--) { + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + response_count++; + } + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return ((uint32_t)(response - response_head)); +} +#endif + + +// Process JTAG Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + uint32_t ir; + + response_count = 0U; + response_value = 0U; + response_head = response; + response += 3; + + DAP_TransferAbort = 0U; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + goto end; + } + + request_count = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8); + request += 2; + if (request_count == 0U) { + goto end; + } + + request_value = *request++; + + // Select JTAG chain + ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + JTAG_IR(ir); + + if ((request_value & DAP_TRANSFER_RnW) != 0U) { + // Post read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Read register block + while (request_count--) { + // Read DP/AP register + if (request_count == 0U) { + // Last read + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } else { + // Write register block + while (request_count--) { + // Load data + data = (uint32_t)(*(request+0) << 0) | + (uint32_t)(*(request+1) << 8) | + (uint32_t)(*(request+2) << 16) | + (uint32_t)(*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) { + goto end; + } + response_count++; + } + // Check last write + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return ((uint32_t)(response - response_head)); +} +#endif + + +// Process Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_TransferBlock(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_TransferBlock (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_TransferBlock(request, response); + break; +#endif + default: + *(response+0) = 0U; // Response count [7:0] + *(response+1) = 0U; // Response count[15:8] + *(response+2) = 0U; // Response value + num = 3U; + break; + } + + if ((*(request+3) & DAP_TRANSFER_RnW) != 0U) { + // Read register block + num |= 4U << 16; + } else { + // Write register block + num |= (4U + (((uint32_t)(*(request+1)) | (uint32_t)(*(request+2) << 8)) * 4)) << 16; + } + + return (num); +} + + +// Process SWD Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t data; + + // Load data (Ignore DAP index) + data = (uint32_t)(*(request+1) << 0) | + (uint32_t)(*(request+2) << 8) | + (uint32_t)(*(request+3) << 16) | + (uint32_t)(*(request+4) << 24); + + // Write Abort register + SWD_Transfer(DP_ABORT, &data); + + *response = DAP_OK; + return (1U); +} +#endif + + +// Process JTAG Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t data; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) { + *response = DAP_ERROR; + return (1U); + } + + // Select JTAG chain + JTAG_IR(JTAG_ABORT); + + // Load data + data = (uint32_t)(*(request+1) << 0) | + (uint32_t)(*(request+2) << 8) | + (uint32_t)(*(request+3) << 16) | + (uint32_t)(*(request+4) << 24); + + // Write Abort register + JTAG_WriteAbort(data); + + *response = DAP_OK; + return (1U); +} +#endif + + +// Process Write ABORT command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +static uint32_t DAP_WriteAbort(const uint8_t *request, uint8_t *response) { + uint32_t num; + + switch (DAP_Data.debug_port) { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_WriteAbort (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_WriteAbort(request, response); + break; +#endif + default: + *response = DAP_ERROR; + num = 1U; + break; + } + return ((5U << 16) | num); +} + + +// Process DAP Vendor command request and prepare response +// Default function (can be overridden) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +__WEAK uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { + (void)request; + *response = ID_DAP_Invalid; + return ((1U << 16) | 1U); +} + + +// Process DAP command request and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t DAP_ProcessCommand(const uint8_t *request, uint8_t *response) { + uint32_t num; + + if ((*request >= ID_DAP_Vendor0) && (*request <= ID_DAP_Vendor31)) { + return DAP_ProcessVendorCommand(request, response); + } + + *response++ = *request; + + switch (*request++) { + case ID_DAP_Info: + num = DAP_Info(*request, response+1); + *response = (uint8_t)num; + return ((2U << 16) + 2U + num); + + case ID_DAP_HostStatus: + num = DAP_HostStatus(request, response); + break; + + case ID_DAP_Connect: + num = DAP_Connect(request, response); + break; + case ID_DAP_Disconnect: + num = DAP_Disconnect(response); + break; + + case ID_DAP_Delay: + num = DAP_Delay(request, response); + break; + + case ID_DAP_ResetTarget: + num = DAP_ResetTarget(response); + break; + + case ID_DAP_SWJ_Pins: + num = DAP_SWJ_Pins(request, response); + break; + case ID_DAP_SWJ_Clock: + num = DAP_SWJ_Clock(request, response); + break; + case ID_DAP_SWJ_Sequence: + num = DAP_SWJ_Sequence(request, response); + break; + + case ID_DAP_SWD_Configure: + num = DAP_SWD_Configure(request, response); + break; + case ID_DAP_SWD_Sequence: + num = DAP_SWD_Sequence(request, response); + break; + + case ID_DAP_JTAG_Sequence: + num = DAP_JTAG_Sequence(request, response); + break; + case ID_DAP_JTAG_Configure: + num = DAP_JTAG_Configure(request, response); + break; + case ID_DAP_JTAG_IDCODE: + num = DAP_JTAG_IDCode(request, response); + break; + + case ID_DAP_TransferConfigure: + num = DAP_TransferConfigure(request, response); + break; + case ID_DAP_Transfer: + num = DAP_Transfer(request, response); + break; + case ID_DAP_TransferBlock: + num = DAP_TransferBlock(request, response); + break; + + case ID_DAP_WriteABORT: + num = DAP_WriteAbort(request, response); + break; + +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + case ID_DAP_SWO_Transport: + num = SWO_Transport(request, response); + break; + case ID_DAP_SWO_Mode: + num = SWO_Mode(request, response); + break; + case ID_DAP_SWO_Baudrate: + num = SWO_Baudrate(request, response); + break; + case ID_DAP_SWO_Control: + num = SWO_Control(request, response); + break; + case ID_DAP_SWO_Status: + num = SWO_Status(response); + break; + case ID_DAP_SWO_ExtendedStatus: + num = SWO_ExtendedStatus(request, response); + break; + case ID_DAP_SWO_Data: + num = SWO_Data(request, response); + break; +#endif + + default: + *(response-1) = ID_DAP_Invalid; + return ((1U << 16) | 1U); + } + + return ((1U << 16) + 1U + num); +} + + +// Execute DAP command (process request and prepare response) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t DAP_ExecuteCommand(const uint8_t *request, uint8_t *response) { + uint32_t cnt, num, n; + + if (*request == ID_DAP_ExecuteCommands) { + *response++ = *request++; + cnt = *request++; + *response++ = (uint8_t)cnt; + num = (2U << 16) | 2U; + while (cnt--) { + n = DAP_ProcessCommand(request, response); + num += n; + request += (uint16_t)(n >> 16); + response += (uint16_t) n; + } + return (num); + } + + return DAP_ProcessCommand(request, response); +} + + +// Setup DAP +void DAP_Setup(void) { + + // Default settings + DAP_Data.debug_port = 0U; + DAP_Data.fast_clock = 0U; + DAP_Data.clock_delay = CLOCK_DELAY(DAP_DEFAULT_SWJ_CLOCK); + DAP_Data.transfer.idle_cycles = 0U; + DAP_Data.transfer.retry_count = 100U; + DAP_Data.transfer.match_retry = 0U; + DAP_Data.transfer.match_mask = 0x00000000U; +#if (DAP_SWD != 0) + DAP_Data.swd_conf.turnaround = 1U; + DAP_Data.swd_conf.data_phase = 0U; +#endif +#if (DAP_JTAG != 0) + DAP_Data.jtag_dev.count = 0U; +#endif + + DAP_SETUP(); // Device specific setup +} diff --git a/components/DAP/source/DAP_vendor.c b/components/DAP/source/DAP_vendor.c new file mode 100644 index 0000000..a4ae496 --- /dev/null +++ b/components/DAP/source/DAP_vendor.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: DAP_vendor.c CMSIS-DAP Vendor Commands + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + +//************************************************************************************************** +/** +\defgroup DAP_Vendor_Adapt_gr Adapt Vendor Commands +\ingroup DAP_Vendor_gr +@{ + +The file DAP_vendor.c provides template source code for extension of a Debug Unit with +Vendor Commands. Copy this file to the project folder of the Debug Unit and add the +file to the MDK-ARM project under the file group Configuration. +*/ + +/** Process DAP Vendor Command and prepare Response Data +\param request pointer to request data +\param response pointer to response data +\return number of bytes in response (lower 16 bits) + number of bytes in request (upper 16 bits) +*/ +uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { + uint32_t num = (1U << 16) | 1U; + + *response++ = *request; // copy Command ID + + switch (*request++) { // first byte in request is Command ID + case ID_DAP_Vendor0: +#if 0 // example user command + num += 1U << 16; // increment request count + if (*request == 1U) { // when first command data byte is 1 + *response++ = 'X'; // send 'X' as response + num++; // increment response count + } +#endif + break; + + case ID_DAP_Vendor1: break; + case ID_DAP_Vendor2: break; + case ID_DAP_Vendor3: break; + case ID_DAP_Vendor4: break; + case ID_DAP_Vendor5: break; + case ID_DAP_Vendor6: break; + case ID_DAP_Vendor7: break; + case ID_DAP_Vendor8: break; + case ID_DAP_Vendor9: break; + case ID_DAP_Vendor10: break; + case ID_DAP_Vendor11: break; + case ID_DAP_Vendor12: break; + case ID_DAP_Vendor13: break; + case ID_DAP_Vendor14: break; + case ID_DAP_Vendor15: break; + case ID_DAP_Vendor16: break; + case ID_DAP_Vendor17: break; + case ID_DAP_Vendor18: break; + case ID_DAP_Vendor19: break; + case ID_DAP_Vendor20: break; + case ID_DAP_Vendor21: break; + case ID_DAP_Vendor22: break; + case ID_DAP_Vendor23: break; + case ID_DAP_Vendor24: break; + case ID_DAP_Vendor25: break; + case ID_DAP_Vendor26: break; + case ID_DAP_Vendor27: break; + case ID_DAP_Vendor28: break; + case ID_DAP_Vendor29: break; + case ID_DAP_Vendor30: break; + case ID_DAP_Vendor31: break; + } + + return (num); +} + +///@} diff --git a/components/DAP/source/JTAG_DP.c b/components/DAP/source/JTAG_DP.c new file mode 100644 index 0000000..24b1f3f --- /dev/null +++ b/components/DAP/source/JTAG_DP.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: JTAG_DP.c CMSIS-DAP JTAG DP I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + + +// JTAG Macros + +#define PIN_TCK_SET PIN_SWCLK_TCK_SET +#define PIN_TCK_CLR PIN_SWCLK_TCK_CLR +#define PIN_TMS_SET PIN_SWDIO_TMS_SET +#define PIN_TMS_CLR PIN_SWDIO_TMS_CLR + +#define JTAG_CYCLE_TCK() \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDI(tdi) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDO(tdo) \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDIO(tdi,tdo) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + + +#if (DAP_JTAG != 0) + + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +void JTAG_Sequence (uint32_t info, const uint8_t *tdi, uint8_t *tdo) { + uint32_t i_val; + uint32_t o_val; + uint32_t bit; + uint32_t n, k; + + n = info & JTAG_SEQUENCE_TCK; + if (n == 0U) { + n = 64U; + } + + if (info & JTAG_SEQUENCE_TMS) { + PIN_TMS_SET(); + } else { + PIN_TMS_CLR(); + } + + while (n) { + i_val = *tdi++; + o_val = 0U; + for (k = 8U; k && n; k--, n--) { + JTAG_CYCLE_TDIO(i_val, bit); + i_val >>= 1; + o_val >>= 1; + o_val |= bit << 7; + } + o_val >>= k; + if (info & JTAG_SEQUENCE_TDO) { + *tdo++ = (uint8_t)o_val; + } + } +} + + +// JTAG Set IR +// ir: IR value +// return: none +#define JTAG_IR_Function(speed) /**/ \ +static void JTAG_IR_##speed (uint32_t ir) { \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + JTAG_CYCLE_TCK(); /* Select-IR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-IR */ \ + JTAG_CYCLE_TCK(); /* Shift-IR */ \ + \ + PIN_TDI_OUT(1U); \ + for (n = DAP_Data.jtag_dev.ir_before[DAP_Data.jtag_dev.index]; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + for (n = DAP_Data.jtag_dev.ir_length[DAP_Data.jtag_dev.index] - 1U; n; n--) { \ + JTAG_CYCLE_TDI(ir); /* Set IR bits (except last) */ \ + ir >>= 1; \ + } \ + n = DAP_Data.jtag_dev.ir_after[DAP_Data.jtag_dev.index]; \ + if (n) { \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit */ \ + PIN_TDI_OUT(1U); \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-IR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit & Exit1-IR */ \ + } \ + \ + JTAG_CYCLE_TCK(); /* Update-IR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1U); \ +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +#define JTAG_TransferFunction(speed) /**/ \ +static uint8_t JTAG_Transfer##speed (uint32_t request, uint32_t *data) { \ + uint32_t ack; \ + uint32_t bit; \ + uint32_t val; \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-DR */ \ + JTAG_CYCLE_TCK(); /* Shift-DR */ \ + \ + for (n = DAP_Data.jtag_dev.index; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + \ + JTAG_CYCLE_TDIO(request >> 1, bit); /* Set RnW, Get ACK.0 */ \ + ack = bit << 1; \ + JTAG_CYCLE_TDIO(request >> 2, bit); /* Set A2, Get ACK.1 */ \ + ack |= bit << 0; \ + JTAG_CYCLE_TDIO(request >> 3, bit); /* Set A3, Get ACK.2 */ \ + ack |= bit << 2; \ + \ + if (ack != DAP_TRANSFER_OK) { \ + /* Exit on error */ \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Exit1-DR */ \ + goto exit; \ + } \ + \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read Transfer */ \ + val = 0U; \ + for (n = 31U; n; n--) { \ + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ \ + val |= bit << 31; \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; \ + if (n) { \ + JTAG_CYCLE_TDO(bit); /* Get D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ \ + } \ + val |= bit << 31; \ + if (data) { *data = val; } \ + } else { \ + /* Write Transfer */ \ + val = *data; \ + for (n = 31U; n; n--) { \ + JTAG_CYCLE_TDI(val); /* Set D0..D30 */ \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; \ + if (n) { \ + JTAG_CYCLE_TDI(val); /* Set D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(val); /* Set D31 & Exit1-DR */ \ + } \ + } \ + \ +exit: \ + JTAG_CYCLE_TCK(); /* Update-DR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1U); \ + \ + /* Capture Timestamp */ \ + if (request & DAP_TRANSFER_TIMESTAMP) { \ + DAP_Data.timestamp = TIMESTAMP_GET(); \ + } \ + \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + while (n--) { \ + JTAG_CYCLE_TCK(); /* Idle */ \ + } \ + \ + return ((uint8_t)ack); \ +} + + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_FAST() +JTAG_IR_Function(Fast) +JTAG_TransferFunction(Fast) + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +JTAG_IR_Function(Slow) +JTAG_TransferFunction(Slow) + + +// JTAG Read IDCODE register +// return: value read +uint32_t JTAG_ReadIDCode (void) { + uint32_t bit; + uint32_t val; + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + val = 0U; + for (n = 31U; n; n--) { + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ + val |= bit << 31; + val >>= 1; + } + PIN_TMS_SET(); + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ + val |= bit << 31; + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + + return (val); +} + + +// JTAG Write ABORT register +// data: value to write +// return: none +void JTAG_WriteAbort (uint32_t data) { + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + PIN_TDI_OUT(0U); + JTAG_CYCLE_TCK(); /* Set RnW=0 (Write) */ + JTAG_CYCLE_TCK(); /* Set A2=0 */ + JTAG_CYCLE_TCK(); /* Set A3=0 */ + + for (n = 31U; n; n--) { + JTAG_CYCLE_TDI(data); /* Set D0..D30 */ + data >>= 1; + } + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1U; + if (n) { + JTAG_CYCLE_TDI(data); /* Set D31 */ + for (--n; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass after data */ + } + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ + } else { + PIN_TMS_SET(); + JTAG_CYCLE_TDI(data); /* Set D31 & Exit1-DR */ + } + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + PIN_TDI_OUT(1U); +} + + +// JTAG Set IR +// ir: IR value +// return: none +void JTAG_IR (uint32_t ir) { + if (DAP_Data.fast_clock) { + JTAG_IR_Fast(ir); + } else { + JTAG_IR_Slow(ir); + } +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t JTAG_Transfer(uint32_t request, uint32_t *data) { + if (DAP_Data.fast_clock) { + return JTAG_TransferFast(request, data); + } else { + return JTAG_TransferSlow(request, data); + } +} + + +#endif /* (DAP_JTAG != 0) */ diff --git a/components/DAP/source/SWO.c b/components/DAP/source/SWO.c new file mode 100644 index 0000000..d331a0c --- /dev/null +++ b/components/DAP/source/SWO.c @@ -0,0 +1,946 @@ +/** + * @brief Modify this file to fit esp8266 Uart + * + */ + +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: SWO.c CMSIS-DAP SWO I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "uart_modify.h" + + +EventGroupHandle_t kSWO_Thread_event_group; +EventGroupHandle_t kUART_Monitoe_event_group; +#define SWO_GOT_DATA BIT0 +#define SWO_ERROR_TIME_OUT BIT1 + +#define UART_GOT_DATA BIT0 + + +#if (SWO_STREAM != 0) +#ifdef DAP_FW_V1 +#error "SWO Streaming Trace not supported in DAP V1!" +#endif +#endif + +#if (SWO_UART != 0) + +#ifndef USART_PORT +#define USART_PORT UART_NUM_0 /* USART Port Number */ +#endif + + + +static uint8_t USART_Ready = 0U; + +#endif /* (SWO_UART != 0) */ + +#if ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) + +#define SWO_STREAM_TIMEOUT (50 / portTICK_RATE_MS) /* Stream timeout in ms */ + +#define USB_BLOCK_SIZE 512U /* USB Block Size */ +#define TRACE_BLOCK_SIZE 64U /* Trace Block Size (2^n: 32...512) */ + +// Trace State +static uint8_t TraceTransport = 0U; /* Trace Transport */ +static uint8_t TraceMode = 0U; /* Trace Mode */ +static uint8_t TraceStatus = 0U; /* Trace Status without Errors */ +static uint8_t TraceError[2] = {0U, 0U}; /* Trace Error flags (banked) */ +static uint8_t TraceError_n = 0U; /* Active Trace Error bank */ + +// Trace Buffer +static uint8_t TraceBuf[SWO_BUFFER_SIZE]; /* Trace Buffer (must be 2^n) */ +static volatile uint32_t TraceIndexI = 0U; /* Incoming Trace Index */ +static volatile uint32_t TraceIndexO = 0U; /* Outgoing Trace Index */ +static volatile uint8_t TraceUpdate; /* Trace Update Flag */ +static uint32_t TraceBlockSize; /* Current Trace Block Size */ + +#if (TIMESTAMP_CLOCK != 0U) +// Trace Timestamp +static volatile struct +{ + uint32_t index; + uint32_t tick; +} TraceTimestamp; +#endif + +// Trace Helper functions +static void ClearTrace(void); +static void ResumeTrace(void); +static uint32_t GetTraceCount(void); +static uint8_t GetTraceStatus(void); +void SetTraceError(uint8_t flag); + +#if (SWO_STREAM != 0) + +static volatile uint8_t TransferBusy = 0U; /* Transfer Busy Flag */ +static uint32_t TransferSize; /* Current Transfer Size */ +#endif + +#if (SWO_UART != 0) + + +void usart_monitor_task(void *argument) +{ + uint32_t index_i; + uint32_t index_o; + uint32_t count; + uint32_t num; + uint32_t flags; + + kUART_Monitoe_event_group = xEventGroupCreate(); + for (;;) + { + flags = xEventGroupWaitBits(kUART_Monitoe_event_group, UART_GOT_DATA, + pdTRUE, pdFALSE, portMAX_DELAY); + if (flags & UART_GOT_DATA) + { +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.tick = TIMESTAMP_GET(); +#endif + index_o = TraceIndexO; + index_i = TraceIndexI; + index_i += TraceBlockSize; + TraceIndexI = index_i; +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.index = index_i; +#endif + + num = TRACE_BLOCK_SIZE - (index_i & (TRACE_BLOCK_SIZE - 1U)); + // num is the number of bytes we need to read + // (to achieve the size of TRACE_BLOCK_SIZE) + count = index_i - index_o; + // Amount of data that has not been processed yet + + // (SWO_BUFFER_SIZE-num): the remaining usable length of the buffer after reading this data + if (count <= (SWO_BUFFER_SIZE - num)) + { + index_i &= SWO_BUFFER_SIZE - 1U; + TraceBlockSize = num; + my_uart_read_bytes(USART_PORT, &TraceBuf[index_i], num, 20 / portTICK_RATE_MS); + //pUSART->Receive(&TraceBuf[index_i], num); + } + else + { + // Not enough buffers + TraceStatus = DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED; + } + TraceUpdate = 1U; +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) + { + if (count >= (USB_BLOCK_SIZE - (index_o & (USB_BLOCK_SIZE - 1U)))) + { + xEventGroupSetBits(kSWO_Thread_event_group, SWO_GOT_DATA); + } + } +#endif + } + } + + // if (event & ARM_USART_EVENT_RX_OVERFLOW) + // { + // SetTraceError(DAP_SWO_BUFFER_OVERRUN); + // } + // if (event & (ARM_USART_EVENT_RX_BREAK | + // ARM_USART_EVENT_RX_FRAMING_ERROR | + // ARM_USART_EVENT_RX_PARITY_ERROR)) + // { + // SetTraceError(DAP_SWO_STREAM_ERROR); + // } +} + +// Enable or disable UART SWO Mode +// enable: enable flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t UART_SWO_Mode(uint32_t enable) +{ + int32_t status; + + USART_Ready = 0U; + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE}; + my_uart_param_config(USART_PORT, &uart_config); + +#define BUF_SIZE (1024) + my_uart_driver_install(USART_PORT, BUF_SIZE, 0, 0, NULL, 0); + + if (enable != 0U) + { + my_uart_param_config(USART_PORT, &uart_config); + status = my_uart_driver_install(USART_PORT, BUF_SIZE, 0, 0, NULL, 0); + if (status != ESP_OK) + { + return (0U); + } + } + else + { + my_uart_driver_delete(USART_PORT); + } + return (1U); + + +} + +// Configure UART SWO Baudrate +// baudrate: requested baudrate +// return: actual baudrate or 0 when not configured +__WEAK uint32_t UART_SWO_Baudrate(uint32_t baudrate) +{ + int32_t status; + uint32_t index; + uint32_t num; + + if (baudrate > SWO_UART_MAX_BAUDRATE) + { + baudrate = SWO_UART_MAX_BAUDRATE; + } + + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) + { + size_t len = 0; + my_uart_get_buffered_data_len(USART_PORT, &len); + my_uart_flush(USART_PORT); + TraceIndexI += len; + // pUSART->Control(ARM_USART_CONTROL_RX, 0U); + // if (pUSART->GetStatus().rx_busy) + // { + // TraceIndexI += pUSART->GetRxCount(); + // pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + // } + } + + ///////////// + status = my_uart_set_baudrate(USART_PORT, baudrate); + + if (status == ESP_OK) + { + USART_Ready = 1U; + } + else + { + USART_Ready = 0U; + return (0U); + } + + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) + { + if ((TraceStatus & DAP_SWO_CAPTURE_PAUSED) == 0U) + { + index = TraceIndexI & (SWO_BUFFER_SIZE - 1U); + num = TRACE_BLOCK_SIZE - (index & (TRACE_BLOCK_SIZE - 1U)); + TraceBlockSize = num; + //pUSART->Receive(&TraceBuf[index], num); + my_uart_read_bytes(USART_PORT, &TraceBuf[index], num, 20 / portTICK_RATE_MS); + } + //pUSART->Control(ARM_USART_CONTROL_RX, 1U); ////TODO: + } + + return (baudrate); +} + +// Control UART SWO Capture +// active: active flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t UART_SWO_Control(uint32_t active) +{ + int32_t status; + + if (active) + { + if (!USART_Ready) + { + return (0U); + } + TraceBlockSize = 1U; + status = my_uart_read_bytes(USART_PORT, &TraceBuf[0], 1U, 20 / portTICK_RATE_MS); + if (status == ESP_FAIL) + { + return (0U); + } + // status = pUSART->Control(ARM_USART_CONTROL_RX, 1U); + // if (status != ARM_DRIVER_OK) + // { + // return (0U); + // } ////TODO: + } + else + { + size_t len = 0; + my_uart_get_buffered_data_len(USART_PORT, &len); + my_uart_flush(USART_PORT); + TraceIndexI += len; + // pUSART->Control(ARM_USART_CONTROL_RX, 0U); + // if (pUSART->GetStatus().rx_busy) + // { + // TraceIndexI += pUSART->GetRxCount(); + // pUSART->Control(ARM_USART_ABORT_RECEIVE, 0U); + // } + } + return (1U); +} + +// Start UART SWO Capture +// buf: pointer to buffer for capturing +// num: number of bytes to capture +__WEAK void UART_SWO_Capture(uint8_t *buf, uint32_t num) +{ + TraceBlockSize = num; + my_uart_read_bytes(USART_PORT, buf, num, 20 / portTICK_RATE_MS); +} + +// Get UART SWO Pending Trace Count +// return: number of pending trace data bytes +__WEAK uint32_t UART_SWO_GetCount(void) +{ + uint32_t count; + + // if (pUSART->GetStatus().rx_busy) + // { + // count = pUSART->GetRxCount(); + // } + // else + // { + // count = 0U; + // } + my_uart_get_buffered_data_len(USART_PORT, &count); + return (count); +} + +#endif /* (SWO_UART != 0) */ + +#if (SWO_MANCHESTER != 0) + +// Enable or disable Manchester SWO Mode +// enable: enable flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t Manchester_SWO_Mode(uint32_t enable) +{ + return (0U); +} + +// Configure Manchester SWO Baudrate +// baudrate: requested baudrate +// return: actual baudrate or 0 when not configured +__WEAK uint32_t Manchester_SWO_Baudrate(uint32_t baudrate) +{ + return (0U); +} + +// Control Manchester SWO Capture +// active: active flag +// return: 1 - Success, 0 - Error +__WEAK uint32_t Manchester_SWO_Control(uint32_t active) +{ + return (0U); +} + +// Start Manchester SWO Capture +// buf: pointer to buffer for capturing +// num: number of bytes to capture +__WEAK void Manchester_SWO_Capture(uint8_t *buf, uint32_t num) +{ +} + +// Get Manchester SWO Pending Trace Count +// return: number of pending trace data bytes +__WEAK uint32_t Manchester_SWO_GetCount(void) +{ + return (0U); +} + +#endif /* (SWO_MANCHESTER != 0) */ + +// Clear Trace Errors and Data +static void ClearTrace(void) +{ + +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) + { + if (TransferBusy != 0U) + { + SWO_AbortTransfer(); + TransferBusy = 0U; + } + } +#endif + + TraceError[0] = 0U; + TraceError[1] = 0U; + TraceError_n = 0U; + TraceIndexI = 0U; + TraceIndexO = 0U; + +#if (TIMESTAMP_CLOCK != 0U) + TraceTimestamp.index = 0U; + TraceTimestamp.tick = 0U; +#endif +} + +// Resume Trace Capture +static void ResumeTrace(void) +{ + uint32_t index_i; + uint32_t index_o; + + if (TraceStatus == (DAP_SWO_CAPTURE_ACTIVE | DAP_SWO_CAPTURE_PAUSED)) + { + index_i = TraceIndexI; + index_o = TraceIndexO; + if ((index_i - index_o) < SWO_BUFFER_SIZE) + { + index_i &= SWO_BUFFER_SIZE - 1U; + switch (TraceMode) + { +#if (SWO_UART != 0) + case DAP_SWO_UART: + TraceStatus = DAP_SWO_CAPTURE_ACTIVE; + UART_SWO_Capture(&TraceBuf[index_i], 1U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + TraceStatus = DAP_SWO_CAPTURE_ACTIVE; + Manchester_SWO_Capture(&TraceBuf[index_i], 1U); + break; +#endif + default: + break; + } + } + } +} + +// Get Trace Count +// return: number of available data bytes in trace buffer +static uint32_t GetTraceCount(void) +{ + uint32_t count; + + if (TraceStatus == DAP_SWO_CAPTURE_ACTIVE) + { + do + { + TraceUpdate = 0U; + count = TraceIndexI - TraceIndexO; + switch (TraceMode) + { +#if (SWO_UART != 0) + case DAP_SWO_UART: + count += UART_SWO_GetCount(); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + count += Manchester_SWO_GetCount(); + break; +#endif + default: + break; + } + } while (TraceUpdate != 0U); + } + else + { + count = TraceIndexI - TraceIndexO; + } + + return (count); +} + +// Get Trace Status (clear Error flags) +// return: Trace Status (Active flag and Error flags) +static uint8_t GetTraceStatus(void) +{ + uint8_t status; + uint32_t n; + + n = TraceError_n; + TraceError_n ^= 1U; + status = TraceStatus | TraceError[n]; + TraceError[n] = 0U; + + return (status); +} + +// Set Trace Error flag(s) +// flag: error flag(s) to set +void SetTraceError(uint8_t flag) +{ + TraceError[TraceError_n] |= flag; +} + +// Process SWO Transport command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Transport(const uint8_t *request, uint8_t *response) +{ + uint8_t transport; + uint32_t result; + + if ((TraceStatus & DAP_SWO_CAPTURE_ACTIVE) == 0U) + { + transport = *request; + switch (transport) + { + case 0U: + case 1U: +#if (SWO_STREAM != 0) + case 2U: +#endif + TraceTransport = transport; + result = 1U; + break; + default: + result = 0U; + break; + } + } + else + { + result = 0U; + } + + if (result != 0U) + { + *response = DAP_OK; + } + else + { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + +// Process SWO Mode command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Mode(const uint8_t *request, uint8_t *response) +{ + uint8_t mode; + uint32_t result; + + mode = *request; + + switch (TraceMode) + { +#if (SWO_UART != 0) + case DAP_SWO_UART: + UART_SWO_Mode(0U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + Manchester_SWO_Mode(0U); + break; +#endif + default: + break; + } + + switch (mode) + { + case DAP_SWO_OFF: + result = 1U; + break; +#if (SWO_UART != 0) + case DAP_SWO_UART: + result = UART_SWO_Mode(1U); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + result = Manchester_SWO_Mode(1U); + break; +#endif + default: + result = 0U; + break; + } + if (result != 0U) + { + TraceMode = mode; + } + else + { + TraceMode = DAP_SWO_OFF; + } + + TraceStatus = 0U; + + if (result != 0U) + { + *response = DAP_OK; + } + else + { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + +// Process SWO Baudrate command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Baudrate(const uint8_t *request, uint8_t *response) +{ + uint32_t baudrate; + + baudrate = (uint32_t)(*(request + 0) << 0) | + (uint32_t)(*(request + 1) << 8) | + (uint32_t)(*(request + 2) << 16) | + (uint32_t)(*(request + 3) << 24); + + switch (TraceMode) + { +#if (SWO_UART != 0) + case DAP_SWO_UART: + baudrate = UART_SWO_Baudrate(baudrate); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + baudrate = Manchester_SWO_Baudrate(baudrate); + break; +#endif + default: + baudrate = 0U; + break; + } + + if (baudrate == 0U) + { + TraceStatus = 0U; + } + + *response++ = (uint8_t)(baudrate >> 0); + *response++ = (uint8_t)(baudrate >> 8); + *response++ = (uint8_t)(baudrate >> 16); + *response = (uint8_t)(baudrate >> 24); + + return ((4U << 16) | 4U); +} + +// Process SWO Control command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Control(const uint8_t *request, uint8_t *response) +{ + uint8_t active; + uint32_t result; + + active = *request & DAP_SWO_CAPTURE_ACTIVE; + + if (active != (TraceStatus & DAP_SWO_CAPTURE_ACTIVE)) + { + if (active) + { + ClearTrace(); + } + switch (TraceMode) + { +#if (SWO_UART != 0) + case DAP_SWO_UART: + result = UART_SWO_Control(active); + break; +#endif +#if (SWO_MANCHESTER != 0) + case DAP_SWO_MANCHESTER: + result = Manchester_SWO_Control(active); + break; +#endif + default: + result = 0U; + break; + } + if (result != 0U) + { + TraceStatus = active; +#if (SWO_STREAM != 0) + if (TraceTransport == 2U) + { + xEventGroupSetBits(kSWO_Thread_event_group, SWO_GOT_DATA); + } +#endif + } + } + else + { + result = 1U; + } + + if (result != 0U) + { + *response = DAP_OK; + } + else + { + *response = DAP_ERROR; + } + + return ((1U << 16) | 1U); +} + +// Process SWO Status command and prepare response +// response: pointer to response data +// return: number of bytes in response +uint32_t SWO_Status(uint8_t *response) +{ + uint8_t status; + uint32_t count; + + status = GetTraceStatus(); + count = GetTraceCount(); + + *response++ = status; + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + *response++ = (uint8_t)(count >> 16); + *response = (uint8_t)(count >> 24); + + return (5U); +} + +// Process SWO Extended Status command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_ExtendedStatus(const uint8_t *request, uint8_t *response) +{ + uint8_t cmd; + uint8_t status; + uint32_t count; +#if (TIMESTAMP_CLOCK != 0U) + uint32_t index; + uint32_t tick; +#endif + uint32_t num; + + num = 0U; + cmd = *request; + + if (cmd & 0x01U) + { + status = GetTraceStatus(); + *response++ = status; + num += 1U; + } + + if (cmd & 0x02U) + { + count = GetTraceCount(); + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + *response++ = (uint8_t)(count >> 16); + *response++ = (uint8_t)(count >> 24); + num += 4U; + } + +#if (TIMESTAMP_CLOCK != 0U) + if (cmd & 0x04U) + { + do + { + TraceUpdate = 0U; + index = TraceTimestamp.index; + tick = TraceTimestamp.tick; + } while (TraceUpdate != 0U); + *response++ = (uint8_t)(index >> 0); + *response++ = (uint8_t)(index >> 8); + *response++ = (uint8_t)(index >> 16); + *response++ = (uint8_t)(index >> 24); + *response++ = (uint8_t)(tick >> 0); + *response++ = (uint8_t)(tick >> 8); + *response++ = (uint8_t)(tick >> 16); + *response++ = (uint8_t)(tick >> 24); + num += 4U; + } +#endif + + return ((1U << 16) | num); +} + +// Process SWO Data command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response (lower 16 bits) +// number of bytes in request (upper 16 bits) +uint32_t SWO_Data(const uint8_t *request, uint8_t *response) +{ + uint8_t status; + uint32_t count; + uint32_t index; + uint32_t n, i; + + status = GetTraceStatus(); + count = GetTraceCount(); + + if (TraceTransport == 1U) + { + n = (uint32_t)(*(request + 0) << 0) | + (uint32_t)(*(request + 1) << 8); + if (n > (DAP_PACKET_SIZE - 4U)) + { + n = DAP_PACKET_SIZE - 4U; + } + if (count > n) + { + count = n; + } + } + else + { + count = 0U; + } + + *response++ = status; + *response++ = (uint8_t)(count >> 0); + *response++ = (uint8_t)(count >> 8); + + if (TraceTransport == 1U) + { + index = TraceIndexO; + for (i = index, n = count; n; n--) + { + i &= SWO_BUFFER_SIZE - 1U; + *response++ = TraceBuf[i++]; + } + TraceIndexO = index + count; + ResumeTrace(); + } + + return ((2U << 16) | (3U + count)); +} + +#if (SWO_STREAM != 0) + +// SWO Data Transfer complete callback +void SWO_TransferComplete(void) +{ + TraceIndexO += TransferSize; + TransferBusy = 0U; + ResumeTrace(); + xEventGroupSetBits(kSWO_Thread_event_group, SWO_GOT_DATA); +} + +// SWO Thread +void SWO_Thread(void *argument) +{ + uint32_t timeout; + uint32_t flags; + uint32_t count; + uint32_t index; + uint32_t i, n; + (void)argument; + + timeout = portMAX_DELAY; + + kSWO_Thread_event_group = xEventGroupCreate(); + for (;;) + { + flags = xEventGroupWaitBits(kSWO_Thread_event_group, SWO_GOT_DATA | SWO_ERROR_TIME_OUT, + pdTRUE, pdFALSE, timeout); + if (TraceStatus & DAP_SWO_CAPTURE_ACTIVE) + { + timeout = SWO_STREAM_TIMEOUT; + } + else + { + timeout = portMAX_DELAY; + flags = SWO_ERROR_TIME_OUT; + } + if (TransferBusy == 0U) + { + count = GetTraceCount(); + if (count != 0U) + { + index = TraceIndexO & (SWO_BUFFER_SIZE - 1U); + n = SWO_BUFFER_SIZE - index; + if (count > n) + { + count = n; + } + if ((flags & SWO_ERROR_TIME_OUT) == 0) + { + i = index & (USB_BLOCK_SIZE - 1U); + if (i == 0U) + { + count &= ~(USB_BLOCK_SIZE - 1U); + // Take down to the nearest number that is a multiple of USB_BLOCK_SIZE + } + else + { + n = USB_BLOCK_SIZE - i; + if (count >= n) + { + count = n; + } + else + { + count = 0U; + } + } + } + if (count != 0U) + { + TransferSize = count; + TransferBusy = 1U; + SWO_QueueTransfer(&TraceBuf[index], count); //through USB + } + } + } + } +} + +#endif /* (SWO_STREAM != 0) */ + +#endif /* ((SWO_UART != 0) || (SWO_MANCHESTER != 0)) */ diff --git a/components/DAP/source/SW_DP.c b/components/DAP/source/SW_DP.c new file mode 100644 index 0000000..803cf42 --- /dev/null +++ b/components/DAP/source/SW_DP.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2013-2017 ARM Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ---------------------------------------------------------------------- + * + * $Date: 1. December 2017 + * $Revision: V2.0.0 + * + * Project: CMSIS-DAP Source + * Title: SW_DP.c CMSIS-DAP SW DP I/O + * + *---------------------------------------------------------------------------*/ + +#include "DAP_config.h" +#include "DAP.h" + + +// SW Macros + +#define PIN_SWCLK_SET PIN_SWCLK_TCK_SET +#define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR + +#define SW_CLOCK_CYCLE() \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define SW_WRITE_BIT(bit) \ + PIN_SWDIO_OUT(bit); \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define SW_READ_BIT(bit) \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + bit = PIN_SWDIO_IN(); \ + PIN_SWCLK_SET(); \ + PIN_DELAY() + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + + +// Generate SWJ Sequence +// count: sequence bit count +// data: pointer to sequence bit data +// return: none +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +void SWJ_Sequence (uint32_t count, const uint8_t *data) { + uint32_t val; + uint32_t n; + + val = 0U; + n = 0U; + while (count--) { + if (n == 0U) { + val = *data++; + n = 8U; + } + if (val & 1U) { + PIN_SWDIO_TMS_SET(); + } else { + PIN_SWDIO_TMS_CLR(); + } + SW_CLOCK_CYCLE(); + val >>= 1; + n--; + } +} +#endif + + +// Generate SWD Sequence +// info: sequence information +// swdo: pointer to SWDIO generated data +// swdi: pointer to SWDIO captured data +// return: none +#if (DAP_SWD != 0) +void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) { + uint32_t val; + uint32_t bit; + uint32_t n, k; + + n = info & SWD_SEQUENCE_CLK; + if (n == 0U) { + n = 64U; + } + + if (info & SWD_SEQUENCE_DIN) { + while (n) { + val = 0U; + for (k = 8U; k && n; k--, n--) { + SW_READ_BIT(bit); + val >>= 1; + val |= bit << 7; + } + val >>= k; + *swdi++ = (uint8_t)val; + } + } else { + while (n) { + val = *swdo++; + for (k = 8U; k && n; k--, n--) { + SW_WRITE_BIT(val); + val >>= 1; + } + } + } +} +#endif + + +#if (DAP_SWD != 0) + + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +#define SWD_TransferFunction(speed) /**/ \ +static uint8_t SWD_Transfer##speed (uint32_t request, uint32_t *data) { \ + uint32_t ack; \ + uint32_t bit; \ + uint32_t val; \ + uint32_t parity; \ + \ + uint32_t n; \ + \ + /* Packet Request */ \ + parity = 0U; \ + SW_WRITE_BIT(1U); /* Start Bit */ \ + bit = request >> 0; \ + SW_WRITE_BIT(bit); /* APnDP Bit */ \ + parity += bit; \ + bit = request >> 1; \ + SW_WRITE_BIT(bit); /* RnW Bit */ \ + parity += bit; \ + bit = request >> 2; \ + SW_WRITE_BIT(bit); /* A2 Bit */ \ + parity += bit; \ + bit = request >> 3; \ + SW_WRITE_BIT(bit); /* A3 Bit */ \ + parity += bit; \ + SW_WRITE_BIT(parity); /* Parity Bit */ \ + SW_WRITE_BIT(0U); /* Stop Bit */ \ + SW_WRITE_BIT(1U); /* Park Bit */ \ + \ + /* Turnaround */ \ + PIN_SWDIO_OUT_DISABLE(); \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + \ + /* Acknowledge response */ \ + SW_READ_BIT(bit); \ + ack = bit << 0; \ + SW_READ_BIT(bit); \ + ack |= bit << 1; \ + SW_READ_BIT(bit); \ + ack |= bit << 2; \ + \ + if (ack == DAP_TRANSFER_OK) { /* OK response */ \ + /* Data transfer */ \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read data */ \ + val = 0U; \ + parity = 0U; \ + for (n = 32U; n; n--) { \ + SW_READ_BIT(bit); /* Read RDATA[0:31] */ \ + parity += bit; \ + val >>= 1; \ + val |= bit << 31; \ + } \ + SW_READ_BIT(bit); /* Read Parity */ \ + if ((parity ^ bit) & 1U) { \ + ack = DAP_TRANSFER_ERROR; \ + } \ + if (data) { *data = val; } \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + } else { \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + /* Write data */ \ + val = *data; \ + parity = 0U; \ + for (n = 32U; n; n--) { \ + SW_WRITE_BIT(val); /* Write WDATA[0:31] */ \ + parity += val; \ + val >>= 1; \ + } \ + SW_WRITE_BIT(parity); /* Write Parity Bit */ \ + } \ + /* Capture Timestamp */ \ + if (request & DAP_TRANSFER_TIMESTAMP) { \ + DAP_Data.timestamp = TIMESTAMP_GET(); \ + } \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + if (n) { \ + PIN_SWDIO_OUT(0U); \ + for (; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + } \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ + } \ + \ + if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { \ + /* WAIT or FAULT response */ \ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0U)) { \ + for (n = 32U+1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Dummy Read RDATA[0:31] + Parity */ \ + } \ + } \ + /* Turnaround */ \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) { \ + PIN_SWDIO_OUT(0U); \ + for (n = 32U+1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */ \ + } \ + } \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ + } \ + \ + /* Protocol error */ \ + for (n = DAP_Data.swd_conf.turnaround + 32U + 1U; n; n--) { \ + SW_CLOCK_CYCLE(); /* Back off data phase */ \ + } \ + PIN_SWDIO_OUT_ENABLE(); \ + PIN_SWDIO_OUT(1U); \ + return ((uint8_t)ack); \ +} + + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_FAST() +SWD_TransferFunction(Fast) + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +SWD_TransferFunction(Slow) + + +// SWD Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t SWD_Transfer(uint32_t request, uint32_t *data) { + if (DAP_Data.fast_clock) { + return SWD_TransferFast(request, data); + } else { + return SWD_TransferSlow(request, data); + } +} + + +#endif /* (DAP_SWD != 0) */ diff --git a/components/DAP/source/uart_modify.c b/components/DAP/source/uart_modify.c new file mode 100644 index 0000000..e485482 --- /dev/null +++ b/components/DAP/source/uart_modify.c @@ -0,0 +1,1256 @@ +/** + * @brief Made some simple modifications to the official UART + * + */ + +// Copyright 2018-2025 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/ringbuf.h" +#include "freertos/event_groups.h" + +#include "esp_err.h" +#include "esp_log.h" +#include "esp_attr.h" + +// SWO modify +#include "DAP_config.h" +#include "esp8266/uart_struct.h" +#include "esp8266/uart_register.h" +#include "esp8266/pin_mux_register.h" +#include "esp8266/eagle_soc.h" +#include "esp8266/rom_functions.h" + +#include "rom/ets_sys.h" + +#include "uart_modify.h" +#include "driver/uart_select.h" + +#define portYIELD_FROM_ISR() taskYIELD() + +#define UART_ENTER_CRITICAL() portENTER_CRITICAL() +#define UART_EXIT_CRITICAL() portEXIT_CRITICAL() + +static const char *UART_TAG = "uart"; +#define UART_CHECK(a, str, ret_val) \ + if (!(a)) \ + { \ + ESP_LOGE(UART_TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +#define UART_EMPTY_THRESH_DEFAULT (10) +#define UART_FULL_THRESH_DEFAULT (120) +#define UART_TOUT_THRESH_DEFAULT (10) + +typedef struct +{ + uart_event_type_t type; /*!< UART TX data type */ + struct + { + size_t size; + uint8_t data[0]; + } tx_data; +} uart_tx_data_t; + +typedef struct +{ + uart_port_t uart_num; /*!< UART port number*/ + int queue_size; /*!< UART event queue size*/ + QueueHandle_t xQueueUart; /*!< UART queue handler*/ + uart_mode_t uart_mode; /*!< UART controller actual mode set by uart_set_mode() */ + + // rx parameters + int rx_buffered_len; /*!< UART cached data length */ + SemaphoreHandle_t rx_mux; /*!< UART RX data mutex*/ + int rx_buf_size; /*!< RX ring buffer size */ + RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/ + bool rx_buffer_full_flg; /*!< RX ring buffer full flag. */ + int rx_cur_remain; /*!< Data number that waiting to be read out in ring buffer item*/ + uint8_t *rx_ptr; /*!< pointer to the current data in ring buffer*/ + uint8_t *rx_head_ptr; /*!< pointer to the head of RX item*/ + uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/ + uint8_t rx_stash_len; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */ + + // tx parameters + SemaphoreHandle_t tx_fifo_sem; /*!< UART TX FIFO semaphore*/ + SemaphoreHandle_t tx_done_sem; /*!< UART TX done semaphore*/ + SemaphoreHandle_t tx_mux; /*!< UART TX mutex*/ + int tx_buf_size; /*!< TX ring buffer size */ + RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler*/ + bool tx_waiting_fifo; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/ + uint8_t *tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/ + uart_tx_data_t *tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/ + uint32_t tx_len_tot; /*!< Total length of current item in ring buffer*/ + uint32_t tx_len_cur; + bool wait_tx_done_flg; + uart_select_notif_callback_t uart_select_notif_callback; /*!< Notification about select() events */ +} uart_obj_t; + +static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; +// DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR +static DRAM_ATTR uart_dev_t *const UART[UART_NUM_MAX] = {&uart0, &uart1}; + +typedef void (*uart_isr_t)(void *); +typedef struct +{ + uart_isr_t fn; /*!< isr function */ + void *args; /*!< isr function args */ +} uart_isr_func_t; + +static uart_isr_func_t uart_isr_func[UART_NUM_MAX]; + +// SWO modify +extern EventGroupHandle_t kUART_Monitoe_event_group; +#define UART_GOT_DATA BIT0 +extern void SetTraceError(uint8_t flag); +#define DAP_SWO_CAPTURE_ACTIVE (1U << 0) +#define DAP_SWO_CAPTURE_PAUSED (1U << 1) +#define DAP_SWO_STREAM_ERROR (1U << 6) +#define DAP_SWO_BUFFER_OVERRUN (1U << 7) +// + +esp_err_t my_uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->conf0.bit_num = data_bit; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_get_word_length(uart_port_t uart_num, uart_word_length_t *data_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((data_bit), "empty pointer", ESP_FAIL); + + *(data_bit) = UART[uart_num]->conf0.bit_num; + return ESP_OK; +} + +esp_err_t my_uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->conf0.stop_bit_num = stop_bit; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t *stop_bit) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((stop_bit), "empty pointer", ESP_FAIL); + + (*stop_bit) = UART[uart_num]->conf0.stop_bit_num; + return ESP_OK; +} + +esp_err_t my_uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK(((parity_mode == UART_PARITY_DISABLE) || (parity_mode == UART_PARITY_EVEN) || (parity_mode == UART_PARITY_ODD)), + "parity_mode error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->conf0.parity = (parity_mode & 0x1); + UART[uart_num]->conf0.parity_en = ((parity_mode >> 1) & 0x1); + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_get_parity(uart_port_t uart_num, uart_parity_t *parity_mode) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((parity_mode), "empty pointer", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + + if (UART[uart_num]->conf0.parity_en) + { + if (UART[uart_num]->conf0.parity) + { + (*parity_mode) = UART_PARITY_ODD; + } + else + { + (*parity_mode) = UART_PARITY_EVEN; + } + } + else + { + (*parity_mode) = UART_PARITY_DISABLE; + } + + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->clk_div.val = (uint32_t)(UART_CLK_FREQ / baud_rate) & 0xFFFFF; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_get_baudrate(uart_port_t uart_num, uint32_t *baudrate) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((baudrate), "empty pointer", ESP_ERR_INVALID_ARG); + + (*baudrate) = (UART_CLK_FREQ / (UART[uart_num]->clk_div.val & 0xFFFFF)); + return ESP_OK; +} + +esp_err_t my_uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((((inverse_mask & ~UART_LINE_INV_MASK) == 0) || (inverse_mask == 0)), "inverse_mask error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->conf0.val &= ~UART_LINE_INV_MASK; + UART[uart_num]->conf0.val |= inverse_mask; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "uart_flow ctrl error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + + if (flow_ctrl & UART_HW_FLOWCTRL_RTS) + { + UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh; + UART[uart_num]->conf1.rx_flow_en = 1; + } + else + { + UART[uart_num]->conf1.rx_flow_en = 0; + } + + if (flow_ctrl & UART_HW_FLOWCTRL_CTS) + { + UART[uart_num]->conf0.tx_flow_en = 1; + } + else + { + UART[uart_num]->conf0.tx_flow_en = 0; + } + + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t *flow_ctrl) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE; + + if (UART[uart_num]->conf1.rx_flow_en) + { + val |= UART_HW_FLOWCTRL_RTS; + } + + if (UART[uart_num]->conf0.tx_flow_en) + { + val |= UART_HW_FLOWCTRL_CTS; + } + + (*flow_ctrl) = val; + return ESP_OK; +} + +esp_err_t my_uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_ARG); + uint32_t baudrate; + uint32_t byte_delay_us = 0; + BaseType_t res; + portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait; + + // Take tx_mux + res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait); + if (res == pdFALSE) + { + return ESP_ERR_TIMEOUT; + } + + if (false == p_uart_obj[uart_num]->wait_tx_done_flg) + { + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_OK; + } + + my_uart_get_baudrate(uart_num, &baudrate); + byte_delay_us = (uint32_t)(10000000 / baudrate); // (1/baudrate)*10*1000_000 us + + ticks_to_wait = ticks_end - xTaskGetTickCount(); + // wait for tx done sem. + if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, ticks_to_wait)) + { + while (1) + { + if (UART[uart_num]->status.txfifo_cnt == 0) + { + ets_delay_us(byte_delay_us); // Delay one byte time to guarantee transmission completion + break; + } + } + p_uart_obj[uart_num]->wait_tx_done_flg = false; + } + else + { + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_ERR_TIMEOUT; + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return ESP_OK; +} + +esp_err_t my_uart_enable_swap(void) +{ + // wait for tx done. + my_uart_wait_tx_done(UART_NUM_0, portMAX_DELAY); + + UART_ENTER_CRITICAL(); + // MTCK -> UART0_CTS -> U0RXD + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS); + // MTD0 -> UART0_RTS -> U0TXD + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_UART0_RTS); + // enable swap U0TXD <-> UART0_RTS and U0RXD <-> UART0_CTS + SET_PERI_REG_MASK(UART_SWAP_REG, 0x4); + UART_EXIT_CRITICAL(); + + return ESP_OK; +} + +esp_err_t my_uart_disable_swap(void) +{ + // wait for tx done. + my_uart_wait_tx_done(UART_NUM_0, portMAX_DELAY); + + UART_ENTER_CRITICAL(); + // disable swap U0TXD <-> UART0_RTS and U0RXD <-> UART0_CTS + CLEAR_PERI_REG_MASK(UART_SWAP_REG, 0x4); + UART_EXIT_CRITICAL(); + + return ESP_OK; +} + +static esp_err_t uart_reset_rx_fifo(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->conf0.rxfifo_rst = 0x1; + UART[uart_num]->conf0.rxfifo_rst = 0x0; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_clear_intr_status(uart_port_t uart_num, uint32_t mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->int_clr.val |= mask; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->int_ena.val |= enable_mask; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->int_ena.val &= ~disable_mask; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_enable_rx_intr(uart_port_t uart_num) +{ + return my_uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA); +} + +esp_err_t my_uart_disable_rx_intr(uart_port_t uart_num) +{ + return my_uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA); +} + +esp_err_t my_uart_disable_tx_intr(uart_port_t uart_num) +{ + return my_uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA); +} + +esp_err_t my_uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + UART[uart_num]->int_clr.txfifo_empty = 1; + UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & 0x7f; + UART[uart_num]->int_ena.txfifo_empty = enable & 0x1; + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +static void uart_intr_service(void *arg) +{ + // UART intr process + uint32_t uart_num = 0; + // read status to get interrupt status for UART0-1 + uint32_t uart_intr_status = UART[uart_num]->int_st.val; + + if (uart_isr_func == NULL) + { + return; + } + + do + { + uart_intr_status = UART[uart_num]->int_st.val; + if (uart_intr_status != 0) + { + if (uart_isr_func[uart_num].fn != NULL) + { + uart_isr_func[uart_num].fn(uart_isr_func[uart_num].args); + } + } + } while (++uart_num < UART_NUM_MAX); +} + +esp_err_t my_uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + _xt_isr_mask(1 << ETS_UART_INUM); + _xt_isr_attach(ETS_UART_INUM, uart_intr_service, NULL); + uart_isr_func[uart_num].fn = fn; + uart_isr_func[uart_num].args = arg; + _xt_isr_unmask(1 << ETS_UART_INUM); + UART_EXIT_CRITICAL(); + return ESP_OK; +} + +esp_err_t my_uart_param_config(uart_port_t uart_num, uart_config_t *uart_conf) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + if (uart_num == UART_NUM_1) + { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } + else + { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD); + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); + + if (uart_conf->flow_ctrl & UART_HW_FLOWCTRL_RTS) + { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); + } + + if (uart_conf->flow_ctrl & UART_HW_FLOWCTRL_CTS) + { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS); + } + + my_uart_set_hw_flow_ctrl(uart_num, uart_conf->flow_ctrl, uart_conf->rx_flow_ctrl_thresh); + } + + my_uart_set_baudrate(uart_num, uart_conf->baud_rate); + my_uart_set_word_length(uart_num, uart_conf->data_bits); + my_uart_set_stop_bits(uart_num, uart_conf->stop_bits); + my_uart_set_parity(uart_num, uart_conf->parity); + uart_reset_rx_fifo(uart_num); + + return ESP_OK; +} + +esp_err_t my_uart_intr_config(uart_port_t uart_num, uart_intr_config_t *intr_conf) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + my_uart_clear_intr_status(uart_num, UART_INTR_MASK); + UART_ENTER_CRITICAL(); + UART[uart_num]->int_clr.val = UART_INTR_MASK; + + if (intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) + { + UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & 0x7f); + UART[uart_num]->conf1.rx_tout_en = 1; + } + else + { + UART[uart_num]->conf1.rx_tout_en = 0; + } + + if (intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) + { + UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh; + } + + if (intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) + { + UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh; + } + + // my_uart_clear_intr_status(UART[uart_num], mask); + UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask; + _xt_isr_unmask(0x1 << ETS_UART_INUM); + UART_EXIT_CRITICAL(); + + return ESP_OK; +} + +// internal isr handler for default driver code. +static void uart_rx_intr_handler_default(void *param) +{ + uart_obj_t *p_uart = (uart_obj_t *)param; + uint8_t uart_num = p_uart->uart_num; + uart_dev_t *uart_reg = UART[uart_num]; + int rx_fifo_len = uart_reg->status.rxfifo_cnt; + uint8_t buf_idx = 0; + uint32_t uart_intr_status = UART[uart_num]->int_st.val; + uart_event_t uart_event; + BaseType_t task_woken = 0; + + + while (uart_intr_status != 0x0) + { + uart_select_notif_t notify = UART_SELECT_ERROR_NOTIF; + + buf_idx = 0; + uart_event.type = UART_EVENT_MAX; + + if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) + { + my_uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); + my_uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M); + + // TX semaphore will only be used when tx_buf_size is zero. + if (p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) + { + p_uart->tx_waiting_fifo = false; + xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &task_woken); + + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } + else + { + // We don't use TX ring buffer, because the size is zero. + if (p_uart->tx_buf_size == 0) + { + continue; + } + + int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt; + bool en_tx_flg = false; + + // We need to put a loop here, in case all the buffer items are very short. + // That would cause a watch_dog reset because empty interrupt happens so often. + // Although this is a loop in ISR, this loop will execute at most 128 turns. + while (tx_fifo_rem) + { + if (p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) + { + size_t size; + p_uart->tx_head = (uart_tx_data_t *)xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size); + + if (p_uart->tx_head) + { + // The first item is the data description + // Get the first item to get the data information + if (p_uart->tx_len_tot == 0) + { + p_uart->tx_ptr = NULL; + p_uart->tx_len_tot = p_uart->tx_head->tx_data.size; + // We have saved the data description from the 1st item, return buffer. + vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &task_woken); + + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } + else if (p_uart->tx_ptr == NULL) + { + // Update the TX item pointer, we will need this to return item to buffer. + p_uart->tx_ptr = (uint8_t *)p_uart->tx_head; + en_tx_flg = true; + p_uart->tx_len_cur = size; + } + } + else + { + // Can not get data from ring buffer, return; + break; + } + } + + if (p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) + { + // To fill the TX FIFO. + int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur; + + for (buf_idx = 0; buf_idx < send_len; buf_idx++) + { + UART[uart_num]->fifo.rw_byte = *(p_uart->tx_ptr++) & 0xff; + } + + p_uart->tx_len_tot -= send_len; + p_uart->tx_len_cur -= send_len; + tx_fifo_rem -= send_len; + + if (p_uart->tx_len_cur == 0) + { + // Return item to ring buffer. + vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &task_woken); + + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + + p_uart->tx_head = NULL; + p_uart->tx_ptr = NULL; + } + + if (p_uart->tx_len_tot == 0) + { + en_tx_flg = false; + xSemaphoreGiveFromISR(p_uart->tx_done_sem, &task_woken); + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } + else + { + en_tx_flg = true; + } + } + } + + if (en_tx_flg) + { + my_uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); + my_uart_enable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M); + } + } + } + else if ((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)) + { + rx_fifo_len = uart_reg->status.rxfifo_cnt; + + if (p_uart->rx_buffer_full_flg == false) + { + // We have to read out all data in RX FIFO to clear the interrupt signal + while (buf_idx < rx_fifo_len) + { + p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte; + } + + // Get the buffer from the FIFO + // After Copying the Data From FIFO ,Clear intr_status + my_uart_clear_intr_status(uart_num, UART_RXFIFO_TOUT_INT_CLR_M | UART_RXFIFO_FULL_INT_CLR_M); + uart_event.type = UART_DATA; + uart_event.size = rx_fifo_len; + p_uart->rx_stash_len = rx_fifo_len; + + // If we fail to push data to ring buffer, we will have to stash the data, and send next time. + // Mainly for applications that uses flow control or small ring buffer. + if (pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &task_woken)) + { + my_uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M); + uart_event.type = UART_BUFFER_FULL; + p_uart->rx_buffer_full_flg = true; + // SWO modify + // When we cannot write to the ring buffer, we also think that the serial port is "overflow". + SetTraceError(DAP_SWO_BUFFER_OVERRUN); + } + else + { + p_uart->rx_buffered_len += p_uart->rx_stash_len; + xEventGroupSetBitsFromISR(kUART_Monitoe_event_group, UART_GOT_DATA, pdFALSE); + } + + notify = UART_SELECT_READ_NOTIF; + + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } + else + { + my_uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M); + my_uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M); + } + } + else if (uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) + { + // When fifo overflows, we reset the fifo. + uart_reset_rx_fifo(uart_num); + uart_reg->int_clr.rxfifo_ovf = 1; + uart_event.type = UART_FIFO_OVF; + notify = UART_SELECT_ERROR_NOTIF; + // SWO modify + // Unfortunately, Overflow occurs usually there is no flow control. + // Although the overflow situation often occurs, + // the buffer stability of the serial port is better, + // and there is basically no data loss. + ////TODO: Can we get rid of this code? + SetTraceError(DAP_SWO_BUFFER_OVERRUN); + } + else if (uart_intr_status & UART_FRM_ERR_INT_ST_M) + { + uart_reg->int_clr.frm_err = 1; + uart_event.type = UART_FRAME_ERR; + notify = UART_SELECT_ERROR_NOTIF; + // SWO modify + SetTraceError(DAP_SWO_STREAM_ERROR); + } + else if (uart_intr_status & UART_PARITY_ERR_INT_ST_M) + { + uart_reg->int_clr.parity_err = 1; + uart_event.type = UART_PARITY_ERR; + notify = UART_SELECT_ERROR_NOTIF; + // SWO modify + SetTraceError(DAP_SWO_STREAM_ERROR); + } + else + { + uart_reg->int_clr.val = uart_intr_status; // simply clear all other intr status + uart_event.type = UART_EVENT_MAX; + notify = UART_SELECT_ERROR_NOTIF; + // SWO modify + SetTraceError(DAP_SWO_STREAM_ERROR); + } + +#ifdef CONFIG_USING_ESP_VFS + if (uart_event.type != UART_EVENT_MAX && p_uart->uart_select_notif_callback) + { + p_uart->uart_select_notif_callback(uart_num, notify, &task_woken); + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } +#else + (void)notify; +#endif + + if (uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) + { + if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void *)&uart_event, &task_woken)) + { + ESP_EARLY_LOGV(UART_TAG, "UART event queue full"); + } + + if (task_woken == pdTRUE) + { + portYIELD_FROM_ISR(); + } + } + + uart_intr_status = uart_reg->int_st.val; + } +} + +// Fill UART tx_fifo and return a number, +// This function by itself is not thread-safe, always call from within a muxed section. +static int uart_fill_fifo(uart_port_t uart_num, const char *buffer, uint32_t len) +{ + uint8_t i = 0; + uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt; + uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt); + uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len); + + for (i = 0; i < copy_cnt; i++) + { + UART[uart_num]->fifo.rw_byte = buffer[i]; + } + + return copy_cnt; +} + +int my_uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + UART_CHECK(buffer, "buffer null", (-1)); + + if (len == 0) + { + return 0; + } + + xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); + int tx_len = uart_fill_fifo(uart_num, (const char *)buffer, len); + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return tx_len; +} + +static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size) +{ + if (size == 0) + { + return 0; + } + + size_t original_size = size; + + // lock for uart_tx + xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); + p_uart_obj[uart_num]->wait_tx_done_flg = true; + if (p_uart_obj[uart_num]->tx_buf_size > 0) + { + int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf); + int offset = 0; + uart_tx_data_t evt; + evt.tx_data.size = size; + evt.type = UART_DATA; + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void *)&evt, sizeof(uart_tx_data_t), portMAX_DELAY); + + while (size > 0) + { + int send_size = size > max_size / 2 ? max_size / 2 : size; + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void *)(src + offset), send_size, portMAX_DELAY); + size -= send_size; + offset += send_size; + my_uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); + } + } + else + { + while (size) + { + // semaphore for tx_fifo available + if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) + { + size_t sent = uart_fill_fifo(uart_num, (char *)src, size); + + if (sent < size) + { + p_uart_obj[uart_num]->tx_waiting_fifo = true; + my_uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); + } + + size -= sent; + src += sent; + } + } + + xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); + xSemaphoreGive(p_uart_obj[uart_num]->tx_done_sem); + } + xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); + return original_size; +} + +int my_uart_write_bytes(uart_port_t uart_num, const char *src, size_t size) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + UART_CHECK(src, "buffer null", (-1)); + + return uart_tx_all(uart_num, src, size); +} + +int my_uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickType_t ticks_to_wait) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); + UART_CHECK((buf), "uart data null", (-1)); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); + + uint8_t *data = NULL; + size_t size; + size_t copy_len = 0; + int len_tmp; + + if (xSemaphoreTake(p_uart_obj[uart_num]->rx_mux, (portTickType)ticks_to_wait) != pdTRUE) + { + return -1; + } + + while (length) + { + if (p_uart_obj[uart_num]->rx_cur_remain == 0) + { + data = (uint8_t *)xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType)ticks_to_wait); + + if (data) + { + p_uart_obj[uart_num]->rx_head_ptr = data; + p_uart_obj[uart_num]->rx_ptr = data; + p_uart_obj[uart_num]->rx_cur_remain = size; + } + else + { + xSemaphoreGive(p_uart_obj[uart_num]->rx_mux); + return copy_len; + } + } + + if (p_uart_obj[uart_num]->rx_cur_remain > length) + { + len_tmp = length; + } + else + { + len_tmp = p_uart_obj[uart_num]->rx_cur_remain; + } + + memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp); + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffered_len -= len_tmp; + p_uart_obj[uart_num]->rx_ptr += len_tmp; + UART_EXIT_CRITICAL(); + p_uart_obj[uart_num]->rx_cur_remain -= len_tmp; + copy_len += len_tmp; + length -= len_tmp; + + if (p_uart_obj[uart_num]->rx_cur_remain == 0) + { + vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr); + p_uart_obj[uart_num]->rx_head_ptr = NULL; + p_uart_obj[uart_num]->rx_ptr = NULL; + + if (p_uart_obj[uart_num]->rx_buffer_full_flg) + { + BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); + + if (res == pdTRUE) + { + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + UART_EXIT_CRITICAL(); + my_uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num); + } + } + } + } + + xSemaphoreGive(p_uart_obj[uart_num]->rx_mux); + return copy_len; +} + +esp_err_t my_uart_get_buffered_data_len(uart_port_t uart_num, size_t *size) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_ARG); + + *size = p_uart_obj[uart_num]->rx_buffered_len; + return ESP_OK; +} + +esp_err_t my_uart_flush(uart_port_t uart_num) __attribute__((alias("my_uart_flush_input"))); + +esp_err_t my_uart_flush_input(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_ARG); + uart_obj_t *p_uart = p_uart_obj[uart_num]; + uint8_t *data; + size_t size; + + // rx sem protect the ring buffer read related functions + xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY); + my_uart_disable_rx_intr(p_uart_obj[uart_num]->uart_num); + + while (true) + { + if (p_uart->rx_head_ptr) + { + vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr); + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffered_len -= p_uart->rx_cur_remain; + UART_EXIT_CRITICAL(); + p_uart->rx_ptr = NULL; + p_uart->rx_cur_remain = 0; + p_uart->rx_head_ptr = NULL; + } + + data = (uint8_t *)xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType)0); + + if (data == NULL) + { + if (p_uart_obj[uart_num]->rx_buffered_len != 0) + { + ESP_LOGE(UART_TAG, "rx_buffered_len error"); + p_uart_obj[uart_num]->rx_buffered_len = 0; + } + + // We also need to clear the `rx_buffer_full_flg` here. + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + UART_EXIT_CRITICAL(); + break; + } + + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffered_len -= size; + UART_EXIT_CRITICAL(); + vRingbufferReturnItem(p_uart->rx_ring_buf, data); + + if (p_uart_obj[uart_num]->rx_buffer_full_flg) + { + BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); + + if (res == pdTRUE) + { + UART_ENTER_CRITICAL(); + p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + UART_EXIT_CRITICAL(); + } + } + } + + p_uart->rx_ptr = NULL; + p_uart->rx_cur_remain = 0; + p_uart->rx_head_ptr = NULL; + uart_reset_rx_fifo(uart_num); + my_uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num); + xSemaphoreGive(p_uart->rx_mux); + return ESP_OK; +} + +esp_err_t my_uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int no_use) +{ + esp_err_t r; + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((rx_buffer_size > UART_FIFO_LEN) || ((uart_num == UART_NUM_1) && (rx_buffer_size == 0)), "uart rx buffer length error(>128)", ESP_ERR_INVALID_ARG); + UART_CHECK((tx_buffer_size > UART_FIFO_LEN) || (tx_buffer_size == 0), "uart tx buffer length error(>128 or 0)", ESP_ERR_INVALID_ARG); + UART_CHECK((queue_size >= 0), "queue_size error(>=0)", ESP_ERR_INVALID_ARG); + + if (p_uart_obj[uart_num] == NULL) + { + p_uart_obj[uart_num] = (uart_obj_t *)calloc(1, sizeof(uart_obj_t)); + + if (p_uart_obj[uart_num] == NULL) + { + ESP_LOGE(UART_TAG, "UART driver malloc error"); + return ESP_FAIL; + } + + p_uart_obj[uart_num]->uart_num = uart_num; + p_uart_obj[uart_num]->uart_mode = UART_MODE_UART; + p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary(); + p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary(); + xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); + p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex(); + p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex(); + p_uart_obj[uart_num]->queue_size = queue_size; + p_uart_obj[uart_num]->tx_ptr = NULL; + p_uart_obj[uart_num]->tx_head = NULL; + p_uart_obj[uart_num]->tx_len_tot = 0; + p_uart_obj[uart_num]->rx_buffered_len = 0; + p_uart_obj[uart_num]->wait_tx_done_flg = false; + + if (uart_queue) + { + p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t)); + *uart_queue = p_uart_obj[uart_num]->xQueueUart; + ESP_LOGI(UART_TAG, "queue free spaces: %d", (int)uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart)); + } + else + { + p_uart_obj[uart_num]->xQueueUart = NULL; + } + + p_uart_obj[uart_num]->rx_buffer_full_flg = false; + p_uart_obj[uart_num]->tx_waiting_fifo = false; + p_uart_obj[uart_num]->rx_ptr = NULL; + p_uart_obj[uart_num]->rx_cur_remain = 0; + p_uart_obj[uart_num]->rx_head_ptr = NULL; + p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF); + p_uart_obj[uart_num]->rx_buf_size = rx_buffer_size; + + if (tx_buffer_size > 0) + { + p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT); + p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size; + } + else + { + p_uart_obj[uart_num]->tx_ring_buf = NULL; + p_uart_obj[uart_num]->tx_buf_size = 0; + } + + p_uart_obj[uart_num]->uart_select_notif_callback = NULL; + } + else + { + ESP_LOGE(UART_TAG, "UART driver already installed"); + return ESP_FAIL; + } + + r = my_uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num]); + + if (r != ESP_OK) + { + goto err; + } + + uart_intr_config_t uart_intr = { + .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M, + .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT, + .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT, + .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT}; + r = my_uart_intr_config(uart_num, &uart_intr); + + if (r != ESP_OK) + { + goto err; + } + + return r; + +err: + ESP_LOGE(UART_TAG, "driver install error"); + my_uart_driver_delete(uart_num); + return r; +} + +// Make sure no other tasks are still using UART before you call this function +esp_err_t my_uart_driver_delete(uart_port_t uart_num) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + + if (p_uart_obj[uart_num] == NULL) + { + ESP_LOGI(UART_TAG, "ALREADY NULL"); + return ESP_OK; + } + + my_uart_disable_rx_intr(uart_num); + my_uart_disable_tx_intr(uart_num); + _xt_isr_mask(0x1 << ETS_UART_INUM); + + if (p_uart_obj[uart_num]->tx_fifo_sem) + { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem); + p_uart_obj[uart_num]->tx_fifo_sem = NULL; + } + + if (p_uart_obj[uart_num]->tx_done_sem) + { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem); + p_uart_obj[uart_num]->tx_done_sem = NULL; + } + + if (p_uart_obj[uart_num]->tx_mux) + { + vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux); + p_uart_obj[uart_num]->tx_mux = NULL; + } + + if (p_uart_obj[uart_num]->rx_mux) + { + vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux); + p_uart_obj[uart_num]->rx_mux = NULL; + } + + if (p_uart_obj[uart_num]->xQueueUart) + { + vQueueDelete(p_uart_obj[uart_num]->xQueueUart); + p_uart_obj[uart_num]->xQueueUart = NULL; + } + + if (p_uart_obj[uart_num]->rx_ring_buf) + { + vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf); + p_uart_obj[uart_num]->rx_ring_buf = NULL; + } + + if (p_uart_obj[uart_num]->tx_ring_buf) + { + vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf); + p_uart_obj[uart_num]->tx_ring_buf = NULL; + } + + free(p_uart_obj[uart_num]); + p_uart_obj[uart_num] = NULL; + + return ESP_OK; +} + +void uart_set_select_notif_callback(uart_port_t uart_num, uart_select_notif_callback_t uart_select_notif_callback) +{ + if (uart_num < UART_NUM_MAX && p_uart_obj[uart_num]) + { + p_uart_obj[uart_num]->uart_select_notif_callback = (uart_select_notif_callback_t)uart_select_notif_callback; + } +} + +esp_err_t my_uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((tout_thresh < 127), "tout_thresh max value is 126", ESP_ERR_INVALID_ARG); + + UART_ENTER_CRITICAL(); + + // The tout_thresh = 1, defines TOUT interrupt timeout equal to + // transmission time of one symbol (~11 bit) on current baudrate + if (tout_thresh > 0) + { + UART[uart_num]->conf1.rx_tout_thrhd = (tout_thresh & 0x7f); + UART[uart_num]->conf1.rx_tout_en = 1; + } + else + { + UART[uart_num]->conf1.rx_tout_en = 0; + } + + UART_EXIT_CRITICAL(); + return ESP_OK; +} diff --git a/components/README.md b/components/README.md new file mode 100644 index 0000000..3fc0da1 --- /dev/null +++ b/components/README.md @@ -0,0 +1,2 @@ +# TODO +1. USB \ No newline at end of file diff --git a/components/USBIP/CMakeLists.txt b/components/USBIP/CMakeLists.txt new file mode 100644 index 0000000..3aeba6c --- /dev/null +++ b/components/USBIP/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_ADD_INCLUDEDIRS ". ../../main") +set(COMPONENT_SRCS "MSOS20Descriptors.c USB_handle.c USBd_config.c") + +register_component() \ No newline at end of file diff --git a/components/USBIP/MSOS20Descriptors.c b/components/USBIP/MSOS20Descriptors.c new file mode 100644 index 0000000..6621557 --- /dev/null +++ b/components/USBIP/MSOS20Descriptors.c @@ -0,0 +1,84 @@ +/** + * @file MSOS20Descriptors.c + * @author windowsair + * @brief Store related data of Microsoft OS 2.0 descriptor + * @version 0.1 + * @date 2019-11-21 + * + * @copyright Copyright (c) 2019 + * + */ + + ////TODO: refactoring into structure + +#include +#include "MSOS20Descriptors.h" + +#define USBShort(ui16Value) ((ui16Value) & 0xff), ((ui16Value) >> 8) //((ui16Value) & 0xFF),(((ui16Value) >> 8) & 0xFF) + + + +// Microsoft OS 2.0 descriptor set header +const uint8_t msOs20DescriptorSetHeader[kLengthOfMsOS20] = +{ + // Microsoft OS 2.0 Descriptor Set header (Table 10) + 0x0A, 0x00, // wLength (Shall be set to 0x0A) + MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00, + 0x00, 0x00, 0x03, 0x06, // dwWindowsVersion: Windows 8.1 (NTDDI_WINBLUE) + USBShort(kLengthOfMsOS20), // wTotalLength + + // Support WinUSB + // See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/automatic-installation-of-winusb + + // Microsoft OS 2.0 compatible ID descriptor (Table 13) + 0x14, 0x00, // wLength + USBShort(MS_OS_20_FEATURE_COMPATIBLE_ID), // wDescriptorType + 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatibleID + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompatibleID + + // Microsoft OS 2.0 registry property descriptor (Table 14) + 0x84, 0x00, // wLength + USBShort(MS_OS_20_FEATURE_REG_PROPERTY), + 0x07, 0x00, // wPropertyDataType: REG_MULTI_SZ (Unicode Strings) + 0x2A, 0x00, // wPropertyNameLength + 'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0,'t',0,'e',0,'r',0, + 'f',0,'a',0,'c',0,'e',0,'G',0,'U',0,'I',0,'D',0,'s',0,0,0, + // Set to "DeviceInterfaceGUID" to support WinUSB + 0x50, 0x00, // wPropertyDataLength + // WinUSB GUID + '{',0,'C',0,'D',0,'B',0,'3',0,'B',0,'5',0,'A',0,'D',0,'-',0, + '2',0,'9',0,'3',0,'B',0,'-',0,'4',0,'6',0,'6',0,'3',0,'-',0, + 'A',0,'A',0,'3',0,'6',0,'-',0,'1',0,'A',0,'A',0,'E',0,'4',0, + '6',0,'4',0,'6',0,'3',0,'7',0,'7',0,'6',0,'}',0,0,0,0,0, + // identify a CMSIS-DAP V2 configuration, + // must set to "{CDB3B5AD-293B-4663-AA36-1AAE46463776}" + +}; + +const uint8_t bosDescriptor[kLengthOfBos] = +{ + // Universal Serial Bus 3.0 Specification, Table 9-9. + 0x05, // bLength of this descriptor + USB_DESCRIPTOR_TYPE_BOS, // BOS Descriptor type(Constant) + USBShort(kLengthOfBos), // wLength + 0x01, // bNumDeviceCaps + + // Microsoft OS 2.0 platform capability descriptor header (Table 4) + // See also: + // Universal Serial Bus 3.0 Specification : Format of a Device Capability Descriptor, Table 9-10. + + 0x1C, // bLength of this first device capability descriptor + // bLength -> The total length of the remaining arrays containing this field + USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, // bDescriptorType + USB_DEVICE_CAPABILITY_TYPE_PLATFORM, // bDevCapabilityType + + // Capability-Dependent (See USB3.0 Specification Table 9-10.) + 0x00, // bReserved + USB_DEVICE_CAPABILITY_UUID, // MS_OS_20_Platform_Capability_ID + + 0x00, 0x00, 0x03, 0x06, // dwWindowsVersion: Windows 8.1 (NTDDI_WINBLUE) + USBShort(kLengthOfMsOS20), // wMSOSDescriptorSetTotalLength(length of descriptor set header) + kValueOfbMS_VendorCode, // bMS_VendorCode (0x01 will be ok) + ////TODO:change this + 0, // bAltEnumCode +}; \ No newline at end of file diff --git a/components/USBIP/MSOS20Descriptors.h b/components/USBIP/MSOS20Descriptors.h new file mode 100644 index 0000000..51bbcb1 --- /dev/null +++ b/components/USBIP/MSOS20Descriptors.h @@ -0,0 +1,81 @@ +/** + * @file MSOS20Descriptors.h + * @author windowsair + * @brief + * @version 0.1 + * @date 2019-11-21 + * + * @copyright Copyright (c) 2019 + * + */ + +#ifndef __MSOS20DESCRIPTORS_H__ +#define __MSOS20DESCRIPTORS_H__ + +#define kLengthOfMsOS20 0xA2 +#define kLengthOfBos 0x21 +#define kValueOfbMS_VendorCode 0x01// Just set to 0x01 +extern const uint8_t bosDescriptor[kLengthOfBos]; +extern const uint8_t msOs20DescriptorSetHeader[kLengthOfMsOS20]; + +/* Microsoft OS 2.0 Descriptors BEGIN */ + +// Platform capability BOS descriptor, Table 1. +#define USB_DEVICE_CAPABILITY_TYPE_PLATFORM 5 + +// Platform capability UUID, Table 3. +// {D8DD60DF-4589-4CC7-9CD2-659D9E648A9F} +#define USB_DEVICE_CAPABILITY_UUID 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F + + +// Microsoft OS 2.0 descriptor wIndex values enum, Table 8. +#define MS_OS_20_DESCRIPTOR_INDEX 7 +#define MS_OS_20_SET_ALT_ENUMERATION 8 + + +// Microsoft OS 2.0 descriptor types enum for wDescriptorType values, Table 9. +#define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00 +#define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 +#define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 +#define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 +#define MS_OS_20_FEATURE_REG_PROPERTY 0x04 +#define MS_OS_20_FEATURE_MIN_RESUME_TIME 0x05 +#define MS_OS_20_FEATURE_MODEL_ID 0x06 +#define MS_OS_20_FEATURE_CCGP_DEVICE 0x07 + +/* Microsoft OS 2.0 Descriptors END */ + + + +/* Wireless USB Standard Extension Descriptor Types BEGIN */ + +// Wireless USB Specification 1.1 revison 1.1, Table 7-21. +#define USB_DESCRIPTOR_TYPE_SECURITY 12 +#define USB_DESCRIPTOR_TYPE_KEY 13 +#define USB_DESCRIPTOR_TYPE_ENCRYPTION_TYPE 14 +#define USB_DESCRIPTOR_TYPE_BOS 15 +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 16 +#define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINT_COMPANION 17 + +/* Wireless USB Standard Extension Descriptor Types END */ + + +/* Microsoft Extended Compat ID OS Feature Descriptor BEGIN */ + +#define USB_MS_EXTENDED_COMPAT_ID_VERSION 0x0100 +#define USB_MS_EXTENDED_COMPAT_ID_TYPE 0x04 + +#define USB_COMPATID_NONE {0} +#define USB_SUBCOMPATID_NONE {0} +#define USB_COMPATID_WINUSB "WINUSB\0" +#define USB_COMPATID_RNDIS "RNDIS\0\0" +#define USB_COMPATID_PTP "PTP\0\0\0\0" +#define USB_COMPATID_MTP "MTP\0\0\0\0" +#define USB_COMPATID_BLUETOOTH "BLUTUTH" +#define USB_SUBCOMPATID_BT_V11 "11\0\0\0\0\0" +#define USB_SUBCOMPATID_BT_V12 "12\0\0\0\0\0" +#define USB_SUBCOMPATID_BT_V20EDR "EDR\0\0\0\0" + +/* Microsoft Extended Compat ID OS Feature Descriptor END */ + +#endif \ No newline at end of file diff --git a/components/USBIP/USB_handle.c b/components/USBIP/USB_handle.c new file mode 100644 index 0000000..f9fe76a --- /dev/null +++ b/components/USBIP/USB_handle.c @@ -0,0 +1,333 @@ +/** + * @file USB_handle.c + * @brief Handle all Standard Device Requests on endpoint 0 + * @version 0.1 + * @date 2020-01-23 + * + * @copyright Copyright (c) 2020 + * + */ +#include +#include +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include +#include "USB_handle.h" +#include "USBd_config.h" +#include "usbip_server.h" +#include "usb_defs.h" +#include "MSOS20Descriptors.h" + +// const char *strings_list[] = { +// 0, // reserved: available languages +// "windowsair", +// "CMSIS-DAP v2", +// "1234", +// }; + +const char *strings_list[] = { + 0, // reserved: available languages + "windowsair", + "esp8266 CMSIS-DAP", + "1234", +}; +// handle functions +static void handleGetDescriptor(usbip_stage2_header *header); + +////TODO: may be ok +void handleUSBControlRequest(usbip_stage2_header *header) +{ + // Table 9-3. Standard Device Requests + + switch (header->u.cmd_submit.request.bmRequestType) + { + case 0x00: // ignore.. + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_CLEAR_FEATURE: + os_printf("* CLEAR FEATURE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_FEATURE: + os_printf("* SET FEATURE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_ADDRESS: + os_printf("* SET ADDRESS\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_DESCRIPTOR: + os_printf("* SET DESCRIPTOR\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_CONFIGURATION: + os_printf("* SET CONFIGURATION\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + case 0x01: // ignore... + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_CLEAR_FEATURE: + os_printf("* CLEAR FEATURE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_FEATURE: + os_printf("* SET FEATURE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_INTERFACE: + os_printf("* SET INTERFACE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + case 0x02: // ignore.. + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_CLEAR_FEATURE: + os_printf("* CLEAR FEATURE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_FEATURE: + os_printf("* SET INTERFACE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + + case 0x80: // *IMPORTANT* +#if (USE_WINUSB == 0) + case 0x81: +#endif + { + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_GET_CONFIGURATION: + os_printf("* GET CONIFGTRATION\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_GET_DESCRIPTOR: + handleGetDescriptor(header); ////TODO: device_qualifier + break; + case USB_REQ_GET_STATUS: + os_printf("* GET STATUS\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + } +#if (USE_WINUSB == 1) + case 0x81: // ignore... + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_GET_INTERFACE: + os_printf("* GET INTERFACE\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_SET_SYNCH_FRAME: + os_printf("* SET SYNCH FRAME\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + case USB_REQ_GET_STATUS: + os_printf("* GET STATUS\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; +#endif + case 0x82: // ignore... + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_GET_STATUS: + os_printf("* GET STATUS\r\n"); + send_stage2_submit_data(header, 0, 0, 0); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + case 0xC0: // Microsoft OS 2.0 vendor-specific descriptor + { + uint16_t *wIndex = (uint16_t *)(&(header->u.cmd_submit.request.wIndex)); + switch (*wIndex) + { + case MS_OS_20_DESCRIPTOR_INDEX: + os_printf("* GET MSOS 2.0 vendor-specific descriptor\r\n"); + send_stage2_submit_data(header, 0, msOs20DescriptorSetHeader, sizeof(msOs20DescriptorSetHeader)); + break; + case MS_OS_20_SET_ALT_ENUMERATION: + // set alternate enumeration command + // bAltEnumCode set to 0 + os_printf("Set alternate enumeration.This should not happen.\r\n"); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d,wIndex:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest, *wIndex); + break; + } + break; + } + case 0x21: // Set_Idle for HID + switch (header->u.cmd_submit.request.bRequest) + { + case USB_REQ_SET_IDLE: + os_printf("* SET IDLE\r\n"); + send_stage2_submit(header, 0, 0); + break; + + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } + break; + default: + os_printf("USB unknown request, bmRequestType:%d,bRequest:%d\r\n", + header->u.cmd_submit.request.bmRequestType, header->u.cmd_submit.request.bRequest); + break; + } +} + +static void handleGetDescriptor(usbip_stage2_header *header) +{ + // 9.4.3 Get Descriptor + switch (header->u.cmd_submit.request.wValue.u8hi) + { + case USB_DT_DEVICE: // get device descriptor + os_printf("* GET 0x01 DEVICE DESCRIPTOR\r\n"); + send_stage2_submit_data(header, 0, &kUSBd0DeviceDescriptor[0], sizeof(kUSBd0DeviceDescriptor)); + break; + + case USB_DT_CONFIGURATION: // get configuration descriptor + os_printf("* GET 0x02 CONFIGURATION DESCRIPTOR\r\n"); + ////TODO: ? + if (header->u.cmd_submit.data_length == USB_DT_CONFIGURATION_SIZE) + { + os_printf("Sending only first part of CONFIG\r\n"); + + send_stage2_submit(header, 0, header->u.cmd_submit.data_length); + send(kSock, kUSBd0ConfigDescriptor, sizeof(kUSBd0ConfigDescriptor), 0); + } + else + { + os_printf("Sending ALL CONFIG\r\n"); + + send_stage2_submit(header, 0, header->u.cmd_submit.data_length); + send(kSock, kUSBd0ConfigDescriptor, sizeof(kUSBd0ConfigDescriptor), 0); + send(kSock, kUSBd0InterfaceDescriptor, sizeof(kUSBd0InterfaceDescriptor), 0); + } + break; + + case USB_DT_STRING: + //os_printf("* GET 0x03 STRING DESCRIPTOR\r\n"); + + if (header->u.cmd_submit.request.wValue.u8lo == 0) + { + os_printf("** REQUESTED list of supported languages\r\n"); + send_stage2_submit_data(header, 0, kLangDescriptor, sizeof(kLangDescriptor)); + } + else if (header->u.cmd_submit.request.wValue.u8lo != 0xee) + { + //os_printf("low bit : %d\r\n", (int)header->u.cmd_submit.request.wValue.u8lo); + //os_printf("high bit : %d\r\n", (int)header->u.cmd_submit.request.wValue.u8hi); + int slen = strlen(strings_list[header->u.cmd_submit.request.wValue.u8lo]); + int wslen = slen * 2; + int buff_len = sizeof(usb_string_descriptor) + wslen; + char temp_buff[64]; + usb_string_descriptor *desc = (usb_string_descriptor *)temp_buff; + desc->bLength = buff_len; + desc->bDescriptorType = USB_DT_STRING; + for (int i = 0; i < slen; i++) + { + desc->wData[i] = strings_list[header->u.cmd_submit.request.wValue.u8lo][i]; + + } + send_stage2_submit_data(header, 0, (uint8_t *)temp_buff, buff_len); + } + else + { + os_printf("low bit : %d\r\n", (int)header->u.cmd_submit.request.wValue.u8lo); + os_printf("high bit : %d\r\n", (int)header->u.cmd_submit.request.wValue.u8hi); + os_printf("***Unsupported String descriptor***\r\n"); + } + break; + + case USB_DT_INTERFACE: + os_printf("* GET 0x04 INTERFACE DESCRIPTOR (UNIMPLEMENTED)\r\n"); + ////TODO:UNIMPLEMENTED + send_stage2_submit(header, 0, 0); + break; + + case USB_DT_ENDPOINT: + os_printf("* GET 0x05 ENDPOINT DESCRIPTOR (UNIMPLEMENTED)\r\n"); + ////TODO:UNIMPLEMENTED + send_stage2_submit(header, 0, 0); + break; + + case USB_DT_DEVICE_QUALIFIER: + os_printf("* GET 0x06 DEVICE QUALIFIER DESCRIPTOR\r\n"); + + usb_device_qualifier_descriptor desc; + + memset(&desc, 0, sizeof(usb_device_qualifier_descriptor)); + + send_stage2_submit_data(header, 0, &desc, sizeof(usb_device_qualifier_descriptor)); + break; + + case USB_DT_OTHER_SPEED_CONFIGURATION: + os_printf("GET 0x07 [UNIMPLEMENTED] USB_DT_OTHER_SPEED_CONFIGURATION\r\n"); + ////TODO:UNIMPLEMENTED + send_stage2_submit(header, 0, 0); + break; + + case USB_DT_INTERFACE_POWER: + os_printf("GET 0x08 [UNIMPLEMENTED] USB_DT_INTERFACE_POWER\r\n"); + ////TODO:UNIMPLEMENTED + send_stage2_submit(header, 0, 0); + break; + + case USB_DT_BOS: + os_printf("* GET 0x0F BOS DESCRIPTOR\r\n"); + send_stage2_submit_data(header, 0, bosDescriptor, sizeof(bosDescriptor)); + break; + case USB_DT_HID_REPORT: + os_printf("* GET 0x22 HID REPORT DESCRIPTOR\r\n"); + send_stage2_submit_data(header, 0, (void *)kHidReportDescriptor, sizeof(kHidReportDescriptor)); + break; + default: + os_printf("USB unknown Get Descriptor requested:%d\r\n", header->u.cmd_submit.request.wValue.u8lo); + os_printf("low bit :%d\r\n",header->u.cmd_submit.request.wValue.u8lo); + os_printf("high bit :%d\r\n",header->u.cmd_submit.request.wValue.u8hi); + break; + } +} diff --git a/components/USBIP/USB_handle.h b/components/USBIP/USB_handle.h new file mode 100644 index 0000000..ac4eeec --- /dev/null +++ b/components/USBIP/USB_handle.h @@ -0,0 +1,7 @@ +#ifndef __USB_HANDLE_H__ +#define __USB_HANDLE_H__ + +#include "usbip_defs.h" +void handleUSBControlRequest(usbip_stage2_header *header); + +#endif \ No newline at end of file diff --git a/components/USBIP/USBd_config.c b/components/USBIP/USBd_config.c new file mode 100644 index 0000000..0061a8b --- /dev/null +++ b/components/USBIP/USBd_config.c @@ -0,0 +1,310 @@ + ////TODO: refactoring into structure +/** + * @file USBd_config.c + * @brief Standard USB Descriptor Definitions + fix bugs 2020-1-23 + * @version 0.2 + * @date 2020-1-23 + * + * + */ +#include +#include +#include "USBd_config.h" +#include "usb_defs.h" + +#define USBShort(ui16Value) ((ui16Value) & 0xff), ((ui16Value) >> 8) //((ui16Value) & 0xFF),(((ui16Value) >> 8) & 0xFF) + + +/** + * @brief step 1. Build Standard Device Descriptor + * + */ + +// Standard Device Descriptor +const uint8_t kUSBd0DeviceDescriptor[0x12] = +{ + 0x12, // bLength + USB_DT_DEVICE, // bDescriptorType + USBShort(0x0210), // bcdUSB + ////TODO: Is it also available elsewhere? + + // We need to use a device other than the USB-IF standard, set to 0x00 + 0x00, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + + USBD0_MAX_PACKET0, // bMaxPacketSize0 Maximum packet size for default pipe. + USBShort(USBD0_DEV_DESC_IDVENDOR), // idVendor Vendor ID (VID). + USBShort(USBD0_DEV_DESC_IDPRODUCT), // idProduct Product ID (PID). + USBShort(USBD0_DEV_DESC_BCDDEVICE), // bcdDevice Device Version BCD. + 0x01, // iManufacturer Index of Manufacturer string identifier. + 0x02, // iProduct Index of Product string identifier. + 0x03 * USBD0_STR_DESC_SER_EN, // iSerialNumber Index of Product serial number. + 0x01 // bNumConfigurations Number of configurations. +}; + + + + +/** + * @brief step 2. Buid Standard Configuration Descriptor + * + */ + + +// Standard Interface Descriptor + +#if (USE_WINUSB ==1) +const uint8_t kUSBd0InterfaceDescriptor[0x1E]= +{ + 0x09, // bLength + USB_DT_INTERFACE, // bDescriptorType + USBD_CUSTOM_CLASS0_IF0_NUM, // bInterfaceNumber + USBD_CUSTOM_CLASS0_IF0_ALT, // bAlternateSetting + 0x03, // bNumEndpoints(we will use 3 endpoints) + // + USBD_CUSTOM_CLASS0_IF0_CLASS, // bInterfaceClass + USBD_CUSTOM_CLASS0_IF0_SUBCLASS, // bInterfaceSubClass + USBD_CUSTOM_CLASS0_IF0_PROTOCOL, // bInterfaceProtocol + 0x00, // iInterface + // Index of string descriptor describing this interface + ////TODO: fix this 0x04 ? + + + // Standard Endpoint Descriptor + + // Endpoint 1: Bulk Out – used for commands received from host PC. + // Endpoint 2: Bulk In – used for responses send to host PC. + // Endpoint 3: Bulk In (optional) – used for streaming SWO trace + + // ATTENTION: + // physical endpoint 1 indeed included two "endpoints": Bulk OUT and Bulk IN + // physical endpoint 1 -> Endpoint 1 & Endpoint 2 + // physical endpoint 2 -> Endpoint 3 + + // See also : + // http://www.keil.com/pack/doc/CMSIS/DAP/html/group__DAP__ConfigUSB__gr.html + + /* Pysical endpoint 1 */ + + // "Endpoint 1: Bulk Out – used for commands received from host PC." PC -> Device + 0x07, // bLength + USB_DT_ENDPOINT, // bDescriptorType + 0x01, // bEndpointAddress + USB_ENDPOINT_ATTR_BULK, // bmAttributes + USBShort(512), // wMaxPacketSize + // We assume that it always runs in High Speed. + 0x00, // bInterval + + /* Pysical endpoint 1 */ + + // "Endpoint 2: Bulk In – used for responses send to host PC." Device -> PC + 0x07, // bLength + USB_DT_ENDPOINT, // bDescriptorType + 0x81, // bEndpointAddress + USB_ENDPOINT_ATTR_BULK, // bmAttributes + USBShort(512), // wMaxPacketSize + 0x00, // bInterval + + /* Pysical endpoint 2 */ + + // "Endpoint 3: Bulk In (optional) – used for streaming SWO trace" Device -> PC + 0x07, // bLength + USB_DT_ENDPOINT, // bDescriptorType + 0x82, // bEndpointAddress + USB_ENDPOINT_ATTR_BULK, // bmAttributes + USBShort(512), // wMaxPacketSize + 0x00, // bInterval + + +}; + +#else +const uint8_t kUSBd0InterfaceDescriptor[0x20]= +{ + 0x09, // bLength + USB_DT_INTERFACE, // bDescriptorType + USBD_CUSTOM_CLASS0_IF0_NUM, // bInterfaceNumber + USBD_CUSTOM_CLASS0_IF0_ALT, // bAlternateSetting + 0x02, // bNumEndpoints ----> 2 endpoint for USB HID + // + USBD_CUSTOM_CLASS0_IF0_CLASS, // bInterfaceClass + USBD_CUSTOM_CLASS0_IF0_SUBCLASS, // bInterfaceSubClass + USBD_CUSTOM_CLASS0_IF0_PROTOCOL, // bInterfaceProtocol + 0x00, // iInterface + // Index of string descriptor describing this interface + + // HID Descriptor + 0x09, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType1 + 0x21, 0x00, // wDescriptorLength1 + + // Standard Endpoint Descriptor + + // We perform all transfer operations on Pysical endpoint 1. + + /* Pysical endpoint 1 */ + + 0x07, // bLength + USB_DT_ENDPOINT, // bDescriptorType + 0x81, // bEndpointAddress + USB_ENDPOINT_ATTR_INTERRUPT, // bmAttributes + USBShort(64), // wMaxPacketSize + 0x01, // bInterval + + /* Pysical endpoint 1 */ + + 0x07, // bLength + USB_DT_ENDPOINT, // bDescriptorType + 0x01, // bEndpointAddress + USB_ENDPOINT_ATTR_INTERRUPT, // bmAttributes + USBShort(64), // wMaxPacketSize + 0x01, // bInterval +}; +#endif + +// Standard Configuration Descriptor +#define LENGTHOFCONFIGDESCRIPTOR 9 + +#if (USE_WINUSB == 1) +const uint8_t kUSBd0ConfigDescriptor[LENGTHOFCONFIGDESCRIPTOR] = +{ + // Configuration descriptor header. + + 0x09, // bLength + USB_DT_CONFIGURATION, // bDescriptorType + + USBShort((sizeof(kUSBd0InterfaceDescriptor)) + (LENGTHOFCONFIGDESCRIPTOR)), + // wTotalLength + + 0x01, // bNumInterfaces + // There is only one interface in the CMSIS-DAP project + 0x01, // bConfigurationValue: 0x01 is used to select this configuration */ + 0x00, // iConfiguration: no string to describe this configuration */ + USBD0_CFG_DESC_BMATTRIBUTES, // bmAttributes + + USBD0_CFG_DESC_BMAXPOWER, // bMaxPower +}; + +#else +const uint8_t kUSBd0ConfigDescriptor[LENGTHOFCONFIGDESCRIPTOR] = +{ + // Configuration descriptor header. + + 0x09, // bLength + USB_DT_CONFIGURATION, // bDescriptorType + + USBShort((sizeof(kUSBd0InterfaceDescriptor)) + (LENGTHOFCONFIGDESCRIPTOR)), + // wTotalLength + + 0x01, // bNumInterfaces + // There is only one interface in the CMSIS-DAP project + 0x01, // bConfigurationValue: 0x01 is used to select this configuration */ + 0x00, // iConfiguration: no string to describe this configuration */ + USBD0_CFG_DESC_BMATTRIBUTES, // bmAttributes + + USBD0_CFG_DESC_BMAXPOWER, // bMaxPower +}; +#endif + + +// USB HID Report Descriptor +const uint8_t kHidReportDescriptor[0x21] = { + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x01, // Usage (0x01) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Size (8) + 0x95, 0xFF, // Report Count (64) + 0x09, 0x01, // Usage (0x01) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0xFF, // Report Count (64) + 0x09, 0x01, // Usage (0x01) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x95, 0x01, // Report Count (1) + 0x09, 0x01, // Usage (0x01) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + // 33 bytes +}; + + + + + + +/** + * @brief step 3. Build String Descriptor + * + */ + + +const uint8_t kLangDescriptor[0x04] = +{ + 4, + USB_DT_STRING, + USBShort(USB_LANGID_ENGLISH_US) +}; + + +/** + * @brief We will use these string descriptor: + * 1. Manufacturer string -> "KEIL - Tools By ARM" + * 2. Product string -> "LPC-Link-II" + * 3. Serial number string -> "0001A0000000" + * 4. Interface string -> "LPC-Link-II CMSIS-DAP" + * + * + */ + +const uint8_t kManufacturerString[0x28] = +{ + 0x28, // bLength + 0x03, // bDescriptorType + // "KEIL - Tools By ARM" + 'K', 0, 'E', 0, 'I', 0, 'L', 0, ' ', 0, '-', 0, ' ', 0, 'T', 0, 'o', 0, 'o', 0, + 'l', 0, 's', 0, ' ', 0, 'B', 0, 'y', 0, ' ', 0, 'A', 0, 'R', 0, 'M', 0 +}; + +const uint8_t kProductString[0x18] = +{ + 0x18, // bLength + 0x03, // bDescriptorType + // "LPC-Link-II" + 'L', 0, 'P', 0, 'C', 0, '-', 0, 'L', 0, 'i', 0, 'n', 0, 'k', 0, '-', 0, 'I', 0, + 'I', 0 +}; + +const uint8_t kSerialNumberString[0x1A] = +{ + 0x1A, // bLength + 0x03, // bDescriptorType + // "0001A0000000" + '0', 0, '0', 0, '0', 0, '1', 0, 'A', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, + '0', 0, '0', 0 +}; + +const uint8_t kInterfaceString[0x2C] = +{ + 0x2C, // bLength + 0x03, // bDescriptorType + // "LPC-Link-II CMSIS-DAP" + 'L', 0, 'P', 0, 'C', 0, '-', 0, 'L', 0, 'i', 0, 'n', 0, 'k', 0, '-', 0, 'I', 0, + 'I', 0, ' ', 0, 'C', 0, 'M', 0, 'S', 0, 'I', 0, 'S', 0, '-', 0, 'D', 0, 'A', 0, + 'P', 0 +}; + +const uint8_t * const kUSBd0StringDescriptorsSet[0x05] = +{ + kLangDescriptor, + kManufacturerString, + kProductString, + kSerialNumberString, + kInterfaceString +}; \ No newline at end of file diff --git a/components/USBIP/USBd_config.h b/components/USBIP/USBd_config.h new file mode 100644 index 0000000..dc3a3e2 --- /dev/null +++ b/components/USBIP/USBd_config.h @@ -0,0 +1,66 @@ +#ifndef __USBD_CONFIG_H__ +#define __USBD_CONFIG_H__ + +#define USE_WINUSB 0 + +// Vendor ID assigned by USB-IF (idVendor). +#define USBD0_DEV_DESC_IDVENDOR 0xC251 +// Product ID assigned by manufacturer (idProduct). +#define USBD0_DEV_DESC_IDPRODUCT 0xF00A +// Device Release Number in binary-coded decimal (bcdDevice). +#define USBD0_DEV_DESC_BCDDEVICE 0x0100 + +// Maximum packet size for Endpoint 0 (bMaxPacketSize0). +#define USBD0_MAX_PACKET0 64 + +// If disabled Serial Number String will not be assigned to USB Device. +#define USBD0_STR_DESC_SER_EN 1 + +// bmAttributes +#define USBD0_CFG_DESC_BMATTRIBUTES 0x80 + +// bMaxPower +#define USBD0_CFG_DESC_BMAXPOWER 250 + +// Interface Number +#define USBD_CUSTOM_CLASS0_IF0_NUM 0 + +// Alternate Setting +#define USBD_CUSTOM_CLASS0_IF0_ALT 0 + +// Class Code +#if (USE_WINUSB == 1) +#define USBD_CUSTOM_CLASS0_IF0_CLASS 0xFF // 0xFF: Vendor Specific +#else +#define USBD_CUSTOM_CLASS0_IF0_CLASS 0x03 // 0x03: HID class +#endif + +// Subclass Code +#define USBD_CUSTOM_CLASS0_IF0_SUBCLASS 0x00 + +// Protocol Code +#define USBD_CUSTOM_CLASS0_IF0_PROTOCOL 0x00 + +///////////////////////////////////////////// + +// common part +extern const uint8_t kUSBd0DeviceDescriptor[0x12]; +extern const uint8_t kLangDescriptor[0x04]; +extern const uint8_t kManufacturerString[0x28]; +extern const uint8_t kProductString[0x18]; +extern const uint8_t kSerialNumberString[0x1A]; + +#if (USE_WINUSB == 1) +extern const uint8_t kUSBd0InterfaceDescriptor[0x1E]; +extern const uint8_t kUSBd0ConfigDescriptor[0x09]; +extern const uint8_t kInterfaceString[0x2C]; + +#else +extern const uint8_t kUSBd0InterfaceDescriptor[0x20]; +extern const uint8_t kUSBd0ConfigDescriptor[0x09]; +extern const uint8_t kInterfaceString[0x2C]; +extern const uint8_t kHidReportDescriptor[0x21]; + +#endif + +#endif \ No newline at end of file diff --git a/components/USBIP/usb_defs.h b/components/USBIP/usb_defs.h new file mode 100644 index 0000000..0377dc4 --- /dev/null +++ b/components/USBIP/usb_defs.h @@ -0,0 +1,308 @@ +/** + * @file usb_defs.h + * @brief Modify + * @version 0.1 + * @date 2020-01-22 + * + * @copyright Copyright (c) 2020 + * + */ + +// +// Created by thevoidnn on 10/25/17. +// + +#ifndef __USB_DEFS_H__ +#define __USB_DEFS_H__ + +#include + +#define USB_CLASS_MISCELLANEOUS_DEVICE 0xef +#define USB_MISC_SUBCLASS_COMMON 0x02 +#define USB_MISC_PROTOCOL_INTERFACE_ASSOCIATION_DESCRIPTOR 0x01 + +typedef union { + struct + { + uint8_t u8lo; + uint8_t u8hi; + } __attribute__((packed)); + uint16_t u16; +} word_t; + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + word_t wValue; // 16bit + word_t wIndex; + word_t wLength; +} __attribute__((packed)) usb_standard_request; + +//#define USB_CLASS_HID 3 + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 + +//struct usb_hid_descriptor { +// uint8_t bLength; +// uint8_t bDescriptorType; +// uint16_t bcdHID; +// uint8_t bCountryCode; +// uint8_t bNumDescriptors; +//} __attribute__((packed)); +//#define USB_DT_HID_SIZE sizeof(struct usb_hid_descriptor) + +//struct usb_hid_report_descriptor { +// uint8_t bDescriptorType; +// uint16_t wReportLength; +//} __attribute__((packed)); + +#define USB_DT_REPORT_SIZE sizeof(struct usb_hid_report_descriptor) + +/* Class Definition */ +#define USB_CLASS_VENDOR 0xFF + +/////////////////////////////////////////////////////////////// +/* Table 9-2. Format of Setup Data */ +/* bmRequestType bit definitions */ + +/* bit 7 : Direction */ +#define USB_REQ_TYPE_OUT 0x00 // Host-to-device +#define USB_REQ_TYPE_IN 0x80 // Device-to-host +/* bits 6..5 : Type */ +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +//#define USB_REQ_TYPE_RESERVED 0x60 +/* bits 4..0 : Recipient */ +#define USB_REQ_TYPE_DEVICE 0x00 +#define USB_REQ_TYPE_INTERFACE 0x01 +#define USB_REQ_TYPE_ENDPOINT 0x02 +#define USB_REQ_TYPE_OTHER 0x03 +//#define USB_REQ_TYPE_RESERVED 0x1F +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Standard Request Codes - Table 9-4 */ +#define USB_REQ_GET_STATUS 0 +#define USB_REQ_CLEAR_FEATURE 1 +/* Reserved for future use: 2 */ +#define USB_REQ_SET_FEATURE 3 +/* Reserved for future use: 3 */ +#define USB_REQ_SET_ADDRESS 5 +#define USB_REQ_GET_DESCRIPTOR 6 +#define USB_REQ_SET_DESCRIPTOR 7 +#define USB_REQ_GET_CONFIGURATION 8 +#define USB_REQ_SET_CONFIGURATION 9 +#define USB_REQ_GET_INTERFACE 10 +#define USB_REQ_SET_INTERFACE 11 +#define USB_REQ_SET_SYNCH_FRAME 12 + +// USB HID Request +#define USB_REQ_GET_REPORT 0x01 +#define USB_REQ_GET_IDLE 0x02 +#define USB_REQ_GET_PROTOCOL 0x03 +#define USB_REQ_SET_REPORT 0x09 +#define USB_REQ_SET_IDLE 0X0A +#define USB_REQ_SET_PROTOCOL 0X0B +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Descriptor Types - Table 9-5 */ +#define USB_DT_DEVICE 1 +#define USB_DT_CONFIGURATION 2 +#define USB_DT_STRING 3 +#define USB_DT_INTERFACE 4 +#define USB_DT_ENDPOINT 5 +#define USB_DT_DEVICE_QUALIFIER 6 +#define USB_DT_OTHER_SPEED_CONFIGURATION 7 +#define USB_DT_INTERFACE_POWER 8 +#define USB_DT_BOS 15 +/* From ECNs */ +#define USB_DT_OTG 9 +#define USB_DT_DEBUG 10 +#define USB_DT_INTERFACE_ASSOCIATION 11 +/* USB HID */ +#define USB_DT_HID 0x21 +#define USB_DT_HID_REPORT 0x22 +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Standard Feature Selectors - Table 9-6 */ +#define USB_FEAT_ENDPOINT_HALT 0 // Recipient: Device +#define USB_FEAT_DEVICE_REMOTE_WAKEUP 1 // Recipient: Endpoint +#define USB_FEAT_TEST_MODE 2 // Recipient: Device + +/* Information Returned by a GetStatus() Request to a Device - Figure 9-4 */ +#define USB_DEV_STATUS_SELF_POWERED 0x01 +#define USB_DEV_STATUS_REMOTE_WAKEUP 0x02 +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Standard Device Descriptor - Table 9-8 */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} __attribute__((packed)) usb_device_descriptor; +#define USB_DT_DEVICE_SIZE sizeof(usb_device_descriptor) +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Device_Qualifier Descriptor - Table 9-9 + * Not used in this implementation. + */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +} __attribute__((packed)) usb_device_qualifier_descriptor; +/////////////////////////////////////////////////////////////// + +/* This is only defined as a top level named struct to improve c++ + * compatibility. You should never need to instance this struct + * in user code! */ +typedef struct +{ + uint8_t *cur_altsetting; + uint8_t num_altsetting; + const struct usb_iface_assoc_descriptor *iface_assoc; + const struct usb_interface_descriptor *altsetting; +} __attribute__((packed)) usb_interface; + +/////////////////////////////////////////////////////////////// +/* USB Standard Configuration Descriptor - Table 9-10 */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} __attribute__((packed)) usb_config_descriptor; +#define USB_DT_CONFIGURATION_SIZE sizeof(usb_config_descriptor) +/////////////////////////////////////////////////////////////// + +/* USB Configuration Descriptor *bmAttributes* bit definitions */ +#define USB_CONFIG_ATTR_DEFAULT 0x80 /** always required (USB2.0 table 9-10) */ +#define USB_CONFIG_ATTR_SELF_POWERED 0x40 +#define USB_CONFIG_ATTR_REMOTE_WAKEUP 0x20 + +/* Other Speed Configuration is the same as Configuration Descriptor. + * - Table 9-11 + */ + +/////////////////////////////////////////////////////////////// +/* USB Standard Interface Descriptor - Table 9-12 */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} __attribute__((packed)) usb_interface_descriptor; +#define USB_DT_INTERFACE_SIZE sizeof(usb_interface_descriptor) +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* USB Standard Endpoint Descriptor - Table 9-13 */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __attribute__((packed))usb_endpoint_descriptor; +#define USB_DT_ENDPOINT_SIZE sizeof(usb_endpoint_descriptor) +/////////////////////////////////////////////////////////////// + +/* USB bEndpointAddress helper macros */ +#define USB_ENDPOINT_ADDR_OUT(x) (x) +#define USB_ENDPOINT_ADDR_IN(x) (0x80 | (x)) + +/////////////////////////////////////////////////////////////// +/* USB Endpoint Descriptor bmAttributes bit definitions - Table 9-13 */ +/* bits 1..0 : Transfer type */ +#define USB_ENDPOINT_ATTR_CONTROL 0x00 +#define USB_ENDPOINT_ATTR_ISOCHRONOUS 0x01 +#define USB_ENDPOINT_ATTR_BULK 0x02 +#define USB_ENDPOINT_ATTR_INTERRUPT 0x03 +#define USB_ENDPOINT_ATTR_TYPE 0x03 +// If not an isochronous endpoint, bits 5..2 are reserved +// and must be set to zero. +/* bits 3..2 : Sync type (only if ISOCHRONOUS) */ +#define USB_ENDPOINT_ATTR_NOSYNC 0x00 +#define USB_ENDPOINT_ATTR_ASYNC 0x04 +#define USB_ENDPOINT_ATTR_ADAPTIVE 0x08 +#define USB_ENDPOINT_ATTR_SYNC 0x0C +#define USB_ENDPOINT_ATTR_SYNCTYPE 0x0C +/* bits 5..4 : Usage type (only if ISOCHRONOUS) */ +#define USB_ENDPOINT_ATTR_DATA 0x00 +#define USB_ENDPOINT_ATTR_FEEDBACK 0x10 +#define USB_ENDPOINT_ATTR_IMPLICIT_FEEDBACK_DATA 0x20 +#define USB_ENDPOINT_ATTR_USAGETYPE 0x30 +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +/* Table 9-15 specifies String Descriptor Zero. + * Table 9-16 specified UNICODE String Descriptor. + */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wData[]; +} __attribute__((packed)) usb_string_descriptor; + +/* From ECN: Interface Association Descriptors, Table 9-Z */ +typedef struct +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} __attribute__((packed)) usb_iface_assoc_descriptor; +#define USB_DT_INTERFACE_ASSOCIATION_SIZE \ + sizeof(usb_iface_assoc_descriptor) + +enum usb_language_id +{ + USB_LANGID_ENGLISH_US = 0x409, +}; +/////////////////////////////////////////////////////////////// + +#endif diff --git a/components/USBIP/usbip_defs.h b/components/USBIP/usbip_defs.h new file mode 100644 index 0000000..d36d16e --- /dev/null +++ b/components/USBIP/usbip_defs.h @@ -0,0 +1,210 @@ +/** + * @file usbip_defs.h + * @brief Simple modification + * @version 0.1 + * @date 2020-01-22 + * + * @copyright Copyright (c) 2020 + * + */ + +// Focus on the following structures in this file: +// usbip_stage2_header +// usbip_stage1_response_devlist + +// +// Created by thevoidnn on 10/25/17. +// + +#ifndef __USBIP_DEFS_H__ +#define __USBIP_DEFS_H__ + +#include +#include "usb_defs.h" + +#define USBIP_SYSFS_PATH_SIZE 256 +#define USBIP_BUSID_SIZE 32 + +enum usbip_stage1_command +{ + // Offset 2 + USBIP_STAGE1_CMD_DEVICE_LIST = 0x05, // OP_REQ_DEVLIST + USBIP_STAGE1_CMD_DEVICE_ATTACH = 0x03, // OP_REQ_IMPORT +}; + +enum usbip_stager2_command +{ + //Offset 0 + USBIP_STAGE2_REQ_SUBMIT = 0x0001, + USBIP_STAGE2_REQ_UNLINK = 0x0002, + USBIP_STAGE2_RSP_SUBMIT = 0x0003, + USBIP_STAGE2_RSP_UNLINK = 0x0004, +}; + +enum usbip_stage2_direction +{ + USBIP_DIR_OUT = 0x00, + USBIP_DIR_IN = 0x01, +}; + +typedef struct +{ + uint16_t version; + uint16_t command; + uint32_t status; +} __attribute__((__packed__)) usbip_stage1_header; +///////////////////////////////////////////////////////////// + +// Device description +typedef struct +{ + char path[USBIP_SYSFS_PATH_SIZE]; + char busid[USBIP_BUSID_SIZE]; + + uint32_t busnum; + uint32_t devnum; + uint32_t speed; + + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + + uint8_t bConfigurationValue; + uint8_t bNumConfigurations; + uint8_t bNumInterfaces; +} __attribute__((packed)) usbip_stage1_usb_device; + +// Interface description +typedef struct +{ + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t padding; +} __attribute__((packed)) usbip_stage1_usb_interface; + +typedef struct +{ + usbip_stage1_usb_device udev; + usbip_stage1_usb_interface uinf[]; +} __attribute__((packed)) usbip_stage1_response_devlist_entry; + +typedef struct +{ + uint32_t list_size; + usbip_stage1_response_devlist_entry devices[]; +} __attribute__((__packed__)) usbip_stage1_response_devlist; + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// + +/** + * struct usbip_header_basic - data pertinent to every URB request + * RESPONSE & REQUEST + * + * @command: the usbip request type + * @seqnum: sequential number that identifies requests; incremented per + * connection + * @devid: specifies a remote USB device uniquely instead of busnum and devnum; + * in the stub driver, this value is ((busnum << 16) | devnum) + * @direction: direction of the transfer + * @ep: endpoint number + */ +typedef struct +{ + uint32_t command; + uint32_t seqnum; + uint32_t devid; + uint32_t direction; + uint32_t ep; +} __attribute__((packed)) usbip_stage2_header_basic; + +/** + * struct usbip_header_cmd_submit - USBIP_CMD_SUBMIT packet header + * >>>REQUEST + * + * @transfer_flags: URB flags + * @transfer_buffer_length: the data size for (in) or (out) transfer + * @start_frame: initial frame for isochronous or interrupt transfers + * @number_of_packets: number of isochronous packets + * @interval: maximum time for the request on the server-side host controller + * @setup: setup data for a control request + */ +typedef struct +{ + uint32_t transfer_flags; + int32_t data_length; + + /* it is difficult for usbip to sync frames (reserved only?) */ + int32_t start_frame; + int32_t number_of_packets; + int32_t interval; + + union { + uint8_t setup[8]; + usb_standard_request request; + }; +} __attribute__((packed)) usbip_stage2_header_cmd_submit; + +/** + * struct usbip_header_ret_submit - USBIP_RET_SUBMIT packet header + * <<>>REQUEST + * @seqnum: the URB seqnum to unlink + */ +typedef struct +{ + uint32_t seqnum; +} __attribute__((packed)) usbip_stage2_header_cmd_unlink; + +/** + * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header + * << +#include +#include "usbip_server.h" +#include "DAP_handle.h" +#include "DAP.h" +#include "esp_libc.h" +#include "USBd_config.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/ringbuf.h" +#include "freertos/semphr.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include + +extern int kSock; +extern TaskHandle_t kDAPTaskHandle; +////TODO: Merge this +#define DAP_PACKET_SIZE 255 + +static uint8_t data_out[DAP_PACKET_SIZE]; +static int dap_respond = 0; + +// SWO Trace +static int swo_trace_respond = 0; +static uint8_t *swo_data_to_send; +static uint32_t num_swo_data; + +static RingbufHandle_t dap_dataIN_handle = NULL; +static RingbufHandle_t dap_dataOUT_handle = NULL; +static SemaphoreHandle_t data_response_mux = NULL; + +static void unpack(void *data, int size); + +void handle_dap_data_request(usbip_stage2_header *header, uint32_t length) +{ + uint8_t *data_in = (uint8_t *)header; + data_in = &(data_in[sizeof(usbip_stage2_header)]); + // Point to the beginning of the URB packet + +#if (USE_WINUSB == 1) + dap_respond = DAP_ProcessCommand((uint8_t *)data_in, (uint8_t *)data_out); + //handle_dap_data_response(header); + send_stage2_submit(header, 0, 0); +#else + xRingbufferSend(dap_dataIN_handle, data_in, length - sizeof(usbip_stage2_header), portMAX_DELAY); + //os_printf("LENGTH: %d\r\n", length - sizeof(usbip_stage2_header)); + xTaskNotifyGive(kDAPTaskHandle); + send_stage2_submit(header, 0, 0); + +#endif +} + +void handle_dap_data_response(usbip_stage2_header *header) +{ + if (dap_respond) + { + send_stage2_submit_data(header, 0, data_out, DAP_PACKET_SIZE); + dap_respond = 0; + } + else + { + send_stage2_submit(header, 0, 0); + } +} + +void handle_swo_trace_response(usbip_stage2_header *header) +{ + if (swo_trace_respond) + { + swo_trace_respond = 0; + send_stage2_submit_data(header, 0, data_out, DAP_PACKET_SIZE); + } + else + { + send_stage2_submit(header, 0, 0); + } +} + +// SWO Data Queue Transfer +// buf: pointer to buffer with data +// num: number of bytes to transfer +void SWO_QueueTransfer(uint8_t *buf, uint32_t num) +{ + swo_data_to_send = buf; + num_swo_data = num; + swo_trace_respond = 1; +} + +// SWO Data Abort Transfer +void SWO_AbortTransfer(void) +{ + //USBD_EndpointAbort(0U, USB_ENDPOINT_IN(2U)); + ////TODO: unlink might be useful ... +} + +void DAP_Thread(void *argument) +{ + dap_dataIN_handle = xRingbufferCreate(DAP_PACKET_SIZE * 20, RINGBUF_TYPE_BYTEBUF); + dap_dataOUT_handle = xRingbufferCreate(DAP_PACKET_SIZE * 10, RINGBUF_TYPE_BYTEBUF); + data_response_mux = xSemaphoreCreateMutex(); + size_t packetSize; + uint8_t *item; + + if (dap_dataIN_handle == NULL || dap_dataIN_handle == NULL || + data_response_mux == NULL) + { + os_printf("Can not create DAP ringbuf/mux!\r\n"); + vTaskDelete(NULL); + } + for (;;) + { + + while (1) + { + ulTaskNotifyTake(pdFALSE, portMAX_DELAY); + packetSize = 0; + item = (uint8_t *)xRingbufferReceiveUpTo(dap_dataIN_handle, &packetSize, + (1 / portTICK_RATE_MS), DAP_PACKET_SIZE); + if (packetSize == 0) + { + break; + } + + else if (packetSize < DAP_PACKET_SIZE) + { + os_printf("Wrong data in packet size:%d , data in remain: %d\r\n", packetSize, (int)xRingbufferGetMaxItemSize(dap_dataIN_handle)); + vRingbufferReturnItem(dap_dataIN_handle, (void *)item); + break; + // This may not happen because there is a semaphore acquisition + } + + if (item[0] == ID_DAP_QueueCommands) + item[0] = ID_DAP_ExecuteCommands; + DAP_ProcessCommand(item, data_out); + + vRingbufferReturnItem(dap_dataIN_handle, (void *)item); + xRingbufferSend(dap_dataOUT_handle, data_out, DAP_PACKET_SIZE, portMAX_DELAY); + if (xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) + { + ++dap_respond; + xSemaphoreGive(data_response_mux); + } + } + } +} + +int fast_reply(uint8_t *buf, uint32_t length) +{ + if (length == 48 && buf[3] == 1 && buf[15] == 1 && buf[19] == 1) + { + if (dap_respond > 0) + { + uint8_t *item; + size_t packetSize = 0; + item = (uint8_t *)xRingbufferReceiveUpTo(dap_dataOUT_handle, &packetSize, + (10 / portTICK_RATE_MS), DAP_PACKET_SIZE); + if (packetSize == DAP_PACKET_SIZE) + { + unpack((uint32_t *)buf, sizeof(usbip_stage2_header)); + send_stage2_submit_data((usbip_stage2_header *)buf, 0, item, DAP_PACKET_SIZE); + if (xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) + { + --dap_respond; + xSemaphoreGive(data_response_mux); + } + vRingbufferReturnItem(dap_dataOUT_handle, (void *)item); + return 1; + } + else if (packetSize > 0) + { + os_printf("Wrong data out packet size:%d!\r\n", packetSize); + } + ////TODO: fast reply + } + else + { + buf[3] = 0x3; // command + buf[15] = 0; // direction + buf[0x16] = 0; + buf[0x17] = 0; + buf[27] = 0; + buf[39] = 0; + send(kSock, buf, 48, 0); + return 1; + } + } + return 0; +} + +static void unpack(void *data, int size) +{ + + // Ignore the setup field + int sz = (size / sizeof(uint32_t)) - 2; + uint32_t *ptr = (uint32_t *)data; + + for (int i = 0; i < sz; i++) + { + ptr[i] = ntohl(ptr[i]); + } +} \ No newline at end of file diff --git a/main/DAP_handle.h b/main/DAP_handle.h new file mode 100644 index 0000000..2d71be2 --- /dev/null +++ b/main/DAP_handle.h @@ -0,0 +1,12 @@ +#ifndef __DAP_HANDLE_H__ +#define __DAP_HANDLE_H__ + +#include "usbip_defs.h" + +void handle_dap_data_request(usbip_stage2_header *header, uint32_t length); +void handle_dap_data_response(usbip_stage2_header *header); +void handle_swo_trace_response(usbip_stage2_header *header); + +int fast_reply(uint8_t *buf, uint32_t length); + +#endif \ No newline at end of file diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild deleted file mode 100644 index c1209ac..0000000 --- a/main/Kconfig.projbuild +++ /dev/null @@ -1,37 +0,0 @@ -menu "Example Configuration" - -config WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) for the example to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) for the example to use. - Can be left blank if the network has no security set. - -choice EXAMPLE_IP_MODE - prompt "IP Version" - help - Example can use either IPV4 or IPV6. - -config EXAMPLE_IPV4 - bool "IPV4" - -config EXAMPLE_IPV6 - bool "IPV6" - select LWIP_IPV6 - -endchoice - -config EXAMPLE_PORT - int "Port" - range 0 65535 - default 3333 - help - Local port the example server will listen on. - -endmenu diff --git a/main/component.mk b/main/component.mk deleted file mode 100644 index a98f634..0000000 --- a/main/component.mk +++ /dev/null @@ -1,4 +0,0 @@ -# -# "main" pseudo-component makefile. -# -# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..bc92117 --- /dev/null +++ b/main/main.c @@ -0,0 +1,148 @@ +/* BSD Socket API Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include + +#include "tcp_server.h" +#include "timer.h" +#include "wifi_configuration.h" + + + +extern void SWO_Thread(void *argument); +extern void usart_monitor_task(void *argument); +extern void DAP_Setup(void); +extern void DAP_Thread(void *argument); + +/* FreeRTOS event group to signal when we are connected & ready to make a request */ +static EventGroupHandle_t wifi_event_group; +TaskHandle_t kDAPTaskHandle = NULL; + +const int IPV4_GOTIP_BIT = BIT0; +#ifdef CONFIG_EXAMPLE_IPV6 +const int IPV6_GOTIP_BIT = BIT1; +#endif + + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + /* For accessing reason codes in case of disconnection */ + system_event_info_t *info = &event->event_info; + + switch (event->event_id) + { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + os_printf("SYSTEM_EVENT_STA_START\r\n"); + break; + case SYSTEM_EVENT_STA_CONNECTED: +#ifdef CONFIG_EXAMPLE_IPV6 + /* enable ipv6 */ + tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); +#endif + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT); + os_printf("SYSTEM_EVENT_STA_GOT_IP\r\n"); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + os_printf("Disconnect reason : %d\r\n", info->disconnected.reason); + if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) + { + /*Switch to 802.11 bgn mode */ + esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCAL_11B | WIFI_PROTOCAL_11G | WIFI_PROTOCAL_11N); + } + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT); +#ifdef CONFIG_EXAMPLE_IPV6 + xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT); +#endif + break; + case SYSTEM_EVENT_AP_STA_GOT_IP6: +#ifdef CONFIG_EXAMPLE_IPV6 + xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT); + os_printf("SYSTEM_EVENT_STA_GOT_IP6\r\n"); + + char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip); + os_printf("IPv6: %s\r\n", ip6); +#endif + default: + break; + } + return ESP_OK; +} + +static void initialise_wifi(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + wifi_config_t wifi_config = { + .sta = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + }, + }; + os_printf("Setting WiFi configuration SSID %s...\r\n", wifi_config.sta.ssid); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + +} + +static void wait_for_ip() +{ +#ifdef CONFIG_EXAMPLE_IPV6 + uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT; +#else + uint32_t bits = IPV4_GOTIP_BIT; +#endif + + os_printf("Waiting for AP connection...\r\n"); + xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY); + os_printf("Connected to AP\r\n"); +} + + + + + +void app_main() +{ + ESP_ERROR_CHECK(nvs_flash_init()); + initialise_wifi(); + wait_for_ip(); + DAP_Setup(); // DAP Setup + + xTaskCreate(timer_create_task, "timer_create", 512, NULL, 10, NULL); + xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 20, NULL); + xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 22, &kDAPTaskHandle); + // SWO Trace Task + //xTaskCreate(SWO_Thread, "swo_task", 1024, NULL, 6, NULL); + //xTaskCreate(usart_monitor_task, "uart_task", 512, NULL, 6, NULL); + +} diff --git a/main/tcp_server.c b/main/tcp_server.c index 1930626..99e9fe8 100644 --- a/main/tcp_server.c +++ b/main/tcp_server.c @@ -1,12 +1,16 @@ -/* BSD Socket API Example +/** + * @file tcp_server.c + * @brief Handle main tcp tasks + * @version 0.1 + * @date 2020-01-22 + * + * @copyright Copyright (c) 2020 + * + */ +#include "tcp_server.h" - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ #include +#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -22,110 +26,15 @@ #include "lwip/sys.h" #include -/* The examples use simple WiFi configuration that you can set via - 'make menuconfig'. - If you'd rather not, just change the below entries to strings with - the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" -*/ -#define EXAMPLE_WIFI_SSID "DAP" -#define EXAMPLE_WIFI_PASS "12345678" +#include "wifi_configuration.h" +#include "usbip_server.h" -#define PORT 22350 +uint8_t kState = ACCEPTING; +int kSock = -1; -/* FreeRTOS event group to signal when we are connected & ready to make a request */ -static EventGroupHandle_t wifi_event_group; - -const int IPV4_GOTIP_BIT = BIT0; -#ifdef CONFIG_EXAMPLE_IPV6 -const int IPV6_GOTIP_BIT = BIT1; -#endif - -static const char *TAG = "example"; - -static esp_err_t event_handler(void *ctx, system_event_t *event) +void tcp_server_task(void *pvParameters) { - /* For accessing reason codes in case of disconnection */ - system_event_info_t *info = &event->event_info; - - switch (event->event_id) - { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - os_printf("SYSTEM_EVENT_STA_START\r\n"); - break; - case SYSTEM_EVENT_STA_CONNECTED: -#ifdef CONFIG_EXAMPLE_IPV6 - /* enable ipv6 */ - tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); -#endif - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT); - os_printf("SYSTEM_EVENT_STA_GOT_IP\r\n"); - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - os_printf("Disconnect reason : %d\r\n", info->disconnected.reason); - if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) - { - /*Switch to 802.11 bgn mode */ - esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCAL_11B | WIFI_PROTOCAL_11G | WIFI_PROTOCAL_11N); - } - esp_wifi_connect(); - xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT); -#ifdef CONFIG_EXAMPLE_IPV6 - xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT); -#endif - break; - case SYSTEM_EVENT_AP_STA_GOT_IP6: -#ifdef CONFIG_EXAMPLE_IPV6 - xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT); - os_printf("SYSTEM_EVENT_STA_GOT_IP6\r\n"); - - char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip); - os_printf("IPv6: %s\r\n", ip6); -#endif - default: - break; - } - return ESP_OK; -} - -static void initialise_wifi(void) -{ - tcpip_adapter_init(); - wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); - wifi_config_t wifi_config = { - .sta = { - .ssid = EXAMPLE_WIFI_SSID, - .password = EXAMPLE_WIFI_PASS, - }, - }; - os_printf("Setting WiFi configuration SSID %s...\r\n", wifi_config.sta.ssid); - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); - ESP_ERROR_CHECK(esp_wifi_start()); -} - -static void wait_for_ip() -{ -#ifdef CONFIG_EXAMPLE_IPV6 - uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT; -#else - uint32_t bits = IPV4_GOTIP_BIT; -#endif - - os_printf("Waiting for AP connection...\r\n"); - xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY); - os_printf("Connected to AP"); -} - -static void tcp_server_task(void *pvParameters) -{ - char rx_buffer[2048]; + uint8_t tcp_rx_buffer[305]; char addr_str[128]; int addr_family; int ip_protocol; @@ -157,7 +66,7 @@ static void tcp_server_task(void *pvParameters) os_printf("Unable to create socket: errno %d\r\n", errno); break; } - os_printf("Socket created"); + os_printf("Socket created\r\n"); int err = bind(listen_sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); if (err != 0) @@ -165,7 +74,7 @@ static void tcp_server_task(void *pvParameters) os_printf("Socket unable to bind: errno %d\r\n", errno); break; } - os_printf("Socket binded"); + os_printf("Socket binded\r\n"); err = listen(listen_sock, 1); if (err != 0) @@ -173,86 +82,87 @@ static void tcp_server_task(void *pvParameters) os_printf("Error occured during listen: errno %d\r\n", errno); break; } - os_printf("Socket listening"); + os_printf("Socket listening\r\n"); #ifdef CONFIG_EXAMPLE_IPV6 struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 #else struct sockaddr_in sourceAddr; #endif - uint addrLen = sizeof(sourceAddr); - int sock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen); - if (sock < 0) - { - os_printf("Unable to accept connection: errno %d\r\n", errno); - break; - } - os_printf("Socket accepted"); - + uint32_t addrLen = sizeof(sourceAddr); while (1) { - int len = recv(sock, rx_buffer, 2047, 0); - // Error occured during receiving - if (len < 0) + kSock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen); + if (kSock < 0) { - os_printf("recv failed: errno %d\r\n", errno); + os_printf("Unable to accept connection: errno %d\r\n", errno); break; } - // Connection closed - else if (len == 0) - { - os_printf("Connection closed\r\n"); - break; - } - // Data received - else - { -#ifdef CONFIG_EXAMPLE_IPV6 - // Get the sender's ip address as string - if (sourceAddr.sin6_family == PF_INET) - { - inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); - } - else if (sourceAddr.sin6_family == PF_INET6) - { - inet6_ntoa_r(sourceAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); - } -#else - inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); -#endif + os_printf("Socket accepted\r\n"); - rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string - //os_printf("Received %d bytes from %s:\r\n", len, addr_str); - // os_printf("%s", rx_buffer); - - int err = send(sock, rx_buffer, len, 0); - if (err < 0) + while (1) + { + int len = recv(kSock, tcp_rx_buffer, sizeof(tcp_rx_buffer), 0); + // Error occured during receiving + if (len < 0) { - os_printf("Error occured during sending: errno %d\r\n", errno); + os_printf("recv failed: errno %d\r\n", errno); break; } + // Connection closed + else if (len == 0) + { + os_printf("Connection closed\r\n"); + break; + } + // Data received + else + { + // #ifdef CONFIG_EXAMPLE_IPV6 + // // Get the sender's ip address as string + // if (sourceAddr.sin6_family == PF_INET) + // { + // inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); + // } + // else if (sourceAddr.sin6_family == PF_INET6) + // { + // inet6_ntoa_r(sourceAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); + // } + // #else + // inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); + // #endif + + switch (kState) + { + case ACCEPTING: + kState = ATTACHING; + + case ATTACHING: + attach(tcp_rx_buffer, len); + break; + + case EMULATING: + emulate(tcp_rx_buffer, len); + break; + default: + os_printf("unkonw kstate!\r\n"); + } + } } - } + // kState = ACCEPTING; + if (kSock != -1) + { + os_printf("Shutting down socket and restarting...\r\n"); + //shutdown(kSock, 0); + close(kSock); + if (kState == EMULATING) + kState = ACCEPTING; - if (sock != -1) - { - os_printf("Shutting down socket and restarting...\r\n"); - shutdown(sock, 0); - close(sock); - - shutdown(listen_sock, 0); - close(listen_sock); - vTaskDelay(5); + //shutdown(listen_sock, 0); + //close(listen_sock); + //vTaskDelay(5); + } } } vTaskDelete(NULL); -} - -void app_main() -{ - ESP_ERROR_CHECK(nvs_flash_init()); - initialise_wifi(); - wait_for_ip(); - - xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL); -} +} \ No newline at end of file diff --git a/main/tcp_server.h b/main/tcp_server.h new file mode 100644 index 0000000..877ab2a --- /dev/null +++ b/main/tcp_server.h @@ -0,0 +1,6 @@ +#ifndef __TCP_SERVER_H__ +#define __TCP_SERVER_H__ + +void tcp_server_task(void *pvParameters); + +#endif \ No newline at end of file diff --git a/main/timer.c b/main/timer.c new file mode 100644 index 0000000..6fbe6b7 --- /dev/null +++ b/main/timer.c @@ -0,0 +1,29 @@ +/** + * @file timer.c + * @brief Hardware timer for DAP timestamp + * @version 0.1 + * @date 2020-01-22 + * + * @copyright Copyright (c) 2020 + * + */ +#include +#include +#include "timer.h" +#include "hw_timer.h" +#include "timer_struct.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +void timer_create_task() +{ + // FRC1 frequency 80MHz + vPortEnterCritical(); + frc1.ctrl.div = TIMER_CLKDIV_16; // 80MHz / 16 = 5MHz + frc1.ctrl.intr_type = TIMER_EDGE_INT; + frc1.ctrl.reload = 0x01; + frc1.load.data = 0x7FFFFF; // 23bit?? + frc1.ctrl.en = 0x01; + vPortExitCritical(); + vTaskDelete(NULL); +} \ No newline at end of file diff --git a/main/timer.h b/main/timer.h new file mode 100644 index 0000000..bc569a9 --- /dev/null +++ b/main/timer.h @@ -0,0 +1,6 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +void timer_create_task(); + +#endif \ No newline at end of file diff --git a/main/usbip_server.c b/main/usbip_server.c new file mode 100644 index 0000000..1eb2b75 --- /dev/null +++ b/main/usbip_server.c @@ -0,0 +1,376 @@ +#include +#include +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include + +#include "usbip_server.h" +#include "usbip_defs.h" +#include "usb_defs.h" +#include "USBd_config.h" +#include "DAP_handle.h" +#include "USB_handle.h" +#include "USBd_config.h" + +// attach helper function +static int read_stage1_command(uint8_t *buffer, uint32_t length); +static void handle_device_list(uint8_t *buffer, uint32_t length); +static void handle_device_attach(uint8_t *buffer, uint32_t length); +static void send_stage1_header(uint16_t command, uint32_t status); +static void send_device_list(); +static void send_device_info(); +static void send_interface_info(); + +// emulate helper function +static void pack(void *data, int size); +static void unpack(void *data, int size); +static int handle_submit(usbip_stage2_header *header, uint32_t length); +static int read_stage2_command(usbip_stage2_header *header, uint32_t length); + +static void handle_unlink(usbip_stage2_header *header); +// unlink helper function +static void send_stage2_unlink(usbip_stage2_header *req_header); + + + +int attach(uint8_t *buffer, uint32_t length) +{ + int command = read_stage1_command(buffer, length); + if (command < 0) + { + return -1; + } + + switch (command) + { + case USBIP_STAGE1_CMD_DEVICE_LIST: // OP_REQ_DEVLIST + handle_device_list(buffer, length); + break; + + case USBIP_STAGE1_CMD_DEVICE_ATTACH: // OP_REQ_IMPORT + handle_device_attach(buffer, length); + break; + + default: + os_printf("attach Unknown command: %d\r\n", command); + break; + } + return 0; +} + +static int read_stage1_command(uint8_t *buffer, uint32_t length) +{ + if (length < sizeof(usbip_stage1_header)) + { + return -1; + } + usbip_stage1_header *req = (usbip_stage1_header *)buffer; + return (ntohs(req->command) & 0xFF); // 0x80xx low bit +} + +static void handle_device_list(uint8_t *buffer, uint32_t length) +{ + os_printf("Handling dev list request...\r\n"); + send_stage1_header(USBIP_STAGE1_CMD_DEVICE_LIST, 0); + send_device_list(); +} + +static void handle_device_attach(uint8_t *buffer, uint32_t length) +{ + os_printf("Handling dev attach request...\r\n"); + + //char bus[USBIP_BUSID_SIZE]; + if (length < sizeof(USBIP_BUSID_SIZE)) + { + os_printf("handle device attach failed!\r\n"); + return; + } + //client.readBytes((uint8_t *)bus, USBIP_BUSID_SIZE); + + send_stage1_header(USBIP_STAGE1_CMD_DEVICE_ATTACH, 0); + + send_device_info(); + + kState = EMULATING; +} + +static void send_stage1_header(uint16_t command, uint32_t status) +{ + os_printf("Sending header...\r\n"); + usbip_stage1_header header; + header.version = htons(273); ////TODO: 273??? + // may be : https://github.com/Oxalin/usbip_windows/issues/4 + + header.command = htons(command); + header.status = htonl(status); + + send(kSock, (uint8_t *)&header, sizeof(usbip_stage1_header), 0); +} + +static void send_device_list() +{ + os_printf("Sending device list...\r\n"); + + // send device list size: + os_printf("Sending device list size...\r\n"); + usbip_stage1_response_devlist response_devlist; + + // we have only 1 device, so: + response_devlist.list_size = htonl(1); + + send(kSock, (uint8_t *)&response_devlist, sizeof(usbip_stage1_response_devlist), 0); + + // may be foreach: + + { + // send device info: + send_device_info(); + // send device interfaces: // (1) + send_interface_info(); + } +} + +static void send_device_info() +{ + os_printf("Sending device info...\r\n"); + usbip_stage1_usb_device device; + + strcpy(device.path, "/sys/devices/pci0000:00/0000:00:01.2/usb1/1-1"); + strcpy(device.busid, "1-1"); + + device.busnum = htonl(1); + device.devnum = htonl(1); + device.speed = htonl(3); // See usb_device_speed enum + + device.idVendor = htons(USBD0_DEV_DESC_IDVENDOR); + device.idProduct = htons(USBD0_DEV_DESC_IDPRODUCT); + device.bcdDevice = htons(USBD0_DEV_DESC_BCDDEVICE); + + device.bDeviceClass = 0x00; // We need to use a device other than the USB-IF standard, set to 0x00 + device.bDeviceSubClass = 0x00; + device.bDeviceProtocol = 0x00; + + device.bConfigurationValue = 1; + device.bNumConfigurations = 1; + device.bNumInterfaces = 1; + + send(kSock, (uint8_t *)&device, sizeof(usbip_stage1_usb_device), 0); +} + +static void send_interface_info() +{ + os_printf("Sending interface info...\r\n"); + usbip_stage1_usb_interface interface; + interface.bInterfaceClass = USBD_CUSTOM_CLASS0_IF0_CLASS; + interface.bInterfaceSubClass = USBD_CUSTOM_CLASS0_IF0_SUBCLASS; + interface.bInterfaceProtocol = USBD_CUSTOM_CLASS0_IF0_PROTOCOL; + interface.padding = 0; // shall be set to zero + + send(kSock, (uint8_t *)&interface, sizeof(usbip_stage1_usb_interface), 0); +} + +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// + +int emulate(uint8_t *buffer, uint32_t length) +{ + // usbip_stage2_header header; + #if (USE_WINUSB == 0) + if(fast_reply(buffer, length)) + { + return 0; + } + #endif + int command = read_stage2_command((usbip_stage2_header *)buffer, length); + if (command < 0) + { + return -1; + } + + switch (command) + { + case USBIP_STAGE2_REQ_SUBMIT: + handle_submit((usbip_stage2_header *)buffer , length); + break; + + case USBIP_STAGE2_REQ_UNLINK: + handle_unlink((usbip_stage2_header *)buffer); + break; + + default: + os_printf("emulate unknown command:%d\r\n", command); + //handle_submit((usbip_stage2_header *)buffer, length); + return -1; + } + return 0; +} + +static int read_stage2_command(usbip_stage2_header *header, uint32_t length) +{ + if (length < sizeof(usbip_stage2_header)) + { + return -1; + } + + //client.readBytes((uint8_t *)&header, sizeof(usbip_stage2_header)); + unpack((uint32_t *)header, sizeof(usbip_stage2_header)); + return header->base.command; +} + +/** + * @brief Pack the following packets(Offset 0x00 - 0x28): + * - cmd_submit + * - ret_submit + * - cmd_unlink + * - ret_unlink + * + * @param data Point to packets header + * @param size Packets header size + */ +static void pack(void *data, int size) +{ + + // Ignore the setup field + int sz = (size / sizeof(uint32_t)) - 2; + uint32_t *ptr = (uint32_t *)data; + + for (int i = 0; i < sz; i++) + { + + ptr[i] = htonl(ptr[i]); + } +} + +/** + * @brief Unack the following packets(Offset 0x00 - 0x28): + * - cmd_submit + * - ret_submit + * - cmd_unlink + * - ret_unlink + * + * @param data Point to packets header + * @param size packets header size + */ +static void unpack(void *data, int size) +{ + + // Ignore the setup field + int sz = (size / sizeof(uint32_t)) - 2; + uint32_t *ptr = (uint32_t *)data; + + for (int i = 0; i < sz; i++) + { + ptr[i] = ntohl(ptr[i]); + } +} + +/** + * @brief USB transaction processing + * + */ +static int handle_submit(usbip_stage2_header *header, uint32_t length) +{ + switch (header->base.ep) + { + // control endpoint(endpoint 0) + case 0x00: + handleUSBControlRequest(header); + break; + + // endpoint 1 data receicve and response + case 0x01: + if (header->base.direction == 0) + { + //os_printf("EP 01 DATA FROM HOST"); + handle_dap_data_request(header ,length); + } + else + { + // os_printf("EP 01 DATA TO HOST\r\n"); + handle_dap_data_response(header); + } + break; + // endpoint 2 for SWO trace + case 0x02: + if (header->base.direction == 0) + { + // os_printf("EP 02 DATA FROM HOST"); + send_stage2_submit(header, 0, 0); + } + else + { + // os_printf("EP 02 DATA TO HOST"); + handle_swo_trace_response(header); + } + break; + // request to save data to device + case 0x81: + if (header->base.direction == 0) + { + os_printf("*** WARN! EP 81 DATA TX"); + } + else + { + os_printf("*** WARN! EP 81 DATA RX"); + } + return -1; + + default: + os_printf("*** WARN ! UNKNOWN ENDPOINT: %d\r\n", (int)header->base.ep); + return -1; + } + return 0; +} + +void send_stage2_submit(usbip_stage2_header *req_header, int32_t status, int32_t data_length) +{ + + req_header->base.command = USBIP_STAGE2_RSP_SUBMIT; + req_header->base.direction = !(req_header->base.direction); + + memset(&(req_header->u.ret_submit), 0, sizeof(usbip_stage2_header_ret_submit)); + + req_header->u.ret_submit.status = status; + req_header->u.ret_submit.data_length = data_length; + + pack(req_header, sizeof(usbip_stage2_header)); + send(kSock, req_header, sizeof(usbip_stage2_header), 0); +} + +void send_stage2_submit_data(usbip_stage2_header *req_header, int32_t status, const void *const data, int32_t data_length) +{ + + send_stage2_submit(req_header, status, data_length); + + if (data_length) + { + send(kSock, data, data_length, 0); + } +} + +static void handle_unlink(usbip_stage2_header *header) +{ + os_printf("s2 handling cmd unlink...\r\n"); + send_stage2_unlink(header); +} +static void send_stage2_unlink(usbip_stage2_header *req_header) +{ + + req_header->base.command = USBIP_STAGE2_RSP_UNLINK; + req_header->base.direction = USBIP_DIR_OUT; + + memset(&(req_header->u.ret_unlink), 0, sizeof(usbip_stage2_header_ret_unlink)); + + // req_header.u.ret_unlink.status = 0; + + pack(req_header, sizeof(usbip_stage2_header)); + + send(kSock, req_header, sizeof(usbip_stage2_header), 0); +} \ No newline at end of file diff --git a/main/usbip_server.h b/main/usbip_server.h new file mode 100644 index 0000000..2d0effd --- /dev/null +++ b/main/usbip_server.h @@ -0,0 +1,19 @@ +#ifndef __USBIP_SERVER_H__ +#define __USBIP_SERVER_H__ +#include +#include "usbip_defs.h" +enum state_t +{ + ACCEPTING, + ATTACHING, + EMULATING +}; +extern uint8_t kState; +extern int kSock; + +int attach(uint8_t *buffer, uint32_t length); +int emulate(uint8_t *buffer, uint32_t length); +void send_stage2_submit_data(usbip_stage2_header *req_header, int32_t status, const void * const data, int32_t data_length); +void send_stage2_submit(usbip_stage2_header *req_header, int32_t status, int32_t data_length); + +#endif \ No newline at end of file diff --git a/main/wifi_configuration.h b/main/wifi_configuration.h new file mode 100644 index 0000000..5f84b6d --- /dev/null +++ b/main/wifi_configuration.h @@ -0,0 +1,20 @@ +/** + * @file wifi_configuration.h + * @brief Fill in your wifi configuration information here. + * @version 0.1 + * @date 2020-01-22 + * + * @copyright Copyright (c) 2020 + * + */ +#ifndef __WIFI_CONFIGURATION__ +#define __WIFI_CONFIGURATION__ + +#define WIFI_SSID "DAP" +#define WIFI_PASS "12345678" + +#define PORT 3240 + +#define CONFIG_EXAMPLE_IPV4 1 + +#endif \ No newline at end of file diff --git a/sdkconfig b/sdkconfig index 0b1692e..e20f324 100644 --- a/sdkconfig +++ b/sdkconfig @@ -33,19 +33,19 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set CONFIG_ESPTOOLPY_FLASHMODE="dio" CONFIG_SPI_FLASH_MODE=0x0 -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_SPI_FLASH_FREQ=0x0 +CONFIG_ESPTOOLPY_FLASHFREQ="80m" +CONFIG_SPI_FLASH_FREQ=0xf # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="8MB" -CONFIG_SPI_FLASH_SIZE=0x800000 +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_ESPTOOLPY_FLASHSIZE="16MB" +CONFIG_SPI_FLASH_SIZE=0x1000000 CONFIG_ESPTOOLPY_BEFORE_RESET=y # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set CONFIG_ESPTOOLPY_BEFORE="default_reset" @@ -69,16 +69,11 @@ CONFIG_PARTITION_TABLE_SINGLE_APP=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" -CONFIG_WIFI_SSID="myssid" -CONFIG_WIFI_PASSWORD="mypassword" -CONFIG_EXAMPLE_IPV4=y -# CONFIG_EXAMPLE_IPV6 is not set -CONFIG_EXAMPLE_PORT=3333 # CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y # CONFIG_COMPILER_CXX_EXCEPTIONS is not set CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set @@ -87,7 +82,7 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y # CONFIG_COMPILER_STACK_CHECK is not set # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set CONFIG_APP_UPDATE_CHECK_APP_SUM=y -# CONFIG_APP_UPDATE_CHECK_APP_HASH is not set +CONFIG_APP_UPDATE_CHECK_APP_HASH=y # CONFIG_AWS_IOT_SDK is not set # CONFIG_USING_ESP_CONSOLE is not set CONFIG_ESP_TLS_USING_MBEDTLS=y @@ -107,8 +102,8 @@ CONFIG_ESP_FILENAME_MACRO_NO_PATH=y # CONFIG_ESP_FILENAME_MACRO_NULL is not set CONFIG_USING_NEW_ETS_VPRINTF=y # CONFIG_LINK_ETS_PRINTF_TO_IRAM is not set -# CONFIG_SOC_FULL_ICACHE is not set -CONFIG_SOC_IRAM_SIZE=0xC000 +CONFIG_SOC_FULL_ICACHE=y +CONFIG_SOC_IRAM_SIZE=0x8000 CONFIG_CONSOLE_UART_DEFAULT=y # CONFIG_CONSOLE_UART_CUSTOM is not set # CONFIG_CONSOLE_UART_NONE is not set @@ -130,7 +125,6 @@ CONFIG_TASK_WDT_TIMEOUT_S=15 CONFIG_RESET_REASON=y CONFIG_WIFI_PPT_TASKSTACK_SIZE=2048 CONFIG_EVENT_LOOP_STACK_SIZE=2048 -CONFIG_ESP8266_CORE_GLOBAL_DATA_LINK_IRAM=y # CONFIG_ESP8266_OTA_FROM_OLD is not set # CONFIG_ESP8266_BOOT_COPY_APP is not set CONFIG_ESP_ERR_TO_NAME_LOOKUP=y @@ -141,7 +135,7 @@ CONFIG_WIFI_TX_RATE_SEQUENCE_FROM_HIGH=y # CONFIG_ESP8266_WIFI_QOS_ENABLED is not set # CONFIG_ESP8266_WIFI_AMPDU_RX_ENABLED is not set # CONFIG_ESP8266_WIFI_AMSDU_ENABLED is not set -CONFIG_ESP8266_WIFI_RX_BUFFER_NUM=16 +CONFIG_ESP8266_WIFI_RX_BUFFER_NUM=26 CONFIG_ESP8266_WIFI_LEFT_CONTINUOUS_RX_BUFFER_NUM=4 CONFIG_ESP8266_WIFI_RX_PKT_NUM=7 CONFIG_ESP8266_WIFI_TX_PKT_NUM=6 @@ -151,8 +145,8 @@ CONFIG_ESP8266_WIFI_CONNECT_OPEN_ROUTER_WHEN_PWD_IS_SET=y CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y # CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set CONFIG_ESP_PHY_INIT_DATA_VDD33_CONST=33 -CONFIG_ESP8266_PHY_MAX_WIFI_TX_POWER=20 -# CONFIG_ESP8266_HSPI_HIGH_THROUGHPUT is not set +CONFIG_ESP8266_PHY_MAX_WIFI_TX_POWER=21 +CONFIG_ESP8266_HSPI_HIGH_THROUGHPUT=y CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y CONFIG_HTTP_BUF_SIZE=512 CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 @@ -166,33 +160,31 @@ CONFIG_FREERTOS_MAX_HOOK=2 CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 CONFIG_FREERTOS_ISR_STACKSIZE=512 # CONFIG_FREERTOS_EXTENED_HOOKS is not set -CONFIG_FREERTOS_GLOBAL_DATA_LINK_IRAM=y -# CONFIG_FREERTOS_CODE_LINK_TO_IRAM is not set +CONFIG_FREERTOS_CODE_LINK_TO_IRAM=y CONFIG_FREERTOS_TIMER_STACKSIZE=2048 CONFIG_TASK_SWITCH_FASTER=y # CONFIG_USE_QUEUE_SETS is not set # CONFIG_ENABLE_FREERTOS_SLEEP is not set # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set -# CONFIG_HEAP_DISABLE_IRAM is not set +CONFIG_HEAP_DISABLE_IRAM=y # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set -# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +CONFIG_LOG_DEFAULT_LEVEL_ERROR=y # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set -CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_LOG_DEFAULT_LEVEL=3 +CONFIG_LOG_DEFAULT_LEVEL=1 CONFIG_LOG_COLORS=y # CONFIG_LOG_SET_LEVEL is not set -# CONFIG_LWIP_USE_IRAM is not set -# CONFIG_LWIP_HIGH_THROUGHPUT is not set -CONFIG_LWIP_GLOBAL_DATA_LINK_IRAM=y -CONFIG_TCPIP_RECVMBOX_SIZE=32 +CONFIG_LWIP_USE_IRAM=y +CONFIG_LWIP_HIGH_THROUGHPUT=y +CONFIG_TCPIP_RECVMBOX_SIZE=64 CONFIG_LWIP_ARP_TABLE_SIZE=10 CONFIG_LWIP_ARP_MAXAGE=300 # CONFIG_LWIP_ESP_GRATUITOUS_ARP is not set CONFIG_LWIP_SOCKET_MULTITHREAD=y -# CONFIG_ENABLE_NONBLOCK_SPEEDUP is not set +CONFIG_ENABLE_NONBLOCK_SPEEDUP=y CONFIG_SET_SOLINGER_DEFAULT=y CONFIG_ESP_UDP_SYNC_SEND=y CONFIG_ESP_UDP_SYNC_RETRY_MAX=5 @@ -202,8 +194,8 @@ CONFIG_LWIP_SO_REUSE_RXTOALL=y # CONFIG_LWIP_SO_RCVBUF is not set CONFIG_LWIP_RECV_BUFSIZE_DEFAULT=11680 CONFIG_LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT=10000 -# CONFIG_LWIP_IP_FRAG is not set -# CONFIG_LWIP_IP_REASSEMBLY is not set +CONFIG_LWIP_IP_FRAG=y +CONFIG_LWIP_IP_REASSEMBLY=y CONFIG_LWIP_IP_REASS_MAX_PBUFS=10 # CONFIG_LWIP_IP_SOF_BROADCAST is not set # CONFIG_LWIP_IP_SOF_BROADCAST_RECV is not set @@ -221,7 +213,7 @@ CONFIG_LWIP_IGMP=y CONFIG_ESP_DNS=y CONFIG_DNS_MAX_SERVERS=3 # CONFIG_LWIP_NETIF_LOOPBACK is not set -# CONFIG_TCP_HIGH_SPEED_RETRANSMISSION is not set +CONFIG_TCP_HIGH_SPEED_RETRANSMISSION=y CONFIG_LWIP_MAX_ACTIVE_TCP=5 CONFIG_LWIP_MAX_LISTENING_TCP=8 CONFIG_TCP_MAXRTX=12 @@ -229,7 +221,7 @@ CONFIG_TCP_SYNMAXRTX=6 CONFIG_TCP_MSS=1460 CONFIG_TCP_SND_BUF_DEFAULT=2920 CONFIG_TCP_WND_DEFAULT=5840 -CONFIG_TCP_RECVMBOX_SIZE=6 +CONFIG_TCP_RECVMBOX_SIZE=16 CONFIG_TCP_QUEUE_OOSEQ=y CONFIG_TCP_OVERSIZE_MSS=y # CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set @@ -237,7 +229,7 @@ CONFIG_TCP_OVERSIZE_MSS=y # CONFIG_LWIP_TCP_TIMESTAMPS is not set CONFIG_LWIP_MAX_UDP_PCBS=4 CONFIG_UDP_RECVMBOX_SIZE=6 -CONFIG_TCPIP_TASK_STACK_SIZE=2048 +CONFIG_TCPIP_TASK_STACK_SIZE=4096 CONFIG_LWIP_MAX_RAW_PCBS=4 # CONFIG_LWIP_IPV6 is not set # CONFIG_LWIP_STATS is not set @@ -343,7 +335,6 @@ CONFIG_OPENSSL_ASSERT_DO_NOTHING=y # CONFIG_ENABLE_PTHREAD is not set # CONFIG_USING_SPIFFS is not set CONFIG_IP_LOST_TIMER_INTERVAL=120 -CONFIG_TCPIP_ADAPTER_GLOBAL_DATA_LINK_IRAM=y # CONFIG_util_assert is not set CONFIG_ESP_SHA=y CONFIG_ESP_AES=y @@ -372,9 +363,9 @@ CONFIG_MONITOR_BAUD_OTHER_VAL=74880 CONFIG_MONITOR_BAUD=74880 # CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set CONFIG_OPTIMIZATION_LEVEL_RELEASE=y -CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y +# CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED is not set # CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set -# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=y # CONFIG_CXX_EXCEPTIONS is not set CONFIG_STACK_CHECK_NONE=y # CONFIG_STACK_CHECK_NORM is not set