├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── codeql-analysis.yml │ ├── codeql │ └── codeql-config.yml │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── README_CN.md ├── components ├── DAP │ ├── CMakeLists.txt │ ├── DAP_config.h │ ├── LICENSE │ └── cmsis-dap │ │ ├── include │ │ ├── DAP.h │ │ ├── cmsis_compiler.h │ │ ├── dap_utility.h │ │ ├── gpio_common.h │ │ ├── gpio_op.h │ │ ├── spi_op.h │ │ ├── spi_switch.h │ │ └── swo.h │ │ └── source │ │ ├── DAP.c │ │ ├── DAP_vendor.c │ │ ├── JTAG_DP.c │ │ ├── SWO.c │ │ ├── SW_DP.c │ │ ├── UART.c │ │ ├── dap_utility.c │ │ ├── spi_op.c │ │ └── spi_switch.c ├── SSDP │ ├── CMakeLists.txt │ ├── ssdp.c │ └── ssdp.h ├── USBIP │ ├── CMakeLists.txt │ ├── LICENSE │ ├── MSOS20_descriptor.c │ ├── MSOS20_descriptor.h │ ├── usb_defs.h │ ├── usb_descriptor.c │ ├── usb_descriptor.h │ ├── usb_handle.c │ ├── usb_handle.h │ └── usbip_defs.h ├── dap_proxy │ ├── CMakeLists.txt │ ├── DAP_handle.c │ ├── DAP_handle.h │ ├── LICENSE │ ├── corsacOTA.h │ ├── proxy_server_conf.h │ ├── tcp_server.c │ ├── tcp_server.h │ ├── usbip_server.c │ ├── usbip_server.h │ ├── websocket_server.c │ └── websocket_server.h ├── elaphureLink │ ├── CMakeLists.txt │ ├── LICENSE │ ├── elaphureLink_protocol.c │ └── elaphureLink_protocol.h ├── global_resource │ ├── CMakeLists.txt │ ├── global_module.c │ └── global_module.h ├── kcp │ ├── CMakeLists.txt │ ├── ikcp.c │ ├── ikcp.h │ ├── ikcp_util.c │ └── ikcp_util.h ├── memory_pool │ ├── CMakeLists.txt │ ├── memory_pool.c │ └── memory_pool.h ├── uart_tcp_bridge │ ├── CMakeLists.txt │ ├── uart_tcp_bridge.c │ └── uart_tcp_bridge.h └── utils │ ├── CMakeLists.txt │ └── list.h ├── main ├── CMakeLists.txt ├── dap_configuration.h ├── idf_component.yml └── main.c ├── partitions.csv ├── project_components ├── api_router │ ├── CMakeLists.txt │ ├── api_json_module.c │ ├── api_json_module.h │ ├── api_json_router.c │ └── api_json_router.h ├── html │ ├── CMakeLists.txt │ ├── index.html.gz │ ├── version.txt │ └── ws.sharedworker.js.gz ├── request_runner │ ├── CMakeLists.txt │ ├── request_runner.c │ └── request_runner.h ├── web_server │ ├── CMakeLists.txt │ ├── uri_modules │ │ ├── uri_api.c │ │ ├── uri_html_base.c │ │ └── uri_ws.c │ ├── web_server.c │ ├── web_server.h │ ├── web_uri_module.c │ └── web_uri_module.h ├── wifi_manager │ ├── CMakeLists.txt │ ├── wifi_api.c │ ├── wifi_api.h │ ├── wifi_api_json.c │ ├── wifi_configuration.h │ ├── wifi_event_handler.c │ ├── wifi_event_handler.h │ ├── wifi_json_utils.c │ ├── wifi_json_utils.h │ ├── wifi_manager.c │ ├── wifi_manager.h │ ├── wifi_storage.c │ ├── wifi_storage.h │ └── wifi_storage_priv.h ├── wt_common │ ├── CMakeLists.txt │ └── wt_data_def.h ├── wt_mdns │ ├── CMakeLists.txt │ ├── wt_mdns_config.c │ └── wt_mdns_config.h ├── wt_storage │ ├── CMakeLists.txt │ ├── wt_nvs.c │ ├── wt_nvs.h │ ├── wt_storage.c │ └── wt_storage.h └── wt_system │ ├── CMakeLists.txt │ ├── wt_system.c │ ├── wt_system.h │ ├── wt_system_api.h │ ├── wt_system_api_json.c │ ├── wt_system_json_utils.c │ └── wt_system_json_utils.h ├── sdkconfig.defaults ├── sdkconfig.defaults.esp32 ├── sdkconfig.defaults.esp32c3 └── sdkconfig.defaults.esp32s3 /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **chip used** 11 | esp32/esp32s3/esp32c3… 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots/logs** 20 | If applicable, add screenshots or logs to help explain your problem. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master, develop ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master, develop ] 20 | 21 | jobs: 22 | analyze: 23 | name: Analyze 24 | runs-on: ubuntu-20.04 25 | 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | language: [ 'cpp' ] 30 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 31 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 32 | 33 | steps: 34 | - name: Checkout repository 35 | uses: actions/checkout@v4 36 | with: 37 | submodules: recursive 38 | 39 | # Initializes the CodeQL tools for scanning. 40 | - name: Initialize CodeQL 41 | uses: github/codeql-action/init@v3 42 | with: 43 | languages: ${{ matrix.language }} 44 | config-file: ./.github/workflows/codeql/codeql-config.yml 45 | # If you wish to specify custom queries, you can do so here or in a config file. 46 | # By default, queries listed here will override any specified in a config file. 47 | # Prefix the list here with "+" to use these queries and those in the config file. 48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 49 | 50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 51 | # If this step fails, then you should remove it and run the build manually (see below) 52 | # - name: Autobuild 53 | # uses: github/codeql-action/autobuild@v1 54 | 55 | # ℹ️ Command-line programs to run using the OS shell. 56 | # 📚 https://git.io/JvXDl 57 | 58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 59 | # and modify them (or add more) to build your code if your project 60 | # uses a compiled language 61 | 62 | - if: matrix.language == 'cpp' || matrix.language == 'c' 63 | name: Build 64 | run: | 65 | sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 66 | wget https://github.com/espressif/esp-idf/releases/download/v5.2.1/esp-idf-v5.2.1.zip 67 | unzip esp-idf-v5.2.1.zip 68 | ./esp-idf-v5.2.1/install.sh esp32c3 69 | . ./esp-idf-v5.2.1/export.sh 70 | idf.py set-target esp32c3 71 | idf.py build 72 | 73 | - name: Perform CodeQL Analysis 74 | uses: github/codeql-action/analyze@v3 75 | -------------------------------------------------------------------------------- /.github/workflows/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "My CodeQL config" 2 | 3 | languages: cpp 4 | 5 | paths-ignore: 6 | - ESP8266_RTOS_SDK 7 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '**.md' 7 | - 'circuit' 8 | 9 | 10 | #env: 11 | # UPLOAD_USER_FIRMWARE: false 12 | 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-20.04 17 | continue-on-error: false 18 | strategy: 19 | matrix: 20 | target-hardware: [esp32c3,esp32,esp32s3] 21 | 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | submodules: recursive 27 | 28 | # - name: Generate release tag 29 | # id: tag 30 | # if: env.UPLOAD_USER_FIRMWARE == 'true' && steps.script.outputs.status == 'success' && !cancelled() 31 | # run: | 32 | # echo "::set-output name=release_tag::UserBuild_$(date +"%Y.%m.%d_%H-%M")" 33 | # echo "::set-output name=status::success" 34 | 35 | 36 | - name: Build for esp32/esp32c3 37 | if: matrix.target-hardware != 'esp8266' 38 | uses: espressif/esp-idf-ci-action@v1 39 | with: 40 | esp_idf_version: v5.2.1 41 | target: ${{ matrix.target-hardware }} 42 | path: './' 43 | 44 | # - name: Merge bin files (esp32) 45 | # if: matrix.target-hardware == 'esp32' 46 | # run: | 47 | # git clone https://github.com/espressif/esptool.git 48 | # git -C ./esptool/ checkout tags/v4.7.0 -b merge_wirless_bin 49 | # sudo python3 ./esptool/esptool.py --chip ${{ matrix.target-hardware }} merge_bin -o build/wireless_esp_dap_full.bin 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/wireless_tools_esp32.bin 50 | # sudo mv build/wireless_tools_esp32.bin build/wireless_esp_dap_app.bin 51 | 52 | # - name: Merge bin files (esp32c3) 53 | # if: matrix.target-hardware == 'esp32c3' 54 | # run: | 55 | # git clone https://github.com/espressif/esptool.git 56 | # git -C ./esptool/ checkout tags/v4.7.0 -b merge_wirless_bin 57 | # sudo python3 ./esptool/esptool.py --chip ${{ matrix.target-hardware }} merge_bin -o build/wireless_esp_dap_full.bin 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/wireless_tools_esp32.bin 58 | # sudo mv build/wireless_tools_esp32.bin build/wireless_esp_dap_app.bin 59 | 60 | - name: merge bin files (esp32) 61 | if: matrix.target-hardware == 'esp32' 62 | uses: espressif/esp-idf-ci-action@v1 63 | with: 64 | esp_idf_version: v5.2.1 65 | target: ${{ matrix.target-hardware }} 66 | path: './' 67 | command: esptool.py --chip ${{ matrix.target-hardware }} merge_bin -o build/wireless_tools_esp32_full.bin 0x1000 build/bootloader/bootloader.bin 0xF000 build/partition_table/partition-table.bin 0x20000 build/wireless_tools_esp32.bin 68 | 69 | 70 | - name: merge bin files (esp32c3) 71 | if: matrix.target-hardware == 'esp32c3' 72 | uses: espressif/esp-idf-ci-action@v1 73 | with: 74 | esp_idf_version: v5.2.1 75 | target: ${{ matrix.target-hardware }} 76 | path: './' 77 | command: esptool.py --chip ${{ matrix.target-hardware }} merge_bin -o build/wireless_tools_esp32_full.bin 0x0 build/bootloader/bootloader.bin 0xF000 build/partition_table/partition-table.bin 0x20000 build/wireless_tools_esp32.bin 78 | 79 | 80 | - name: merge bin files (esp32s3) 81 | if: matrix.target-hardware == 'esp32s3' 82 | uses: espressif/esp-idf-ci-action@v1 83 | with: 84 | esp_idf_version: v5.2.1 85 | target: ${{ matrix.target-hardware }} 86 | path: './' 87 | command: esptool.py --chip ${{ matrix.target-hardware }} merge_bin -o build/wireless_tools_esp32_full.bin 0x0 build/bootloader/bootloader.bin 0xF000 build/partition_table/partition-table.bin 0x20000 build/wireless_tools_esp32.bin 88 | 89 | 90 | - name: Upload firmware 91 | uses: actions/upload-artifact@v2 92 | with: 93 | name: firmware_${{ matrix.target-hardware }}.zip 94 | path: | 95 | build/wireless_tools_esp32_full.bin 96 | build/wireless_tools_esp32.bin 97 | build/bootloader/bootloader.bin 98 | build/partition_table/partition-table.bin 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | build/ 3 | tmp/ 4 | .history/ 5 | sdkconfig.old 6 | sdkconfig 7 | .idea/ 8 | dependencies.lock 9 | package-lock.json 10 | managed_components/ 11 | /version.txt -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | # Colored Compiler Output with ninja 3 | add_compile_options (-fdiagnostics-color=always) 4 | 5 | # sync with git version to version.txt 6 | function(write_git_version_to_file output_directory output_file) 7 | # use git versioning 8 | execute_process( 9 | COMMAND git describe --tags 10 | WORKING_DIRECTORY ${output_directory} 11 | OUTPUT_VARIABLE git_describe_output 12 | OUTPUT_STRIP_TRAILING_WHITESPACE 13 | ERROR_QUIET 14 | ) 15 | # Process the output to keep only version info 16 | string(REGEX REPLACE "-[0-9]*-g[0-9a-f]*" "" version_cleaned "${git_describe_output}") 17 | file(WRITE "${CMAKE_SOURCE_DIR}/${output_file}" "${version_cleaned}\n") 18 | message(STATUS "Version written to version.txt: ${version_cleaned}") 19 | endfunction() 20 | 21 | write_git_version_to_file(${CMAKE_SOURCE_DIR} version.txt) 22 | 23 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 24 | set(EXTRA_COMPONENT_DIRS project_components) 25 | 26 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 27 | project(wireless_tools_esp32) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [中文](README_CN.md) 2 | 3 | ## Introduce 4 | 5 | Wireless debugging with ***only one ESP Chip*** ! 6 | 7 | Realized by USBIP and CMSIS-DAP protocol stack. 8 | 9 | > 👉 5m range, 100kb size firmware(Hex) earse and download test: 10 | 11 |

