├── .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 | 
55 |
56 |
57 | There is built-in ipv4 only mDNS server. You can access the device using `dap.local`.
58 |
59 | 
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 | 
214 |
215 |
216 | Here, we use MDK for testing:
217 |
218 | 
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 | 
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 | 
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 | 
188 |
189 | 下面我们用keil MDK来测试:
190 |
191 | 
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 | 
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 |
--------------------------------------------------------------------------------