12 | 13 | ---- 14 | 15 | For Keil users, we now also support [elaphureLink](https://github.com/windowsair/elaphureLink). No need for usbip to start your wireless debugging! 16 | 17 | ## Feature 18 | 19 | 1. SoC Compatibility 20 | - [x] ESP32 21 | - [x] ESP32C3 22 | - [x] ESP32S3 23 | 24 | 2. Debug Communication Mode 25 | - [x] SWD 26 | - [x] JTAG 27 | 28 | 3. USB Communication Mode 29 | - [x] USB-HID 30 | - [x] WCID & WinUSB (Default) 31 | 32 | 4. Debug Trace (Uart) 33 | - [x] Uart TCP Bridge 34 | 35 | 5. More.. 36 | - [x] SWD protocol based on SPI acceleration (Up to 40MHz) 37 | - [x] Support for [elaphureLink](https://github.com/windowsair/elaphureLink), fast Keil debug without drivers 38 | - [x] Support for [elaphure-dap.js](https://github.com/windowsair/elaphure-dap.js), online ARM Cortex-M firmware flash 39 | - [x] Support for OpenOCD/pyOCD 40 | - [x] ... 41 | 42 | 43 | 44 | ## Link your board 45 | 46 | ### WIFI 47 | 48 | The default connected WIFI SSID is `无线DAP` , password `12345678` 49 | 50 | Support for specifying multiple possible WAP. It can be added here: [wifi_configuration.h](main/wifi_configuration.h) 51 | 52 | You can also specify your IP in the above file (We recommend using the static address binding feature of the router). 53 | 54 | ![WIFI](https://user-images.githubusercontent.com/17078589/118365659-517e7880-b5d0-11eb-9a5b-afe43348c2ba.png) 55 | 56 | 57 | There is built-in ipv4 only mDNS server. You can access the device using `dap.local`. 58 | 59 | ![mDNS](https://user-images.githubusercontent.com/17078589/149659052-7b29533f-9660-4811-8125-f8f50490d762.png) 60 | 61 | 62 | 63 | ### Debugger 64 | 65 | 66 | 67 |
68 | ESP32 69 | 70 | | SWD | | 71 | |----------------|--------| 72 | | SWCLK | GPIO14 | 73 | | SWDIO | GPIO13 | 74 | | TVCC | 3V3 | 75 | | GND | GND | 76 | 77 | 78 | -------------- 79 | 80 | 81 | | JTAG | | 82 | |--------------------|---------| 83 | | TCK | GPIO14 | 84 | | TMS | GPIO13 | 85 | | TDI | GPIO18 | 86 | | TDO | GPIO19 | 87 | | nTRST \(optional\) | GPIO25 | 88 | | nRESET | GPIO26 | 89 | | TVCC | 3V3 | 90 | | GND | GND | 91 | 92 |
93 | 94 | 95 |
96 | ESP32C3 97 | 98 | | SWD | | 99 | |----------------|--------| 100 | | SWCLK | GPIO6 | 101 | | SWDIO | GPIO7 | 102 | | TVCC | 3V3 | 103 | | GND | GND | 104 | 105 | 106 | -------------- 107 | 108 | 109 | | JTAG | | 110 | |--------------------|--------| 111 | | TCK | GPIO6 | 112 | | TMS | GPIO7 | 113 | | TDI | GPIO5 | 114 | | TDO | GPIO3 | 115 | | nTRST \(optional\) | GPIO4 | 116 | | nRESET | GPIO10 | 117 | | TVCC | 3V3 | 118 | | GND | GND | 119 | 120 | 121 |
122 | 123 | 124 |
125 | ESP32S3 126 | 127 | | SWD | | 128 | |----------------|--------| 129 | | SWCLK | GPIO12 | 130 | | SWDIO | GPIO11 | 131 | | TVCC | 3V3 | 132 | | GND | GND | 133 | 134 | 135 | -------------- 136 | 137 | 138 | | JTAG | | 139 | |--------------------|--------| 140 | | TCK | GPIO12 | 141 | | TMS | GPIO11 | 142 | | TDI | GPIO10 | 143 | | TDO | GPIO9 | 144 | | nTRST \(optional\) | GPIO14 | 145 | | nRESET | GPIO13 | 146 | | TVCC | 3V3 | 147 | | GND | GND | 148 | 149 | 150 |
151 | 152 | ---- 153 | 154 | 155 | ## Build And Flash 156 | 157 | You can build locally or use Github Action to build online and then download firmware to flash. 158 | 159 | 160 | ### General build and Flash 161 | 162 |
163 | ESP32C3 164 | 165 | 1. Get esp-idf 166 | 167 | For now, please use esp-idf v5.2.1 : https://github.com/espressif/esp-idf/releases/tag/v5.2.1 168 | 169 | 2. Build & Flash 170 | 171 | Build with ESP-IDF build system. 172 | 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") 173 | 174 | The following example shows a possible way to build: 175 | 176 | ```bash 177 | # Set build target 178 | idf.py set-target esp32c3 179 | # Build 180 | idf.py build 181 | # Flash 182 | idf.py -p /dev/ttyS5 flash 183 | ``` 184 | 185 |
186 | 187 | ## Usage 188 | 189 | 1. Get USBIP project 190 | 191 | - Windows: [usbip-win](https://github.com/cezanne/usbip-win) . 192 | - Linux: Distributed as part of the Linux kernel, but we have not yet tested on Linux platform, and the following instructions are all under Windows platform. 193 | 194 | 2. Start ESP chip and connect it to the device to be debugged 195 | 196 | 3. Connect it with usbip: 197 | 198 | ```bash 199 | # HID Mode only 200 | # for pre-compiled version on SourceForge 201 | # or usbip old version 202 | .\usbip.exe -D -a 1-1 203 | 204 | # 👉 Recommend 205 | # HID Mode Or WinUSB Mode 206 | # for usbip-win 0.3.0 kmdf ude 207 | .\usbip.exe attach_ude -r -b 1-1 208 | 209 | ``` 210 | 211 | If all goes well, you should see your device connected. 212 | 213 | ![image](https://user-images.githubusercontent.com/17078589/107849548-f903d780-6e36-11eb-846f-3eaf0c0dc089.png) 214 | 215 | 216 | Here, we use MDK for testing: 217 | 218 | ![target](https://user-images.githubusercontent.com/17078589/73830040-eb3c6f00-483e-11ea-85ee-c40b68a836b2.png) 219 | 220 | 221 | ------ 222 | 223 | ## FAQ 224 | 225 | ### Keil is showing a "RDDI-DAP ERROR" or "SWD/JTAG Communication Failure" message. 226 | 227 | 1. Check your line connection. Don't forget the 3v3 connection cable. 228 | 2. Check that your network connection is stable. 229 | 230 | 231 | ### DAP is slow or often abnormal. 232 | 233 | Note that this project is sensitive to the network environment. If you are using a hotspot on your computer, you can try using network analyzer such as wireshark to observe the status of your AP network. During the idle time, the network should stay silent, while in the working state, there should be no too much packet loss. 234 | 235 | Some LAN broadcast packets can cause serious impact, including: 236 | - DropBox LAN Sync 237 | - Logitech Arx Control 238 | - ... 239 | 240 | 241 | It is also affected by the surrounding radio environment, your AP situation (some NICs have terrible AP performance), distance, etc. 242 | 243 | 244 | ---- 245 | 246 | ## Document 247 | 248 | ### Speed Strategy 249 | 250 | The maximum rate of esp8266 pure IO is about 2MHz. 251 | When you select max clock, we will take the following actions: 252 | 253 | - `clock < 2Mhz` : Similar to the clock speed you choose. 254 | - `2MHz <= clock < 10MHz` : Use the fastest pure IO speed. 255 | - `clock >= 10MHz` : SPI acceleration using 40MHz clock. 256 | 257 | > Note that the most significant speed constraint of this project is still the TCP connection speed. 258 | 259 | 260 | ### For OpenOCD user 261 | 262 | This project was originally designed to run on Keil, but now you can also perform firmware flash on OpenOCD. 263 | 264 | ```bash 265 | > halt 266 | > flash write_image [erase] [unlock] filename [offset] [type] 267 | ``` 268 | 269 | > pyOCD is now supported. 270 | 271 | ### Uart TCP Bridge 272 | 273 | TCP server on PORT 1234. 274 | 275 | UART default baud: 74880 276 | 277 | This feature provides a bridge between TCP and Uart: 278 | ``` 279 | Send data -> TCP -> Uart TX -> external devices 280 | 281 | Recv data <- TCP <- Uart Rx <- external devices 282 | ``` 283 | 284 | ![uart_tcp_bridge](https://user-images.githubusercontent.com/17078589/150290065-05173965-8849-4452-ab7e-ec7649f46620.jpg) 285 | 286 | When the TCP connection is established, bridge will try to resolve the text sent for the first packet. When the text is a valid baud rate, bridge will switch to it. 287 | For example, sending the ASCII text `115200` will switch the baud rate to 115200. 288 | 289 |
290 | ESP32C3 291 | 292 | | | PIN | 293 | |-----|--------| 294 | | RX | GPIO20 | 295 | | TX | GPIO21 | 296 | 297 |
298 | 299 | 300 |
301 | ESP32 302 | 303 | | | PIN | 304 | |-----|--------| 305 | | RX | GPIO22 | 306 | | TX | GPIO23 | 307 | 308 |
309 | 310 |
311 | ESP32S3 312 | 313 | | | PIN | 314 | |-----|--------| 315 | | RX | GPIO18 | 316 | | TX | GPIO17 | 317 | 318 | 319 | 320 |
321 | 322 | 2020.12.1 323 | 324 | TCP transmission speed needs to be further improved. 325 | 326 | 2020.11.11 327 | 328 | Winusb is now available, but it is very slow. 329 | 330 | 331 | 2020.2.4 332 | 333 | 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. 334 | 335 | 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. 336 | 337 | 2020.1.31 338 | 339 | 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. 340 | 341 | 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. 342 | 343 | 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 344 | 345 | 346 | ------ 347 | 348 | ## Credit 349 | 350 | 351 | Credits to the following project, people and organizations: 352 | 353 | > - https://www.github.com/windowsair/wireless-esp8266-dap origin of this project 354 | > - https://github.com/thevoidnn/esp8266-wifi-cmsis-dap for adapter firmware based on CMSIS-DAP v1.0 355 | > - https://github.com/ARM-software/CMSIS_5 for CMSIS 356 | > - https://github.com/cezanne/usbip-win for usbip windows 357 | 358 | - [@windowsair](https://www.github.com/windowsair/wireless-esp8266-dap) 359 | - [@HeavenSpree](https://www.github.com/HeavenSpree) 360 | - [@Zy19930907](https://www.github.com/Zy19930907) 361 | - [@caiguang1997](https://www.github.com/caiguang1997) 362 | - [@ZhuYanzhen1](https://www.github.com/ZhuYanzhen1) 363 | 364 | 365 | ## License 366 | 367 | [MIT LICENSE](LICENSE) 368 | 369 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 只需要**一枚ESP芯片**即可开始无线调试!通过USBIP协议栈和CMSIS-DAP协议栈实现。 4 | 5 | > 👉在5米范围内,擦除并烧写100kb大小的固件(Hex固件) : 6 | 7 |

8 | 9 | ---- 10 | 11 | 对于Keil用户,我们现在支持[elaphureLink](https://github.com/windowsair/elaphureLink)。无需usbip即可开始您的无线调试之旅! 12 | 13 | ## 特性 14 | 15 | 1. 支持的ESP芯片 16 | - [x] ESP32 17 | - [x] ESP32C3 18 | - [x] ESP32S3 19 | 20 | 2. 支持的调试接口: 21 | - [x] SWD 22 | - [x] JTAG 23 | 24 | 3. 支持的USB通信协议: 25 | - [x] USB-HID 26 | - [x] WCID & WinUSB (默认) 27 | 4. 支持的调试跟踪器: 28 | - [x] TCP转发的串口 29 | 30 | 5. 其它 31 | - [x] 通过SPI接口加速的SWD协议(最高可达40MHz) 32 | - [x] 支持 [elaphureLink](https://github.com/windowsair/elaphureLink),无需驱动的快速Keil 调试 33 | - [x] 支持 [elaphure-dap.js](https://github.com/windowsair/elaphure-dap.js),网页端的 ARM Cortex-M 设备固件烧录调试 34 | - [x] 支持 OpenOCD/pyOCD 35 | - [x] ... 36 | 37 | ## 连接你的开发板 38 | 39 | ### WIFI连接 40 | 41 | 固件默认的WIFI SSID是`无线DAP`或者`OTA`,密码是`12345678`。 42 | 43 | 固件中已经内置了一个mDNS服务。你可以通过`dap.local`的地址访问到设备。 44 | 45 | ![mDNS](https://user-images.githubusercontent.com/17078589/149659052-7b29533f-9660-4811-8125-f8f50490d762.png) 46 | 47 | 48 | ### 调试接口连接 49 | 50 | 51 |
52 | ESP32 53 | 54 | | SWD | | 55 | |----------------|--------| 56 | | SWCLK | GPIO14 | 57 | | SWDIO | GPIO13 | 58 | | TVCC | 3V3 | 59 | | GND | GND | 60 | 61 | -------------- 62 | 63 | | JTAG | | 64 | |--------------------|---------| 65 | | TCK | GPIO14 | 66 | | TMS | GPIO13 | 67 | | TDI | GPIO18 | 68 | | TDO | GPIO19 | 69 | | nTRST \(optional\) | GPIO25 | 70 | | nRESET | GPIO26 | 71 | | TVCC | 3V3 | 72 | | GND | GND | 73 | 74 |
75 | 76 |
77 | ESP32C3 78 | 79 | | SWD | | 80 | |----------------|--------| 81 | | SWCLK | GPIO6 | 82 | | SWDIO | GPIO7 | 83 | | TVCC | 3V3 | 84 | | GND | GND | 85 | 86 | -------------- 87 | 88 | | JTAG | | 89 | |--------------------|---------| 90 | | TCK | GPIO6 | 91 | | TMS | GPIO7 | 92 | | TDI | GPIO9 | 93 | | TDO | GPIO8 | 94 | | nTRST \(optional\) | GPIO4 | 95 | | nRESET | GPIO5 | 96 | | TVCC | 3V3 | 97 | | GND | GND | 98 | 99 | 100 |
101 | 102 |
103 | ESP32S3 104 | 105 | | SWD | | 106 | |----------------|--------| 107 | | SWCLK | GPIO12 | 108 | | SWDIO | GPIO11 | 109 | | TVCC | 3V3 | 110 | | GND | GND | 111 | 112 | 113 | -------------- 114 | 115 | 116 | | JTAG | | 117 | |--------------------|--------| 118 | | TCK | GPIO12 | 119 | | TMS | GPIO11 | 120 | | TDI | GPIO10 | 121 | | TDO | GPIO9 | 122 | | nTRST \(optional\) | GPIO14 | 123 | | nRESET | GPIO13 | 124 | | TVCC | 3V3 | 125 | | GND | GND | 126 | 127 |
128 | 129 | ---- 130 | 131 | ## 编译固件并烧写 132 | 133 | 你可以在本地构建或使用Github Action在线构建固件,然后下载固件进行烧写。 134 | 135 | 136 | ### 在本地构建并烧写 137 | 138 |
139 | ESP32C3 140 | 141 | 1. 获取esp-idf 142 | 143 | 目前,请考虑使用esp-idf v5.2.1: https://github.com/espressif/esp-idf/releases/tag/v5.2.1 144 | 145 | 2. 编译和烧写 146 | 147 | 使用ESP-IDF编译系统进行构建。 148 | 更多的信息,请见:[Build System](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html "Build System") 149 | 150 | 151 | 下面例子展示了在Windows上完成这些任务的一种可行方法: 152 | 153 | ```bash 154 | idf.py set-target esp32c3 155 | # 编译 156 | idf.py build 157 | # 烧写 158 | idf.py -p /dev/ttyS5 flash 159 | ``` 160 | 161 | 162 | > 位于项目根目录的`idf.py`脚本仅适用于较老的ESP8266设备,请不要在ESP32设备上使用。 163 | 164 |
165 | 166 | ## 使用 167 | 168 | 1. 获取USBIP项目 169 | 170 | - Windows: [usbip-win](https://github.com/cezanne/usbip-win)。 171 | - Linux:USBIP作为Linux内核的一部分发布,但我们还没有在Linux平台上测试,下面的说明都是在Windows平台下的。 172 | 173 | 2. 启动ESP8266并且把ESP8266连接到同一个WIFI下。 174 | 175 | 3. 通过USBIP连接ESP8266: 176 | 177 | ```bash 178 | # 仅HID模式,用于SourceForge上的预编译版本或者旧的USBIP版本。 179 | .\usbip.exe -D -a 1-1 180 | 181 | # 👉 推荐。HID模式或者WinUSB模式。用于usbip-win 0.3.0 kmdf ude版本。 182 | .\usbip.exe attach_ude -r -b 1-1 183 | ``` 184 | 185 | 如果一切顺利,你应该看到你的设备被连接,如下图所示。 186 | 187 | ![image](https://user-images.githubusercontent.com/17078589/107849548-f903d780-6e36-11eb-846f-3eaf0c0dc089.png) 188 | 189 | 下面我们用keil MDK来测试: 190 | 191 | ![target](https://user-images.githubusercontent.com/17078589/73830040-eb3c6f00-483e-11ea-85ee-c40b68a836b2.png) 192 | 193 | ------ 194 | 195 | ## 经常会问的问题 196 | 197 | ### Keil提示“RDDI-DAP ERROR”或“SWD/JTAG Communication Failure” 198 | 199 | 1. 检查线路连接。别忘了连接3V3引脚。 200 | 2. 检查网络连接是否稳定。 201 | 202 | 203 | ## DAP很慢或者不稳定 204 | 205 | 注意,本项目受限于周围的网络环境。如果你在电脑上使用热点进行连接,你可以尝试使用wireshark等工具对网络连接进行分析。当调试闲置时,线路上应保持静默,而正常工作时一般不会发生太多的丢包。 206 | 207 | 一些局域网广播数据包可能会造成严重影响,这些包可能由这些应用发出: 208 | - DropBox LAN Sync 209 | - Logitech Arx Control 210 | - ... 211 | 212 | 213 | 周围的射频环境同样会造成影响,此外距离、网卡性能等也可能是需要考虑的。 214 | 215 | 216 | ## 文档 217 | 218 | ### 速度策略 219 | 220 | 单独使用ESP8266通用IO时的最大翻转速率只有大概2MHz。当你选择最大时钟时,我们需要采取以下操作: 221 | 222 | - `clock < 2Mhz` :与你选择的时钟速度类似。 223 | - `2MHz <= clock < 10MHz` :使用最快的纯IO速度。 224 | - `clock >= 10MHz` :使用40MHz时钟的SPI加速。 225 | 226 | > 请注意,这个项目最重要的速度制约因素仍然是TCP连接速度。 227 | 228 | ### 对于OpenOCD用户 229 | 230 | 这个项目最初是为在Keil上运行而设计的,但现在你也可以在OpenOCD上通过它来烧录程序。 231 | 232 | ```bash 233 | > halt 234 | > flash write_image [erase] [unlock] filename [offset] [type] 235 | ``` 236 | 237 | > 现已支持 pyOCD 238 | 239 | ### TCP转发的串口 240 | 241 | TCP端口:1234 242 | 243 | 默认UART波特率:74880 244 | 245 | 该功能在TCP和Uart之间提供了一个桥梁: 246 | ``` 247 | 发送数据 -> TCP -> Uart TX -> 外部设备 248 | 249 | 接收数据 <- TCP <- Uart Rx <- 外部设备 250 | ``` 251 | 252 | ![uart_tcp_bridge](https://user-images.githubusercontent.com/17078589/150290065-05173965-8849-4452-ab7e-ec7649f46620.jpg) 253 | 254 | 当TCP连接建立后,ESP芯片将尝试解决首次发送的文本。当文本是一个有效的波特率时,转发器就会切换到该波特率。例如,发送ASCII文本`115200`会将波特率切换为115200。 255 | 由于性能原因,该功能默认不启用。你可以修改 [wifi_configuration.h](main/wifi_configuration.h) 来打开它。 256 | 257 | 258 | ----- 259 | 260 | # 致谢 261 | 262 | 归功于以下项目、人员和组织。 263 | 264 | > - https://www.github.com/windowsair/wireless-esp8266-dap origin of this project 265 | > - https://github.com/thevoidnn/esp8266-wifi-cmsis-dap for adapter firmware based on CMSIS-DAP v1.0 266 | > - https://github.com/ARM-software/CMSIS_5 for CMSIS 267 | > - https://github.com/cezanne/usbip-win for usbip windows 268 | 269 | - [@windowsair](https://www.github.com/windowsair/wireless-esp8266-dap) 270 | - [@HeavenSpree](https://www.github.com/HeavenSpree) 271 | - [@Zy19930907](https://www.github.com/Zy19930907) 272 | - [@caiguang1997](https://www.github.com/caiguang1997) 273 | - [@ZhuYanzhen1](https://www.github.com/ZhuYanzhen1) 274 | 275 | 276 | ## 许可证 277 | [MIT 许可证](LICENSE) 278 | -------------------------------------------------------------------------------- /components/DAP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | ./cmsis-dap/source/*.c 3 | ) 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | ) 9 | -------------------------------------------------------------------------------- /components/DAP/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 windowsair 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/cmsis_compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef __CMSIS_COMPILER_H__ 2 | #define __CMSIS_COMPILER_H__ 3 | 4 | #ifndef __STATIC_FORCEINLINE 5 | #define __STATIC_FORCEINLINE static inline __attribute__((always_inline)) 6 | #endif 7 | #ifndef __STATIC_INLINE 8 | #define __STATIC_INLINE static inline __attribute__((always_inline)) 9 | #endif 10 | #ifndef __FORCEINLINE 11 | #define __FORCEINLINE inline __attribute__((always_inline)) 12 | #endif 13 | #ifndef __WEAK 14 | #define __WEAK __attribute__((weak)) 15 | #endif 16 | 17 | #ifndef __UNUSED 18 | #define __UNUSED __attribute__((unused)) 19 | #endif 20 | 21 | 22 | #endif -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/dap_utility.h: -------------------------------------------------------------------------------- 1 | #ifndef __DAP_UTILITY_H__ 2 | #define __DAP_UTILITY_H__ 3 | 4 | #include 5 | 6 | #ifndef __STATIC_FORCEINLINE 7 | #define __STATIC_FORCEINLINE static inline __attribute__((always_inline)) 8 | #endif 9 | #ifndef __STATIC_INLINE 10 | #define __STATIC_INLINE static inline __attribute__((always_inline)) 11 | #endif 12 | #ifndef __WEAK 13 | #define __WEAK __attribute__((weak)) 14 | #endif 15 | 16 | 17 | extern const uint8_t kParityByteTable[256]; 18 | 19 | __STATIC_FORCEINLINE uint8_t ParityEvenUint32(uint32_t v) 20 | { 21 | v ^= v >> 16; 22 | v ^= v >> 8; 23 | v ^= v >> 4; 24 | v &= 0xf; 25 | return (0x6996 >> v) & 1; 26 | } 27 | 28 | __STATIC_FORCEINLINE uint8_t ParityEvenUint8(uint8_t v) 29 | { 30 | return kParityByteTable[v]; 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/gpio_common.h: -------------------------------------------------------------------------------- 1 | #ifndef __GPIO_COMMON_H__ 2 | #define __GPIO_COMMON_H__ 3 | 4 | #include "sdkconfig.h" 5 | #include "esp_idf_version.h" 6 | 7 | #ifdef CONFIG_IDF_TARGET_ESP8266 8 | #include "esp8266/spi_struct.h" 9 | #include "gpio.h" 10 | #include "esp8266/include/esp8266/gpio_struct.h" 11 | #include "esp8266/include/esp8266/timer_struct.h" 12 | #include "esp8266/pin_mux_register.h" 13 | 14 | #elif defined CONFIG_IDF_TARGET_ESP32 15 | #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0) 16 | #include "soc/io_mux_reg.h" 17 | #include "soc/gpio_struct.h" 18 | #include "soc/dport_access.h" 19 | #include "soc/dport_reg.h" 20 | #include "soc/periph_defs.h" 21 | #include "soc/spi_struct.h" 22 | #include "soc/spi_reg.h" 23 | #include "soc/gpio_periph.h" 24 | #include "hal/gpio_ll.h" 25 | #else 26 | #include "soc/soc/esp32/include/soc/gpio_struct.h" 27 | #include "soc/soc/esp32/include/soc/dport_access.h" 28 | #include "soc/soc/esp32/include/soc/dport_reg.h" 29 | #include "soc/soc/esp32/include/soc/periph_defs.h" 30 | #include "soc/soc/esp32/include/soc/spi_struct.h" 31 | #include "soc/soc/esp32/include/soc/spi_reg.h" 32 | #endif 33 | #include "hal/gpio_types.h" 34 | #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) 35 | #include "soc/gpio_struct.h" 36 | #include "hal/gpio_ll.h" 37 | #include "hal/gpio_hal.h" 38 | #include "hal/clk_gate_ll.h" 39 | #include "soc/gpio_struct.h" 40 | #include "soc/dport_access.h" 41 | #include "soc/periph_defs.h" 42 | #include "soc/usb_serial_jtag_reg.h" 43 | #include "soc/io_mux_reg.h" 44 | #include "soc/spi_struct.h" 45 | #include "soc/spi_reg.h" 46 | #else 47 | #error unknown hardware 48 | #endif 49 | 50 | 51 | #endif -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/gpio_op.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gpio_op.h 3 | * @author windowsair 4 | * @brief esp GPIO operation 5 | * @version 0.1 6 | * @date 2021-03-03 7 | * 8 | * @copyright Copyright (c) 2021 9 | * 10 | */ 11 | 12 | #ifndef __GPIO_OP_H__ 13 | #define __GPIO_OP_H__ 14 | 15 | #include "sdkconfig.h" 16 | #include "cmsis-dap/include/cmsis_compiler.h" 17 | #include "cmsis-dap/include/gpio_common.h" 18 | 19 | 20 | 21 | #ifdef CONFIG_IDF_TARGET_ESP8266 22 | __STATIC_INLINE __UNUSED void GPIO_FUNCTION_SET(int io_num) 23 | { 24 | gpio_pin_reg_t pin_reg; 25 | 26 | pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(io_num)); 27 | 28 | // It should be noted that GPIO0, 2, 4, and 5 need to set the func register to 0, 29 | // and the other GPIO needs to be set to 3 so that IO can be GPIO function. 30 | if ((0x1 << io_num) & (GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5)) { 31 | pin_reg.rtc_pin.func_low_bit = 0; 32 | pin_reg.rtc_pin.func_high_bit = 0; 33 | } else { 34 | pin_reg.func_low_bit = 3; 35 | pin_reg.func_high_bit = 0; 36 | } 37 | 38 | WRITE_PERI_REG(GPIO_PIN_REG(io_num), pin_reg.val); 39 | } 40 | #elif defined CONFIG_IDF_TARGET_ESP32 41 | __STATIC_INLINE __UNUSED void GPIO_FUNCTION_SET(int io_num) 42 | { 43 | // function number 2 is GPIO_FUNC for each pin 44 | // Note that the index starts at 0, so we are using function 3. 45 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[io_num], PIN_FUNC_GPIO); 46 | } 47 | #elif defined CONFIG_IDF_TARGET_ESP32C3 48 | __STATIC_INLINE __UNUSED void GPIO_FUNCTION_SET(int io_num) 49 | { 50 | // Disable USB Serial JTAG if pins 18 or pins 19 needs to select an IOMUX function 51 | if (io_num == IO_MUX_GPIO18_REG || io_num == IO_MUX_GPIO19_REG) { 52 | CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); 53 | } 54 | PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[io_num], PIN_FUNC_GPIO); 55 | } 56 | #elif defined CONFIG_IDF_TARGET_ESP32S3 57 | __STATIC_INLINE __UNUSED void GPIO_FUNCTION_SET(int io_num) 58 | { 59 | gpio_ll_iomux_func_sel(GPIO_PIN_MUX_REG[io_num], PIN_FUNC_GPIO); 60 | } 61 | #endif 62 | 63 | 64 | #ifdef CONFIG_IDF_TARGET_ESP8266 65 | __STATIC_INLINE __UNUSED void GPIO_SET_DIRECTION_NORMAL_OUT(int io_num) 66 | { 67 | GPIO.enable_w1ts |= (0x1 << io_num); 68 | // PP out 69 | GPIO.pin[io_num].driver = 0; 70 | } 71 | #elif defined CONFIG_IDF_TARGET_ESP32 72 | __STATIC_INLINE __UNUSED void GPIO_SET_DIRECTION_NORMAL_OUT(int io_num) 73 | { 74 | GPIO.enable_w1ts = (0x1 << io_num); 75 | // PP out 76 | GPIO.pin[io_num].pad_driver = 0; 77 | } 78 | #elif defined CONFIG_IDF_TARGET_ESP32C3 79 | __STATIC_INLINE __UNUSED void GPIO_SET_DIRECTION_NORMAL_OUT(int io_num) 80 | { 81 | GPIO.enable_w1ts.enable_w1ts = (0x1 << io_num); 82 | // PP out 83 | GPIO.pin[io_num].pad_driver = 0; 84 | } 85 | #elif defined CONFIG_IDF_TARGET_ESP32S3 86 | __STATIC_INLINE __UNUSED void GPIO_SET_DIRECTION_NORMAL_OUT(int io_num) 87 | { 88 | gpio_ll_output_enable(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num); 89 | // PP out 90 | gpio_ll_od_disable(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num); 91 | } 92 | #endif 93 | 94 | 95 | #if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 96 | __STATIC_INLINE __UNUSED void GPIO_SET_LEVEL_HIGH(int io_num) 97 | { 98 | GPIO.out_w1ts |= (0x1 << io_num); 99 | } 100 | //FIXME: esp32 101 | __STATIC_INLINE __UNUSED void GPIO_SET_LEVEL_LOW(int io_num) 102 | { 103 | GPIO.out_w1tc |= (0x1 << io_num); 104 | } 105 | #elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 106 | __STATIC_INLINE __UNUSED void GPIO_SET_LEVEL_HIGH(int io_num) 107 | { 108 | gpio_ll_set_level(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num, 1); 109 | } 110 | __STATIC_INLINE __UNUSED void GPIO_SET_LEVEL_LOW(int io_num) 111 | { 112 | gpio_ll_set_level(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num, 0); 113 | } 114 | #endif 115 | 116 | 117 | #if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 118 | __STATIC_INLINE __UNUSED int GPIO_GET_LEVEL(int io_num) 119 | { 120 | return ((GPIO.in >> io_num) & 0x1) ? 1 : 0; 121 | } 122 | #elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 123 | __STATIC_INLINE __UNUSED int GPIO_GET_LEVEL(int io_num) 124 | { 125 | return gpio_ll_get_level(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num); 126 | } 127 | #endif 128 | 129 | 130 | 131 | 132 | #if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32C3 133 | __STATIC_INLINE __UNUSED void GPIO_PULL_UP_ONLY_SET(int io_num) 134 | { 135 | // disable pull down 136 | REG_CLR_BIT(GPIO_PIN_MUX_REG[io_num], FUN_PD); 137 | // enable pull up 138 | REG_SET_BIT(GPIO_PIN_MUX_REG[io_num], FUN_PU); 139 | } 140 | #elif defined CONFIG_IDF_TARGET_ESP32S3 141 | __STATIC_INLINE __UNUSED void GPIO_PULL_UP_ONLY_SET(int io_num) 142 | { 143 | // disable pull down 144 | gpio_ll_pulldown_dis(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num); 145 | // enable pull up 146 | gpio_ll_pullup_en(GPIO_HAL_GET_HW(GPIO_PORT_0), io_num); 147 | } 148 | #elif defined CONFIG_IDF_TARGET_ESP8266 149 | __STATIC_INLINE __UNUSED void GPIO_PULL_UP_ONLY_SET(int io_num) 150 | { 151 | gpio_pin_reg_t pin_reg; 152 | 153 | pin_reg.val = READ_PERI_REG(GPIO_PIN_REG(io_num)); 154 | pin_reg.pullup = 1; 155 | WRITE_PERI_REG(GPIO_PIN_REG(io_num), pin_reg.val); 156 | } 157 | #endif 158 | 159 | 160 | // static void GPIO_SET_DIRECTION_NORMAL_IN(int io_num) 161 | // { 162 | // GPIO.enable_w1tc |= (0x1 << io_num); 163 | // } 164 | 165 | 166 | 167 | #endif -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/spi_op.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPI_OP_H__ 2 | #define __SPI_OP_H__ 3 | 4 | #include 5 | 6 | 7 | void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf); 8 | void DAP_SPI_ReadBits(const uint8_t count, uint8_t *buf); 9 | 10 | void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *ack, uint8_t TrnAfterACK); 11 | void DAP_SPI_Read_Data(uint32_t* resData, uint8_t* resParity); 12 | void DAP_SPI_Write_Data(uint32_t data, uint8_t parity); 13 | 14 | void DAP_SPI_Generate_Cycle(uint8_t num); 15 | void DAP_SPI_Fast_Cycle(); 16 | 17 | void DAP_SPI_Protocol_Error_Read(); 18 | void DAP_SPI_Protocol_Error_Write(); 19 | 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/spi_switch.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPI_SWITCH_H__ 2 | #define __SPI_SWITCH_H__ 3 | 4 | void DAP_SPI_Init(); 5 | void DAP_SPI_Deinit(); 6 | void DAP_SPI_Enable(); 7 | void DAP_SPI_Disable(); 8 | 9 | void DAP_SPI_Acquire(); 10 | void DAP_SPI_Release(); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/include/swo.h: -------------------------------------------------------------------------------- 1 | #ifndef __SWO_H__ 2 | #define __SWO_H__ 3 | 4 | #include "freertos/FreeRTOS.h" 5 | #include "freertos/task.h" 6 | #include "freertos/event_groups.h" 7 | 8 | // event group bits 9 | #define SWO_GOT_DATA 0x00000001 10 | #define UART_GOT_DATA 0x00000002 11 | #define SWO_ERROR_TIME_OUT 0x00000004 12 | 13 | extern EventGroupHandle_t kSwoThreadEventGroup; 14 | extern volatile uint8_t kSwoTransferBusy; 15 | 16 | 17 | void SetTraceError(uint8_t flag); // Use in the uart handler 18 | 19 | #endif -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/source/DAP_vendor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2017 ARM Limited. All rights reserved. 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the License); you may 7 | * not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 14 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * ---------------------------------------------------------------------- 19 | * 20 | * $Date: 1. December 2017 21 | * $Revision: V2.0.0 22 | * 23 | * Project: CMSIS-DAP Source 24 | * Title: DAP_vendor.c CMSIS-DAP Vendor Commands 25 | * 26 | *---------------------------------------------------------------------------*/ 27 | 28 | #include "cmsis-dap/include/DAP.h" 29 | 30 | //************************************************************************************************** 31 | /** 32 | \defgroup DAP_Vendor_Adapt_gr Adapt Vendor Commands 33 | \ingroup DAP_Vendor_gr 34 | @{ 35 | 36 | The file DAP_vendor.c provides template source code for extension of a Debug Unit with 37 | Vendor Commands. Copy this file to the project folder of the Debug Unit and add the 38 | file to the MDK-ARM project under the file group Configuration. 39 | */ 40 | 41 | /** Process DAP Vendor Command and prepare Response Data 42 | \param request pointer to request data 43 | \param response pointer to response data 44 | \return number of bytes in response (lower 16 bits) 45 | number of bytes in request (upper 16 bits) 46 | */ 47 | uint32_t DAP_ProcessVendorCommand(const uint8_t *request, uint8_t *response) { 48 | uint32_t num = (1U << 16) | 1U; 49 | 50 | *response++ = *request; // copy Command ID 51 | 52 | switch (*request++) { // first byte in request is Command ID 53 | case ID_DAP_Vendor0: 54 | #if 0 // example user command 55 | num += 1U << 16; // increment request count 56 | if (*request == 1U) { // when first command data byte is 1 57 | *response++ = 'X'; // send 'X' as response 58 | num++; // increment response count 59 | } 60 | #endif 61 | break; 62 | 63 | case ID_DAP_Vendor1: break; 64 | case ID_DAP_Vendor2: break; 65 | case ID_DAP_Vendor3: break; 66 | case ID_DAP_Vendor4: break; 67 | case ID_DAP_Vendor5: break; 68 | case ID_DAP_Vendor6: break; 69 | case ID_DAP_Vendor7: break; 70 | case ID_DAP_Vendor8: break; 71 | case ID_DAP_Vendor9: break; 72 | case ID_DAP_Vendor10: break; 73 | case ID_DAP_Vendor11: break; 74 | case ID_DAP_Vendor12: break; 75 | case ID_DAP_Vendor13: break; 76 | case ID_DAP_Vendor14: break; 77 | case ID_DAP_Vendor15: break; 78 | case ID_DAP_Vendor16: break; 79 | case ID_DAP_Vendor17: break; 80 | case ID_DAP_Vendor18: break; 81 | case ID_DAP_Vendor19: break; 82 | case ID_DAP_Vendor20: break; 83 | case ID_DAP_Vendor21: break; 84 | case ID_DAP_Vendor22: break; 85 | case ID_DAP_Vendor23: break; 86 | case ID_DAP_Vendor24: break; 87 | case ID_DAP_Vendor25: break; 88 | case ID_DAP_Vendor26: break; 89 | case ID_DAP_Vendor27: break; 90 | case ID_DAP_Vendor28: break; 91 | case ID_DAP_Vendor29: break; 92 | case ID_DAP_Vendor30: break; 93 | case ID_DAP_Vendor31: break; 94 | } 95 | 96 | return (num); 97 | } 98 | 99 | ///@} 100 | -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/source/dap_utility.c: -------------------------------------------------------------------------------- 1 | #include "cmsis-dap/include/dap_utility.h" 2 | 3 | const uint8_t kParityByteTable[256] = 4 | { 5 | #define P2(n) n, (n)^1, (n)^1, n 6 | #define P4(n) P2(n), P2((n)^1), P2((n)^1), P2(n) 7 | #define P6(n) P4(n), P4((n)^1), P4((n)^1), P4(n) 8 | 9 | P6(0), P6(1), P6(1), P6(0) 10 | }; 11 | -------------------------------------------------------------------------------- /components/DAP/cmsis-dap/source/spi_op.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file spi_op.c 3 | * @author windowsair 4 | * @brief Using SPI for common transfer operations 5 | * @change: 2020-11-25 first version 6 | * 2021-2-11 Support SWD sequence 7 | * 2021-3-10 Support 3-wire SPI 8 | * 2022-9-15 Support ESP32C3 9 | * 2024-6-9 Fix DAP_SPI_WriteBits issue 10 | * @version 0.5 11 | * @date 2024-6-9 12 | * 13 | * @copyright MIT License 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "main/dap_configuration.h" 22 | 23 | #include "cmsis-dap/include/cmsis_compiler.h" 24 | #include "cmsis-dap/include/spi_op.h" 25 | #include "cmsis-dap/include/spi_switch.h" 26 | #include "cmsis-dap/include/gpio_common.h" 27 | 28 | #ifdef CONFIG_IDF_TARGET_ESP8266 29 | #define DAP_SPI SPI1 30 | #elif defined CONFIG_IDF_TARGET_ESP32 31 | #define DAP_SPI SPI2 32 | #elif defined CONFIG_IDF_TARGET_ESP32C3 33 | #define DAP_SPI GPSPI2 34 | #elif defined CONFIG_IDF_TARGET_ESP32S3 35 | #define DAP_SPI GPSPI2 36 | #else 37 | #error unknown hardware 38 | #endif 39 | 40 | 41 | #ifdef CONFIG_IDF_TARGET_ESP8266 42 | #define SET_MOSI_BIT_LEN(x) DAP_SPI.user1.usr_mosi_bitlen = x 43 | #define SET_MISO_BIT_LEN(x) DAP_SPI.user1.usr_miso_bitlen = x 44 | #define START_AND_WAIT_SPI_TRANSMISSION_DONE() \ 45 | do { \ 46 | DAP_SPI.cmd.usr = 1; \ 47 | while (DAP_SPI.cmd.usr) continue; \ 48 | } while(0) 49 | 50 | #elif defined CONFIG_IDF_TARGET_ESP32 51 | #define SET_MOSI_BIT_LEN(x) DAP_SPI.mosi_dlen.usr_mosi_dbitlen = x 52 | #define SET_MISO_BIT_LEN(x) DAP_SPI.miso_dlen.usr_miso_dbitlen = x 53 | #define START_AND_WAIT_SPI_TRANSMISSION_DONE() \ 54 | do { \ 55 | DAP_SPI.cmd.usr = 1; \ 56 | while (DAP_SPI.cmd.usr) continue; \ 57 | } while(0) 58 | 59 | #elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 60 | #define SET_MOSI_BIT_LEN(x) DAP_SPI.ms_dlen.ms_data_bitlen = x 61 | #define SET_MISO_BIT_LEN(x) DAP_SPI.ms_dlen.ms_data_bitlen = x 62 | #define START_AND_WAIT_SPI_TRANSMISSION_DONE() \ 63 | do { \ 64 | DAP_SPI.cmd.update = 1; \ 65 | while (DAP_SPI.cmd.update) continue; \ 66 | DAP_SPI.cmd.usr = 1; \ 67 | while (DAP_SPI.cmd.usr) continue; \ 68 | } while(0) 69 | #endif 70 | 71 | /** 72 | * @brief Calculate integer division and round up 73 | * 74 | * @param A 75 | * @param B 76 | * @return result 77 | */ 78 | __STATIC_FORCEINLINE int div_round_up(int A, int B) 79 | { 80 | return (A + B - 1) / B; 81 | } 82 | 83 | 84 | /** 85 | * @brief Write bits. LSB & little-endian 86 | * Note: No check. The pointer must be valid. 87 | * @param count Number of bits to be written (<= 64 bits, no length check) 88 | * @param buf Data Buf 89 | */ 90 | void DAP_SPI_WriteBits(const uint8_t count, const uint8_t *buf) 91 | { 92 | uint32_t data[16]; 93 | int nbytes, i; 94 | 95 | DAP_SPI.user.usr_command = 0; 96 | DAP_SPI.user.usr_addr = 0; 97 | 98 | // have data to send 99 | DAP_SPI.user.usr_mosi = 1; 100 | DAP_SPI.user.usr_miso = 0; 101 | SET_MOSI_BIT_LEN(count - 1); 102 | 103 | nbytes = div_round_up(count, 8); 104 | memcpy(data, buf, nbytes); 105 | 106 | for (i = 0; i < nbytes; i++) { 107 | DAP_SPI.data_buf[i] = data[i]; 108 | } 109 | 110 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 111 | } 112 | 113 | 114 | 115 | /** 116 | * @brief Read bits. LSB & little-endian 117 | * Note: No check. The pointer must be valid. 118 | * @param count Number of bits to be read (<= 64 bits, no length check) 119 | * @param buf Data Buf 120 | */ 121 | void DAP_SPI_ReadBits(const uint8_t count, uint8_t *buf) { 122 | int i; 123 | uint32_t data_buf[2]; 124 | 125 | uint8_t * pData = (uint8_t *)data_buf; 126 | 127 | DAP_SPI.user.usr_mosi = 0; 128 | DAP_SPI.user.usr_miso = 1; 129 | 130 | #if (USE_SPI_SIO == 1) 131 | DAP_SPI.user.sio = true; 132 | #endif 133 | 134 | SET_MISO_BIT_LEN(count - 1U); 135 | 136 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 137 | 138 | #if (USE_SPI_SIO == 1) 139 | DAP_SPI.user.sio = false; 140 | #endif 141 | 142 | data_buf[0] = DAP_SPI.data_buf[0]; 143 | data_buf[1] = DAP_SPI.data_buf[1]; 144 | 145 | for (i = 0; i < div_round_up(count, 8); i++) 146 | { 147 | buf[i] = pData[i]; 148 | } 149 | // last byte use mask: 150 | buf[i-1] = buf[i-1] & ((2 >> (count % 8)) - 1); 151 | } 152 | 153 | #if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 154 | /** 155 | * @brief Step1: Packet Request 156 | * 157 | * @param packetHeaderData data from host 158 | * @param ack ack from target 159 | * @param TrnAfterACK num of trn after ack 160 | */ 161 | __FORCEINLINE void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *ack, uint8_t TrnAfterACK) 162 | { 163 | uint32_t dataBuf; 164 | 165 | // have data to send 166 | DAP_SPI.user.usr_mosi = 1; 167 | SET_MOSI_BIT_LEN(8 - 1); 168 | 169 | DAP_SPI.user.usr_miso = 1; 170 | 171 | #if (USE_SPI_SIO == 1) 172 | DAP_SPI.user.sio = true; 173 | #endif 174 | 175 | // 1 bit Trn(Before ACK) + 3bits ACK + TrnAferACK - 1(prescribed) 176 | SET_MISO_BIT_LEN(1U + 3U + TrnAfterACK - 1U); 177 | 178 | // copy data to reg 179 | DAP_SPI.data_buf[0] = (packetHeaderData << 0) | (0U << 8) | (0U << 16) | (0U << 24); 180 | 181 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 182 | 183 | #if (USE_SPI_SIO == 1) 184 | DAP_SPI.user.sio = false; 185 | #endif 186 | 187 | dataBuf = DAP_SPI.data_buf[0]; 188 | *ack = (dataBuf >> 1) & 0b111; 189 | } // defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 190 | #elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 191 | __FORCEINLINE void DAP_SPI_Send_Header(const uint8_t packetHeaderData, uint8_t *ack, uint8_t TrnAfterACK) 192 | { 193 | uint32_t dataBuf; 194 | 195 | // have data to send 196 | DAP_SPI.user.usr_mosi = 0; 197 | DAP_SPI.user.usr_command = 1; 198 | DAP_SPI.user.usr_miso = 1; 199 | 200 | // 8bits Header + 1 bit Trn(Before ACK) - 1(prescribed) 201 | DAP_SPI.user2.usr_command_bitlen = 8U + 1U - 1U; 202 | DAP_SPI.user2.usr_command_value = packetHeaderData; 203 | 204 | 205 | #if (USE_SPI_SIO == 1) 206 | DAP_SPI.user.sio = true; 207 | #endif 208 | 209 | // 3bits ACK + TrnAferACK - 1(prescribed) 210 | SET_MISO_BIT_LEN(3U + TrnAfterACK - 1U); 211 | 212 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 213 | 214 | #if (USE_SPI_SIO == 1) 215 | DAP_SPI.user.sio = false; 216 | #endif 217 | 218 | DAP_SPI.user.usr_command = 0; 219 | 220 | dataBuf = DAP_SPI.data_buf[0]; 221 | *ack = dataBuf & 0b111; 222 | } 223 | #endif 224 | 225 | 226 | /** 227 | * @brief Step2: Read Data 228 | * 229 | * @param resData data from target 230 | * @param resParity parity from target 231 | */ 232 | __FORCEINLINE void DAP_SPI_Read_Data(uint32_t *resData, uint8_t *resParity) 233 | { 234 | volatile uint64_t dataBuf; 235 | uint32_t *pU32Data = (uint32_t *)&dataBuf; 236 | 237 | DAP_SPI.user.usr_mosi = 0; 238 | DAP_SPI.user.usr_miso = 1; 239 | 240 | #if (USE_SPI_SIO == 1) 241 | DAP_SPI.user.sio = true; 242 | #endif 243 | 244 | // 1 bit Trn(End) + 32bis data + 1bit parity - 1(prescribed) 245 | SET_MISO_BIT_LEN(1U + 32U + 1U - 1U); 246 | 247 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 248 | 249 | #if (USE_SPI_SIO == 1) 250 | DAP_SPI.user.sio = false; 251 | #endif 252 | 253 | pU32Data[0] = DAP_SPI.data_buf[0]; 254 | pU32Data[1] = DAP_SPI.data_buf[1]; 255 | 256 | *resData = (dataBuf >> 0U) & 0xFFFFFFFFU; // 32bits Response Data 257 | *resParity = (dataBuf >> (0U + 32U)) & 1U; // 1bit parity 258 | } 259 | 260 | #if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 261 | /** 262 | * @brief Step2: Write Data 263 | * 264 | * @param data data from host 265 | * @param parity parity from host 266 | */ 267 | __FORCEINLINE void DAP_SPI_Write_Data(uint32_t data, uint8_t parity) 268 | { 269 | DAP_SPI.user.usr_mosi = 1; 270 | DAP_SPI.user.usr_miso = 0; 271 | 272 | SET_MOSI_BIT_LEN(32U + 1U - 1U); 273 | 274 | // copy data to reg 275 | DAP_SPI.data_buf[0] = data; 276 | DAP_SPI.data_buf[1] = parity; 277 | 278 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 279 | } 280 | #elif defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 281 | __FORCEINLINE void DAP_SPI_Write_Data(uint32_t data, uint8_t parity) 282 | { 283 | DAP_SPI.user.usr_mosi = 1; 284 | DAP_SPI.user.usr_miso = 0; 285 | 286 | // esp32c3 can not send 33 bits of data correctly, we need to send an additional bit 287 | // that will not be recognized as the start bit. 288 | SET_MOSI_BIT_LEN(32U + 1U + 1U - 1U); 289 | DAP_SPI.data_buf[0] = data; 290 | DAP_SPI.data_buf[1] = parity == 0 ? 0b00 : 0b01; 291 | 292 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 293 | } 294 | #endif 295 | 296 | 297 | #if defined CONFIG_IDF_TARGET_ESP8266 || defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32S3 298 | /** 299 | * @brief Generate Clock Cycle 300 | * 301 | * @param num Cycle Num 302 | */ 303 | __FORCEINLINE void DAP_SPI_Generate_Cycle(uint8_t num) 304 | { 305 | //// TODO: It may take long time to generate just one clock 306 | DAP_SPI.user.usr_mosi = 1; 307 | DAP_SPI.user.usr_miso = 0; 308 | SET_MOSI_BIT_LEN(num - 1U); 309 | 310 | DAP_SPI.data_buf[0] = 0x00000000U; 311 | 312 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 313 | } 314 | #elif defined CONFIG_IDF_TARGET_ESP32C3 315 | __FORCEINLINE void DAP_SPI_Generate_Cycle(uint8_t num) 316 | { 317 | //// TODO: It may take long time to generate just one clock 318 | DAP_SPI.user.usr_mosi = 0; 319 | DAP_SPI.user.usr_miso = 1; 320 | 321 | // esp32c3 can not send a single bit, therefore we use read operation instead. 322 | SET_MISO_BIT_LEN(num - 1U); 323 | 324 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 325 | } 326 | #endif 327 | 328 | #if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 329 | /** 330 | * @brief Quickly generate 1 clock 331 | * 332 | */ 333 | __FORCEINLINE void DAP_SPI_Fast_Cycle() 334 | { 335 | DAP_SPI_Release(); 336 | DAP_SPI_Acquire(); 337 | } 338 | #endif 339 | 340 | /** 341 | * @brief Generate Protocol Error Cycle 342 | * 343 | */ 344 | __FORCEINLINE void DAP_SPI_Protocol_Error_Read() 345 | { 346 | DAP_SPI.user.usr_mosi = 1; 347 | DAP_SPI.user.usr_miso = 0; 348 | SET_MOSI_BIT_LEN(32U + 1U - 1); // 32bit ignore data + 1 bit - 1(prescribed) 349 | 350 | DAP_SPI.data_buf[0] = 0xFFFFFFFFU; 351 | DAP_SPI.data_buf[1] = 0xFFFFFFFFU; 352 | 353 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 354 | } 355 | 356 | 357 | /** 358 | * @brief Generate Protocol Error Cycle 359 | * 360 | */ 361 | __FORCEINLINE void DAP_SPI_Protocol_Error_Write() 362 | { 363 | DAP_SPI.user.usr_mosi = 1; 364 | DAP_SPI.user.usr_miso = 0; 365 | SET_MOSI_BIT_LEN(1U + 32U + 1U - 1); // 1bit Trn + 32bit ignore data + 1 bit - 1(prescribed) 366 | 367 | DAP_SPI.data_buf[0] = 0xFFFFFFFFU; 368 | DAP_SPI.data_buf[1] = 0xFFFFFFFFU; 369 | 370 | START_AND_WAIT_SPI_TRANSMISSION_DONE(); 371 | } 372 | -------------------------------------------------------------------------------- /components/SSDP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES ssdp.c 2 | ) 3 | 4 | idf_component_register( 5 | SRCS ${SOURCES} 6 | INCLUDE_DIRS "." 7 | PRIV_REQUIRES esp_netif memory_pool wt_storage 8 | ) 9 | -------------------------------------------------------------------------------- /components/SSDP/ssdp.c: -------------------------------------------------------------------------------- 1 | #include "ssdp.h" 2 | 3 | #include 4 | 5 | #include "esp_log.h" 6 | #include "esp_mac.h" 7 | #include "esp_netif.h" 8 | #include "lwip/err.h" 9 | #include "lwip/sockets.h" 10 | #include "memory_pool.h" 11 | #include "wt_nvs.h" 12 | 13 | #define TAG "SSDP" 14 | 15 | #define SSDP_PORT 1900 16 | #define SSDP_MULTICAST_TTL 4 17 | #define SSDP_UUID_BASE "9079d7e9-92c6-45b3-aa28-77cdcc" 18 | #define SSDP_MULTICAST_ADDR "239.255.255.250" 19 | #define HEADER_SEARCH "M-SEARCH" 20 | #define SSDP_DEVICE_TYPE "urn:schemas-upnp-org:device:Basic:1" 21 | #define SSDP_MODEL_NAME "wireless-proxy" 22 | #define SSDP_DEFAULT_FRIENDLY_NAME "允斯调试器" 23 | #define SSDP_MANUFACTURER "允斯工作室" 24 | 25 | #ifndef SSDP_MODEL_URL 26 | #define SSDP_MODEL_URL "https://yunsi.studio/" 27 | #endif 28 | 29 | static struct ssdp_ctx_t { 30 | TaskHandle_t ssdp_service_task; 31 | ip4_addr_t ip; 32 | ip4_addr_t gw; 33 | uint8_t uuid_end[3]; /* actually use MAC[3:5] */ 34 | char friendly_name[32]; 35 | } ssdp_ctx; 36 | 37 | static volatile uint8_t ssdp_running = false; 38 | static int ssdp_socket = -1; 39 | 40 | static void ssdp_service_task(void *pvParameters); 41 | static int ssdp_handle_data(int sock, in_addr_t remote_addr, uint16_t remote_port, 42 | char *buf, int len); 43 | static int ssdp_get_friendly_name(); 44 | 45 | static int create_ssdp_socket(int *sock) 46 | { 47 | int err; 48 | 49 | *sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 50 | if (*sock < 0) { 51 | ESP_LOGE(TAG, "Failed to create socket. Error %d", errno); 52 | return -1; 53 | } 54 | 55 | int opt = 1; 56 | if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) != 0) { 57 | ESP_LOGE(TAG, "setsockopt SO_REUSEADDR failed %d\n", errno); 58 | goto err; 59 | } 60 | 61 | struct sockaddr_in addr = { 62 | .sin_family = AF_INET, 63 | .sin_port = htons(SSDP_PORT), 64 | .sin_addr.s_addr = htonl(INADDR_ANY) 65 | }; 66 | err = bind(*sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); 67 | if (err < 0) { 68 | ESP_LOGE(TAG, "Failed to bind socket. Error %d", errno); 69 | goto err; 70 | } 71 | 72 | /* Multicast TTL (independent to normal interface TTL) 73 | * should be set to small value like 2~4 */ 74 | opt = SSDP_MULTICAST_TTL; 75 | if (setsockopt(*sock, IPPROTO_IP, IP_MULTICAST_TTL, &opt, sizeof(opt)) < 0) { 76 | ESP_LOGE(TAG, "Failed to set IP_MULTICAST_TTL. Error %d", errno); 77 | err = errno; 78 | goto err; 79 | } 80 | 81 | /* Receive multicast packet sent from this device, 82 | * useful when other service need to be aware of multicast notification */ 83 | opt = 0; 84 | if (setsockopt(*sock, IPPROTO_IP, IP_MULTICAST_LOOP, &opt, sizeof(opt)) < 0) { 85 | ESP_LOGE(TAG, "Failed to unset IP_MULTICAST_LOOP. Error %d", errno); 86 | err = errno; 87 | goto err; 88 | } 89 | 90 | struct ip_mreq mreq; 91 | mreq.imr_multiaddr.s_addr = inet_addr(SSDP_MULTICAST_ADDR); 92 | mreq.imr_interface.s_addr = htonl(INADDR_ANY); 93 | if (setsockopt(*sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { 94 | perror("Adding to multicast group failed"); 95 | goto err; 96 | } 97 | 98 | return 0; 99 | 100 | err: 101 | close(*sock); 102 | return -1; 103 | } 104 | 105 | static int ssdp_send_notify(int sock, char *buf, int buf_len) 106 | { 107 | int msg_len = snprintf( 108 | buf, buf_len, 109 | "NOTIFY * HTTP/1.1\r\n" 110 | "HOST: 239.255.255.250:1900\r\n" 111 | "NTS: ssdp:alive\r\n" 112 | "NT: upnp:rootdevice\r\n" 113 | "CACHE-CONTROL: max-age=3600\r\n" 114 | "SERVER: FreeRTOS/v10 UPnP/1.1 product/version\r\n" 115 | "USN: uuid:"SSDP_UUID_BASE"%02x%02x%02x::upnp:rootdevice\r\n" 116 | "LOCATION: http://%s:%u/SSDP.xml\r\n", 117 | ssdp_ctx.uuid_end[0], ssdp_ctx.uuid_end[1], ssdp_ctx.uuid_end[2], 118 | ip4addr_ntoa((const ip4_addr_t *)&ssdp_ctx.ip), 80 119 | ); 120 | buf[msg_len] = '\0'; 121 | struct sockaddr_in dest_addr; 122 | dest_addr.sin_family = AF_INET; 123 | dest_addr.sin_port = htons(SSDP_PORT); 124 | dest_addr.sin_addr.s_addr = inet_addr(SSDP_MULTICAST_ADDR); 125 | 126 | int err = sendto(sock, buf, msg_len, 0, 127 | (struct sockaddr *)&dest_addr, sizeof(dest_addr)); 128 | if (err < 0) { 129 | ESP_LOGE(TAG, "IPV4 sendto failed. errno: %d", errno); 130 | return errno; 131 | } 132 | 133 | return 0; 134 | } 135 | 136 | static int ssdp_send_response(int sock, in_addr_t remote_addr, uint16_t remote_port, char *buf, int buf_len) 137 | { 138 | int msg_len = snprintf( 139 | buf, buf_len, 140 | "HTTP/1.1 200 OK\r\n" 141 | "EXT:\r\n" 142 | "ST: ""upnp:rootdevice""\r\n" 143 | "CACHE-CONTROL: max-age=3600\r\n" 144 | "SERVER: FreeRTOS/v10 UPnP/1.1 product/version\r\n" 145 | "USN: uuid:"SSDP_UUID_BASE"%02x%02x%02x" /* MAC=UUID */ 146 | "::""upnp:rootdevice""\r\n" 147 | "LOCATION: http://%s:%u/SSDP.xml\r\n" /* ip:port */ 148 | "\r\n", 149 | ssdp_ctx.uuid_end[0], ssdp_ctx.uuid_end[1], ssdp_ctx.uuid_end[2], /* MAC=UUID */ 150 | ip4addr_ntoa((const ip4_addr_t *)&ssdp_ctx.ip), 80 /* ip:port */ 151 | ); 152 | 153 | buf[msg_len] = '\0'; 154 | 155 | struct sockaddr_in dest_addr; 156 | dest_addr.sin_family = AF_INET; 157 | dest_addr.sin_port = remote_port; 158 | dest_addr.sin_addr.s_addr = remote_addr; 159 | 160 | int err = sendto(sock, buf, msg_len, 0, 161 | (struct sockaddr *)&dest_addr, sizeof(dest_addr)); 162 | if (err < 0) { 163 | ESP_LOGE(TAG, "IPV4 sendto failed. errno: %d", errno); 164 | return errno; 165 | } 166 | 167 | return 0; 168 | } 169 | 170 | static int ssdp_handle_data(int sock, in_addr_t remote_addr, uint16_t remote_port, 171 | char *buf, int len) 172 | { 173 | /* on M-SEARCH: send RESPONSE anyway (even if this device doesn't match search type) 174 | * on NOTIFY : ignore 175 | * on RESPONSE: HTTP/1.1 200 OK : ignore 176 | * */ 177 | if (memcmp(buf, HEADER_SEARCH, strlen(HEADER_SEARCH)) != 0) { 178 | return 0; 179 | } 180 | 181 | return ssdp_send_response(sock, remote_addr, remote_port, buf, len); 182 | } 183 | 184 | static void ssdp_service_handle_socket() 185 | { 186 | char *buf = memory_pool_get(portMAX_DELAY); 187 | 188 | while (1) { 189 | struct sockaddr_storage remote_addr; 190 | socklen_t socklen = sizeof(remote_addr); 191 | int len = recvfrom(ssdp_socket, buf, memory_pool_get_buf_size(), 0, 192 | (struct sockaddr *)&remote_addr, &socklen); 193 | if (len < 0) { 194 | ESP_LOGE(TAG, "multicast recvfrom failed: errno %d", errno); 195 | break; 196 | } else if (len == 0) { 197 | continue; 198 | } 199 | buf[len] = '\0'; 200 | 201 | uint16_t remote_port = ((struct sockaddr_in *)&remote_addr)->sin_port; 202 | in_addr_t remote_ip = ((struct sockaddr_in *)&remote_addr)->sin_addr.s_addr; 203 | ssdp_handle_data(ssdp_socket, remote_ip, remote_port, 204 | buf, memory_pool_get_buf_size()); 205 | } 206 | 207 | memory_pool_put(buf); 208 | } 209 | 210 | static void ssdp_service_task(void *pvParameters) 211 | { 212 | ESP_LOGD(TAG, "ssdp_service_task()"); 213 | ssdp_running = true; 214 | 215 | int err; 216 | while (ssdp_running) { 217 | err = create_ssdp_socket(&ssdp_socket); 218 | if (err) { 219 | ssdp_socket = -1; 220 | ESP_LOGE(TAG, "Failed to create multicast socket"); 221 | vTaskDelay(pdMS_TO_TICKS(1000)); 222 | continue; 223 | } 224 | 225 | ssdp_service_handle_socket(); 226 | 227 | ESP_LOGE(TAG, "Shutting down socket and restarting..."); 228 | shutdown(ssdp_socket, 0); 229 | close(ssdp_socket); 230 | ssdp_socket = -1; 231 | } 232 | 233 | vTaskDelete(NULL); 234 | } 235 | 236 | /* 237 | * Global Functions 238 | */ 239 | esp_err_t ssdp_init() 240 | { 241 | ssdp_ctx.ssdp_service_task = NULL; 242 | ssdp_socket = -1; 243 | ssdp_running = false; 244 | ssdp_ctx.ip.addr = 0; 245 | ssdp_ctx.gw.addr = 0; 246 | 247 | uint8_t mac[6]; 248 | esp_base_mac_addr_get(mac); 249 | for (int i = 0; i < 3; ++i) { 250 | /* use MAC last 3 bytes, as the first 3 bytes do not change */ 251 | ssdp_ctx.uuid_end[i] = mac[i + 3]; 252 | } 253 | 254 | /* get name from nvs, if failed: use default */ 255 | if (ssdp_get_friendly_name()) 256 | ssdp_set_friendly_name(SSDP_DEFAULT_FRIENDLY_NAME); 257 | return ESP_OK; 258 | } 259 | 260 | esp_err_t ssdp_start() 261 | { 262 | if (ssdp_socket != -1 || ssdp_ctx.ssdp_service_task) { 263 | ESP_LOGE(TAG, "SSDP already started"); 264 | return ESP_ERR_INVALID_STATE; 265 | } 266 | 267 | /* get a default ip from available netif */ 268 | esp_err_t err; 269 | esp_netif_ip_info_t ip_info = {0}; 270 | esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); 271 | if (netif == NULL) { 272 | netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"); 273 | } 274 | if (netif == NULL) { 275 | netif = esp_netif_get_handle_from_ifkey("ETH_DEF"); 276 | } 277 | 278 | err = esp_netif_get_ip_info(netif, &ip_info); 279 | if (err != ESP_OK) { 280 | /* fallback to 0.0.0.0 default IP */ 281 | ssdp_ctx.ip.addr = 0; 282 | ssdp_ctx.gw.addr = 0; 283 | } else { 284 | ssdp_ctx.ip.addr = ip_info.ip.addr; 285 | ssdp_ctx.gw.addr = ip_info.gw.addr; 286 | } 287 | 288 | BaseType_t res = xTaskCreatePinnedToCore( 289 | ssdp_service_task, "ssdp task", 4096, NULL, 290 | tskIDLE_PRIORITY + 1, &ssdp_ctx.ssdp_service_task, 291 | 0); 292 | if (res != pdPASS || ssdp_ctx.ssdp_service_task == NULL) { 293 | ESP_LOGE(TAG, "Failed to create task"); 294 | err = ESP_FAIL; 295 | } 296 | return err; 297 | } 298 | 299 | void ssdp_stop() 300 | { 301 | ESP_LOGD(TAG, "Stopping SSDP"); 302 | if (ssdp_socket != -1) { 303 | shutdown(ssdp_socket, 0); 304 | close(ssdp_socket); 305 | ssdp_socket = -1; 306 | } 307 | ssdp_running = false; 308 | ssdp_ctx.ssdp_service_task = NULL; 309 | } 310 | 311 | 312 | #define WT_NVS_KEY_SSDP_FRIENDLY_NAME 0x80 313 | #define WT_NVS_NS_NETWORK "net" 314 | 315 | int ssdp_get_friendly_name() 316 | { 317 | return wt_nvs_get_once(WT_NVS_NS_NETWORK, WT_NVS_KEY_SSDP_FRIENDLY_NAME, 318 | ssdp_ctx.friendly_name, sizeof(ssdp_ctx.friendly_name)); 319 | } 320 | 321 | int ssdp_set_friendly_name(const char *name) 322 | { 323 | snprintf(ssdp_ctx.friendly_name, sizeof(ssdp_ctx.friendly_name), 324 | "%s-%02X-%02X", name, ssdp_ctx.uuid_end[1], ssdp_ctx.uuid_end[2]); 325 | ssdp_ctx.friendly_name[sizeof(ssdp_ctx.friendly_name) - 1] = '\0'; 326 | return 0; 327 | } 328 | 329 | int ssdp_set_ip_gw(const uint32_t *ip, const uint32_t *gw) 330 | { 331 | ssdp_ctx.ip.addr = *ip; 332 | ssdp_ctx.gw.addr = *gw; 333 | 334 | char *buf = memory_pool_get(portMAX_DELAY); 335 | 336 | /* send a ssdp notification to the new connected network */ 337 | ssdp_send_notify(ssdp_socket, buf, memory_pool_get_buf_size()); 338 | memory_pool_put(buf); 339 | return 0; 340 | } 341 | 342 | int ssdp_get_schema_str(char *buf, uint32_t buf_len) 343 | { 344 | int write_size = snprintf( 345 | buf, buf_len - 1, 346 | "" 347 | "" 348 | "" 349 | "1" 350 | "0" 351 | "" 352 | "http://%s:%u" /* ip, port */ 353 | "" 354 | "%s" /* friendly_name */ 355 | ""SSDP_DEVICE_TYPE"" 356 | "/" 357 | "0000" 358 | ""SSDP_MODEL_NAME"" 359 | "0000" 360 | ""SSDP_MODEL_URL"" 361 | ""SSDP_MANUFACTURER"" 362 | "https://yunsi.studio" 363 | "" 364 | "\r\n" 365 | "\r\n", 366 | ip4addr_ntoa((const ip4_addr_t *)&ssdp_ctx.ip), 80, /* ip, port */ 367 | ssdp_ctx.friendly_name /* friendly_name */ 368 | ); 369 | 370 | buf[write_size] = '\0'; 371 | return write_size < buf_len - 1; 372 | } -------------------------------------------------------------------------------- /components/SSDP/ssdp.h: -------------------------------------------------------------------------------- 1 | #ifndef SSDP_HEADER_GUARD 2 | #define SSDP_HEADER_GUARD 3 | #include 4 | #include 5 | 6 | esp_err_t ssdp_init(); 7 | esp_err_t ssdp_start(); 8 | void ssdp_stop(); 9 | 10 | int ssdp_set_friendly_name(const char *name); 11 | int ssdp_set_ip_gw(const uint32_t *ip, const uint32_t *gw); 12 | int ssdp_get_schema_str(char *buf, uint32_t buf_len); 13 | 14 | 15 | #endif /* SSDP_HEADER_GUARD */ -------------------------------------------------------------------------------- /components/USBIP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | idf_component_register( 4 | SRCS ${SOURCES} 5 | INCLUDE_DIRS "." 6 | PRIV_REQUIRES dap_proxy 7 | ) -------------------------------------------------------------------------------- /components/USBIP/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 windowsair 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /components/USBIP/MSOS20_descriptor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MSOS20_descriptor.c 3 | * @author windowsair 4 | * @brief Store related data of Microsoft OS 2.0 descriptor 5 | * @change: 2021-5-12 Add support for USB 3.0 6 | * @version 0.2 7 | * @date 2021-5-12 8 | * 9 | * @copyright Copyright (c) 2021 10 | * 11 | */ 12 | 13 | ////TODO: refactoring into structure 14 | 15 | #include 16 | 17 | #include "components/USBIP/MSOS20_descriptor.h" 18 | 19 | #define USBShort(ui16Value) ((ui16Value) & 0xff), ((ui16Value) >> 8) //((ui16Value) & 0xFF),(((ui16Value) >> 8) & 0xFF) 20 | 21 | 22 | 23 | // Microsoft OS 2.0 descriptor set header 24 | const uint8_t msOs20DescriptorSetHeader[kLengthOfMsOS20] = 25 | { 26 | // Microsoft OS 2.0 Descriptor Set header (Table 10) 27 | 0x0A, 0x00, // wLength (Shall be set to 0x0A) 28 | MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00, 29 | 0x00, 0x00, 0x03, 0x06, // dwWindowsVersion: Windows 8.1 (NTDDI_WINBLUE) 30 | USBShort(kLengthOfMsOS20), // wTotalLength 31 | 32 | // Support WinUSB 33 | // See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/automatic-installation-of-winusb 34 | 35 | // Microsoft OS 2.0 compatible ID descriptor (Table 13) 36 | 0x14, 0x00, // wLength 37 | USBShort(MS_OS_20_FEATURE_COMPATIBLE_ID), // wDescriptorType 38 | 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatibleID 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompatibleID 40 | 41 | // Microsoft OS 2.0 registry property descriptor (Table 14) 42 | 0x84, 0x00, // wLength 43 | USBShort(MS_OS_20_FEATURE_REG_PROPERTY), 44 | 0x07, 0x00, // wPropertyDataType: REG_MULTI_SZ (Unicode Strings) 45 | 0x2A, 0x00, // wPropertyNameLength 46 | 'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0,'t',0,'e',0,'r',0, 47 | 'f',0,'a',0,'c',0,'e',0,'G',0,'U',0,'I',0,'D',0,'s',0,0,0, 48 | // Set to "DeviceInterfaceGUID" to support WinUSB 49 | 0x50, 0x00, // wPropertyDataLength 50 | // WinUSB GUID 51 | '{',0,'C',0,'D',0,'B',0,'3',0,'B',0,'5',0,'A',0,'D',0,'-',0, 52 | '2',0,'9',0,'3',0,'B',0,'-',0,'4',0,'6',0,'6',0,'3',0,'-',0, 53 | 'A',0,'A',0,'3',0,'6',0,'-',0,'1',0,'A',0,'A',0,'E',0,'4',0, 54 | '6',0,'4',0,'6',0,'3',0,'7',0,'7',0,'6',0,'}',0,0,0,0,0, 55 | // identify a CMSIS-DAP V2 configuration, 56 | // must set to "{CDB3B5AD-293B-4663-AA36-1AAE46463776}" 57 | 58 | }; 59 | 60 | const uint8_t bosDescriptor[kLengthOfBos] = 61 | { 62 | // USB 3.0 Specification, Table 9-9. 63 | 0x05, // bLength of this descriptor 64 | USB_DESCRIPTOR_TYPE_BOS, // BOS Descriptor type(Constant) 65 | USBShort(kLengthOfBos), // wLength 66 | 67 | 68 | #if (USE_USB_3_0 == 1) 69 | 0x03, // bNumDeviceCaps -> USB2.0 extension & SuperSpeed USB Device & OS2.0 descriptor 70 | #else 71 | 0x01, // bNumDeviceCaps -> only 0x01 for OS2.0 descriptor 72 | #endif // USE_USB_3_0 == 1 73 | 74 | #if (USE_USB_3_0 == 1) 75 | // USB 2.0 extension, USB 3.0 Specification, Table 9-12. 76 | 0x07, // bLength of this descriptor 77 | USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, // DEVICE CAPABILITY Descriptor type 78 | USB_DEVICE_CAPABILITY_TYPE_USB2_0_EXTENSION, // Capability type: USB 2.0 EXTENSION 79 | 0x02, 0x00, 0x00, 0x00, // bmAttributes -> LPM Support 80 | 81 | // SuperSpeed USB Device, USB 3.0 Specification, Table 9-13. 82 | 0x0A, // bLength of this descriptor 83 | USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, // DEVICE CAPABILITY Descriptor type 84 | USB_DEVICE_CAPABILITY_TYPE_SUPERSPEED_USB, // Capability type: SUPERSPEED_USB 85 | 0x00, // bmAttributes -> LTM Capable 86 | 0x08, 0x00, // wSpeedsSupported -> only support SuperSpeed 87 | 0x03, // bFunctionalitySupport 88 | 0x00, // bU1DevExitLat -> 0 may be ok 89 | 0x00, 0x00, // wU2DevExitLat -> 0 may be ok 90 | #endif // USE_USB_3_0 == 1 91 | 92 | 93 | 94 | // Microsoft OS 2.0 platform capability descriptor header (Table 4) 95 | // See also: 96 | // USB 3.0 Specification : Format of a Device Capability Descriptor, Table 9-10. 97 | 98 | 0x1C, // bLength of this first device capability descriptor 99 | // bLength -> The total length of the remaining arrays containing this field 100 | USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY, // bDescriptorType 101 | USB_DEVICE_CAPABILITY_TYPE_PLATFORM, // bDevCapabilityType 102 | 103 | // Capability-Dependent (See USB 3.0 Specification Table 9-10.) 104 | 0x00, // bReserved 105 | USB_DEVICE_CAPABILITY_UUID, // MS_OS_20_Platform_Capability_ID 106 | 107 | 0x00, 0x00, 0x03, 0x06, // dwWindowsVersion: Windows 8.1 (NTDDI_WINBLUE) 108 | USBShort(kLengthOfMsOS20), // wMSOSDescriptorSetTotalLength(length of descriptor set header) 109 | kValueOfbMS_VendorCode, // bMS_VendorCode (0x01 will be ok) 110 | ////TODO:change this 111 | 0, // bAltEnumCode 112 | }; -------------------------------------------------------------------------------- /components/USBIP/MSOS20_descriptor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MSOS20_descriptor.h 3 | * @author windowsair 4 | * @brief 5 | * @version 0.2 6 | * @date 2021-5-12 7 | * 8 | * @copyright Copyright (c) 2021 9 | * 10 | */ 11 | 12 | #ifndef __MSOS20_DESCRIPTOR_H__ 13 | #define __MSOS20_DESCRIPTOR_H__ 14 | 15 | 16 | #define kLengthOfMsOS20 0xA2 17 | 18 | #if (USE_USB_3_0 == 1) 19 | #define kLengthOfBos 0x32 20 | #else 21 | #define kLengthOfBos 0x21 22 | #endif // USE_USB_3_0 == 1 23 | 24 | #define kValueOfbMS_VendorCode 0x01// Just set to 0x01 25 | extern const uint8_t bosDescriptor[kLengthOfBos]; 26 | extern const uint8_t msOs20DescriptorSetHeader[kLengthOfMsOS20]; 27 | 28 | /* Microsoft OS 2.0 Descriptors BEGIN */ 29 | 30 | // Platform capability BOS descriptor, Table 1. 31 | #define USB_DEVICE_CAPABILITY_TYPE_PLATFORM 5 32 | 33 | // USB 2.0 Extension Descriptor, USB3.0 Specification Table 9-11 34 | #define USB_DEVICE_CAPABILITY_TYPE_USB2_0_EXTENSION 2 35 | // SuperSpeed USB specific device level capabilities, USB3.0 Specification Table 9-11 36 | #define USB_DEVICE_CAPABILITY_TYPE_SUPERSPEED_USB 3 37 | 38 | // Platform capability UUID, Table 3. 39 | // {D8DD60DF-4589-4CC7-9CD2-659D9E648A9F} 40 | #define USB_DEVICE_CAPABILITY_UUID 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F 41 | 42 | 43 | // Microsoft OS 2.0 descriptor wIndex values enum, Table 8. 44 | #define MS_OS_20_DESCRIPTOR_INDEX 7 45 | #define MS_OS_20_SET_ALT_ENUMERATION 8 46 | 47 | 48 | // Microsoft OS 2.0 descriptor types enum for wDescriptorType values, Table 9. 49 | #define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00 50 | #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 51 | #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 52 | #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 53 | #define MS_OS_20_FEATURE_REG_PROPERTY 0x04 54 | #define MS_OS_20_FEATURE_MIN_RESUME_TIME 0x05 55 | #define MS_OS_20_FEATURE_MODEL_ID 0x06 56 | #define MS_OS_20_FEATURE_CCGP_DEVICE 0x07 57 | 58 | /* Microsoft OS 2.0 Descriptors END */ 59 | 60 | 61 | 62 | /* Wireless USB Standard Extension Descriptor Types BEGIN */ 63 | 64 | // Wireless USB Specification 1.1 revison 1.1, Table 7-21. 65 | #define USB_DESCRIPTOR_TYPE_SECURITY 12 66 | #define USB_DESCRIPTOR_TYPE_KEY 13 67 | #define USB_DESCRIPTOR_TYPE_ENCRYPTION_TYPE 14 68 | #define USB_DESCRIPTOR_TYPE_BOS 15 69 | #define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 16 70 | #define USB_DESCRIPTOR_TYPE_WIRELESS_ENDPOINT_COMPANION 17 71 | 72 | /* Wireless USB Standard Extension Descriptor Types END */ 73 | 74 | 75 | /* Microsoft Extended Compat ID OS Feature Descriptor BEGIN */ 76 | 77 | #define USB_MS_EXTENDED_COMPAT_ID_VERSION 0x0100 78 | #define USB_MS_EXTENDED_COMPAT_ID_TYPE 0x04 79 | 80 | #define USB_COMPATID_NONE {0} 81 | #define USB_SUBCOMPATID_NONE {0} 82 | #define USB_COMPATID_WINUSB "WINUSB\0" 83 | #define USB_COMPATID_RNDIS "RNDIS\0\0" 84 | #define USB_COMPATID_PTP "PTP\0\0\0\0" 85 | #define USB_COMPATID_MTP "MTP\0\0\0\0" 86 | #define USB_COMPATID_BLUETOOTH "BLUTUTH" 87 | #define USB_SUBCOMPATID_BT_V11 "11\0\0\0\0\0" 88 | #define USB_SUBCOMPATID_BT_V12 "12\0\0\0\0\0" 89 | #define USB_SUBCOMPATID_BT_V20EDR "EDR\0\0\0\0" 90 | 91 | /* Microsoft Extended Compat ID OS Feature Descriptor END */ 92 | 93 | #endif -------------------------------------------------------------------------------- /components/USBIP/usb_defs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file usb_defs.h 3 | * @brief Modify 4 | * @version 0.1 5 | * @date 2020-01-22 6 | * 7 | * @copyright Copyright (c) 2020 8 | * 9 | */ 10 | 11 | // 12 | // Created by thevoidnn on 10/25/17. 13 | // 14 | 15 | #ifndef __USB_DEFS_H__ 16 | #define __USB_DEFS_H__ 17 | 18 | #include 19 | 20 | #define USB_CLASS_MISCELLANEOUS_DEVICE 0xef 21 | #define USB_MISC_SUBCLASS_COMMON 0x02 22 | #define USB_MISC_PROTOCOL_INTERFACE_ASSOCIATION_DESCRIPTOR 0x01 23 | 24 | typedef union { 25 | struct 26 | { 27 | uint8_t u8lo; 28 | uint8_t u8hi; 29 | } __attribute__((packed)); 30 | uint16_t u16; 31 | } word_t; 32 | 33 | typedef struct 34 | { 35 | uint8_t bmRequestType; 36 | uint8_t bRequest; 37 | word_t wValue; // 16bit 38 | word_t wIndex; 39 | word_t wLength; 40 | } __attribute__((packed)) usb_standard_request; 41 | 42 | //#define USB_CLASS_HID 3 43 | 44 | #define USB_DT_HID 0x21 45 | #define USB_DT_REPORT 0x22 46 | 47 | //struct usb_hid_descriptor { 48 | // uint8_t bLength; 49 | // uint8_t bDescriptorType; 50 | // uint16_t bcdHID; 51 | // uint8_t bCountryCode; 52 | // uint8_t bNumDescriptors; 53 | //} __attribute__((packed)); 54 | //#define USB_DT_HID_SIZE sizeof(struct usb_hid_descriptor) 55 | 56 | //struct usb_hid_report_descriptor { 57 | // uint8_t bDescriptorType; 58 | // uint16_t wReportLength; 59 | //} __attribute__((packed)); 60 | 61 | #define USB_DT_REPORT_SIZE sizeof(struct usb_hid_report_descriptor) 62 | 63 | /* Class Definition */ 64 | #define USB_CLASS_VENDOR 0xFF 65 | 66 | /////////////////////////////////////////////////////////////// 67 | /* Table 9-2. Format of Setup Data */ 68 | /* bmRequestType bit definitions */ 69 | 70 | /* bit 7 : Direction */ 71 | #define USB_REQ_TYPE_OUT 0x00 // Host-to-device 72 | #define USB_REQ_TYPE_IN 0x80 // Device-to-host 73 | /* bits 6..5 : Type */ 74 | #define USB_REQ_TYPE_STANDARD 0x00 75 | #define USB_REQ_TYPE_CLASS 0x20 76 | #define USB_REQ_TYPE_VENDOR 0x40 77 | //#define USB_REQ_TYPE_RESERVED 0x60 78 | /* bits 4..0 : Recipient */ 79 | #define USB_REQ_TYPE_DEVICE 0x00 80 | #define USB_REQ_TYPE_INTERFACE 0x01 81 | #define USB_REQ_TYPE_ENDPOINT 0x02 82 | #define USB_REQ_TYPE_OTHER 0x03 83 | //#define USB_REQ_TYPE_RESERVED 0x1F 84 | /////////////////////////////////////////////////////////////// 85 | 86 | /////////////////////////////////////////////////////////////// 87 | /* USB Standard Request Codes - Table 9-4 */ 88 | #define USB_REQ_GET_STATUS 0 89 | #define USB_REQ_CLEAR_FEATURE 1 90 | /* Reserved for future use: 2 */ 91 | #define USB_REQ_SET_FEATURE 3 92 | /* Reserved for future use: 3 */ 93 | #define USB_REQ_SET_ADDRESS 5 94 | #define USB_REQ_GET_DESCRIPTOR 6 95 | #define USB_REQ_SET_DESCRIPTOR 7 96 | #define USB_REQ_GET_CONFIGURATION 8 97 | #define USB_REQ_SET_CONFIGURATION 9 98 | #define USB_REQ_GET_INTERFACE 10 99 | #define USB_REQ_SET_INTERFACE 11 100 | #define USB_REQ_SET_SYNCH_FRAME 12 101 | 102 | // USB HID Request 103 | #define USB_REQ_GET_REPORT 0x01 104 | #define USB_REQ_GET_IDLE 0x02 105 | #define USB_REQ_GET_PROTOCOL 0x03 106 | #define USB_REQ_SET_REPORT 0x09 107 | #define USB_REQ_SET_IDLE 0X0A 108 | #define USB_REQ_SET_PROTOCOL 0X0B 109 | /////////////////////////////////////////////////////////////// 110 | 111 | /////////////////////////////////////////////////////////////// 112 | /* USB Descriptor Types - Table 9-5 */ 113 | #define USB_DT_DEVICE 1 114 | #define USB_DT_CONFIGURATION 2 115 | #define USB_DT_STRING 3 116 | #define USB_DT_INTERFACE 4 117 | #define USB_DT_ENDPOINT 5 118 | #define USB_DT_DEVICE_QUALIFIER 6 119 | #define USB_DT_OTHER_SPEED_CONFIGURATION 7 120 | #define USB_DT_INTERFACE_POWER 8 121 | #define USB_DT_BOS 15 122 | #define USB_DT_SUPERSPEED_USB_ENDPOINT_COMPANION 48 123 | /* From ECNs */ 124 | #define USB_DT_OTG 9 125 | #define USB_DT_DEBUG 10 126 | #define USB_DT_INTERFACE_ASSOCIATION 11 127 | /* USB HID */ 128 | #define USB_DT_HID 0x21 129 | #define USB_DT_HID_REPORT 0x22 130 | /////////////////////////////////////////////////////////////// 131 | 132 | /////////////////////////////////////////////////////////////// 133 | /* USB Standard Feature Selectors - Table 9-6 */ 134 | #define USB_FEAT_ENDPOINT_HALT 0 // Recipient: Device 135 | #define USB_FEAT_DEVICE_REMOTE_WAKEUP 1 // Recipient: Endpoint 136 | #define USB_FEAT_TEST_MODE 2 // Recipient: Device 137 | 138 | /* Information Returned by a GetStatus() Request to a Device - Figure 9-4 */ 139 | #define USB_DEV_STATUS_SELF_POWERED 0x01 140 | #define USB_DEV_STATUS_REMOTE_WAKEUP 0x02 141 | /////////////////////////////////////////////////////////////// 142 | 143 | /////////////////////////////////////////////////////////////// 144 | /* USB Standard Device Descriptor - Table 9-8 */ 145 | typedef struct 146 | { 147 | uint8_t bLength; 148 | uint8_t bDescriptorType; 149 | uint16_t bcdUSB; 150 | uint8_t bDeviceClass; 151 | uint8_t bDeviceSubClass; 152 | uint8_t bDeviceProtocol; 153 | uint8_t bMaxPacketSize0; 154 | uint16_t idVendor; 155 | uint16_t idProduct; 156 | uint16_t bcdDevice; 157 | uint8_t iManufacturer; 158 | uint8_t iProduct; 159 | uint8_t iSerialNumber; 160 | uint8_t bNumConfigurations; 161 | } __attribute__((packed)) usb_device_descriptor; 162 | #define USB_DT_DEVICE_SIZE sizeof(usb_device_descriptor) 163 | /////////////////////////////////////////////////////////////// 164 | 165 | /////////////////////////////////////////////////////////////// 166 | /* USB Device_Qualifier Descriptor - Table 9-9 167 | * Not used in this implementation. 168 | */ 169 | typedef struct 170 | { 171 | uint8_t bLength; 172 | uint8_t bDescriptorType; 173 | uint16_t bcdUSB; 174 | uint8_t bDeviceClass; 175 | uint8_t bDeviceSubClass; 176 | uint8_t bDeviceProtocol; 177 | uint8_t bMaxPacketSize0; 178 | uint8_t bNumConfigurations; 179 | uint8_t bReserved; 180 | } __attribute__((packed)) usb_device_qualifier_descriptor; 181 | /////////////////////////////////////////////////////////////// 182 | 183 | /* This is only defined as a top level named struct to improve c++ 184 | * compatibility. You should never need to instance this struct 185 | * in user code! */ 186 | typedef struct 187 | { 188 | uint8_t *cur_altsetting; 189 | uint8_t num_altsetting; 190 | const struct usb_iface_assoc_descriptor *iface_assoc; 191 | const struct usb_interface_descriptor *altsetting; 192 | } __attribute__((packed)) usb_interface; 193 | 194 | /////////////////////////////////////////////////////////////// 195 | /* USB Standard Configuration Descriptor - Table 9-10 */ 196 | typedef struct 197 | { 198 | uint8_t bLength; 199 | uint8_t bDescriptorType; 200 | uint16_t wTotalLength; 201 | uint8_t bNumInterfaces; 202 | uint8_t bConfigurationValue; 203 | uint8_t iConfiguration; 204 | uint8_t bmAttributes; 205 | uint8_t bMaxPower; 206 | } __attribute__((packed)) usb_config_descriptor; 207 | #define USB_DT_CONFIGURATION_SIZE sizeof(usb_config_descriptor) 208 | /////////////////////////////////////////////////////////////// 209 | 210 | /* USB Configuration Descriptor *bmAttributes* bit definitions */ 211 | #define USB_CONFIG_ATTR_DEFAULT 0x80 /** always required (USB2.0 table 9-10) */ 212 | #define USB_CONFIG_ATTR_SELF_POWERED 0x40 213 | #define USB_CONFIG_ATTR_REMOTE_WAKEUP 0x20 214 | 215 | /* Other Speed Configuration is the same as Configuration Descriptor. 216 | * - Table 9-11 217 | */ 218 | 219 | /////////////////////////////////////////////////////////////// 220 | /* USB Standard Interface Descriptor - Table 9-12 */ 221 | typedef struct 222 | { 223 | uint8_t bLength; 224 | uint8_t bDescriptorType; 225 | uint8_t bInterfaceNumber; 226 | uint8_t bAlternateSetting; 227 | uint8_t bNumEndpoints; 228 | uint8_t bInterfaceClass; 229 | uint8_t bInterfaceSubClass; 230 | uint8_t bInterfaceProtocol; 231 | uint8_t iInterface; 232 | } __attribute__((packed)) usb_interface_descriptor; 233 | #define USB_DT_INTERFACE_SIZE sizeof(usb_interface_descriptor) 234 | /////////////////////////////////////////////////////////////// 235 | 236 | /////////////////////////////////////////////////////////////// 237 | /* USB Standard Endpoint Descriptor - Table 9-13 */ 238 | typedef struct 239 | { 240 | uint8_t bLength; 241 | uint8_t bDescriptorType; 242 | uint8_t bEndpointAddress; 243 | uint8_t bmAttributes; 244 | uint16_t wMaxPacketSize; 245 | uint8_t bInterval; 246 | } __attribute__((packed))usb_endpoint_descriptor; 247 | #define USB_DT_ENDPOINT_SIZE sizeof(usb_endpoint_descriptor) 248 | /////////////////////////////////////////////////////////////// 249 | 250 | /* USB bEndpointAddress helper macros */ 251 | #define USB_ENDPOINT_ADDR_OUT(x) (x) 252 | #define USB_ENDPOINT_ADDR_IN(x) (0x80 | (x)) 253 | 254 | /////////////////////////////////////////////////////////////// 255 | /* USB Endpoint Descriptor bmAttributes bit definitions - Table 9-13 */ 256 | /* bits 1..0 : Transfer type */ 257 | #define USB_ENDPOINT_ATTR_CONTROL 0x00 258 | #define USB_ENDPOINT_ATTR_ISOCHRONOUS 0x01 259 | #define USB_ENDPOINT_ATTR_BULK 0x02 260 | #define USB_ENDPOINT_ATTR_INTERRUPT 0x03 261 | #define USB_ENDPOINT_ATTR_TYPE 0x03 262 | // If not an isochronous endpoint, bits 5..2 are reserved 263 | // and must be set to zero. 264 | /* bits 3..2 : Sync type (only if ISOCHRONOUS) */ 265 | #define USB_ENDPOINT_ATTR_NOSYNC 0x00 266 | #define USB_ENDPOINT_ATTR_ASYNC 0x04 267 | #define USB_ENDPOINT_ATTR_ADAPTIVE 0x08 268 | #define USB_ENDPOINT_ATTR_SYNC 0x0C 269 | #define USB_ENDPOINT_ATTR_SYNCTYPE 0x0C 270 | /* bits 5..4 : Usage type (only if ISOCHRONOUS) */ 271 | #define USB_ENDPOINT_ATTR_DATA 0x00 272 | #define USB_ENDPOINT_ATTR_FEEDBACK 0x10 273 | #define USB_ENDPOINT_ATTR_IMPLICIT_FEEDBACK_DATA 0x20 274 | #define USB_ENDPOINT_ATTR_USAGETYPE 0x30 275 | /////////////////////////////////////////////////////////////// 276 | 277 | /////////////////////////////////////////////////////////////// 278 | /* Table 9-15 specifies String Descriptor Zero. 279 | * Table 9-16 specified UNICODE String Descriptor. 280 | */ 281 | typedef struct 282 | { 283 | uint8_t bLength; 284 | uint8_t bDescriptorType; 285 | uint16_t wData[]; 286 | } __attribute__((packed)) usb_string_descriptor; 287 | 288 | /* From ECN: Interface Association Descriptors, Table 9-Z */ 289 | typedef struct 290 | { 291 | uint8_t bLength; 292 | uint8_t bDescriptorType; 293 | uint8_t bFirstInterface; 294 | uint8_t bInterfaceCount; 295 | uint8_t bFunctionClass; 296 | uint8_t bFunctionSubClass; 297 | uint8_t bFunctionProtocol; 298 | uint8_t iFunction; 299 | } __attribute__((packed)) usb_iface_assoc_descriptor; 300 | #define USB_DT_INTERFACE_ASSOCIATION_SIZE \ 301 | sizeof(usb_iface_assoc_descriptor) 302 | 303 | enum usb_language_id 304 | { 305 | USB_LANGID_ENGLISH_US = 0x409, 306 | }; 307 | /////////////////////////////////////////////////////////////// 308 | 309 | #endif 310 | -------------------------------------------------------------------------------- /components/USBIP/usb_descriptor.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_DESCRIPTOR_H__ 2 | #define __USB_DESCRIPTOR_H__ 3 | 4 | #include "main/dap_configuration.h" 5 | 6 | // Vendor ID assigned by USB-IF (idVendor). 7 | #define USBD0_DEV_DESC_IDVENDOR 0xC251 8 | // Product ID assigned by manufacturer (idProduct). 9 | #define USBD0_DEV_DESC_IDPRODUCT 0xF00A 10 | // Device Release Number in binary-coded decimal (bcdDevice). 11 | #define USBD0_DEV_DESC_BCDDEVICE 0x0100 12 | 13 | // Maximum packet size for Endpoint 0 (bMaxPacketSize0). 14 | #define USBD0_MAX_PACKET0 64 15 | 16 | // If disabled Serial Number String will not be assigned to USB Device. 17 | #define USBD0_STR_DESC_SER_EN 1 18 | 19 | // bmAttributes 20 | #define USBD0_CFG_DESC_BMATTRIBUTES 0x80 21 | 22 | // bMaxPower 23 | #define USBD0_CFG_DESC_BMAXPOWER 250 24 | 25 | // Interface Number 26 | #define USBD_CUSTOM_CLASS0_IF0_NUM 0 27 | 28 | // Alternate Setting 29 | #define USBD_CUSTOM_CLASS0_IF0_ALT 0 30 | 31 | // Class Code 32 | #if (USE_WINUSB == 1) 33 | #define USBD_CUSTOM_CLASS0_IF0_CLASS 0xFF // 0xFF: Vendor Specific 34 | #else 35 | #define USBD_CUSTOM_CLASS0_IF0_CLASS 0x03 // 0x03: HID class 36 | #endif 37 | 38 | // Subclass Code 39 | #define USBD_CUSTOM_CLASS0_IF0_SUBCLASS 0x00 40 | 41 | // Protocol Code 42 | #define USBD_CUSTOM_CLASS0_IF0_PROTOCOL 0x00 43 | 44 | ///////////////////////////////////////////// 45 | 46 | // common part 47 | extern const uint8_t kUSBd0DeviceDescriptor[0x12]; 48 | extern const uint8_t kLangDescriptor[0x04]; 49 | extern const uint8_t kManufacturerString[0x28]; 50 | extern const uint8_t kProductString[0x18]; 51 | extern const uint8_t kSerialNumberString[0x1A]; 52 | 53 | #if (USE_WINUSB == 1) 54 | 55 | #if (USE_USB_3_0 == 1) 56 | extern const uint8_t kUSBd0InterfaceDescriptor[0x30]; 57 | #else 58 | extern const uint8_t kUSBd0InterfaceDescriptor[0x1E]; 59 | #endif // USE_USB_3_0 == 1 60 | 61 | extern const uint8_t kUSBd0ConfigDescriptor[0x09]; 62 | extern const uint8_t kInterfaceString[0x2C]; 63 | 64 | #else 65 | extern const uint8_t kUSBd0InterfaceDescriptor[0x20]; 66 | extern const uint8_t kUSBd0ConfigDescriptor[0x09]; 67 | extern const uint8_t kInterfaceString[0x2C]; 68 | extern const uint8_t kHidReportDescriptor[0x21]; 69 | 70 | #endif 71 | 72 | #endif -------------------------------------------------------------------------------- /components/USBIP/usb_handle.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_HANDLE_H__ 2 | #define __USB_HANDLE_H__ 3 | 4 | #include "components/USBIP/usbip_defs.h" 5 | 6 | void handleUSBControlRequest(usbip_stage2_header *header); 7 | 8 | #endif -------------------------------------------------------------------------------- /components/USBIP/usbip_defs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file usbip_defs.h 3 | * @brief Simple modification 4 | * @version 0.1 5 | * @date 2020-01-22 6 | * 7 | * @copyright Copyright (c) 2020 8 | * 9 | */ 10 | 11 | // Focus on the following structures in this file: 12 | // usbip_stage2_header 13 | // usbip_stage1_response_devlist 14 | 15 | // 16 | // Created by thevoidnn on 10/25/17. 17 | // 18 | 19 | #ifndef __USBIP_DEFS_H__ 20 | #define __USBIP_DEFS_H__ 21 | 22 | #include 23 | 24 | #include "components/USBIP/usb_defs.h" 25 | 26 | #define USBIP_SYSFS_PATH_SIZE 256 27 | #define USBIP_BUSID_SIZE 32 28 | 29 | enum usbip_stage1_command 30 | { 31 | // Offset 2 32 | USBIP_STAGE1_CMD_DEVICE_LIST = 0x05, // OP_REQ_DEVLIST 33 | USBIP_STAGE1_CMD_DEVICE_ATTACH = 0x03, // OP_REQ_IMPORT 34 | }; 35 | 36 | enum usbip_stager2_command 37 | { 38 | //Offset 0 39 | USBIP_STAGE2_REQ_SUBMIT = 0x0001, 40 | USBIP_STAGE2_REQ_UNLINK = 0x0002, 41 | USBIP_STAGE2_RSP_SUBMIT = 0x0003, 42 | USBIP_STAGE2_RSP_UNLINK = 0x0004, 43 | }; 44 | 45 | enum usbip_stage2_direction 46 | { 47 | USBIP_DIR_OUT = 0x00, 48 | USBIP_DIR_IN = 0x01, 49 | }; 50 | 51 | typedef struct 52 | { 53 | uint16_t version; 54 | uint16_t command; 55 | uint32_t status; 56 | } __attribute__((__packed__)) usbip_stage1_header; 57 | ///////////////////////////////////////////////////////////// 58 | 59 | // Device description 60 | typedef struct 61 | { 62 | char path[USBIP_SYSFS_PATH_SIZE]; 63 | char busid[USBIP_BUSID_SIZE]; 64 | 65 | uint32_t busnum; 66 | uint32_t devnum; 67 | uint32_t speed; 68 | 69 | uint16_t idVendor; 70 | uint16_t idProduct; 71 | uint16_t bcdDevice; 72 | 73 | uint8_t bDeviceClass; 74 | uint8_t bDeviceSubClass; 75 | uint8_t bDeviceProtocol; 76 | 77 | uint8_t bConfigurationValue; 78 | uint8_t bNumConfigurations; 79 | uint8_t bNumInterfaces; 80 | } __attribute__((packed)) usbip_stage1_usb_device; 81 | 82 | // Interface description 83 | typedef struct 84 | { 85 | uint8_t bInterfaceClass; 86 | uint8_t bInterfaceSubClass; 87 | uint8_t bInterfaceProtocol; 88 | uint8_t padding; 89 | } __attribute__((packed)) usbip_stage1_usb_interface; 90 | 91 | typedef struct 92 | { 93 | usbip_stage1_usb_device udev; 94 | usbip_stage1_usb_interface uinf[]; 95 | } __attribute__((packed)) usbip_stage1_response_devlist_entry; 96 | 97 | typedef struct 98 | { 99 | uint32_t list_size; 100 | usbip_stage1_response_devlist_entry devices[]; 101 | } __attribute__((__packed__)) usbip_stage1_response_devlist; 102 | 103 | /////////////////////////////////////////////////////////////// 104 | /////////////////////////////////////////////////////////////// 105 | /////////////////////////////////////////////////////////////// 106 | 107 | /** 108 | * struct usbip_header_basic - data pertinent to every URB request 109 | * RESPONSE & REQUEST 110 | * 111 | * @command: the usbip request type 112 | * @seqnum: sequential number that identifies requests; incremented per 113 | * connection 114 | * @devid: specifies a remote USB device uniquely instead of busnum and devnum; 115 | * in the stub driver, this value is ((busnum << 16) | devnum) 116 | * @direction: direction of the transfer 117 | * @ep: endpoint number 118 | */ 119 | typedef struct 120 | { 121 | uint32_t command; 122 | uint32_t seqnum; 123 | uint32_t devid; 124 | uint32_t direction; 125 | uint32_t ep; 126 | } __attribute__((packed)) usbip_stage2_header_basic; 127 | 128 | /** 129 | * struct usbip_header_cmd_submit - USBIP_CMD_SUBMIT packet header 130 | * >>>REQUEST 131 | * 132 | * @transfer_flags: URB flags 133 | * @transfer_buffer_length: the data size for (in) or (out) transfer 134 | * @start_frame: initial frame for isochronous or interrupt transfers 135 | * @number_of_packets: number of isochronous packets 136 | * @interval: maximum time for the request on the server-side host controller 137 | * @setup: setup data for a control request 138 | */ 139 | typedef struct 140 | { 141 | uint32_t transfer_flags; 142 | int32_t data_length; 143 | 144 | /* it is difficult for usbip to sync frames (reserved only?) */ 145 | int32_t start_frame; 146 | int32_t number_of_packets; 147 | int32_t interval; 148 | 149 | union { 150 | uint8_t setup[8]; 151 | usb_standard_request request; 152 | }; 153 | } __attribute__((packed)) usbip_stage2_header_cmd_submit; 154 | 155 | /** 156 | * struct usbip_header_ret_submit - USBIP_RET_SUBMIT packet header 157 | * <<>>REQUEST 177 | * @seqnum: the URB seqnum to unlink 178 | */ 179 | typedef struct 180 | { 181 | uint32_t seqnum; 182 | } __attribute__((packed)) usbip_stage2_header_cmd_unlink; 183 | 184 | /** 185 | * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header 186 | * << 15 | #include 16 | 17 | #include "usbip_server.h" 18 | #include "DAP_handle.h" 19 | #include "main/dap_configuration.h" 20 | #include "cmsis-dap/include/DAP.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "lwip/err.h" 28 | #include "lwip/sockets.h" 29 | 30 | #define DAP_BUFFER_NUM 10 31 | 32 | #if (USE_WINUSB == 1) 33 | typedef struct 34 | { 35 | uint32_t length; 36 | uint8_t buf[DAP_PACKET_SIZE]; 37 | } DapPacket_t; 38 | #else 39 | typedef struct 40 | { 41 | uint8_t buf[DAP_PACKET_SIZE]; 42 | } DapPacket_t; 43 | #endif 44 | 45 | #define DAP_HANDLE_SIZE (sizeof(DapPacket_t)) 46 | 47 | 48 | int kRestartDAPHandle = NO_SIGNAL; 49 | TaskHandle_t kDAPTaskHandle = NULL; 50 | 51 | 52 | static DapPacket_t DAPDataProcessed; 53 | static int dap_respond = 0; 54 | 55 | // SWO Trace 56 | static uint8_t *swo_data_to_send = NULL; 57 | static uint32_t swo_data_num; 58 | 59 | // DAP handle 60 | static RingbufHandle_t dap_dataIN_handle = NULL; 61 | static RingbufHandle_t dap_dataOUT_handle = NULL; 62 | static SemaphoreHandle_t data_response_mux = NULL; 63 | 64 | 65 | void malloc_dap_ringbuf() { 66 | if (data_response_mux && xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) 67 | { 68 | if (dap_dataIN_handle == NULL) { 69 | dap_dataIN_handle = xRingbufferCreate(DAP_HANDLE_SIZE * DAP_BUFFER_NUM, RINGBUF_TYPE_BYTEBUF); 70 | } 71 | if (dap_dataOUT_handle == NULL) { 72 | dap_dataOUT_handle = xRingbufferCreate(DAP_HANDLE_SIZE * DAP_BUFFER_NUM, RINGBUF_TYPE_BYTEBUF); 73 | } 74 | 75 | xSemaphoreGive(data_response_mux); 76 | } 77 | } 78 | 79 | void free_dap_ringbuf() { 80 | if (data_response_mux && xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) { 81 | if (dap_dataIN_handle) { 82 | vRingbufferDelete(dap_dataIN_handle); 83 | } 84 | if (dap_dataOUT_handle) { 85 | vRingbufferDelete(dap_dataOUT_handle); 86 | } 87 | 88 | dap_dataIN_handle = dap_dataOUT_handle = NULL; 89 | xSemaphoreGive(data_response_mux); 90 | } 91 | 92 | } 93 | 94 | 95 | void handle_dap_data_request(usbip_stage2_header *header, uint32_t length) 96 | { 97 | uint8_t *data_in = (uint8_t *)header; 98 | data_in = &(data_in[sizeof(usbip_stage2_header)]); 99 | // Point to the beginning of the URB packet 100 | 101 | #if (USE_WINUSB == 1) 102 | send_stage2_submit_data_fast(header, NULL, 0); 103 | 104 | // always send constant size buf -> cuz we don't care about the IN packet size 105 | // and to unify the style, we set aside the length of the section 106 | xRingbufferSend(dap_dataIN_handle, data_in - sizeof(uint32_t), DAP_HANDLE_SIZE, portMAX_DELAY); 107 | xTaskNotifyGive(kDAPTaskHandle); 108 | 109 | #else 110 | send_stage2_submit_data_fast(header, NULL, 0); 111 | 112 | xRingbufferSend(dap_dataIN_handle, data_in, DAP_HANDLE_SIZE, portMAX_DELAY); 113 | xTaskNotifyGive(kDAPTaskHandle); 114 | 115 | #endif 116 | 117 | // dap_respond = DAP_ProcessCommand((uint8_t *)data_in, (uint8_t *)data_out); 118 | // //handle_dap_data_response(header); 119 | // send_stage2_submit(header, 0, 0); 120 | } 121 | 122 | void handle_swo_trace_response(usbip_stage2_header *header) 123 | { 124 | #if (SWO_FUNCTION_ENABLE == 1) 125 | if (kSwoTransferBusy) 126 | { 127 | // busy indicates that there is data to be send 128 | os_printf("swo use data\r\n"); 129 | send_stage2_submit_data(header, 0, (void *)swo_data_to_send, swo_data_num); 130 | SWO_TransferComplete(); 131 | } 132 | else 133 | { 134 | // nothing to send. 135 | send_stage2_submit(header, 0, 0); 136 | } 137 | #else 138 | send_stage2_submit(header, 0, 0); 139 | #endif 140 | } 141 | 142 | // SWO Data Queue Transfer 143 | // buf: pointer to buffer with data 144 | // num: number of bytes to transfer 145 | void SWO_QueueTransfer(uint8_t *buf, uint32_t num) 146 | { 147 | swo_data_to_send = buf; 148 | swo_data_num = num; 149 | } 150 | 151 | void DAP_Thread(void *argument) 152 | { 153 | dap_dataIN_handle = xRingbufferCreate(DAP_HANDLE_SIZE * DAP_BUFFER_NUM, RINGBUF_TYPE_BYTEBUF); 154 | dap_dataOUT_handle = xRingbufferCreate(DAP_HANDLE_SIZE * DAP_BUFFER_NUM, RINGBUF_TYPE_BYTEBUF); 155 | data_response_mux = xSemaphoreCreateMutex(); 156 | kDAPTaskHandle = xTaskGetCurrentTaskHandle(); 157 | size_t packetSize; 158 | int resLength; 159 | DapPacket_t *item; 160 | 161 | if (dap_dataIN_handle == NULL || dap_dataIN_handle == NULL || 162 | data_response_mux == NULL) 163 | { 164 | printf("Can not create DAP ringbuf/mux!\r\n"); 165 | vTaskDelete(NULL); 166 | } 167 | for (;;) 168 | { 169 | 170 | while (1) 171 | { 172 | if (kRestartDAPHandle) 173 | { 174 | free_dap_ringbuf(); 175 | 176 | if (kRestartDAPHandle == RESET_HANDLE) { 177 | malloc_dap_ringbuf(); 178 | if (dap_dataIN_handle == NULL || dap_dataIN_handle == NULL) 179 | { 180 | printf("Can not create DAP ringbuf/mux!\r\n"); 181 | vTaskDelete(NULL); 182 | } 183 | } 184 | 185 | kRestartDAPHandle = NO_SIGNAL; 186 | } 187 | 188 | ulTaskNotifyTake(pdFALSE, portMAX_DELAY); // wait event 189 | 190 | 191 | if (dap_dataIN_handle == NULL || dap_dataOUT_handle == NULL) { 192 | continue; // may be use elaphureLink, wait... 193 | } 194 | 195 | 196 | packetSize = 0; 197 | item = (DapPacket_t *)xRingbufferReceiveUpTo(dap_dataIN_handle, &packetSize, 198 | pdMS_TO_TICKS(1), DAP_HANDLE_SIZE); 199 | if (packetSize == 0) 200 | { 201 | break; 202 | } 203 | 204 | else if (packetSize < DAP_HANDLE_SIZE) 205 | { 206 | printf("Wrong data in packet size:%d , data in remain: %d\r\n", packetSize, 207 | (int) xRingbufferGetMaxItemSize(dap_dataIN_handle)); 208 | vRingbufferReturnItem(dap_dataIN_handle, (void *)item); 209 | break; 210 | // This may not happen because there is a semaphore acquisition 211 | } 212 | 213 | if (item->buf[0] == ID_DAP_QueueCommands) 214 | { 215 | item->buf[0] = ID_DAP_ExecuteCommands; 216 | } 217 | 218 | resLength = DAP_ProcessCommand((uint8_t *)item->buf, (uint8_t *)DAPDataProcessed.buf); // use first 4 byte to save length 219 | resLength &= 0xFFFF; // res length in lower 16 bits 220 | 221 | vRingbufferReturnItem(dap_dataIN_handle, (void *)item); // process done. 222 | 223 | // now prepare to reply 224 | #if (USE_WINUSB == 1) 225 | DAPDataProcessed.length = resLength; 226 | #endif 227 | xRingbufferSend(dap_dataOUT_handle, (void *)&DAPDataProcessed, DAP_HANDLE_SIZE, portMAX_DELAY); 228 | 229 | if (xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) 230 | { 231 | ++dap_respond; 232 | xSemaphoreGive(data_response_mux); 233 | } 234 | } 235 | } 236 | } 237 | 238 | int fast_reply(uint8_t *buf, uint32_t length, int dap_req_num) 239 | { 240 | usbip_stage2_header *buf_header = (usbip_stage2_header *)buf; 241 | 242 | if (dap_req_num > 0) { 243 | DapPacket_t *item; 244 | size_t packetSize = 0; 245 | item = (DapPacket_t *)xRingbufferReceiveUpTo(dap_dataOUT_handle, &packetSize, 246 | portMAX_DELAY, DAP_HANDLE_SIZE); 247 | if (packetSize == DAP_HANDLE_SIZE) { 248 | #if (USE_WINUSB == 1) 249 | send_stage2_submit_data_fast((usbip_stage2_header *)buf, item->buf, item->length); 250 | #else 251 | send_stage2_submit_data_fast((usbip_stage2_header *)buf, item->buf, DAP_HANDLE_SIZE); 252 | #endif 253 | 254 | if (xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) { 255 | --dap_respond; 256 | xSemaphoreGive(data_response_mux); 257 | } 258 | 259 | vRingbufferReturnItem(dap_dataOUT_handle, (void *)item); 260 | return 1; 261 | } else if (packetSize > 0) { 262 | printf("Wrong data out packet size:%d!\r\n", packetSize); 263 | } 264 | ////TODO: fast reply 265 | } else { 266 | buf_header->base.command = PP_HTONL(USBIP_STAGE2_RSP_SUBMIT); 267 | buf_header->base.direction = PP_HTONL(USBIP_DIR_OUT); 268 | buf_header->u.ret_submit.status = 0; 269 | buf_header->u.ret_submit.data_length = 0; 270 | buf_header->u.ret_submit.error_count = 0; 271 | usbip_network_send(kSock, buf, 48, 0); 272 | return 1; 273 | } 274 | 275 | return 0; 276 | } 277 | 278 | void handle_dap_unlink() 279 | { 280 | // `USBIP_CMD_UNLINK` means calling `usb_unlink_urb()` or `usb_kill_urb()`. 281 | // Note that execution of an URB is inherently an asynchronous operation, and there may be 282 | // synchronization problems in the following solutions. 283 | 284 | // One of the reasons this happens is that the host wants to abort the URB transfer operation 285 | // as soon as possible. USBIP network fluctuations will also cause this error, but I don't know 286 | // whether this is the main reason. 287 | 288 | // Unlink may be applied to zero length URB of "DIR_IN", or a URB containing data. 289 | // In the case of unlink, for the new "DIR_IN" request, it may always return an older response, 290 | // which will lead to panic. This code is a compromise for eliminating the lagging response 291 | // caused by UNLINK. It will clean up the buffers that may have data for return to the host. 292 | // In general, we assume that there is at most one piece of data that has not yet been returned. 293 | if (dap_respond > 0) 294 | { 295 | DapPacket_t *item; 296 | size_t packetSize = 0; 297 | item = (DapPacket_t *)xRingbufferReceiveUpTo(dap_dataOUT_handle, &packetSize, 298 | pdMS_TO_TICKS(10), DAP_HANDLE_SIZE); 299 | if (packetSize == DAP_HANDLE_SIZE) 300 | { 301 | if (xSemaphoreTake(data_response_mux, portMAX_DELAY) == pdTRUE) 302 | { 303 | --dap_respond; 304 | xSemaphoreGive(data_response_mux); 305 | } 306 | 307 | vRingbufferReturnItem(dap_dataOUT_handle, (void *)item); 308 | } 309 | } 310 | } -------------------------------------------------------------------------------- /components/dap_proxy/DAP_handle.h: -------------------------------------------------------------------------------- 1 | #ifndef __DAP_HANDLE_H__ 2 | #define __DAP_HANDLE_H__ 3 | 4 | #include "components/USBIP/usbip_defs.h" 5 | 6 | enum reset_handle_t 7 | { 8 | NO_SIGNAL = 0, 9 | RESET_HANDLE = 1, 10 | DELETE_HANDLE = 2, 11 | }; 12 | 13 | void handle_dap_data_request(usbip_stage2_header *header, uint32_t length); 14 | void handle_swo_trace_response(usbip_stage2_header *header); 15 | void handle_dap_unlink(); 16 | 17 | int fast_reply(uint8_t *buf, uint32_t length, int dap_req_num); 18 | void DAP_Thread(void *argument); 19 | 20 | #endif -------------------------------------------------------------------------------- /components/dap_proxy/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 windowsair 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /components/dap_proxy/corsacOTA.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2021 windowsair 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | #ifndef _CORSACOTA_H_ 23 | #define _CORSACOTA_H_ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | typedef signed int co_err_t; 30 | 31 | #define CO_OK 0 32 | #define CO_FAIL -1 33 | #define CO_ERROR_IO_PENDING -2 34 | #define CO_ERROR_NO_MEM 0x101 35 | #define CO_ERROR_INVALID_ARG 0x102 36 | #define CO_ERROR_INVALID_SIZE 0x104 37 | #define CO_ERROR_INVALID_OTA_PTN -3 38 | 39 | #define CO_RES_SUCCESS 0 40 | #define CO_RES_SYSTEM_ERROR 1 41 | #define CO_RES_INVALID_ARG 2 42 | #define CO_RES_INVALID_SIZE 3 43 | #define CO_RES_INVALID_STATUS 4 44 | 45 | /** 46 | * @brief corsacOTA instance handle. Only one instance is allowed. 47 | * 48 | */ 49 | typedef void *co_handle_t; 50 | 51 | typedef struct co_config { 52 | char *thread_name; // corsacOTA thread name 53 | int stack_size; // corsacOTA thread stack size 54 | int thread_prio; // corsacOTA thread priority 55 | 56 | int listen_port; // corsacOTA server listen port 57 | int max_listen_num; // Maximum number of connections. In fact, after the handshake is complete, there is only one connection to provide services. 58 | 59 | int wait_timeout_sec; // Timeout (in seconds) 60 | int wait_timeout_usec; // Timeout (in microseconds) 61 | 62 | } co_config_t; 63 | 64 | /** 65 | * @brief Start the corsacOTA server 66 | * 67 | * @param config Configuration for new instance of the server 68 | * @return 69 | * - ESP_OK : Server Init successfully 70 | * - ESP_ERR_INVALID_ARG : Null argument 71 | * - ESP_ERR_NO_MEM : Failed to allocate memory for instance 72 | */ 73 | int corsacOTA_init(co_handle_t *handle, co_config_t *config); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif -------------------------------------------------------------------------------- /components/dap_proxy/proxy_server_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef PROXY_SERVER_CONF_H_GUARD 2 | #define PROXY_SERVER_CONF_H_GUARD 3 | 4 | #define DAP_PROXY_PORT 3240 5 | 6 | #endif //PROXY_SERVER_CONF_H_GUARD -------------------------------------------------------------------------------- /components/dap_proxy/tcp_server.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tcp_server.c 3 | * @brief Handle main tcp tasks 4 | * @version 0.1 5 | * @date 2020-01-22 6 | * 7 | * @copyright Copyright (c) 2020 8 | * 9 | */ 10 | #include 11 | 12 | #include "usbip_server.h" 13 | #include "DAP_handle.h" 14 | 15 | #include "components/elaphureLink/elaphureLink_protocol.h" 16 | #include "proxy_server_conf.h" 17 | 18 | #include "freertos/FreeRTOS.h" 19 | #include "freertos/task.h" 20 | 21 | #include "lwip/err.h" 22 | #include "lwip/sockets.h" 23 | #include "websocket_server.h" 24 | 25 | extern TaskHandle_t kDAPTaskHandle; 26 | extern int kRestartDAPHandle; 27 | 28 | int kSock = -1; 29 | 30 | void tcp_server_task(void *pvParameters) 31 | { 32 | uint8_t tcp_rx_buffer[1500] = {0}; 33 | char addr_str[128]; 34 | enum usbip_server_state_t usbip_state = WAIT_DEVLIST; 35 | uint8_t *data; 36 | int addr_family; 37 | int ip_protocol; 38 | int header; 39 | int ret, sz; 40 | 41 | int on = 1; 42 | while (1) 43 | { 44 | 45 | #ifdef CONFIG_EXAMPLE_IPV4 46 | struct sockaddr_in destAddr; 47 | destAddr.sin_addr.s_addr = htonl(INADDR_ANY); 48 | destAddr.sin_family = AF_INET; 49 | destAddr.sin_port = htons(DAP_PROXY_PORT); 50 | addr_family = AF_INET; 51 | ip_protocol = IPPROTO_IP; 52 | inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); 53 | #else // IPV6 54 | struct sockaddr_in6 destAddr; 55 | bzero(&destAddr.sin6_addr.un, sizeof(destAddr.sin6_addr.un)); 56 | destAddr.sin6_family = AF_INET6; 57 | destAddr.sin6_port = htons(DAP_PROXY_PORT); 58 | addr_family = AF_INET6; 59 | ip_protocol = IPPROTO_IPV6; 60 | inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); 61 | #endif 62 | 63 | int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); 64 | if (listen_sock < 0) 65 | { 66 | printf("Unable to create socket: errno %d\r\n", errno); 67 | break; 68 | } 69 | printf("Socket created\r\n"); 70 | 71 | setsockopt(listen_sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); 72 | setsockopt(listen_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)); 73 | 74 | int err = bind(listen_sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); 75 | if (err != 0) 76 | { 77 | printf("Socket unable to bind: errno %d\r\n", errno); 78 | break; 79 | } 80 | printf("Socket binded\r\n"); 81 | 82 | err = listen(listen_sock, 1); 83 | if (err != 0) 84 | { 85 | printf("Error occured during listen: errno %d\r\n", errno); 86 | break; 87 | } 88 | printf("Socket listening\r\n"); 89 | 90 | #ifdef CONFIG_EXAMPLE_IPV6 91 | struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 92 | #else 93 | struct sockaddr_in sourceAddr; 94 | #endif 95 | uint32_t addrLen = sizeof(sourceAddr); 96 | while (1) 97 | { 98 | kSock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen); 99 | if (kSock < 0) 100 | { 101 | printf("Unable to accept connection: errno %d\r\n", errno); 102 | break; 103 | } 104 | setsockopt(kSock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); 105 | setsockopt(kSock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)); 106 | printf("Socket accepted\r\n"); 107 | 108 | // Read header 109 | sz = 4; 110 | data = &tcp_rx_buffer[0]; 111 | do { 112 | ret = recv(kSock, data, sz, 0); 113 | if (ret <= 0) 114 | goto cleanup; 115 | sz -= ret; 116 | data += ret; 117 | } while (sz > 0); 118 | 119 | header = *((int *)(tcp_rx_buffer)); 120 | header = ntohl(header); 121 | 122 | if (header == EL_LINK_IDENTIFIER) { 123 | el_dap_work(tcp_rx_buffer, sizeof(tcp_rx_buffer)); 124 | } else if ((header & 0xFFFF) == 0x8003 || 125 | (header & 0xFFFF) == 0x8005) { // usbip OP_REQ_DEVLIST/OP_REQ_IMPORT 126 | if ((header & 0xFFFF) == 0x8005) 127 | usbip_state = WAIT_DEVLIST; 128 | else 129 | usbip_state = WAIT_IMPORT; 130 | usbip_worker(tcp_rx_buffer, sizeof(tcp_rx_buffer), &usbip_state); 131 | } else if (header == 0x47455420) { // string "GET " 132 | websocket_worker(kSock, tcp_rx_buffer, sizeof(tcp_rx_buffer)); 133 | } else { 134 | printf("Unknown protocol\n"); 135 | } 136 | 137 | cleanup: 138 | if (kSock != -1) 139 | { 140 | printf("Shutting down socket and restarting...\r\n"); 141 | //shutdown(kSock, 0); 142 | close(kSock); 143 | 144 | // Restart DAP Handle 145 | el_process_buffer_free(); 146 | 147 | kRestartDAPHandle = RESET_HANDLE; 148 | if (kDAPTaskHandle) 149 | xTaskNotifyGive(kDAPTaskHandle); 150 | 151 | //shutdown(listen_sock, 0); 152 | //close(listen_sock); 153 | //vTaskDelay(5); 154 | } 155 | } 156 | } 157 | vTaskDelete(NULL); 158 | } -------------------------------------------------------------------------------- /components/dap_proxy/tcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_SERVER_H__ 2 | #define __TCP_SERVER_H__ 3 | 4 | void tcp_server_task(void *pvParameters); 5 | 6 | #endif -------------------------------------------------------------------------------- /components/dap_proxy/usbip_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __USBIP_SERVER_H__ 2 | #define __USBIP_SERVER_H__ 3 | #include 4 | #include 5 | 6 | #include "components/USBIP/usbip_defs.h" 7 | 8 | enum usbip_server_state_t 9 | { 10 | WAIT_DEVLIST = 0, 11 | WAIT_IMPORT, 12 | WAIT_URB, 13 | }; 14 | 15 | extern int kSock; 16 | 17 | int usbip_worker(uint8_t *base, uint32_t length, enum usbip_server_state_t *state); 18 | void send_stage2_submit_data(usbip_stage2_header *req_header, int32_t status, const void * const data, int32_t data_length); 19 | void send_stage2_submit(usbip_stage2_header *req_header, int32_t status, int32_t data_length); 20 | void send_stage2_submit_data_fast(usbip_stage2_header *req_header, const void *const data, int32_t data_length); 21 | int usbip_network_send(int s, const void *dataptr, size_t size, int flags); 22 | 23 | #endif -------------------------------------------------------------------------------- /components/dap_proxy/websocket_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __WEBSOCKET_SERVER_H__ 2 | #define __WEBSOCKET_SERVER_H__ 3 | 4 | #include 5 | 6 | int websocket_worker(int fd, uint8_t *base, uint32_t length); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /components/elaphureLink/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | idf_component_register( 4 | SRCS ${SOURCES} 5 | INCLUDE_DIRS "." 6 | PRIV_REQUIRES dap_proxy 7 | ) -------------------------------------------------------------------------------- /components/elaphureLink/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 windowsair 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /components/elaphureLink/elaphureLink_protocol.c: -------------------------------------------------------------------------------- 1 | #include "components/elaphureLink/elaphureLink_protocol.h" 2 | 3 | #include "DAP_handle.h" 4 | 5 | #include "lwip/err.h" 6 | #include "lwip/sockets.h" 7 | #include "lwip/sys.h" 8 | #include 9 | 10 | extern int kRestartDAPHandle; 11 | extern int kSock; 12 | extern int usbip_network_send(int s, const void *dataptr, size_t size, int flags); 13 | 14 | extern void malloc_dap_ringbuf(); 15 | extern void free_dap_ringbuf(); 16 | 17 | extern uint32_t DAP_ExecuteCommand(const uint8_t *request, uint8_t *response); 18 | 19 | uint8_t* el_process_buffer = NULL; 20 | 21 | void el_process_buffer_malloc() { 22 | if (el_process_buffer != NULL) 23 | return; 24 | 25 | free_dap_ringbuf(); 26 | 27 | el_process_buffer = malloc(1500); 28 | } 29 | 30 | void el_process_buffer_free() { 31 | if (el_process_buffer != NULL) { 32 | free(el_process_buffer); 33 | el_process_buffer = NULL; 34 | } 35 | } 36 | 37 | int el_handshake_process(int fd, void *buffer, size_t len) { 38 | if (len != sizeof(el_request_handshake)) { 39 | return -1; 40 | } 41 | 42 | el_request_handshake* req = (el_request_handshake*)buffer; 43 | 44 | if (ntohl(req->el_link_identifier) != EL_LINK_IDENTIFIER) { 45 | return -1; 46 | } 47 | 48 | if (ntohl(req->command) != EL_COMMAND_HANDSHAKE) { 49 | return -1; 50 | } 51 | 52 | el_response_handshake res; 53 | res.el_link_identifier = htonl(EL_LINK_IDENTIFIER); 54 | res.command = htonl(EL_COMMAND_HANDSHAKE); 55 | res.el_dap_version = htonl(EL_DAP_VERSION); 56 | 57 | usbip_network_send(fd, &res, sizeof(el_response_handshake), 0); 58 | 59 | return 0; 60 | } 61 | 62 | void el_dap_data_process(void* buffer, size_t len) { 63 | int res = DAP_ExecuteCommand(buffer, (uint8_t *)el_process_buffer); 64 | res &= 0xFFFF; 65 | 66 | usbip_network_send(kSock, el_process_buffer, res, 0); 67 | } 68 | 69 | int el_dap_work(uint8_t* base, size_t len) 70 | { 71 | uint8_t *data; 72 | int sz, ret; 73 | 74 | // read command code and protocol version 75 | data = base + 4; 76 | sz = 8; 77 | do { 78 | ret = recv(kSock, data, sz, 0); 79 | if (ret <= 0) 80 | return ret; 81 | sz -= ret; 82 | data += ret; 83 | } while (sz > 0); 84 | 85 | ret = el_handshake_process(kSock, base, 12); 86 | if (ret) 87 | return ret; 88 | 89 | kRestartDAPHandle = DELETE_HANDLE; 90 | el_process_buffer_malloc(); 91 | // data process 92 | while(1) { 93 | ret = recv(kSock, base, len, 0); 94 | if (ret <= 0) 95 | return ret; 96 | el_dap_data_process(base, ret); 97 | } 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /components/elaphureLink/elaphureLink_protocol.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELAPHURELINK_PROTOCOL_H__ 2 | #define __ELAPHURELINK_PROTOCOL_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define EL_LINK_IDENTIFIER 0x8a656c70 8 | 9 | #define EL_DAP_VERSION 0x00000001 10 | 11 | #define EL_COMMAND_HANDSHAKE 0x00000000 12 | 13 | 14 | typedef struct 15 | { 16 | uint32_t el_link_identifier; 17 | uint32_t command; 18 | uint32_t el_proxy_version; 19 | } __attribute__((packed)) el_request_handshake; 20 | 21 | 22 | typedef struct 23 | { 24 | uint32_t el_link_identifier; 25 | uint32_t command; 26 | uint32_t el_dap_version; 27 | } __attribute__((packed)) el_response_handshake; 28 | 29 | 30 | /** 31 | * @brief elahpureLink Proxy handshake phase process 32 | * 33 | * @param fd socket fd 34 | * @param buffer packet buffer 35 | * @param len packet length 36 | * @return 0 on Success, other on failed. 37 | */ 38 | int el_handshake_process(int fd, void* buffer, size_t len); 39 | 40 | 41 | /** 42 | * @brief Process dap data and send to socket 43 | * 44 | * @param buffer dap data buffer 45 | * @param len dap data length 46 | */ 47 | void el_dap_data_process(void* buffer, size_t len); 48 | 49 | 50 | int el_dap_work(uint8_t* base, size_t len); 51 | 52 | void el_process_buffer_malloc(); 53 | void el_process_buffer_free(); 54 | 55 | #endif -------------------------------------------------------------------------------- /components/global_resource/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | *.c 3 | ) 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | REQUIRES utils wt_common 9 | ) -------------------------------------------------------------------------------- /components/global_resource/global_module.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "global_module.h" 8 | #include 9 | #include 10 | 11 | #define TAG __FILE_NAME__ 12 | #define GLOBAL_MODULE_MAX 10 13 | 14 | static global_module_t module_arr[GLOBAL_MODULE_MAX] = {0}; 15 | static uint8_t module_count = 0; 16 | 17 | int global_module_reg(const global_module_t *g_mod) 18 | { 19 | if (g_mod->module_id > GLOBAL_MODULE_MAX) { 20 | ESP_LOGE(TAG, "g_id > max"); 21 | return 1; 22 | } 23 | 24 | if (module_arr[g_mod->module_id].init != NULL) { 25 | ESP_LOGE(TAG, "g_id.init not NULL"); 26 | return 1; 27 | } 28 | 29 | ESP_LOGI(TAG, "g_id: %d", g_mod->module_id); 30 | module_arr[g_mod->module_id].module_id = g_mod->module_id; 31 | module_arr[g_mod->module_id].init = g_mod->init; 32 | module_count++; 33 | return 0; 34 | } 35 | 36 | int global_module_init() 37 | { 38 | for (int i = 0; i < GLOBAL_MODULE_MAX; ++i) { 39 | if (module_arr[i].init) { 40 | module_arr[i].init(); 41 | } 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /components/global_resource/global_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef GLOBAL_MODULE_H_GUARD 8 | #define GLOBAL_MODULE_H_GUARD 9 | 10 | #include 11 | 12 | typedef int (*global_module_init_func)(void); 13 | 14 | typedef struct global_module_t { 15 | global_module_init_func init; 16 | uint8_t module_id; 17 | } global_module_t; 18 | 19 | int global_module_reg(const global_module_t *g_mod); 20 | 21 | int global_module_init(); 22 | 23 | #define GLOBAL_MODULE_REGISTER(NAME, GLOBAL_MODULE_CFG) \ 24 | __attribute__((used, constructor)) void cons_G_MOD_ ## NAME(); \ 25 | void cons_G_MOD_ ## NAME() { global_module_reg(GLOBAL_MODULE_CFG); } 26 | 27 | 28 | #endif //GLOBAL_MODULE_H_GUARD -------------------------------------------------------------------------------- /components/kcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_ADD_INCLUDEDIRS ".") 2 | set(COMPONENT_SRCS "./ikcp.c ./ikcp_util.c") 3 | 4 | 5 | 6 | register_component() -------------------------------------------------------------------------------- /components/kcp/ikcp_util.c: -------------------------------------------------------------------------------- 1 | #include "components/kcp/ikcp_util.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static inline __attribute__((always_inline)) void itimeofday(long* sec, long* usec) 9 | { 10 | struct timeval time; 11 | gettimeofday(&time, NULL); 12 | if (sec) *sec = time.tv_sec; 13 | if (usec) *usec = time.tv_usec; 14 | } 15 | 16 | // get clock in millisecond 64 17 | IINT64 iclock64(void) 18 | { 19 | long s, u; 20 | IINT64 value; 21 | itimeofday(&s, &u); 22 | value = ((IINT64)s) * 1000 + (u / 1000); 23 | return value; 24 | } 25 | 26 | IUINT32 iclock() 27 | { 28 | return (IUINT32)(iclock64() & 0xfffffffful); 29 | } -------------------------------------------------------------------------------- /components/kcp/ikcp_util.h: -------------------------------------------------------------------------------- 1 | #ifndef __IKCP_UTIL_H__ 2 | #define __IKCP_UTIL_H__ 3 | 4 | #include "components/kcp/ikcp.h" 5 | 6 | IINT64 iclock64(void); 7 | IUINT32 iclock(); 8 | 9 | #endif -------------------------------------------------------------------------------- /components/memory_pool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | *.c 3 | ) 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | REQUIRES 9 | ) -------------------------------------------------------------------------------- /components/memory_pool/memory_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "memory_pool.h" 8 | #include 9 | #include 10 | 11 | #define BUFFER_NR 7 12 | #define BUFFER_SZ 2048 13 | 14 | static uint8_t buf[BUFFER_NR][BUFFER_SZ]; 15 | 16 | /* TODO: use CAS */ 17 | static QueueHandle_t buf_queue = NULL; 18 | 19 | int memory_pool_init() 20 | { 21 | if (buf_queue != NULL) 22 | return 0; 23 | 24 | buf_queue = xQueueCreate(BUFFER_NR, sizeof(void *)); 25 | if (buf_queue == NULL) { 26 | return 1; 27 | } 28 | for (int i = 0; i < BUFFER_NR; ++i) { 29 | uint8_t *buf_ptr = buf[i]; 30 | if (xQueueSend(buf_queue, &buf_ptr, 0) != pdTRUE) { 31 | return 1; 32 | } 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | void *memory_pool_get(uint32_t tick_wait) 39 | { 40 | void *ptr = NULL; 41 | xQueueReceive(buf_queue, &ptr, tick_wait); 42 | assert(ptr); 43 | return ptr; 44 | } 45 | 46 | void memory_pool_put(void *ptr) 47 | { 48 | #ifdef WT_DEBUG_MODE 49 | printf("put buf %d\n", uxQueueMessagesWaiting(buf_queue)); 50 | #endif 51 | if (unlikely(xQueueSend(buf_queue, &ptr, 0) != pdTRUE)) { 52 | assert(0); 53 | } 54 | } 55 | 56 | inline uint32_t memory_pool_get_buf_size() 57 | { 58 | return BUFFER_SZ; 59 | } 60 | -------------------------------------------------------------------------------- /components/memory_pool/memory_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef STATIC_BUFFER_H_GUARD 8 | #define STATIC_BUFFER_H_GUARD 9 | 10 | #include 11 | 12 | int memory_pool_init(); 13 | 14 | void *memory_pool_get(uint32_t tick_wait); 15 | 16 | void memory_pool_put(void *ptr); 17 | 18 | uint32_t memory_pool_get_buf_size(); 19 | 20 | 21 | #endif //STATIC_BUFFER_H_GUARD -------------------------------------------------------------------------------- /components/uart_tcp_bridge/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | 4 | idf_component_register( 5 | SRCS ${SOURCES} 6 | INCLUDE_DIRS "." 7 | PRIV_REQUIRES driver 8 | ) -------------------------------------------------------------------------------- /components/uart_tcp_bridge/uart_tcp_bridge.h: -------------------------------------------------------------------------------- 1 | #ifndef _UART_BRIDGE_H_ 2 | #define _UART_BRIDGE_H_ 3 | 4 | #define UART_BRIDGE_PORT 1234 5 | #define UART_BRIDGE_BAUDRATE 74880 6 | 7 | void uart_bridge_init(); 8 | void uart_bridge_task(); 9 | void uart_bridge_close(); 10 | 11 | 12 | #endif -------------------------------------------------------------------------------- /components/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | 4 | idf_component_register( 5 | SRCS ${SOURCES} 6 | INCLUDE_DIRS "." 7 | ) -------------------------------------------------------------------------------- /components/utils/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2009, Jouni Malinen 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | */ 6 | 7 | #ifndef LIST_H_GUARD 8 | #define LIST_H_GUARD 9 | 10 | 11 | #include 12 | 13 | /** 14 | * struct dl_list - Doubly-linked list 15 | */ 16 | struct dl_list { 17 | struct dl_list *next; 18 | struct dl_list *prev; 19 | }; 20 | 21 | static inline void dl_list_init(struct dl_list *list) 22 | { 23 | list->next = list; 24 | list->prev = list; 25 | } 26 | 27 | static inline void dl_list_add(struct dl_list *list, struct dl_list *item) 28 | { 29 | item->next = list->next; 30 | item->prev = list; 31 | list->next->prev = item; 32 | list->next = item; 33 | } 34 | 35 | static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item) 36 | { 37 | dl_list_add(list->prev, item); 38 | } 39 | 40 | static inline void dl_list_del(struct dl_list *item) 41 | { 42 | item->next->prev = item->prev; 43 | item->prev->next = item->next; 44 | item->next = NULL; 45 | item->prev = NULL; 46 | } 47 | 48 | static inline int dl_list_empty(struct dl_list *list) 49 | { 50 | return list->next == list; 51 | } 52 | 53 | static inline unsigned int dl_list_len(struct dl_list *list) 54 | { 55 | struct dl_list *item; 56 | int count = 0; 57 | for (item = list->next; item != list; item = item->next) 58 | count++; 59 | return count; 60 | } 61 | 62 | #ifndef offsetof 63 | #define offsetof(type, member) ((long) &((type *) 0)->member) 64 | #endif 65 | 66 | #define dl_list_entry(item, type, member) \ 67 | ((type *) ((char *) item - offsetof(type, member))) 68 | 69 | #define dl_list_first(list, type, member) \ 70 | (dl_list_empty((list)) ? NULL : \ 71 | dl_list_entry((list)->next, type, member)) 72 | 73 | #define dl_list_last(list, type, member) \ 74 | (dl_list_empty((list)) ? NULL : \ 75 | dl_list_entry((list)->prev, type, member)) 76 | 77 | #define dl_list_for_each(item, list, type, member) \ 78 | for (item = dl_list_entry((list)->next, type, member); \ 79 | &item->member != (list); \ 80 | item = dl_list_entry(item->member.next, type, member)) 81 | 82 | #define dl_list_for_each_safe(item, n, list, type, member) \ 83 | for (item = dl_list_entry((list)->next, type, member), \ 84 | n = dl_list_entry(item->member.next, type, member); \ 85 | &item->member != (list); \ 86 | item = n, n = dl_list_entry(n->member.next, type, member)) 87 | 88 | #define dl_list_for_each_reverse(item, list, type, member) \ 89 | for (item = dl_list_entry((list)->prev, type, member); \ 90 | &item->member != (list); \ 91 | item = dl_list_entry(item->member.prev, type, member)) 92 | 93 | #define DEFINE_DL_LIST(name) \ 94 | struct dl_list name = { &(name), &(name) } 95 | 96 | #endif //LIST_H_GUARD -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | 4 | idf_component_register( 5 | SRCS ${SOURCES} 6 | INCLUDE_DIRS "." 7 | ) -------------------------------------------------------------------------------- /main/dap_configuration.h: -------------------------------------------------------------------------------- 1 | #ifndef __DAP_CONFIGURATION_H__ 2 | #define __DAP_CONFIGURATION_H__ 3 | 4 | /** 5 | * @brief Specify the use of WINUSB 6 | * 7 | */ 8 | #define USE_WINUSB 1 9 | 10 | /** 11 | * @brief Enable this option, no need to physically connect MOSI and MISO 12 | * 13 | */ 14 | #define USE_SPI_SIO 1 15 | 16 | 17 | /** 18 | * @brief Specify to enable USB 3.0 19 | * 20 | */ 21 | #define USE_USB_3_0 0 22 | 23 | 24 | // For USB 3.0, it must be 1024 byte. 25 | #if (USE_USB_3_0 == 1) 26 | #define USB_ENDPOINT_SIZE 1024U 27 | #else 28 | #define USB_ENDPOINT_SIZE 512U 29 | #endif 30 | 31 | /// Maximum Package Size for Command and Response data. 32 | /// This configuration settings is used to optimize the communication performance with the 33 | /// debugger and depends on the USB peripheral. Typical vales are 64 for Full-speed USB HID or WinUSB, 34 | /// 1024 for High-speed USB HID and 512 for High-speed USB WinUSB. 35 | 36 | #if (USE_WINUSB == 1) 37 | #define DAP_PACKET_SIZE 512U // 512 for WinUSB. 38 | #else 39 | #define DAP_PACKET_SIZE 255U // 255 for USB HID 40 | #endif 41 | 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/mdns: "*" 4 | ## Required IDF version 5 | idf: 6 | version: ">=5.2.0" 7 | # # Put list of dependencies here 8 | # # For components maintained by Espressif: 9 | # component: "~1.0.0" 10 | # # For 3rd party components: 11 | # username/component: ">=1.0.0,<2.0.0" 12 | # username2/component2: 13 | # version: "~1.0.0" 14 | # # For transient dependencies `public` flag can be set. 15 | # # `public` flag doesn't have an effect dependencies of the `main` component. 16 | # # All dependencies of `main` are public by default. 17 | # public: true 18 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "tcp_server.h" 7 | #include "cmsis-dap/include/DAP.h" 8 | #include "DAP_handle.h" 9 | #include "wt_mdns_config.h" 10 | #include "wt_storage.h" 11 | #include "wifi_manager.h" 12 | #include "web_server.h" 13 | #include "memory_pool.h" 14 | #include "request_runner.h" 15 | #include "uart_tcp_bridge.h" 16 | #include "global_module.h" 17 | 18 | #include 19 | 20 | void app_main() 21 | { 22 | assert(memory_pool_init() == 0); // static buffer 23 | assert(request_runner_init() == 0); 24 | wt_storage_init(); 25 | ESP_ERROR_CHECK(esp_netif_init()); 26 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 27 | wt_mdns_init(); 28 | 29 | wifi_manager_init(); 30 | DAP_Setup(); 31 | 32 | global_module_init(); 33 | 34 | start_webserver(); 35 | 36 | xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 14, NULL); 37 | 38 | // DAP handle task 39 | xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 10, NULL); 40 | 41 | xTaskCreate(uart_bridge_task, "uart_server", 4096, NULL, 2, NULL); 42 | } 43 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name , Type , SubType , Offset , Size , Flags 2 | # 1st stage ROM ,data, , 3 | # 2nd stage boot ,data,0x1000, 4 | # partition table,data,0xF000,4K(0x1000), 5 | begin ,0x40,0x00 , ,0k , 6 | nvs ,data,nvs ,0x10000 ,16K , 7 | phy_init,data,phy , ,4K , 8 | none0 ,0x40,0x00 , ,0k , 9 | ota_0 ,app ,ota_0 ,0x20000 ,0x1B0000, 10 | wt_nvs ,data,nvs , ,64K , 11 | coredump,data,coredump,0x390000,64K , -------------------------------------------------------------------------------- /project_components/api_router/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c 2 | ) 3 | 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | REQUIRES json request_runner wt_common 9 | PRIV_REQUIRES memory_pool 10 | ) 11 | -------------------------------------------------------------------------------- /project_components/api_router/api_json_module.c: -------------------------------------------------------------------------------- 1 | #include "api_json_module.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define TAG __FILE_NAME__ 8 | 9 | #define API_MODULE_MAX 10 10 | 11 | typedef struct api_json_module_t { 12 | api_json_on_req on_req; 13 | } api_json_module_t; 14 | 15 | static api_json_module_t module_arr[API_MODULE_MAX] = {0}; 16 | static uint8_t module_count = 0; 17 | 18 | void api_json_module_dump() 19 | { 20 | for (int i = 0; i < API_MODULE_MAX; ++i) { 21 | printf("%d = %p\n", i, module_arr[i].on_req); 22 | } 23 | } 24 | 25 | int api_json_module_add(api_json_init_func func) 26 | { 27 | api_json_module_cfg_t api_module; 28 | int err; 29 | 30 | api_module.module_id = -1; 31 | api_module.on_req = NULL; 32 | 33 | err = func(&api_module); 34 | if (err) { 35 | printf("module %p init failed\n", func); 36 | return 1; 37 | } 38 | 39 | if (api_module.module_id >= API_MODULE_MAX) { 40 | printf("module ID should be smaller than API_MODULE_MAX=%d\n", API_MODULE_MAX); 41 | return 1; 42 | } 43 | 44 | if (module_arr[api_module.module_id].on_req != NULL) { 45 | printf("module ID %d is already in use\n", api_module.module_id); 46 | return 1; 47 | } 48 | 49 | module_arr[api_module.module_id].on_req = api_module.on_req; 50 | module_count++; 51 | printf("%p is added\n", func); 52 | return 0; 53 | } 54 | 55 | int api_json_module_call(uint8_t id, uint16_t cmd, api_json_req_t *in, api_json_module_async_t *out) 56 | { 57 | if (unlikely(id >= API_MODULE_MAX || module_arr[id].on_req == NULL)) { 58 | return API_JSON_BAD_REQUEST; 59 | } 60 | 61 | return module_arr[id].on_req(cmd, in, out); 62 | } 63 | -------------------------------------------------------------------------------- /project_components/api_router/api_json_module.h: -------------------------------------------------------------------------------- 1 | #ifndef API_JSON_MODULE_H_GUARD 2 | #define API_JSON_MODULE_H_GUARD 3 | 4 | #include "request_runner.h" 5 | #include 6 | #include 7 | 8 | typedef struct api_json_req_t { 9 | cJSON *in; 10 | cJSON *out; 11 | union { 12 | struct { 13 | uint8_t big_buffer: 1; 14 | uint8_t reserved: 7; 15 | }; 16 | uint8_t out_flag; 17 | }; 18 | } api_json_req_t; 19 | 20 | typedef struct api_json_module_req_t { 21 | int (*func)(api_json_req_t *req); 22 | void *arg; /* request context (=api_json_req) */ 23 | } api_json_module_req_t; 24 | 25 | typedef struct api_json_module_async_t { 26 | api_json_module_req_t module; 27 | req_task_cb_t req_task; 28 | } api_json_module_async_t; 29 | 30 | 31 | typedef enum api_json_req_status_e { 32 | API_JSON_OK = 0, 33 | API_JSON_ASYNC = 1, 34 | API_JSON_BAD_REQUEST = 2, 35 | API_JSON_INTERNAL_ERR = 3, 36 | API_JSON_UNSUPPORTED_CMD = 4, 37 | API_JSON_PROPERTY_ERR = 5, 38 | API_JSON_BUSY = 6, 39 | } api_json_req_status_e; 40 | 41 | typedef int (*api_json_on_req)(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *rsp); 42 | 43 | typedef struct api_json_module_cfg_t { 44 | api_json_on_req on_req; /* input request callback */ 45 | uint8_t module_id; 46 | } api_json_module_cfg_t; 47 | 48 | typedef int (*api_json_init_func)(api_json_module_cfg_t *api_module); 49 | 50 | void api_json_module_dump(); 51 | 52 | int api_json_module_add(api_json_init_func); 53 | 54 | #define API_JSON_MODULE_REGISTER(INIT) \ 55 | __attribute__((used, constructor)) void cons_ ## INIT(); \ 56 | void cons_ ## INIT() { api_json_module_add(INIT); } 57 | 58 | int api_json_module_call(uint8_t id, uint16_t cmd, api_json_req_t *in, api_json_module_async_t *out); 59 | 60 | #endif //API_JSON_MODULE_H_GUARD 61 | -------------------------------------------------------------------------------- /project_components/api_router/api_json_router.c: -------------------------------------------------------------------------------- 1 | #include "api_json_router.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define TAG __FILENAME__ 9 | 10 | int api_json_router_init() 11 | { 12 | return 0; 13 | } 14 | 15 | int api_json_route(api_json_req_t *req, api_json_module_async_t *rsp) 16 | { 17 | uint16_t cmd; 18 | uint8_t module_id; 19 | cJSON *cmd_json; 20 | cJSON *module_json; 21 | 22 | if (unlikely(req == NULL)) { 23 | return API_JSON_BAD_REQUEST; 24 | } 25 | 26 | cmd_json = cJSON_GetObjectItem(req->in, "cmd"); 27 | module_json = cJSON_GetObjectItem(req->in, "module"); 28 | 29 | if (!cJSON_IsNumber(cmd_json) || !cJSON_IsNumber(module_json)) { 30 | return API_JSON_BAD_REQUEST; 31 | } 32 | 33 | cmd = cmd_json->valueint; 34 | module_id = module_json->valueint; 35 | 36 | ESP_LOGI(TAG, "cmd %d received\n", cmd); 37 | 38 | return api_json_module_call(module_id, cmd, req, rsp); 39 | } 40 | -------------------------------------------------------------------------------- /project_components/api_router/api_json_router.h: -------------------------------------------------------------------------------- 1 | #ifndef API_JSON_ROUTER_H_GUARD 2 | #define API_JSON_ROUTER_H_GUARD 3 | 4 | #include "api_json_module.h" 5 | 6 | int api_json_router_init(); 7 | 8 | int api_json_route(api_json_req_t *req, api_json_module_async_t *out); 9 | 10 | #endif //API_JSON_ROUTER_H_GUARD -------------------------------------------------------------------------------- /project_components/html/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB HTML_FILES 2 | *.gz 3 | ) 4 | 5 | idf_component_register( 6 | EMBED_FILES ${HTML_FILES} 7 | ) 8 | -------------------------------------------------------------------------------- /project_components/html/index.html.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerms/wireless-esp32-tools/6a625c0c5791068e020ce18c4c0090db6d0321b6/project_components/html/index.html.gz -------------------------------------------------------------------------------- /project_components/html/version.txt: -------------------------------------------------------------------------------- 1 | v0.1.3 2 | -------------------------------------------------------------------------------- /project_components/html/ws.sharedworker.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kerms/wireless-esp32-tools/6a625c0c5791068e020ce18c4c0090db6d0321b6/project_components/html/ws.sharedworker.js.gz -------------------------------------------------------------------------------- /project_components/request_runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | *.c 3 | ) 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | REQUIRES 9 | ) -------------------------------------------------------------------------------- /project_components/request_runner/request_runner.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "request_runner.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | static QueueHandle_t long_run_queue = NULL; 16 | static QueueHandle_t send_out_queue = NULL; 17 | 18 | _Noreturn static void req_long_task(void *arg); 19 | 20 | _Noreturn static void req_send_out_task(void *arg); 21 | 22 | _Noreturn void req_long_task(void *arg) 23 | { 24 | req_task_cb_t *req; 25 | while (1) { 26 | if (unlikely(xQueueReceive(long_run_queue, &req, portMAX_DELAY) != pdTRUE)) { 27 | continue; 28 | } 29 | req->status = req->module.cb(req->module.arg); 30 | 31 | /* if send out queue is busy, set status and let the cb to cancel send out 32 | * */ 33 | if (req_queue_push_send_out(req, pdMS_TO_TICKS(20)) != 0) { 34 | req->status = -1; 35 | req->send_out.cb(req->send_out.arg, req->status); 36 | } 37 | } 38 | } 39 | 40 | _Noreturn void req_send_out_task(void *arg) 41 | { 42 | req_task_cb_t *req; 43 | while (1) { 44 | if (likely(xQueueReceive(send_out_queue, &req, portMAX_DELAY))) { 45 | req->send_out.cb(req->send_out.arg, req->status); 46 | } 47 | } 48 | } 49 | 50 | int request_runner_init() 51 | { 52 | BaseType_t res; 53 | if (long_run_queue != NULL || send_out_queue != NULL) { 54 | return 0; 55 | } 56 | 57 | long_run_queue = xQueueCreate(2, sizeof(req_task_cb_t *)); 58 | send_out_queue = xQueueCreate(4, sizeof(req_task_cb_t *)); 59 | assert(long_run_queue != NULL && send_out_queue != NULL); 60 | 61 | res = xTaskCreate(req_long_task, "Ltask", 4 * 1024, NULL, 8, NULL); 62 | res &= xTaskCreate(req_send_out_task, "send out task", 4 * 1024, NULL, 9, NULL); 63 | assert(res == pdPASS); 64 | return 0; 65 | } 66 | 67 | int req_queue_push_long_run(req_task_cb_t *req, uint32_t delay) 68 | { 69 | if (unlikely(xQueueSend(long_run_queue, &req, delay) != pdTRUE)) { 70 | return 1; 71 | } 72 | 73 | return 0; 74 | } 75 | 76 | int req_queue_push_send_out(req_task_cb_t *req, uint32_t delay) 77 | { 78 | if (unlikely(xQueueSend(send_out_queue, &req, delay) != pdTRUE)) { 79 | return 1; 80 | } 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /project_components/request_runner/request_runner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef REQUEST_RUNNER_H_GUARD 8 | #define REQUEST_RUNNER_H_GUARD 9 | 10 | #include 11 | 12 | typedef struct req_send_out_cb_t { 13 | void (*cb)(void *arg, int status); 14 | void *arg; /* socket info */ 15 | } req_send_out_cb_t; 16 | 17 | typedef struct req_module_cb_t { 18 | int (*cb)(void *arg); 19 | void *arg; 20 | } req_module_cb_t; 21 | 22 | typedef struct req_task_cb_t { 23 | req_module_cb_t module; 24 | req_send_out_cb_t send_out; 25 | int status; 26 | } req_task_cb_t; 27 | 28 | int request_runner_init(); 29 | 30 | int req_queue_push_long_run(req_task_cb_t *req, uint32_t delay); 31 | int req_queue_push_send_out(req_task_cb_t *req, uint32_t delay); 32 | 33 | 34 | #endif //REQUEST_RUNNER_H_GUARD -------------------------------------------------------------------------------- /project_components/web_server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | web_server.c 3 | web_uri_module.c 4 | uri_modules/uri_ws.c 5 | uri_modules/uri_api.c 6 | uri_modules/uri_html_base.c 7 | ) 8 | 9 | idf_component_register( 10 | SRCS ${SOURCES} 11 | INCLUDE_DIRS "." 12 | REQUIRES esp_http_server 13 | PRIV_REQUIRES request_runner api_router json memory_pool utils html SSDP 14 | ) 15 | 16 | idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) 17 | 18 | -------------------------------------------------------------------------------- /project_components/web_server/uri_modules/uri_api.c: -------------------------------------------------------------------------------- 1 | #include "web_uri_module.h" 2 | #include "api_json_router.h" 3 | #include "request_runner.h" 4 | #include "memory_pool.h" 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #define TAG __FILE_NAME__ 12 | 13 | #define HTTPD_STATUS_503 "503 Busy" 14 | 15 | typedef struct post_request_t { 16 | api_json_req_t json; 17 | api_json_module_async_t async; 18 | httpd_req_t *req_out; 19 | char buf[0]; 20 | } post_request_t; 21 | 22 | static void async_send_out_cb(void *arg, int module_status); 23 | static int uri_api_send_out(httpd_req_t *req, post_request_t *post_req, int err); 24 | 25 | 26 | static esp_err_t api_post_handler(httpd_req_t *req) 27 | { 28 | uint32_t buf_len; 29 | int data_len; 30 | int err; 31 | post_request_t *post_req; 32 | char *buf; 33 | uint32_t remaining = req->content_len; 34 | 35 | buf_len = memory_pool_get_buf_size() - sizeof(post_request_t); 36 | if (unlikely(buf_len < remaining)) { 37 | ESP_LOGE(TAG, "req size %lu > buf_len %lu", remaining, buf_len); 38 | return ESP_FAIL; 39 | } 40 | 41 | post_req = memory_pool_get(pdMS_TO_TICKS(20)); 42 | if (unlikely(post_req == NULL)) { 43 | ESP_LOGE(TAG, "static buf busy"); 44 | return ESP_FAIL; 45 | } 46 | buf = post_req->buf; 47 | 48 | data_len = httpd_req_recv(req, buf, buf_len); 49 | if (unlikely(data_len <= 0)) { 50 | ESP_LOGE(TAG, "httpd recv error"); 51 | err = ESP_FAIL; 52 | goto put_buf; 53 | } 54 | 55 | ESP_LOGI(TAG, "=========== RECEIVED DATA ========== %d", httpd_req_to_sockfd(req)); 56 | ESP_LOGI(TAG, "%.*s", data_len, buf); 57 | ESP_LOGI(TAG, "===================================="); 58 | ESP_LOGI(TAG, "heap min: %lu, cur: %lu", esp_get_minimum_free_heap_size(), esp_get_free_heap_size()); 59 | 60 | /* Decode */ 61 | post_req->json.in = cJSON_ParseWithLength(buf, data_len); 62 | if (unlikely(post_req->json.in == NULL)) { 63 | httpd_resp_set_status(req, HTTPD_400); 64 | goto end; 65 | } 66 | 67 | post_req->json.out = NULL; 68 | err = api_json_route(&post_req->json, &post_req->async); 69 | if (err == API_JSON_ASYNC) { 70 | httpd_req_async_handler_begin(req, &post_req->req_out); 71 | post_req->async.req_task.send_out.cb = async_send_out_cb; 72 | post_req->async.req_task.send_out.arg = post_req; 73 | if (req_queue_push_long_run(&post_req->async.req_task, pdMS_TO_TICKS(20))) { 74 | /* queued failed */ 75 | httpd_req_async_handler_complete(post_req->req_out); 76 | httpd_resp_set_status(req, HTTPD_STATUS_503); 77 | goto end; 78 | } 79 | return ESP_OK; 80 | } else if (unlikely(err != API_JSON_OK)) { 81 | httpd_resp_set_status(req, HTTPD_400); 82 | goto end; 83 | } 84 | 85 | if (post_req->json.out == NULL) { 86 | goto end; 87 | } 88 | 89 | /* api function returns something, send back to http client */ 90 | err = uri_api_send_out(req, post_req, 0); 91 | goto put_buf; 92 | 93 | end: 94 | cJSON_Delete(post_req->json.in); 95 | err = httpd_resp_send(req, NULL, 0); 96 | if (unlikely(err)) { 97 | ESP_LOGE(TAG, "resp_send err: %s", esp_err_to_name(err)); 98 | } 99 | put_buf: 100 | memory_pool_put(post_req); 101 | return err; 102 | } 103 | 104 | int uri_api_send_out(httpd_req_t *req, post_request_t *post_req, int err) 105 | { 106 | char *buf; 107 | uint32_t buf_len; 108 | 109 | buf = post_req->buf; 110 | buf_len = memory_pool_get_buf_size() - sizeof(post_request_t); 111 | cJSON_Delete(post_req->json.in); 112 | if (post_req->json.out) { 113 | ESP_LOGI(TAG, "json out ok"); 114 | httpd_resp_set_type(req, HTTPD_TYPE_JSON); 115 | err = !cJSON_PrintPreallocated(post_req->json.out, buf, buf_len - 5, 0); 116 | cJSON_Delete(post_req->json.out); 117 | } 118 | 119 | if (unlikely(err)) { 120 | httpd_resp_set_status(req, HTTPD_500); 121 | return httpd_resp_send(req, NULL, 0); 122 | } 123 | 124 | return httpd_resp_send(req, buf, strlen(buf)); 125 | } 126 | 127 | void async_send_out_cb(void *arg, int module_status) 128 | { 129 | post_request_t *req = arg; 130 | if (module_status != API_JSON_OK) { 131 | httpd_sess_trigger_close(req->req_out->handle, 132 | httpd_req_to_sockfd(req->req_out)); 133 | } 134 | 135 | uri_api_send_out(req->req_out, req, module_status); 136 | 137 | /* clean resources */ 138 | httpd_req_async_handler_complete(req->req_out); 139 | memory_pool_put(req); 140 | }; 141 | 142 | /** 143 | * REGISTER MODULE 144 | * */ 145 | 146 | static const httpd_uri_t uri_api = { 147 | .uri = "/api", 148 | .method = HTTP_POST, 149 | .handler = api_post_handler, 150 | .user_ctx = NULL 151 | }; 152 | 153 | static int URI_API_INIT(const httpd_uri_t **uri_conf) { 154 | *uri_conf = &uri_api; 155 | return 0; 156 | } 157 | 158 | static int URI_API_EXIT(const httpd_uri_t **uri_conf) { 159 | *uri_conf = &uri_api; 160 | return 0; 161 | } 162 | 163 | WEB_URI_MODULE_REGISTER(0x81, URI_API_INIT, URI_API_EXIT) 164 | 165 | 166 | -------------------------------------------------------------------------------- /project_components/web_server/uri_modules/uri_html_base.c: -------------------------------------------------------------------------------- 1 | #include "web_uri_module.h" 2 | #include "ssdp.h" 3 | 4 | #include 5 | #include 6 | #include "memory_pool.h" 7 | 8 | #define TAG __FILE_NAME__ 9 | 10 | #define MAKE_U32(b0, b1, b2, b3) ((b0) | (b1) << 8 | (b2) << 16 | (b3) << 24) 11 | #define URI_ROOT MAKE_U32 ('/', '\0', '\0', '\0')/* / */ 12 | #define URI_WS_DOT MAKE_U32('/', 'w', 's', '.') /* /ws. */ 13 | #define URI_SSDP MAKE_U32 ('/', 'S', 'S', 'D') /* /SSD */ 14 | 15 | #define HTML_INDEX "index_html_gz" 16 | #define JS_WS_SHARED "ws_sharedworker_js_gz" 17 | 18 | #define SEND_FILE(req, filename) do { \ 19 | extern const unsigned char filename##_start[] asm("_binary_" filename "_start"); \ 20 | extern const unsigned char filename##_end[] asm("_binary_" filename "_end"); \ 21 | const ssize_t file_size = filename##_end - filename##_start; \ 22 | httpd_resp_send(req, (const char *)filename##_start, file_size); \ 23 | } while(0) 24 | 25 | static esp_err_t html_base_get_handler(httpd_req_t *req) 26 | { 27 | /* this "hash" actually use the first 4 chars as an int32_t "hash" */ 28 | const int *URI_HASH = (const int *)req->uri; 29 | 30 | httpd_resp_set_hdr(req, "Connection", "close"); 31 | 32 | if (*URI_HASH == URI_WS_DOT) { 33 | httpd_resp_set_type(req, "text/javascript"); 34 | httpd_resp_set_hdr(req, "Content-encoding", "gzip"); 35 | SEND_FILE(req, JS_WS_SHARED); 36 | } else if (*URI_HASH == URI_SSDP) { 37 | httpd_resp_set_type(req, "text/xml"); 38 | char *buf = memory_pool_get(portMAX_DELAY); 39 | ssdp_get_schema_str(buf, memory_pool_get_buf_size()); 40 | httpd_resp_send(req, buf, strlen(buf)); 41 | } else { 42 | httpd_resp_set_type(req, "text/html"); 43 | httpd_resp_set_hdr(req, "Content-encoding", "gzip"); 44 | SEND_FILE(req, HTML_INDEX); 45 | } 46 | 47 | return ESP_OK; 48 | } 49 | 50 | /** 51 | * REGISTER MODULE 52 | * */ 53 | 54 | static const httpd_uri_t hello = { 55 | .uri = "/", 56 | .method = HTTP_GET, 57 | .handler = html_base_get_handler, 58 | }; 59 | 60 | static int URI_HTML_BASE_INIT(const httpd_uri_t **uri_conf) { 61 | *uri_conf = &hello; 62 | return 0; 63 | } 64 | 65 | static int URI_HTML_BASE_EXIT(const httpd_uri_t **uri_conf) { 66 | *uri_conf = &hello; 67 | return 0; 68 | } 69 | 70 | WEB_URI_MODULE_REGISTER(0x90, URI_HTML_BASE_INIT, URI_HTML_BASE_EXIT); 71 | -------------------------------------------------------------------------------- /project_components/web_server/web_server.c: -------------------------------------------------------------------------------- 1 | #include "web_server.h" 2 | #include "web_uri_module.h" 3 | #include "ssdp.h" 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define TAG "web server" 13 | 14 | #define MAKE_U32(b0, b1, b2, b3) ((b0) | (b1) << 8 | (b2) << 16 | (b3) << 24) 15 | #define URI_WS_STR MAKE_U32('/', 'w', 's', '\0') 16 | #define URI_API_STR MAKE_U32('/', 'a', 'p', 'i') 17 | 18 | static httpd_handle_t http_server = NULL; 19 | 20 | /** 21 | * 3 types of ref: 22 | * - 1. "/" 23 | * - 2. "/entry" 24 | * - 3. "/dir/" 25 | * 4 types of target 26 | * - 1. "/.*" 27 | * - 2. "/entry" 28 | * - 2. "/dir/" 29 | * - 3. "/dir/.*" 30 | * */ 31 | static bool uri_match(const char *reference_uri, const char *uri_to_match, size_t match_upto) 32 | { 33 | const uint32_t *ptr32_ref = (const uint32_t *) reference_uri; 34 | const uint32_t *ptr32_target = (const uint32_t *) uri_to_match; 35 | size_t ref_length; 36 | 37 | /* optimized for /ws quick access */ 38 | if (likely(match_upto == 3)) { 39 | if (likely(*ptr32_ref == URI_WS_STR)) { 40 | ESP_LOGI(TAG, "cmp ws"); 41 | return *ptr32_target == *ptr32_ref; 42 | } 43 | } 44 | 45 | /* ref should be shorter than target */ 46 | ref_length = strlen(reference_uri); 47 | if (ref_length > match_upto) { 48 | ESP_LOGI(TAG, "no match length ref %s t: %s", reference_uri, uri_to_match); 49 | return false; 50 | } 51 | 52 | // strict matching "/entry" for ref = "/entry" 53 | if (ref_length == match_upto) { 54 | if (memcmp(reference_uri, uri_to_match, ref_length) == 0) { 55 | ESP_LOGI(TAG, "strict match %s", reference_uri); 56 | return true; 57 | } 58 | } 59 | 60 | // if ref = /dir/ targets are /dir/ and /dir/* 61 | if (reference_uri[ref_length - 1] == '/' && ref_length > 1) { 62 | if (memcmp(reference_uri, uri_to_match, ref_length) == 0) { 63 | ESP_LOGI(TAG, "match /dir/"); 64 | return true; 65 | } else { 66 | ESP_LOGI(TAG, "no match /dir/"); 67 | return false; 68 | } 69 | } 70 | 71 | /* Fall back to root pages */ 72 | // match /* when ref if / 73 | if (reference_uri[ref_length - 1] == '/') { 74 | ESP_LOGI(TAG, "match /"); 75 | return true; 76 | } 77 | 78 | ESP_LOGI(TAG, "fall back false %s t: %s", reference_uri, uri_to_match); 79 | return false; 80 | } 81 | 82 | static int8_t opened_socket = 0; 83 | 84 | static esp_err_t web_server_on_open(httpd_handle_t hd, int sockfd) 85 | { 86 | opened_socket++; 87 | ESP_LOGI(TAG, "%d open, now: %d", sockfd, opened_socket); 88 | return ESP_OK; 89 | } 90 | 91 | static void web_server_on_close(httpd_handle_t hd, int sockfd) 92 | { 93 | opened_socket--; 94 | ESP_LOGI(TAG, "%d closed, now: %d", sockfd, opened_socket); 95 | close(sockfd); 96 | } 97 | 98 | void start_webserver(void) 99 | { 100 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 101 | int err; 102 | 103 | config.enable_so_linger = true; 104 | config.linger_timeout = 0; 105 | config.lru_purge_enable = true; 106 | config.uri_match_fn = uri_match; 107 | config.open_fn = web_server_on_open; 108 | config.close_fn = web_server_on_close; 109 | config.keep_alive_enable = 1; 110 | config.keep_alive_count = 1; 111 | 112 | ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); 113 | if ((err = httpd_start(&http_server, &config)) != ESP_OK) { 114 | ESP_LOGE(TAG, "Error starting server!"); 115 | ESP_ERROR_CHECK(err); 116 | } 117 | 118 | ESP_LOGI(TAG, "Registering URI handlers"); 119 | uri_module_init(http_server); 120 | } 121 | 122 | static esp_err_t stop_webserver(httpd_handle_t server) 123 | { 124 | // Stop the httpd server 125 | return httpd_stop(server); 126 | } 127 | 128 | int server_is_running() 129 | { 130 | return http_server != NULL; 131 | } 132 | -------------------------------------------------------------------------------- /project_components/web_server/web_server.h: -------------------------------------------------------------------------------- 1 | #ifndef WEB_SERVER_H_GUARD 2 | #define WEB_SERVER_H_GUARD 3 | 4 | #include 5 | #include 6 | 7 | void disconnect_handler(void* arg, esp_event_base_t event_base, 8 | int32_t event_id, void* event_data); 9 | void connect_handler(void* arg, esp_event_base_t event_base, 10 | int32_t event_id, void* event_data); 11 | 12 | void start_webserver(void); 13 | int server_is_running(); 14 | 15 | 16 | #endif //WEB_SERVER_H_GUARD -------------------------------------------------------------------------------- /project_components/web_server/web_uri_module.c: -------------------------------------------------------------------------------- 1 | #include "web_uri_module.h" 2 | #include "list.h" 3 | 4 | #include 5 | 6 | 7 | #define URI_MODULE_MAX 8 8 | 9 | #define TAG __FILE_NAME__ 10 | 11 | typedef struct uri_module_list_t { 12 | struct dl_list list; 13 | uri_module_t module; 14 | } uri_module_list_t; 15 | 16 | static uri_module_list_t module_arr[URI_MODULE_MAX]; 17 | static uint8_t module_count = 0; 18 | static DEFINE_DL_LIST(list_head); 19 | 20 | int uri_module_init(httpd_handle_t server) 21 | { 22 | int err; 23 | const httpd_uri_t *uri; 24 | uri_module_list_t *item; 25 | uint8_t index = 0; 26 | 27 | dl_list_for_each(item, &list_head, uri_module_list_t, list) { 28 | err = item->module.init(&uri); 29 | ESP_LOGI(TAG, "uri %s init", uri->uri); 30 | if (err) { 31 | ESP_LOGE(TAG, "%d init error", index); 32 | } 33 | 34 | err = httpd_register_uri_handler(server, uri); 35 | if (err) { 36 | ESP_LOGE(TAG, "%d %s", index, esp_err_to_name(err)); 37 | } 38 | index++; 39 | } 40 | return 0; 41 | } 42 | 43 | int uri_module_exit(httpd_handle_t server) 44 | { 45 | 46 | return 0; 47 | } 48 | 49 | int uri_module_add(uint8_t priority, uri_module_func init, uri_module_func exit) 50 | { 51 | ESP_LOGI(TAG, "adding module %p", init); 52 | 53 | if (module_count >= URI_MODULE_MAX) { 54 | ESP_LOGE(TAG, "too much module > URI_MODULE_MAX"); 55 | return 1; 56 | } 57 | 58 | module_arr[module_count].module.exit = exit; 59 | module_arr[module_count].module.init = init; 60 | module_arr[module_count].module.priority = priority; 61 | 62 | uri_module_list_t *item; 63 | dl_list_for_each(item, &list_head, uri_module_list_t, list) { 64 | if (item->module.priority <= priority) { 65 | break; 66 | } 67 | } 68 | dl_list_add(&item->list, &module_arr[module_count].list); 69 | module_count++; 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /project_components/web_server/web_uri_module.h: -------------------------------------------------------------------------------- 1 | #ifndef WEB_URI_MODULE_H_GUARD 2 | #define WEB_URI_MODULE_H_GUARD 3 | 4 | #include 5 | 6 | typedef int (*uri_module_func)(const httpd_uri_t **uri); 7 | 8 | typedef struct uri_module_t { 9 | uri_module_func init; 10 | uri_module_func exit; 11 | uint8_t priority; 12 | } uri_module_t; 13 | 14 | /** 15 | * @param priority smaller number will be called first 16 | * @return 0: SUCCESS, 1: max module count reached 17 | */ 18 | int uri_module_add(uint8_t priority, uri_module_func init, uri_module_func exit); 19 | 20 | /** 21 | * @brief Register a uri module that will be init with PRI(priority) order. 22 | * smaller priority will be called first. 23 | */ 24 | #define WEB_URI_MODULE_REGISTER(PRI, INIT, EXIT) \ 25 | __attribute__((used, constructor(PRI))) void cons_ ## INIT(); \ 26 | void cons_ ## INIT() { uri_module_add(PRI, INIT, EXIT); } 27 | 28 | int uri_module_init(httpd_handle_t server); 29 | int uri_module_exit(httpd_handle_t server); 30 | 31 | #endif //WEB_URI_MODULE_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | wifi_event_handler.c 3 | wifi_manager.c 4 | wifi_api_json.c 5 | wifi_api.c 6 | wifi_json_utils.c 7 | wifi_storage.c 8 | ) 9 | 10 | 11 | idf_component_register( 12 | SRCS ${SOURCES} 13 | INCLUDE_DIRS "." 14 | PRIV_REQUIRES mdns esp_wifi esp_event api_router wt_storage driver SSDP 15 | ) 16 | 17 | idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) 18 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_api.c: -------------------------------------------------------------------------------- 1 | #include "wifi_api.h" 2 | #include "wifi_manager.h" 3 | #include "wifi_configuration.h" 4 | #include "wifi_storage.h" 5 | #include 6 | 7 | void wifi_api_sta_get_ap_info(wifi_api_ap_info_t *ap_info) 8 | { 9 | wifi_ap_record_t ap_record = {0}; 10 | int err; 11 | esp_wifi_sta_get_ap_info(&ap_record); 12 | strncpy(ap_info->ssid, (char *)ap_record.ssid, sizeof(ap_info->ssid)); 13 | strncpy(ap_info->mac, (char *)ap_record.bssid, sizeof(ap_info->mac)); 14 | ap_info->rssi = ap_record.rssi; 15 | ap_info->password[0] = '\0'; 16 | 17 | esp_netif_t *sta_netif = wifi_manager_get_sta_netif(); 18 | esp_netif_ip_info_t ip_info; 19 | esp_netif_get_ip_info(sta_netif, &ip_info); 20 | ip4_addr_set(&ap_info->ip, &ip_info.ip); 21 | ip4_addr_set(&ap_info->gateway, &ip_info.gw); 22 | ip4_addr_set(&ap_info->netmask, &ip_info.netmask); 23 | 24 | esp_netif_dns_info_t dns_info; 25 | err = esp_netif_get_dns_info(wifi_manager_get_sta_netif(), 26 | ESP_NETIF_DNS_MAIN, &dns_info); 27 | if (err) { 28 | ap_info->dns_main.addr = ap_info->gateway.addr; 29 | } else { 30 | ap_info->dns_main.addr = dns_info.ip.u_addr.ip4.addr; 31 | } 32 | 33 | err = esp_netif_get_dns_info(wifi_manager_get_sta_netif(), 34 | ESP_NETIF_DNS_BACKUP, &dns_info); 35 | if (err) { 36 | ap_info->dns_backup.addr = ap_info->gateway.addr; 37 | } else { 38 | ap_info->dns_backup.addr = dns_info.ip.u_addr.ip4.addr; 39 | } 40 | } 41 | 42 | void wifi_api_ap_get_info(wifi_api_ap_info_t *ap_info) 43 | { 44 | wifi_credential_t credential; 45 | int err = wifi_data_get_ap_credential(&credential); 46 | if (err) { 47 | strncpy(ap_info->ssid, WIFI_DEFAULT_AP_SSID, strlen(WIFI_DEFAULT_AP_SSID)+1); 48 | strncpy(ap_info->password, WIFI_DEFAULT_AP_PASS, strlen(WIFI_DEFAULT_AP_PASS)+1); 49 | } else { 50 | strncpy(ap_info->ssid, credential.ssid, sizeof(ap_info->ssid)); 51 | strncpy(ap_info->password, credential.password, sizeof(ap_info->password)); 52 | } 53 | esp_wifi_get_mac(WIFI_IF_AP, (uint8_t *) &ap_info->mac); 54 | IP4_ADDR_EXPAND(&ap_info->ip, WIFI_DEFAULT_AP_IP); 55 | IP4_ADDR_EXPAND(&ap_info->gateway, WIFI_DEFAULT_AP_GATEWAY); 56 | IP4_ADDR_EXPAND(&ap_info->netmask, WIFI_DEFAULT_AP_NETMASK); 57 | ap_info->rssi = 0; 58 | 59 | esp_netif_dns_info_t dns_info; 60 | err = esp_netif_get_dns_info(wifi_manager_get_ap_netif(), 61 | ESP_NETIF_DNS_MAIN, &dns_info); 62 | if (err) { 63 | ap_info->dns_main.addr = ap_info->gateway.addr; 64 | } else { 65 | ap_info->dns_main.addr = dns_info.ip.u_addr.ip4.addr; 66 | } 67 | 68 | err = esp_netif_get_dns_info(wifi_manager_get_ap_netif(), 69 | ESP_NETIF_DNS_BACKUP, &dns_info); 70 | if (err) { 71 | ap_info->dns_backup.addr = ap_info->gateway.addr; 72 | } else { 73 | ap_info->dns_backup.addr = dns_info.ip.u_addr.ip4.addr; 74 | } 75 | } 76 | 77 | static int rssi_comp(const void *a, const void *b) 78 | { 79 | const wifi_api_ap_scan_info_t *r1 = a; 80 | const wifi_api_ap_scan_info_t *r2 = b; 81 | return r2->rssi - r1->rssi; 82 | } 83 | 84 | /** 85 | * @brief blocking function 86 | */ 87 | int wifi_api_get_scan_list(uint16_t *number, wifi_api_ap_scan_info_t *ap_info) 88 | { 89 | wifi_ap_record_t *records; 90 | int err; 91 | 92 | records = malloc(*number * sizeof(wifi_ap_record_t)); 93 | if (records == NULL) { 94 | return ESP_ERR_NO_MEM; 95 | } 96 | 97 | err = wifi_manager_get_scan_list(number, records); 98 | if (err) { 99 | printf("get scan list err\n"); 100 | free(records); 101 | return err; 102 | } 103 | 104 | for (int i = 0; i < *number; ++i) { 105 | printf("%d %d %s\n", i, records[i].rssi, records[i].ssid); 106 | strncpy(ap_info[i].ssid, (char *) records[i].ssid, sizeof(ap_info[i].ssid)); 107 | strncpy(ap_info[i].mac, (char *) records[i].bssid, sizeof(ap_info[i].mac)); 108 | ap_info[i].rssi = records[i].rssi; 109 | } 110 | free(records); 111 | 112 | qsort(ap_info, *number, sizeof(wifi_api_ap_scan_info_t), rssi_comp); 113 | return 0; 114 | } 115 | 116 | static wifi_api_scan_done_cb scan_done_cb; 117 | 118 | static void wifi_manager_scan_done(uint16_t ap_found, wifi_ap_record_t *records, void *arg) 119 | { 120 | wifi_api_ap_scan_info_t *ap_info; 121 | 122 | ap_info = malloc(ap_found * sizeof(wifi_api_ap_scan_info_t)); 123 | for (int i = 0; i < ap_found; ++i) { 124 | strncpy(ap_info[i].ssid, (char *) records[i].ssid, sizeof(ap_info[i].ssid)); 125 | strncpy(ap_info[i].mac, (char *) records[i].bssid, sizeof(ap_info[i].mac)); 126 | ap_info[i].rssi = records[i].rssi; 127 | } 128 | printf("wifi api scan done\n"); 129 | scan_done_cb(ap_found, ap_info, arg); 130 | } 131 | 132 | int wifi_api_connect(const char *ssid, const char *password) 133 | { 134 | return wifi_manager_connect(ssid, password); 135 | } 136 | 137 | int wifi_api_disconnect(void) 138 | { 139 | return wifi_manager_disconnect(); 140 | } 141 | 142 | int wifi_api_sta_set_static_conf(wifi_api_sta_ap_static_info_t *static_info) 143 | { 144 | int err = wifi_manager_sta_set_static_conf(static_info); 145 | if (err) { 146 | return err; 147 | } 148 | 149 | return wifi_data_save_static(static_info); 150 | } 151 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_api.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_API_H_GUARD 2 | #define WIFI_API_H_GUARD 3 | 4 | #include 5 | 6 | #define WIFI_MODULE_ID 1 7 | 8 | typedef enum wifi_api_json_cmd_t { 9 | UNKNOWN = 0, 10 | WIFI_API_JSON_STA_GET_AP_INFO = 1, 11 | WIFI_API_JSON_CONNECT = 2, 12 | WIFI_API_JSON_GET_SCAN = 3, 13 | WIFI_API_JSON_DISCONNECT = 4, 14 | WIFI_API_JSON_AP_GET_INFO = 5, 15 | WIFI_API_JSON_GET_MODE = 6, /* req:{ }, ret:{mode, [delay_off], [delay_on]} */ 16 | WIFI_API_JSON_SET_MODE = 7, /* req:{mode, [delay_off], [delay_on]} */ 17 | WIFI_API_JSON_SET_AP_CRED = 8, /* ssid[32] + password[64] */ 18 | WIFI_API_JSON_STA_GET_STATIC_INFO = 9, 19 | WIFI_API_JSON_STA_SET_STATIC_CONF = 10, /* static_ip_en: 0/1, static_dns_en: 0/1 */ 20 | } wifi_api_json_cmd_t; 21 | 22 | typedef struct wifi_api_ap_info_t { 23 | ip4_addr_t ip; 24 | ip4_addr_t gateway; 25 | ip4_addr_t netmask; 26 | char ssid[32+1]; 27 | char password[64+1]; 28 | char mac[6]; 29 | signed char rssi; 30 | ip4_addr_t dns_main; 31 | ip4_addr_t dns_backup; 32 | } wifi_api_ap_info_t; 33 | 34 | typedef struct wifi_api_ap_scan_info_t { 35 | ip4_addr_t ip; 36 | ip4_addr_t gateway; 37 | ip4_addr_t netmask; 38 | char ssid[32+1]; 39 | char mac[6]; 40 | signed char rssi; 41 | } wifi_api_ap_scan_info_t; 42 | 43 | typedef struct wifi_api_sta_ap_static_info_t { 44 | ip4_addr_t ip; 45 | ip4_addr_t gateway; 46 | ip4_addr_t netmask; 47 | ip4_addr_t dns_main; 48 | ip4_addr_t dns_backup; 49 | uint8_t static_ip_en; 50 | uint8_t static_dns_en; 51 | } wifi_api_sta_ap_static_info_t; 52 | 53 | typedef enum wifi_apsta_mode_e { 54 | /* permanent */ 55 | WIFI_AP_AUTO_STA_ON = 0, 56 | 57 | WIFI_AP_STA_OFF = 4, /* 100 */ 58 | WIFI_AP_OFF_STA_ON = 5, /* 101 */ 59 | WIFI_AP_ON_STA_OFF = 6, /* 110 */ 60 | WIFI_AP_STA_ON = 7, /* 111 */ 61 | 62 | /* temporary */ 63 | WIFI_AP_STOP = 8, 64 | WIFI_AP_START = 9, 65 | WIFI_STA_STOP = 10, 66 | WIFI_STA_START = 11, 67 | } wifi_apsta_mode_e; 68 | 69 | void wifi_api_sta_get_ap_info(wifi_api_ap_info_t *ap_info); 70 | 71 | void wifi_api_ap_get_info(wifi_api_ap_info_t *ap_info); 72 | 73 | typedef void (*wifi_api_scan_done_cb)(uint16_t found, wifi_api_ap_scan_info_t *aps, void *arg); 74 | 75 | int wifi_api_trigger_scan(uint16_t *max_ap_count, wifi_api_scan_done_cb cb, void *cb_arg); 76 | 77 | int wifi_api_get_scan_list(uint16_t *number, wifi_api_ap_scan_info_t *ap_info); 78 | 79 | int wifi_api_connect(const char *ssid, const char *password); 80 | 81 | int wifi_api_disconnect(void); 82 | 83 | int wifi_api_sta_set_static_conf(wifi_api_sta_ap_static_info_t *static_info); 84 | 85 | 86 | #endif //WIFI_API_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_api_json.c: -------------------------------------------------------------------------------- 1 | #include "api_json_module.h" 2 | #include "wifi_api.h" 3 | #include "wifi_json_utils.h" 4 | #include "wifi_manager.h" 5 | 6 | #include 7 | #include 8 | 9 | #include "wifi_storage.h" 10 | 11 | #define TAG __FILENAME__ 12 | 13 | static int wifi_api_json_sta_get_ap_info(api_json_req_t *req); 14 | 15 | static int wifi_api_json_get_scan(api_json_req_t *req); 16 | 17 | static int wifi_api_json_connect(api_json_req_t *req); 18 | 19 | static int wifi_api_json_disconnect(api_json_req_t *req); 20 | 21 | static int wifi_api_json_ap_get_info(api_json_req_t *req); 22 | 23 | static int wifi_api_json_set_mode(api_json_req_t *req); 24 | 25 | static int wifi_api_json_get_mode(api_json_req_t *req); 26 | static int wifi_api_json_set_ap_cred(api_json_req_t *req); 27 | static int wifi_api_json_sta_get_static_info(api_json_req_t *req); 28 | static int wifi_api_json_sta_set_static_conf(api_json_req_t *req); 29 | 30 | /* the upper caller call cb() with void *, this let us use custom function arg */ 31 | static int async_helper_cb(void *arg) 32 | { 33 | api_json_module_req_t *req = arg; 34 | return req->func(req->arg); 35 | } 36 | 37 | static inline int set_async(api_json_req_t *req, api_json_module_async_t *async, int (*func)(api_json_req_t *)) 38 | { 39 | async->module.func = func; 40 | async->module.arg = req; 41 | async->req_task.module.cb = async_helper_cb; 42 | async->req_task.module.arg = &async->module; 43 | return API_JSON_ASYNC; 44 | } 45 | 46 | static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *async) 47 | { 48 | wifi_api_json_cmd_t wifi_cmd = cmd; 49 | switch (wifi_cmd) { 50 | case UNKNOWN: 51 | default: 52 | break; 53 | case WIFI_API_JSON_STA_GET_AP_INFO: 54 | return wifi_api_json_sta_get_ap_info(req); 55 | case WIFI_API_JSON_CONNECT: 56 | return set_async(req, async, wifi_api_json_connect); 57 | case WIFI_API_JSON_GET_SCAN: 58 | return set_async(req, async, wifi_api_json_get_scan); 59 | case WIFI_API_JSON_DISCONNECT: 60 | return wifi_api_json_disconnect(req); 61 | case WIFI_API_JSON_AP_GET_INFO: 62 | return wifi_api_json_ap_get_info(req); 63 | case WIFI_API_JSON_GET_MODE: 64 | return wifi_api_json_get_mode(req); 65 | case WIFI_API_JSON_SET_MODE: 66 | return wifi_api_json_set_mode(req); 67 | case WIFI_API_JSON_SET_AP_CRED: 68 | return wifi_api_json_set_ap_cred(req); 69 | case WIFI_API_JSON_STA_GET_STATIC_INFO: 70 | return wifi_api_json_sta_get_static_info(req); 71 | case WIFI_API_JSON_STA_SET_STATIC_CONF: 72 | return wifi_api_json_sta_set_static_conf(req); 73 | } 74 | 75 | ESP_LOGI(TAG, "cmd %d not executed\n", cmd); 76 | return API_JSON_UNSUPPORTED_CMD; 77 | } 78 | 79 | /* **** 80 | * register module 81 | * */ 82 | static int wifi_api_json_init(api_json_module_cfg_t *cfg) 83 | { 84 | cfg->on_req = on_json_req; 85 | cfg->module_id = WIFI_MODULE_ID; 86 | return 0; 87 | } 88 | 89 | API_JSON_MODULE_REGISTER(wifi_api_json_init) 90 | 91 | 92 | static int wifi_api_json_sta_get_ap_info(api_json_req_t *req) 93 | { 94 | wifi_api_ap_info_t ap_info; 95 | wifi_api_sta_get_ap_info(&ap_info); 96 | req->out = wifi_api_json_serialize_ap_info(&ap_info, WIFI_API_JSON_STA_GET_AP_INFO); 97 | return 0; 98 | } 99 | 100 | static int wifi_api_json_ap_get_info(api_json_req_t *req) 101 | { 102 | wifi_api_ap_info_t ap_info; 103 | wifi_api_ap_get_info(&ap_info); 104 | req->out = wifi_api_json_serialize_ap_info(&ap_info, WIFI_API_JSON_AP_GET_INFO); 105 | return 0; 106 | } 107 | 108 | static int wifi_api_json_get_scan(api_json_req_t *req) 109 | { 110 | wifi_api_ap_scan_info_t ap_info[20]; 111 | uint16_t max_count = 20; 112 | int err; 113 | 114 | ESP_LOGI(TAG, "get scan\n"); 115 | 116 | err = wifi_api_get_scan_list(&max_count, ap_info); 117 | if (err == ESP_ERR_NOT_FINISHED) { 118 | req->out = wifi_api_json_create_err_rsp(req->in, "Wi-Fi scan busy"); 119 | return 1; 120 | } 121 | 122 | ESP_LOGI(TAG, "scan ok\n"); 123 | 124 | req->out = wifi_api_json_serialize_scan_list(ap_info, max_count); 125 | return 0; 126 | } 127 | 128 | 129 | int wifi_api_json_connect(api_json_req_t *req) 130 | { 131 | char *ssid; 132 | char *password; 133 | 134 | ssid = cJSON_GetStringValue(cJSON_GetObjectItem(req->in, "ssid")); 135 | password = cJSON_GetStringValue(cJSON_GetObjectItem(req->in, "password")); 136 | if (ssid == NULL || password == NULL) { 137 | return 1; 138 | } 139 | 140 | int err = wifi_api_connect(ssid, password); 141 | if (err) { 142 | return err; 143 | } 144 | 145 | return wifi_api_json_sta_get_ap_info(req); 146 | }; 147 | 148 | int wifi_api_json_set_mode(api_json_req_t *req) 149 | { 150 | int value; 151 | int err; 152 | 153 | err = wifi_api_json_utils_get_int(req->in, "mode", &value); 154 | if (err) { 155 | req->out = wifi_api_json_create_err_rsp(req->in, "'mode' attribute missing"); 156 | ESP_LOGE(TAG, "ap stop: %s", esp_err_to_name(err)); 157 | return API_JSON_OK; 158 | } 159 | wifi_apsta_mode_e mode = value; 160 | 161 | err = wifi_manager_change_mode(mode); 162 | if (err) { 163 | req->out = wifi_api_json_create_err_rsp(req->in, "Change mode Failed"); 164 | ESP_LOGE(TAG, "ap stop: %s", esp_err_to_name(err)); 165 | return API_JSON_OK; 166 | } 167 | 168 | if (mode == WIFI_AP_AUTO_STA_ON) { 169 | int ap_on_delay; 170 | int ap_off_delay; 171 | err = wifi_api_json_utils_get_int(req->in, "ap_on_delay", &ap_on_delay); 172 | err |= wifi_api_json_utils_get_int(req->in, "ap_off_delay", &ap_off_delay); 173 | if (err == 0) { 174 | wifi_manager_set_ap_auto_delay(&ap_on_delay, &ap_off_delay); 175 | req->out = wifi_api_json_serialize_ap_auto(mode, ap_on_delay, ap_off_delay); 176 | return API_JSON_OK; 177 | } 178 | } 179 | 180 | return API_JSON_OK; 181 | } 182 | 183 | int wifi_api_json_get_mode(api_json_req_t *req) 184 | { 185 | wifi_apsta_mode_e mode; 186 | wifi_mode_t status; 187 | int ap_on_delay, ap_off_delay; 188 | 189 | wifi_manager_get_mode(&mode, &status); 190 | if (mode == WIFI_AP_AUTO_STA_ON) { 191 | wifi_manager_get_ap_auto_delay(&ap_on_delay, &ap_off_delay); 192 | } else { 193 | ap_on_delay = -1; 194 | ap_off_delay = -1; 195 | } 196 | 197 | req->out = wifi_api_json_serialize_get_mode(mode, status, ap_on_delay, ap_off_delay); 198 | return API_JSON_OK; 199 | } 200 | 201 | 202 | int wifi_api_json_disconnect(api_json_req_t *req) 203 | { 204 | return wifi_api_disconnect(); 205 | } 206 | 207 | 208 | int wifi_api_json_set_ap_cred(api_json_req_t *req) 209 | { 210 | wifi_credential_t credential; 211 | int err; 212 | 213 | err = wifi_api_json_get_credential(req->in, (char *)&credential.ssid, (char *)&credential.password); 214 | if (err) { 215 | return API_JSON_PROPERTY_ERR; 216 | } 217 | 218 | if (strlen(credential.password) < 8) { 219 | req->out = wifi_api_json_create_err_rsp(req->in, "password < 8"); 220 | return API_JSON_OK; 221 | } 222 | 223 | err = wifi_data_save_ap_credential(&credential); 224 | if (err) { 225 | return API_JSON_INTERNAL_ERR; 226 | } 227 | 228 | wifi_manager_set_ap_credential(&credential); 229 | return 0; 230 | } 231 | 232 | int wifi_api_json_sta_get_static_info(api_json_req_t *req) 233 | { 234 | wifi_api_sta_ap_static_info_t static_info = {0}; 235 | int err = wifi_data_get_static(&static_info); 236 | if (err) { 237 | return API_JSON_INTERNAL_ERR; 238 | } 239 | 240 | req->out = wifi_api_json_ser_static_info(&static_info); 241 | return API_JSON_OK; 242 | } 243 | 244 | int wifi_api_json_sta_set_static_conf(api_json_req_t *req) 245 | { 246 | wifi_api_sta_ap_static_info_t static_info = {0}; 247 | int err; 248 | wifi_data_get_static(&static_info); 249 | 250 | err = wifi_api_json_deser_static_conf(req->in, &static_info); 251 | if (err) { 252 | return API_JSON_PROPERTY_ERR; 253 | } 254 | 255 | wifi_api_sta_set_static_conf(&static_info); 256 | return API_JSON_OK; 257 | } 258 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_configuration.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_CONFIGURATION_H_GUARD 2 | #define WIFI_CONFIGURATION_H_GUARD 3 | 4 | #define WIFI_DEFAULT_HOSTNAME "无线DAP" 5 | 6 | #define WIFI_DEFAULT_AP_SSID "无线DAP" 7 | #define WIFI_DEFAULT_AP_PASS "12345678" 8 | #define WIFI_DEFAULT_AP_IP 192, 168, 1, 1 9 | #define WIFI_DEFAULT_AP_GATEWAY 192, 168, 1, 1 10 | #define WIFI_DEFAULT_AP_NETMASK 255, 255, 255, 0 11 | 12 | #define WIFI_DEFAULT_STA_SSID "example_ssid" 13 | #define WIFI_DEFAULT_STA_PASS "12345678" 14 | 15 | #if defined CONFIG_IDF_TARGET_ESP32 16 | #define WIFI_LED_ENABLE 0 17 | #elif defined CONFIG_IDF_TARGET_ESP32C3 18 | #define WIFI_LED_ENABLE 0 19 | #elif defined CONFIG_IDF_TARGET_ESP32S3 20 | #define WIFI_LED_ENABLE 0 21 | #endif 22 | 23 | #define WIFI_LED_PIN 9 24 | 25 | #define IP4_ADDR_EXPAND(...) IP4_ADDR(__VA_ARGS__) 26 | 27 | #endif //WIFI_CONFIGURATION_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_event_handler.c: -------------------------------------------------------------------------------- 1 | #include "wifi_event_handler.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "ssdp.h" 11 | #include "wifi_configuration.h" 12 | 13 | #define TAG __FILE_NAME__ 14 | 15 | void event_on_connected(ip_event_got_ip_t *event); 16 | 17 | void ip_event_handler(void *handler_arg __attribute__((unused)), 18 | esp_event_base_t event_base __attribute__((unused)), 19 | int32_t event_id, 20 | void *event_data) 21 | { 22 | switch (event_id) { 23 | case IP_EVENT_STA_GOT_IP: { 24 | ip_event_got_ip_t *event = event_data; 25 | printf("STA GOT IP : %s\n", 26 | ip4addr_ntoa((const ip4_addr_t *) &event->ip_info.ip)); 27 | event_on_connected(event); 28 | ssdp_set_ip_gw(&event->ip_info.ip.addr, &event->ip_info.gw.addr); 29 | break; 30 | } 31 | case IP_EVENT_STA_LOST_IP: { 32 | printf("sta lost ip\n"); 33 | ip4_addr_t ip; 34 | ip4_addr_t gw; 35 | IP4_ADDR_EXPAND(&ip, WIFI_DEFAULT_AP_IP); 36 | IP4_ADDR_EXPAND(&gw, WIFI_DEFAULT_AP_GATEWAY); 37 | ssdp_set_ip_gw(&ip.addr, &gw.addr); 38 | break; 39 | } 40 | case IP_EVENT_AP_STAIPASSIGNED: 41 | printf("event STAIPASSIGNED\n"); 42 | break; 43 | case IP_EVENT_GOT_IP6: 44 | #ifdef CONFIG_EXAMPLE_IPV6 45 | xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT); 46 | printf("SYSTEM_EVENT_STA_GOT_IP6\r\n"); 47 | 48 | char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip); 49 | printf("IPv6: %s\r\n", ip6); 50 | #endif 51 | case IP_EVENT_ETH_GOT_IP: 52 | case IP_EVENT_ETH_LOST_IP: 53 | case IP_EVENT_PPP_GOT_IP: 54 | case IP_EVENT_PPP_LOST_IP: 55 | default: 56 | break; 57 | } 58 | } 59 | 60 | typedef struct wifi_event_ctx_t { 61 | /* WIFI scan */ 62 | struct { 63 | wifi_ap_record_t *ap; 64 | wifi_event_scan_done_cb cb; 65 | uint16_t number; 66 | }; 67 | /* WIFI connect */ 68 | struct { 69 | wifi_event_connect_done_cb cb; 70 | void *arg; 71 | void (*disconn_handler)(void); 72 | uint8_t attempt; 73 | } conn; 74 | uint8_t is_connected; 75 | } wifi_event_ctx_t; 76 | 77 | static wifi_event_ctx_t event_ctx = { 78 | .ap = NULL, 79 | .is_connected = 0, 80 | .conn.disconn_handler = NULL, 81 | }; 82 | 83 | static void wifi_on_scan_done(wifi_event_sta_scan_done_t *event) 84 | { 85 | if (!event_ctx.cb || !event_ctx.ap) { 86 | event_ctx.number = 0; 87 | } else if (event->status == 1) { 88 | /* error */ 89 | event_ctx.number = 0; 90 | } else if (event->number == 0) { 91 | /* no ap found on current channel */ 92 | event_ctx.number = 0; 93 | } 94 | 95 | esp_wifi_scan_get_ap_records(&event_ctx.number, event_ctx.ap); 96 | esp_wifi_clear_ap_list(); 97 | 98 | int i; 99 | for (i = 0; i < event_ctx.number; ++i) { 100 | if (event_ctx.ap[i].rssi < -80) 101 | break; 102 | } 103 | 104 | event_ctx.number = i; 105 | return event_ctx.cb(event_ctx.number, event_ctx.ap); 106 | } 107 | 108 | 109 | int wifi_event_trigger_scan(uint8_t channel, wifi_event_scan_done_cb cb, uint16_t number, wifi_ap_record_t *aps) 110 | { 111 | int err; 112 | 113 | if (aps == NULL) { 114 | return 1; 115 | } 116 | 117 | wifi_scan_config_t config = { 118 | .bssid = NULL, 119 | .ssid = NULL, 120 | .show_hidden = 0, 121 | .scan_type = WIFI_SCAN_TYPE_ACTIVE, 122 | .scan_time.active.min = 10, 123 | .scan_time.active.max = 50, 124 | .channel = channel, 125 | .home_chan_dwell_time = 0, 126 | }; 127 | 128 | err = esp_wifi_scan_start(&config, 0); 129 | if (err) { 130 | ESP_LOGE(TAG, "%s", esp_err_to_name(err)); 131 | return err; 132 | } 133 | 134 | event_ctx.cb = cb; 135 | event_ctx.number = number; 136 | event_ctx.ap = aps; 137 | return 0; 138 | } 139 | 140 | /* 141 | * WIFI EVENT 142 | * */ 143 | 144 | static void reconnect_after_disco(); 145 | 146 | void wifi_event_handler(void *handler_arg __attribute__((unused)), 147 | esp_event_base_t event_base __attribute__((unused)), 148 | int32_t event_id, 149 | void *event_data) 150 | { 151 | switch (event_id) { 152 | case WIFI_EVENT_WIFI_READY: 153 | printf("event: WIFI_EVENT_WIFI_READY\n"); 154 | break; 155 | case WIFI_EVENT_SCAN_DONE: { 156 | wifi_event_sta_scan_done_t *event = event_data; 157 | // printf("event: WIFI_EVENT_SCAN_DONE: ok: %lu, nr: %u, seq: %u\n", 158 | // event->status, event->number, event->scan_id); 159 | wifi_on_scan_done(event); 160 | event_ctx.ap = NULL; 161 | event_ctx.cb = NULL; 162 | break; 163 | } 164 | case WIFI_EVENT_STA_START: 165 | printf("event: WIFI_EVENT_STA_START\n"); 166 | break; 167 | case WIFI_EVENT_STA_CONNECTED: { 168 | wifi_event_sta_connected_t *event = event_data; 169 | uint8_t *m = event->bssid; 170 | printf("event: WIFI_EVENT_STA_CONNECTED\n"); 171 | printf("connected to %02X:%02X:%02X:%02X:%02X:%02X\n", 172 | m[0], m[1], m[2], m[3], m[4], m[5]); 173 | #ifdef CONFIG_EXAMPLE_IPV6 174 | tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); 175 | #endif 176 | event_ctx.is_connected = 1; 177 | break; 178 | } 179 | case WIFI_EVENT_STA_DISCONNECTED: { 180 | wifi_event_sta_disconnected_t *event = event_data; 181 | uint8_t *m = event->bssid; 182 | printf("event: WIFI_EVENT_STA_DISCONNECTED "); 183 | printf("sta %02X:%02X:%02X:%02X:%02X:%02X disconnect reason %d\n", 184 | m[0], m[1], m[2], m[3], m[4], m[5], event->reason); 185 | event_ctx.is_connected = 0; 186 | reconnect_after_disco(); 187 | break; 188 | } 189 | case WIFI_EVENT_AP_START: 190 | printf("event: WIFI_EVENT_AP_START\n"); 191 | break; 192 | case WIFI_EVENT_AP_STACONNECTED: { 193 | wifi_event_ap_staconnected_t *event = event_data; 194 | uint8_t *m = event->mac; 195 | printf("event: WIFI_EVENT_AP_STACONNECTED\n"); 196 | printf("%02X:%02X:%02X:%02X:%02X:%02X is connected\n", 197 | m[0], m[1], m[2], m[3], m[4], m[5]); 198 | break; 199 | } 200 | case WIFI_EVENT_AP_STADISCONNECTED: { 201 | wifi_event_ap_staconnected_t *event = event_data; 202 | uint8_t *m = event->mac; 203 | printf("event: WIFI_EVENT_AP_STADISCONNECTED\n"); 204 | printf("%02X:%02X:%02X:%02X:%02X:%02X is disconnected\n", 205 | m[0], m[1], m[2], m[3], m[4], m[5]); 206 | break; 207 | } 208 | default: 209 | break; 210 | } 211 | } 212 | 213 | void wifi_event_set_disco_handler(void (*disconn_handler)(void)) 214 | { 215 | event_ctx.conn.disconn_handler = disconn_handler; 216 | } 217 | 218 | int wifi_event_trigger_connect(uint8_t attempt, wifi_event_connect_done_cb cb, void *arg) 219 | { 220 | int err; 221 | event_ctx.conn.attempt = attempt; 222 | event_ctx.conn.cb = cb; 223 | event_ctx.conn.arg = arg; 224 | if (event_ctx.is_connected) { 225 | err = esp_wifi_disconnect(); 226 | } else { 227 | err = esp_wifi_connect(); 228 | } 229 | return err; 230 | } 231 | 232 | void event_on_connected(ip_event_got_ip_t *event) 233 | { 234 | if (event_ctx.conn.cb) { 235 | event_ctx.conn.cb(event_ctx.conn.arg, event); 236 | } 237 | event_ctx.conn.attempt = 0; 238 | event_ctx.conn.cb = NULL; 239 | event_ctx.conn.arg = NULL; 240 | } 241 | 242 | void reconnect_after_disco() 243 | { 244 | int err; 245 | 246 | ESP_LOGI(TAG, "reco... atempt %d", event_ctx.conn.attempt); 247 | 248 | if (event_ctx.conn.attempt == 0) { 249 | goto call; 250 | } 251 | 252 | err = esp_wifi_connect(); 253 | if (err) { 254 | event_ctx.conn.attempt = 0; 255 | /* connect err: stop connect and call cb */ 256 | ESP_LOGE(TAG, "wifi connect error %s", esp_err_to_name(err)); 257 | goto call; 258 | } 259 | 260 | event_ctx.conn.attempt--; 261 | return; 262 | 263 | call: 264 | if (event_ctx.conn.cb) { 265 | event_ctx.conn.cb(event_ctx.conn.arg, NULL); 266 | } else { 267 | /* disconnected from extern environment, notify */ 268 | if (event_ctx.conn.disconn_handler) { 269 | event_ctx.conn.disconn_handler(); 270 | } 271 | } 272 | event_ctx.conn.cb = NULL; 273 | event_ctx.conn.arg = NULL; 274 | } 275 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_event_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_EVENT_HANDLER_H_GUARD 2 | #define WIFI_EVENT_HANDLER_H_GUARD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void ip_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data); 10 | 11 | void wifi_event_handler(void *handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data); 12 | 13 | 14 | typedef void (*wifi_event_scan_done_cb)(uint16_t ap_count, wifi_ap_record_t *aps_info); 15 | int wifi_event_trigger_scan(uint8_t channel, wifi_event_scan_done_cb cb, uint16_t number, wifi_ap_record_t *aps); 16 | void wifi_event_set_disco_handler(void (*disconn_handler)(void)); 17 | 18 | /** 19 | * @brief 20 | * @param connect_status 0: SUCCESS, OTHER: ERROR 21 | */ 22 | typedef void (*wifi_event_connect_done_cb)(void *arg, ip_event_got_ip_t *event); 23 | int wifi_event_trigger_connect(uint8_t attempt, wifi_event_connect_done_cb cb, void *arg); 24 | 25 | 26 | #endif //WIFI_EVENT_HANDLER_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_json_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wifi_json_utils.h" 4 | #include "wifi_api.h" 5 | 6 | static void wifi_api_json_set_header(cJSON *root, uint16_t cmd) 7 | { 8 | cJSON_AddNumberToObject(root, "cmd", cmd); 9 | cJSON_AddNumberToObject(root, "module", WIFI_MODULE_ID); 10 | } 11 | 12 | cJSON *wifi_api_json_serialize_ap_info(wifi_api_ap_info_t *ap_info, wifi_api_json_cmd_t cmd) 13 | { 14 | cJSON *root; 15 | 16 | root = cJSON_CreateObject(); 17 | 18 | wifi_api_json_set_header(root, cmd); 19 | cJSON_AddStringToObject(root, "ip", ip4addr_ntoa(&ap_info->ip)); 20 | cJSON_AddStringToObject(root, "gateway", ip4addr_ntoa(&ap_info->gateway)); 21 | cJSON_AddStringToObject(root, "netmask", ip4addr_ntoa(&ap_info->netmask)); 22 | cJSON_AddStringToObject(root, "dns_main", ip4addr_ntoa(&ap_info->dns_main)); 23 | cJSON_AddStringToObject(root, "dns_backup", ip4addr_ntoa(&ap_info->dns_backup)); 24 | cJSON_AddNumberToObject(root, "rssi", ap_info->rssi); 25 | cJSON_AddStringToObject(root, "ssid", ap_info->ssid); 26 | if (ap_info->password[0]) { 27 | cJSON_AddStringToObject(root, "password", ap_info->password); 28 | } 29 | 30 | char mac_str[18]; 31 | char *m = ap_info->mac; 32 | snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", 33 | m[0], m[1], m[2], m[3], m[4], m[5]); 34 | cJSON_AddStringToObject(root, "mac", mac_str); 35 | 36 | return root; 37 | } 38 | 39 | cJSON *wifi_api_json_serialize_scan_list(wifi_api_ap_scan_info_t *aps_info, uint16_t count) 40 | { 41 | cJSON *root; 42 | char mac_str[18]; 43 | 44 | root = cJSON_CreateObject(); 45 | wifi_api_json_set_header(root, WIFI_API_JSON_GET_SCAN); 46 | cJSON *scan_list = cJSON_AddArrayToObject(root, "scan_list"); 47 | 48 | for (int i = 0; i < count; ++i) { 49 | cJSON *ap = cJSON_CreateObject(); 50 | cJSON_AddNumberToObject(ap, "rssi", aps_info[i].rssi); 51 | cJSON_AddStringToObject(ap, "ssid", aps_info[i].ssid); 52 | char *m = aps_info[i].mac; 53 | snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", 54 | m[0], m[1], m[2], m[3], m[4], m[5]); 55 | cJSON_AddStringToObject(ap, "mac", mac_str); 56 | cJSON_AddItemToArray(scan_list, ap); 57 | } 58 | 59 | return root; 60 | } 61 | 62 | cJSON *wifi_api_json_serialize_ap_auto(wifi_apsta_mode_e mode, int ap_on_delay, int ap_off_delay) 63 | { 64 | cJSON *root; 65 | 66 | root = cJSON_CreateObject(); 67 | wifi_api_json_set_header(root, WIFI_API_JSON_GET_SCAN); 68 | cJSON_AddNumberToObject(root, "mode", mode); 69 | cJSON_AddNumberToObject(root, "ap_on_delay", ap_on_delay); 70 | cJSON_AddNumberToObject(root, "ap_off_delay", ap_off_delay); 71 | 72 | return root; 73 | } 74 | 75 | cJSON *wifi_api_json_create_err_rsp(cJSON *req, const char *msg) 76 | { 77 | cJSON *root; 78 | 79 | root = cJSON_Duplicate(req, 1); 80 | cJSON_AddStringToObject(root, "err", msg); 81 | 82 | return root; 83 | } 84 | 85 | int wifi_api_json_utils_get_int(cJSON *req, const char *name, int *out_value) 86 | { 87 | cJSON *item = cJSON_GetObjectItemCaseSensitive(req, name); 88 | 89 | if (!cJSON_IsNumber(item)) { 90 | return 1; 91 | } 92 | 93 | *out_value = item->valueint; 94 | return 0; 95 | } 96 | 97 | cJSON *wifi_api_json_serialize_get_mode(wifi_apsta_mode_e mode, int status, int ap_on_delay, int ap_off_delay) 98 | { 99 | cJSON *root; 100 | 101 | root = cJSON_CreateObject(); 102 | wifi_api_json_set_header(root, WIFI_API_JSON_GET_MODE); 103 | cJSON_AddNumberToObject(root, "mode", mode); 104 | cJSON_AddNumberToObject(root, "status", status); 105 | if (ap_on_delay >= 0 && ap_off_delay >= 0) { 106 | cJSON_AddNumberToObject(root, "ap_on_delay", ap_on_delay); 107 | cJSON_AddNumberToObject(root, "ap_off_delay", ap_off_delay); 108 | } 109 | 110 | return root; 111 | } 112 | 113 | cJSON *wifi_api_json_add_int_item(cJSON *root, const char *name, int item) 114 | { 115 | cJSON_AddNumberToObject(root, name, item); 116 | return root; 117 | } 118 | 119 | int wifi_api_json_get_credential(cJSON *root, char *ssid, char *password) 120 | { 121 | cJSON *json_ssid = cJSON_GetObjectItem(root, "ssid"); 122 | cJSON *json_password = cJSON_GetObjectItem(root, "password"); 123 | 124 | if (!cJSON_IsString(json_ssid) || !cJSON_IsString(json_password)) { 125 | return 1; 126 | } 127 | 128 | strncpy(ssid, cJSON_GetStringValue(json_ssid), 31); 129 | strncpy(password, cJSON_GetStringValue(json_password), 63); 130 | 131 | ssid[31] = '\0'; 132 | password[64] = '\0'; 133 | return 0; 134 | } 135 | 136 | cJSON *wifi_api_json_ser_static_info(wifi_api_sta_ap_static_info_t *info) 137 | { 138 | cJSON *root; 139 | 140 | root = cJSON_CreateObject(); 141 | wifi_api_json_set_header(root, WIFI_API_JSON_STA_GET_STATIC_INFO); 142 | cJSON_AddNumberToObject(root, "static_ip_en", info->static_ip_en); 143 | cJSON_AddNumberToObject(root, "static_dns_en", info->static_dns_en); 144 | 145 | cJSON_AddStringToObject(root, "ip", ip4addr_ntoa(&info->ip)); 146 | cJSON_AddStringToObject(root, "gateway", ip4addr_ntoa(&info->gateway)); 147 | cJSON_AddStringToObject(root, "netmask", ip4addr_ntoa(&info->netmask)); 148 | cJSON_AddStringToObject(root, "dns_main", ip4addr_ntoa(&info->dns_main)); 149 | cJSON_AddStringToObject(root, "dns_backup", ip4addr_ntoa(&info->dns_backup)); 150 | 151 | return root; 152 | } 153 | 154 | int wifi_api_json_deser_static_conf(cJSON *root, wifi_api_sta_ap_static_info_t *static_info) 155 | { 156 | cJSON *static_ip_en = cJSON_GetObjectItemCaseSensitive(root, "static_ip_en"); 157 | cJSON *static_dns_en = cJSON_GetObjectItemCaseSensitive(root, "static_dns_en"); 158 | 159 | if (!cJSON_IsNumber(static_ip_en) || !cJSON_IsNumber(static_dns_en)) { 160 | printf("en error\n"); 161 | return 1; 162 | } 163 | 164 | static_info->static_dns_en = static_dns_en->valueint; 165 | static_info->static_ip_en = static_ip_en->valueint; 166 | 167 | cJSON *ip = cJSON_GetObjectItemCaseSensitive(root, "ip"); 168 | cJSON *gateway = cJSON_GetObjectItemCaseSensitive(root, "gateway"); 169 | cJSON *netmask = cJSON_GetObjectItemCaseSensitive(root, "netmask"); 170 | cJSON *dns_main = cJSON_GetObjectItemCaseSensitive(root, "dns_main"); 171 | cJSON *dns_backup = cJSON_GetObjectItemCaseSensitive(root, "dns_backup"); 172 | 173 | if (cJSON_IsString(ip)) { 174 | ip4addr_aton(ip->valuestring, &static_info->ip); 175 | } 176 | if (cJSON_IsString(gateway)) { 177 | ip4addr_aton(gateway->valuestring, &static_info->gateway); 178 | } 179 | if (cJSON_IsString(netmask)) { 180 | ip4addr_aton(netmask->valuestring, &static_info->netmask); 181 | } 182 | if (cJSON_IsString(dns_main)) { 183 | ip4addr_aton(dns_main->valuestring, &static_info->dns_main); 184 | } 185 | if (cJSON_IsString(dns_backup)) { 186 | ip4addr_aton(dns_backup->valuestring, &static_info->dns_backup); 187 | } 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_json_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_JSON_UTILS_H_GUARD 2 | #define WIFI_JSON_UTILS_H_GUARD 3 | 4 | #include "wifi_api.h" 5 | 6 | cJSON *wifi_api_json_serialize_ap_info(wifi_api_ap_info_t *ap_info, wifi_api_json_cmd_t cmd); 7 | cJSON *wifi_api_json_serialize_scan_list(wifi_api_ap_scan_info_t *aps_info, uint16_t count); 8 | cJSON *wifi_api_json_serialize_ap_auto(wifi_apsta_mode_e mode, int ap_on_delay, int ap_off_delay); 9 | cJSON *wifi_api_json_serialize_get_mode(wifi_apsta_mode_e mode, int status, int ap_on_delay, int ap_off_delay); 10 | 11 | 12 | cJSON *wifi_api_json_create_err_rsp(cJSON *req, const char *msg); 13 | 14 | cJSON *wifi_api_json_add_int_item(cJSON *root, const char *name, int item); 15 | int wifi_api_json_utils_get_int(cJSON *req, const char *name, int *out_value); 16 | int wifi_api_json_get_credential(cJSON *root, char *ssid, char *password); 17 | cJSON *wifi_api_json_ser_static_info(wifi_api_sta_ap_static_info_t *info); 18 | int wifi_api_json_deser_static_conf(cJSON *root, wifi_api_sta_ap_static_info_t *static_info); 19 | 20 | 21 | #endif //WIFI_JSON_UTILS_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_MANAGER_H_GUARD 2 | #define WIFI_MANAGER_H_GUARD 3 | 4 | #include 5 | #include "wifi_api.h" 6 | #include "wifi_storage.h" 7 | 8 | void wifi_manager_init(); 9 | 10 | 11 | void *wifi_manager_get_ap_netif(); 12 | void *wifi_manager_get_sta_netif(); 13 | 14 | typedef void (*wifi_manager_scan_done_cb)(uint16_t ap_found, wifi_ap_record_t *record, void *arg); 15 | int wifi_manager_get_scan_list(uint16_t *number, wifi_ap_record_t *aps); 16 | int wifi_manager_connect(const char *ssid, const char *password); 17 | int wifi_manager_disconnect(void); 18 | int wifi_manager_change_mode(wifi_apsta_mode_e mode); 19 | int wifi_manager_get_mode(wifi_apsta_mode_e *mode, wifi_mode_t *status); 20 | int wifi_manager_get_ap_auto_delay(int *ap_on_delay, int *ap_off_delay); 21 | int wifi_manager_set_ap_auto_delay(int *ap_on_delay, int *ap_off_delay); 22 | int wifi_manager_set_ap_credential(wifi_credential_t *cred); 23 | int wifi_manager_sta_set_static_conf(wifi_api_sta_ap_static_info_t *static_info); 24 | 25 | 26 | #endif //WIFI_MANAGER_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_storage.c: -------------------------------------------------------------------------------- 1 | #include "wifi_storage.h" 2 | #include "wifi_storage_priv.h" 3 | #include "wt_nvs.h" 4 | #include "wifi_api.h" 5 | 6 | #include 7 | 8 | #define WIFI_NVS_NAMESPACE "wt_wifi" 9 | 10 | int wifi_data_get_sta_last_conn_cred(wifi_credential_t *ap_credential) 11 | { 12 | uint32_t ap_bitmap = 0; 13 | nvs_handle_t handle; 14 | int err; 15 | 16 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 17 | if (err) { 18 | return err; 19 | } 20 | 21 | err = wt_nvs_get(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap)); 22 | if (err) { 23 | goto end; 24 | } 25 | if (ap_bitmap == 0) { 26 | err = WT_NVS_ERR_NOT_FOUND; 27 | goto end; 28 | } 29 | 30 | err = wt_nvs_get(handle, KEY_WIFI_STA_LAST_AP_CRED, 31 | ap_credential, sizeof(wifi_credential_t)); 32 | if (err) { 33 | goto end; 34 | } 35 | 36 | end: 37 | wt_nvs_close(handle); 38 | return err; 39 | } 40 | 41 | /* 42 | * Called when connect to an AP, 43 | */ 44 | int wifi_data_save_sta_ap_credential(wifi_credential_t *ap_credential) 45 | { 46 | uint32_t ap_bitmap; 47 | int err; 48 | nvs_handle_t handle; 49 | 50 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 51 | if (err) { 52 | return err; 53 | } 54 | 55 | err = wt_nvs_get(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap)); 56 | if (err) { 57 | if (err != ESP_ERR_NVS_NOT_FOUND) { 58 | goto end; 59 | } 60 | ap_bitmap = 0; 61 | } 62 | if (ap_bitmap == 0) { 63 | ap_bitmap = 1; 64 | err = wt_nvs_set(handle, KEY_WIFI_STA_AP_BITMAP, &ap_bitmap, sizeof(ap_bitmap)); 65 | } 66 | 67 | 68 | wifi_credential_t credential; 69 | err = wt_nvs_get(handle, KEY_WIFI_STA_LAST_AP_CRED, &credential, sizeof(ap_bitmap)); 70 | if (err) { 71 | if (err != ESP_ERR_NVS_NOT_FOUND) { 72 | goto end; 73 | } 74 | } 75 | 76 | err = wt_nvs_set(handle, KEY_WIFI_STA_LAST_AP_CRED, ap_credential, sizeof(wifi_credential_t)); 77 | if (err) { 78 | goto end; 79 | } 80 | 81 | end: 82 | wt_nvs_close(handle); 83 | return err; 84 | } 85 | 86 | int wifi_data_save_wifi_mode(wifi_apsta_mode_e mode) 87 | { 88 | nvs_handle_t handle; 89 | int err; 90 | 91 | uint8_t mode_u8 = mode; 92 | 93 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 94 | if (err) { 95 | return err; 96 | } 97 | 98 | err = wt_nvs_set(handle, KEY_WIFI_APSTA_MODE, &mode_u8, sizeof(mode_u8)); 99 | 100 | wt_nvs_close(handle); 101 | return err; 102 | } 103 | 104 | int wifi_data_get_wifi_mode(wifi_apsta_mode_e *mode) 105 | { 106 | nvs_handle_t handle; 107 | int err; 108 | 109 | uint8_t mode_u8; 110 | 111 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 112 | if (err) { 113 | return err; 114 | } 115 | 116 | err = wt_nvs_get(handle, KEY_WIFI_APSTA_MODE, &mode_u8, sizeof(mode_u8)); 117 | 118 | *mode = mode_u8; 119 | wt_nvs_close(handle); 120 | return err; 121 | } 122 | 123 | int wifi_data_save_ap_credential(wifi_credential_t *ap_credential) 124 | { 125 | nvs_handle_t handle; 126 | int err; 127 | 128 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 129 | if (err) { 130 | return err; 131 | } 132 | 133 | err = wt_nvs_set(handle, KEY_WIFI_AP_CRED, ap_credential, sizeof(wifi_credential_t)); 134 | 135 | wt_nvs_close(handle); 136 | return err; 137 | } 138 | 139 | int wifi_data_get_ap_credential(wifi_credential_t *ap_credential) 140 | { 141 | nvs_handle_t handle; 142 | int err; 143 | 144 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 145 | if (err) { 146 | return err; 147 | } 148 | 149 | err = wt_nvs_get(handle, KEY_WIFI_AP_CRED, ap_credential, sizeof(wifi_credential_t)); 150 | 151 | wt_nvs_close(handle); 152 | return err; 153 | } 154 | 155 | int wifi_data_get_static(wifi_api_sta_ap_static_info_t *static_info) 156 | { 157 | nvs_handle_t handle; 158 | int err; 159 | 160 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 161 | if (err) { 162 | return err; 163 | } 164 | 165 | err = wt_nvs_get(handle, KEY_WIFI_STA_STATIC_BASE, 166 | static_info, sizeof(wifi_api_sta_ap_static_info_t)); 167 | if (err == ESP_ERR_NVS_NOT_FOUND) { 168 | static_info->static_ip_en = 0; 169 | static_info->static_dns_en = 0; 170 | err = ESP_OK; 171 | } else if (err) { 172 | printf("err %d\n", err); 173 | goto end; 174 | } 175 | 176 | if (static_info->static_ip_en > 1) { 177 | static_info->static_ip_en = 0; 178 | } 179 | if (static_info->static_dns_en > 1) { 180 | static_info->static_dns_en = 0; 181 | } 182 | 183 | end: 184 | wt_nvs_close(handle); 185 | return err; 186 | } 187 | 188 | int wifi_data_save_static(wifi_api_sta_ap_static_info_t *static_info) 189 | { 190 | nvs_handle_t handle; 191 | int err; 192 | 193 | err = wt_nvs_open(WIFI_NVS_NAMESPACE, &handle); 194 | if (err) { 195 | return err; 196 | } 197 | 198 | err = wt_nvs_set(handle, KEY_WIFI_STA_STATIC_BASE, 199 | static_info, sizeof(wifi_api_sta_ap_static_info_t)); 200 | if (err) { 201 | goto end; 202 | } 203 | 204 | printf("static info saved\n"); 205 | 206 | end: 207 | wt_nvs_close(handle); 208 | return err; 209 | } 210 | -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_storage.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_STORAGE_H_GUARD 2 | #define WIFI_STORAGE_H_GUARD 3 | 4 | #include 5 | #include "wifi_api.h" 6 | 7 | typedef struct nvs_wifi_credential_t { 8 | char ssid[32]; 9 | char password[64]; 10 | } wifi_credential_t; 11 | 12 | int wifi_data_get_sta_last_conn_cred(wifi_credential_t *ap_credential); 13 | 14 | int wifi_data_save_sta_ap_credential(wifi_credential_t *ap_credential); 15 | 16 | int wifi_data_save_wifi_mode(wifi_apsta_mode_e mode); 17 | 18 | int wifi_data_get_wifi_mode(wifi_apsta_mode_e *mode); 19 | 20 | int wifi_data_get_ap_credential(wifi_credential_t *ap_credential); 21 | 22 | int wifi_data_save_ap_credential(wifi_credential_t *ap_credential); 23 | 24 | int wifi_data_get_static(wifi_api_sta_ap_static_info_t *static_info); 25 | 26 | int wifi_data_save_static(wifi_api_sta_ap_static_info_t *static_info); 27 | 28 | 29 | #endif //WIFI_STORAGE_H_GUARD -------------------------------------------------------------------------------- /project_components/wifi_manager/wifi_storage_priv.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_STORAGE_PRIV_H_GUARD 2 | #define WIFI_STORAGE_PRIV_H_GUARD 3 | 4 | #define WIFI_MAX_AP_CRED_RECORD 1 5 | 6 | typedef struct w_cache_t { 7 | uint32_t ap_bitmap; 8 | wifi_credential_t ap_creds[WIFI_MAX_AP_CRED_RECORD]; 9 | } w_cache_t; 10 | 11 | typedef enum wt_wifi_key_enum { 12 | KEY_WIFI_RESERVED = 0x000, 13 | /* WIFI */ 14 | KEY_WIFI_AP_CRED = 0x1, 15 | 16 | 17 | /* TODO: should have 1 for each AP */ 18 | KEY_WIFI_STA_USE_STATIC = 0x03, /* bit[0:31]=[IP, MASK, GATEWAY, DNS_MAIN, DNS_BACK] */ 19 | 20 | /* STA information */ 21 | KEY_WIFI_STA_LAST_AP_CRED = 0x08, /*!< ssid[32] + password[64] */ 22 | KEY_WIFI_STA_AP_BITMAP = 0x09, /* 32 bit */ 23 | 24 | KEY_WIFI_STA_STATIC_BASE = 0x10, /* [IP:4B, MASK:4B, GW:4B, DNS1:4B, DNS2:4B] = 20B */ 25 | KEY_WIFI_STA_STATIC_LAST = 0x1F, /* [IP:4B, MASK:4B, GW:4B, DNS1:4B, DNS2:4B] */ 26 | 27 | KEY_WIFI_APSTA_MODE = 0xFF, /* 1B */ 28 | KEY_UNUSED_100 = 0x0100, /* avoid: same as 0x1 */ 29 | } wt_wifi_key; 30 | 31 | #endif //WIFI_STORAGE_PRIV_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c 2 | ) 3 | 4 | 5 | idf_component_register( 6 | SRCS ${SOURCES} 7 | INCLUDE_DIRS "." 8 | ) -------------------------------------------------------------------------------- /project_components/wt_common/wt_data_def.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef WT_DATA_DEF_H_GUARD 8 | #define WT_DATA_DEF_H_GUARD 9 | 10 | #include 11 | 12 | #define DECLARE_HANDLE(name) struct name##__ { int unused[0]; }; \ 13 | typedef struct name##__ *name 14 | 15 | typedef enum wt_data_type_t { 16 | WT_DATA_RESERVED = 0x00, 17 | /* primitive type */ 18 | WT_DATA_EVENT = 0x02, 19 | WT_DATA_ROUTE_HDR = 0x03, 20 | WT_DATA_RAW_BROADCAST = 0x04, 21 | 22 | /* data_type */ 23 | /* broadcast data */ 24 | WT_DATA_CMD_BROADCAST = 0x11, 25 | 26 | /* targeted data */ 27 | WT_DATA_RAW = 0x20, 28 | WT_DATA_CMD = 0x21, 29 | WT_DATA_RESPONSE = 0x22, 30 | 31 | /* standard protocols */ 32 | WT_DATA_PROTOBUF = 0x40, 33 | WT_DATA_JSON = 0x41, 34 | WT_DATA_MQTT = 0x42, 35 | } __attribute__((packed)) wt_data_type_t; 36 | _Static_assert(sizeof(wt_data_type_t) == 1, "wt_data_type_t must be 1 byte"); 37 | 38 | typedef struct wt_bin_data_hdr_t { 39 | wt_data_type_t data_type; /* type of the payload */ 40 | union { 41 | /* when targeted message -> bin data handle */ 42 | struct { 43 | uint8_t module_id; /* src when broadcast, else target module */ 44 | uint8_t sub_id; /* src when broadcast, else target sub_id */ 45 | }; 46 | /* not used, only for make the union == 3B */ 47 | struct { 48 | uint8_t dummy1; 49 | uint8_t dummy2; 50 | uint8_t dummy3; 51 | } dummy; 52 | }; 53 | } wt_bin_data_hdr_t; 54 | _Static_assert(sizeof(wt_bin_data_hdr_t) == 4, "wt_data_4B_hdr_t must be 4 byte"); 55 | 56 | typedef struct wt_bin_data_t { 57 | wt_bin_data_hdr_t hdr; 58 | uint8_t payload[0]; 59 | } wt_bin_data_t; 60 | 61 | typedef struct wt_bin_data_internal_t { 62 | struct { 63 | uint64_t Dummy1; 64 | uint64_t Dummy2; 65 | } ws_frame_slot; /* 16 byte padding for httpd_ws_frame */ 66 | struct { /* */ 67 | uint16_t data_len; 68 | uint8_t src_module; 69 | uint8_t src_sub_module; 70 | }; 71 | struct { /* */ 72 | uint8_t send_count; 73 | uint8_t reserved1; 74 | uint16_t reserved2; 75 | }; 76 | wt_bin_data_t data; 77 | } wt_bin_data_internal_t; 78 | 79 | typedef union wt_port_info { 80 | uint8_t name[32]; /* for ease identification */ 81 | struct { /* for socket */ 82 | uint32_t foreign_ip; 83 | uint16_t local_port; 84 | uint16_t foreign_port; 85 | }; 86 | struct { /* for peripheral port number */ 87 | uint8_t periph_num; 88 | }; 89 | } wt_port_info_t; 90 | 91 | #endif //WT_DATA_DEF_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_mdns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c) 2 | 3 | idf_component_register( 4 | SRCS ${SOURCES} 5 | INCLUDE_DIRS "." 6 | PRIV_REQUIRES mdns 7 | ) -------------------------------------------------------------------------------- /project_components/wt_mdns/wt_mdns_config.c: -------------------------------------------------------------------------------- 1 | #include "wt_mdns_config.h" 2 | 3 | #include 4 | #include 5 | 6 | #define MDNS_TAG "wt_mdns" 7 | 8 | void wt_mdns_init() 9 | { 10 | ESP_ERROR_CHECK(mdns_init()); 11 | 12 | /* TODO: read hostname from NVS */ 13 | ESP_ERROR_CHECK(mdns_hostname_set(MDSN_DEFAULT_HOSTNAME)); 14 | 15 | /* TODO: read instance description from NVS */ 16 | ESP_ERROR_CHECK(mdns_instance_name_set(MDSN_INSTANCE_DESC)); 17 | 18 | uint8_t mac[6]; 19 | esp_netif_get_mac(esp_netif_get_default_netif(), mac); 20 | 21 | char value[64]; 22 | snprintf(value, 63, "允斯调试器-%02X-%02X", mac[4], mac[5]); 23 | value[63] = '\0'; 24 | 25 | //structure with TXT records 26 | mdns_txt_item_t serviceTxtData[] = { 27 | {"name", value}, 28 | }; 29 | 30 | //initialize service 31 | ESP_ERROR_CHECK(mdns_service_add("WebServer", "_http", "_tcp", 80, 32 | serviceTxtData, sizeof(serviceTxtData)/sizeof(serviceTxtData[0]))); 33 | ESP_ERROR_CHECK(mdns_service_subtype_add_for_host("WebServer", "_http", "_tcp", NULL, "_server") ); 34 | } 35 | 36 | int wt_mdns_set_hostname(const char *hostname) 37 | { 38 | mdns_hostname_set(hostname); 39 | 40 | /* TODO save to NVS */ 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /project_components/wt_mdns/wt_mdns_config.h: -------------------------------------------------------------------------------- 1 | #ifndef WT_MDNS_CONFIG_H_GUARD 2 | #define WT_MDNS_CONFIG_H_GUARD 3 | 4 | #define MDSN_DEFAULT_HOSTNAME "dap" // + serial number (4 char) 5 | #define MDSN_INSTANCE_DESC "ESP32 无线透传" 6 | 7 | void wt_mdns_init(); 8 | 9 | int wt_mdns_set_hostname(const char* hostname); 10 | 11 | 12 | #endif //WT_MDNS_CONFIG_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_storage/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES wt_nvs.c wt_storage.c) 2 | 3 | idf_component_register( 4 | SRCS ${SOURCES} 5 | INCLUDE_DIRS "." 6 | PRIV_REQUIRES 7 | REQUIRES nvs_flash 8 | ) -------------------------------------------------------------------------------- /project_components/wt_storage/wt_nvs.c: -------------------------------------------------------------------------------- 1 | #include "wt_nvs.h" 2 | 3 | #include 4 | 5 | #define WT_PARTITION_NAME "wt_nvs" 6 | 7 | void wt_nvs_init() 8 | { 9 | // Initialize default NVS 10 | esp_err_t err = nvs_flash_init(); 11 | if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { 12 | // NVS partition was truncated and needs to be erased 13 | // Retry nvs_flash_init 14 | ESP_ERROR_CHECK(nvs_flash_erase()); 15 | err = nvs_flash_init(); 16 | } 17 | ESP_ERROR_CHECK(err); 18 | 19 | err = nvs_flash_init_partition(WT_PARTITION_NAME); 20 | if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { 21 | // NVS partition was truncated and needs to be erased 22 | // Retry nvs_flash_init 23 | ESP_ERROR_CHECK(nvs_flash_erase()); 24 | err = nvs_flash_init_partition(WT_PARTITION_NAME); 25 | } 26 | ESP_ERROR_CHECK(err); 27 | } 28 | 29 | int wt_nvs_open(const char* namespace, nvs_handle_t *out_handle) 30 | { 31 | return nvs_open_from_partition(WT_PARTITION_NAME, namespace, NVS_READWRITE, out_handle); 32 | } 33 | 34 | void wt_nvs_close(nvs_handle_t handle) 35 | { 36 | ESP_ERROR_CHECK(nvs_commit(handle)); 37 | nvs_close(handle); 38 | } 39 | 40 | int wt_nvs_get(nvs_handle_t handle, const uint32_t key, void *data, uint32_t data_size) 41 | { 42 | switch (data_size) { 43 | case 0: { 44 | uint8_t tmp; 45 | return nvs_get_u8(handle, (const char *) &key, &tmp); 46 | } 47 | case 1: 48 | return nvs_get_u8(handle, (const char *) &key, data); 49 | case 2: 50 | return nvs_get_u16(handle, (const char *) &key, data); 51 | case 4: 52 | return nvs_get_u32(handle, (const char *) &key, data); 53 | case 8: 54 | return nvs_get_u64(handle, (const char *) &key, data); 55 | default: 56 | return nvs_get_blob(handle, (const char *) &key, data, 57 | (size_t *) &data_size); 58 | } 59 | } 60 | 61 | int wt_nvs_set(nvs_handle_t handle, const uint32_t key, void *data, uint32_t data_size) 62 | { 63 | switch (data_size) { 64 | case 0: { 65 | uint8_t tmp = 0xFF; 66 | return nvs_set_u8(handle, (const char *) &key, tmp); 67 | } 68 | case 1: 69 | return nvs_set_u8(handle, (const char *) &key, *(uint8_t *)data); 70 | case 2: 71 | return nvs_set_u16(handle, (const char *) &key, *(uint16_t *)data); 72 | case 4: 73 | return nvs_set_u32(handle, (const char *) &key, *(uint32_t *)data); 74 | case 8: 75 | return nvs_set_u64(handle, (const char *) &key, *(uint64_t *)data); 76 | default: 77 | return nvs_set_blob(handle, (const char *) &key, data, data_size); 78 | } 79 | } 80 | 81 | int wt_nvs_get_once(const char* namespace, const uint32_t key, void *data, uint32_t data_size) 82 | { 83 | nvs_handle_t handle; 84 | int err; 85 | err = wt_nvs_open(namespace, &handle); 86 | if (err) { 87 | return err; 88 | } 89 | 90 | err = wt_nvs_get(handle, key, data, data_size); 91 | if (err) { 92 | return err; 93 | } 94 | 95 | wt_nvs_close(handle); 96 | return 0; 97 | } 98 | 99 | int wt_nvs_set_once(const char* namespace, const uint32_t key, void *data, uint32_t data_size) 100 | { 101 | nvs_handle_t handle; 102 | int err; 103 | err = wt_nvs_open(namespace, &handle); 104 | if (err) { 105 | return err; 106 | } 107 | 108 | err = wt_nvs_set(handle, key, data, data_size); 109 | if (err) { 110 | return err; 111 | } 112 | 113 | wt_nvs_close(handle); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /project_components/wt_storage/wt_nvs.h: -------------------------------------------------------------------------------- 1 | #ifndef WT_NVS_H_GUARD 2 | #define WT_NVS_H_GUARD 3 | 4 | #include 5 | #include 6 | 7 | typedef enum wt_nvs_error_enum { 8 | WT_NVS_OK = 0, 9 | WT_NVS_ERR, 10 | WT_NVS_NO_MEM, 11 | WT_NVS_ERR_NOT_FOUND, 12 | 13 | } wt_nvs_key_error; 14 | 15 | int wt_nvs_open(const char* namespace, nvs_handle_t *out_handle); 16 | 17 | void wt_nvs_close(nvs_handle_t handle); 18 | 19 | int wt_nvs_get(nvs_handle_t handle, uint32_t key, void *data, uint32_t data_size); 20 | 21 | int wt_nvs_set(nvs_handle_t handle, uint32_t key, void *data, uint32_t data_size); 22 | 23 | int wt_nvs_get_once(const char* namespace, const uint32_t key, void *data, uint32_t data_size); 24 | int wt_nvs_set_once(const char* namespace, const uint32_t key, void *data, uint32_t data_size); 25 | 26 | int wt_nvs_flush(nvs_handle_t handle); 27 | 28 | void wt_nvs_init(); 29 | 30 | #endif //WT_NVS_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_storage/wt_storage.c: -------------------------------------------------------------------------------- 1 | #include "wt_nvs.h" 2 | #include "wt_storage.h" 3 | 4 | void wt_storage_init() 5 | { 6 | wt_nvs_init(); 7 | } 8 | -------------------------------------------------------------------------------- /project_components/wt_storage/wt_storage.h: -------------------------------------------------------------------------------- 1 | #ifndef WT_STORAGE_H_GUARD 2 | #define WT_STORAGE_H_GUARD 3 | 4 | /** 5 | * @brief Init all storage, including ESP-NVS, SDIO... 6 | */ 7 | void wt_storage_init(); 8 | 9 | #endif //WT_STORAGE_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_system/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES *.c 2 | ) 3 | 4 | idf_component_register( 5 | SRCS ${SOURCES} 6 | INCLUDE_DIRS "." 7 | PRIV_REQUIRES 8 | global_resource esp_app_format api_router 9 | ) 10 | 11 | # Execute the Git command to get the formatted commit date 12 | execute_process( 13 | COMMAND git show -s --format=%cd --date=format:%Y-%m-%d 14 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 15 | OUTPUT_VARIABLE FM_DATE 16 | RESULT_VARIABLE result 17 | ERROR_VARIABLE git_error 18 | OUTPUT_STRIP_TRAILING_WHITESPACE 19 | ) 20 | 21 | if(NOT "${result}" STREQUAL "0") 22 | message(WARNING "Git command failed with: ${git_error}") 23 | endif() 24 | 25 | message(STATUS FM_DATE:${FM_DATE}) 26 | 27 | target_compile_definitions(${COMPONENT_LIB} PRIVATE FW_UPD_DATE="${FM_DATE}") 28 | idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE ON) 29 | -------------------------------------------------------------------------------- /project_components/wt_system/wt_system.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "wt_system.h" 8 | #include "wt_system_api.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define TAG "WT_SYS" 16 | 17 | void wt_system_get_fm_info(wt_fm_info_t *fm_info) 18 | { 19 | const esp_app_desc_t *app_desc = esp_app_get_description(); 20 | strcpy(fm_info->fm_ver, app_desc->version); 21 | memcpy(fm_info->upd_date, FW_UPD_DATE, sizeof(fm_info->upd_date) - 1); 22 | fm_info->upd_date[sizeof(fm_info->upd_date) - 1] = '\0'; 23 | } 24 | 25 | static void reboot_task(void *arg) 26 | { 27 | ESP_LOGW(TAG, "reboot in 2 seconds"); 28 | vTaskDelay(pdMS_TO_TICKS(2000)); 29 | esp_restart(); 30 | } 31 | 32 | void wt_system_reboot() 33 | { 34 | xTaskCreatePinnedToCore(reboot_task, "reboot", 4096, NULL, 3, NULL, 0); 35 | } 36 | 37 | static int wt_system_init(void) 38 | { 39 | return 0; 40 | } 41 | 42 | static const global_module_t module = { 43 | .init = wt_system_init, 44 | .module_id = SYSTEM_MODULE_ID 45 | }; 46 | 47 | GLOBAL_MODULE_REGISTER(WT_SYSTEM, &module); 48 | -------------------------------------------------------------------------------- /project_components/wt_system/wt_system.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef WT_SYSTEM_H_GUARD 8 | #define WT_SYSTEM_H_GUARD 9 | 10 | #include "global_module.h" 11 | 12 | typedef struct wt_fm_info_t { 13 | char fm_ver[32]; 14 | char upd_date[11]; 15 | } wt_fm_info_t; 16 | 17 | void wt_system_get_fm_info(wt_fm_info_t *fm_info); 18 | 19 | /** 20 | * Trigger delayed reboot in 2 seconds 21 | */ 22 | void wt_system_reboot(); 23 | 24 | 25 | #endif //WT_SYSTEM_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_system/wt_system_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef WT_SYSTEM_API_H_GUARD 8 | #define WT_SYSTEM_API_H_GUARD 9 | 10 | #define SYSTEM_MODULE_ID 0 11 | 12 | typedef enum wt_system_cmd_t { 13 | WT_SYS_GET_FM_INFO = 1, 14 | WT_SYS_REBOOT = 2, 15 | 16 | WT_SYS_DO_CRASH = 200, 17 | } wt_system_cmd_t; 18 | 19 | 20 | #endif //WT_SYSTEM_API_H_GUARD -------------------------------------------------------------------------------- /project_components/wt_system/wt_system_api_json.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | #include "wt_system_api.h" 7 | #include "wt_system.h" 8 | #include "api_json_module.h" 9 | #include "wt_system_json_utils.h" 10 | 11 | 12 | static int sys_api_json_get_fm_info(api_json_req_t *req) 13 | { 14 | wt_fm_info_t info; 15 | wt_system_get_fm_info(&info); 16 | req->out = wt_sys_json_ser_fm_info(&info); 17 | return API_JSON_OK; 18 | } 19 | 20 | static int on_json_req(uint16_t cmd, api_json_req_t *req, api_json_module_async_t *async) 21 | { 22 | wt_system_cmd_t ota_cmd = cmd; 23 | switch (ota_cmd) { 24 | default: 25 | break; 26 | case WT_SYS_GET_FM_INFO: 27 | return sys_api_json_get_fm_info(req); 28 | case WT_SYS_REBOOT: 29 | wt_system_reboot(); 30 | return API_JSON_OK; 31 | case WT_SYS_DO_CRASH: { 32 | int *ptr = NULL; 33 | *ptr = 66; 34 | break; 35 | } 36 | } 37 | return API_JSON_UNSUPPORTED_CMD; 38 | } 39 | 40 | 41 | /* **** 42 | * register module 43 | * */ 44 | 45 | static int wt_sys_json_init(api_json_module_cfg_t *cfg) 46 | { 47 | cfg->on_req = on_json_req; 48 | cfg->module_id = SYSTEM_MODULE_ID; 49 | return 0; 50 | } 51 | 52 | API_JSON_MODULE_REGISTER(wt_sys_json_init) 53 | -------------------------------------------------------------------------------- /project_components/wt_system/wt_system_json_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include "wt_system_json_utils.h" 8 | 9 | static void wt_sys_json_add_header(cJSON *root, wt_system_cmd_t cmd) 10 | { 11 | cJSON_AddNumberToObject(root, "cmd", cmd); 12 | cJSON_AddNumberToObject(root, "module", SYSTEM_MODULE_ID); 13 | } 14 | 15 | cJSON *wt_sys_json_ser_fm_info(wt_fm_info_t *info) 16 | { 17 | cJSON *root = cJSON_CreateObject(); 18 | wt_sys_json_add_header(root, WT_SYS_GET_FM_INFO); 19 | cJSON_AddStringToObject(root, "fm_ver", info->fm_ver); 20 | cJSON_AddStringToObject(root, "upd_date", info->upd_date); 21 | return root; 22 | } 23 | -------------------------------------------------------------------------------- /project_components/wt_system/wt_system_json_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2024 kerms 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef WT_SYSTEM_JSON_UTILS_H_GUARD 8 | #define WT_SYSTEM_JSON_UTILS_H_GUARD 9 | 10 | #include "wt_system_api.h" 11 | #include "wt_system.h" 12 | #include 13 | 14 | 15 | cJSON *wt_sys_json_ser_fm_info(wt_fm_info_t *info); 16 | 17 | #endif //WT_SYSTEM_JSON_UTILS_H_GUARD -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # This file is currently only used to trigger the build system's configuration import for different hardware targets 2 | --------------------------------------------------------------------------------