0
0
Fork 0

revert(uart bridge) reverted temporally, will be completely rewritten in the next release

This commit is contained in:
kerms 2024-04-21 15:10:48 +08:00
parent 1eef5dcecf
commit 65ce47a62d
6 changed files with 376 additions and 4 deletions

View File

@ -29,6 +29,8 @@ For Keil users, we now also support [elaphureLink](https://github.com/windowsair
- [x] USB-HID
- [x] WCID & WinUSB (Default)
4. Debug Trace (Uart)
- [x] Uart TCP Bridge
5. More..
- [x] SWD protocol based on SPI acceleration (Up to 40MHz)
@ -257,6 +259,27 @@ Note that if you want to use a 40MHz SPI acceleration, you need to specify the s
> Keil's timing handling is somewhat different from OpenOCD's. For example, OpenOCD lacks the SWD line reset sequence before reading the `IDCODE` registers.
### Uart TCP Bridge
TCP server on PORT 1234.
UART default baud: 74880
This feature provides a bridge between TCP and Uart:
```
Send data -> TCP -> Uart TX -> external devices
Recv data <- TCP <- Uart Rx <- external devices
```
![uart_tcp_bridge](https://user-images.githubusercontent.com/17078589/150290065-05173965-8849-4452-ab7e-ec7649f46620.jpg)
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.
For example, sending the ASCII text `115200` will switch the baud rate to 115200.
------
## Credit

View File

@ -121,7 +121,7 @@
| TVCC | 3V3 |
| GND | GND |
</details>
----
@ -158,12 +158,10 @@ idf.py -p /dev/ttyS5 flash
> 位于项目根目录的`idf.py`脚本仅适用于较老的ESP8266设备请不要在ESP32设备上使用。
</details>
> 我们还提供了预编译固件用于快速评估。详见 [Releases](https://github.com/windowsair/wireless-esp8266-dap/releases)
</details>
## 使用
@ -242,6 +240,27 @@ idf.py -p /dev/ttyS5 flash
> Keil的操作时序与OpenOCD的有些不同。例如OpenOCD在读取 "IDCODE "寄存器之前缺少SWD线复位序列。
### TCP转发的串口
TCP端口1234
默认UART波特率74880
该功能在TCP和Uart之间提供了一个桥梁
```
发送数据 -> TCP -> Uart TX -> 外部设备
接收数据 <- TCP <- Uart Rx <- 外部设备
```
![uart_tcp_bridge](https://user-images.githubusercontent.com/17078589/150290065-05173965-8849-4452-ab7e-ec7649f46620.jpg)
当TCP连接建立后ESP芯片将尝试解决首次发送的文本。当文本是一个有效的波特率时转发器就会切换到该波特率。例如发送ASCII文本`115200`会将波特率切换为115200。
由于性能原因,该功能默认不启用。你可以修改 [wifi_configuration.h](main/wifi_configuration.h) 来打开它。
-----
# 致谢
归功于以下项目、人员和组织。

View File

@ -0,0 +1,8 @@
file(GLOB SOURCES *.c)
idf_component_register(
SRCS ${SOURCES}
INCLUDE_DIRS "."
PRIV_REQUIRES driver
)

View File

@ -0,0 +1,307 @@
/*
Copyright (c) 2015, SuperHouse Automation Pty Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file uart_bridge.c
* @author windowsair
* @brief UART TCP bridge
* @version 0.1
* @date 2021-11-16
*
* @copyright Copyright (c) 2021
*
*/
#include <string.h>
#include <stdint.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "lwip/err.h"
#include "lwip/netbuf.h"
#include "lwip/api.h"
#include "lwip/tcp.h"
#include "uart_tcp_bridge.h"
#ifdef CONFIG_IDF_TARGET_ESP8266
#define UART_BRIDGE_TX UART_NUM_0
#define UART_BRIDGE_RX UART_NUM_1
#elif defined CONFIG_IDF_TARGET_ESP32
#define UART_BRIDGE_TX UART_NUM_2
#define UART_BRIDGE_RX UART_NUM_2
#define UART_BRIDGE_TX_PIN 23
#define UART_BRIDGE_RX_PIN 22
#elif defined CONFIG_IDF_TARGET_ESP32C3
#define UART_BRIDGE_TX UART_NUM_1
#define UART_BRIDGE_RX UART_NUM_1
#define UART_BRIDGE_TX_PIN 19
#define UART_BRIDGE_RX_PIN 18 // PIN18 has 50000ns glitch during the power-up
#elif defined CONFIG_IDF_TARGET_ESP32S3
#define UART_BRIDGE_TX UART_NUM_1
#define UART_BRIDGE_RX UART_NUM_1
#define UART_BRIDGE_TX_PIN 17
#define UART_BRIDGE_RX_PIN 18
#else
#error unknown hardware
#endif
#define EVENTS_QUEUE_SIZE 10
#define UART_BUF_SIZE 512
#ifdef CALLBACK_DEBUG
#define debug(s, ...) printf("%s: " s "\n", "Cb:", ##__VA_ARGS__)
#else
#define debug(s, ...)
#endif
static const char *UART_TAG = "UART";
#define NETCONN_EVT_WIFI_DISCONNECTED (NETCONN_EVT_ERROR + 1)
static QueueHandle_t uart_server_events = NULL;
typedef struct
{
struct netconn *nc;
uint8_t type;
} netconn_events;
static uint8_t uart_read_buffer[UART_BUF_SIZE];
// use lwip buffer to write back
static struct netconn *uart_netconn = NULL;
static bool is_conn_valid = false; // lock free
static bool is_first_time_recv = false;
void uart_bridge_close() {
netconn_events events;
events.type = NETCONN_EVT_WIFI_DISCONNECTED;
xQueueSend(uart_server_events, &events, 1000);
}
static void uart_bridge_reset() {
uart_netconn = NULL;
is_conn_valid = false;
}
static int num_digits(int n) {
if (n < 10)
return 1;
if (n < 100)
return 2;
if (n < 1000)
return 3;
if (n < 10000)
return 4;
if (n < 100000)
return 5;
if (n < 1000000)
return 6;
return 7;
}
/*
* This function will be call in Lwip in each event on netconn
*/
static void netCallback(struct netconn *conn, enum netconn_evt evt, uint16_t length) {
// Show some callback information (debug)
debug("sock:%lu\tsta:%u\tevt:%u\tlen:%u\ttyp:%u\tfla:%02x\terr:%d",
(uint32_t)conn, conn->state, evt, length, conn->type, conn->flags, conn->pending_err);
netconn_events events;
// If netconn got error, it is close or deleted, dont do treatments on it.
if (conn->pending_err) {
return;
}
// Treatments only on rcv events.
switch (evt) {
case NETCONN_EVT_RCVPLUS:
events.nc = conn;
events.type = evt;
break;
default:
return;
break;
}
// Send the event to the queue
xQueueSend(uart_server_events, &events, pdMS_TO_TICKS(1000));
}
/*
* Initialize a server netconn and listen port
*/
static void set_tcp_server_netconn(struct netconn **nc, uint16_t port, netconn_callback callback) {
if (nc == NULL) {
ESP_LOGE(UART_TAG, "%s: netconn missing .\n", __FUNCTION__);
return;
}
*nc = netconn_new_with_callback(NETCONN_TCP, netCallback);
if (!*nc) {
ESP_LOGE(UART_TAG, "Status monitor: Failed to allocate netconn.\n");
return;
}
netconn_set_nonblocking(*nc, NETCONN_FLAG_NON_BLOCKING);
// netconn_set_recvtimeout(*nc, 10);
netconn_bind(*nc, IP_ADDR_ANY, port);
netconn_listen(*nc);
}
/*
* Close and delete a socket properly
*/
static void close_tcp_netconn(struct netconn *nc) {
nc->pending_err = ERR_CLSD; // It is hacky way to be sure than callback will don't do treatment on a netconn closed and deleted
netconn_close(nc);
netconn_delete(nc);
}
static void uart_bridge_setup() {
uart_config_t uart_config = {
.baud_rate = UART_BRIDGE_BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE};
if (UART_BRIDGE_TX == UART_BRIDGE_RX) {
ESP_ERROR_CHECK(uart_param_config(UART_BRIDGE_RX, &uart_config));
ESP_ERROR_CHECK(uart_driver_install(UART_BRIDGE_RX, UART_BUF_SIZE, UART_BUF_SIZE, 0, NULL, 0));
} else {
uart_param_config(UART_BRIDGE_RX, &uart_config);
uart_param_config(UART_BRIDGE_TX, &uart_config);
uart_driver_install(UART_BRIDGE_RX, UART_BUF_SIZE, 0, 0, NULL, 0); // RX only
uart_driver_install(UART_BRIDGE_TX, 0, UART_BUF_SIZE, 0, NULL, 0); // TX only
}
#if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3
ESP_ERROR_CHECK(uart_set_pin(UART_BRIDGE_TX, UART_BRIDGE_TX_PIN, UART_BRIDGE_RX_PIN, -1, -1));
#endif
}
void uart_bridge_init() {
uart_server_events = xQueueCreate(EVENTS_QUEUE_SIZE, sizeof(netconn_events));
}
void uart_bridge_task() {
uart_bridge_setup();
uart_server_events = xQueueCreate(EVENTS_QUEUE_SIZE, sizeof(netconn_events));
struct netconn *nc = NULL; // To create servers
set_tcp_server_netconn(&nc, UART_BRIDGE_PORT, netCallback);
struct netbuf *netbuf = NULL; // To store incoming Data
struct netconn *nc_in = NULL; // To accept incoming netconn
//
char *buffer;
uint16_t len_buf;
size_t uart_buf_len;
while (1) {
netconn_events events;
int ret = xQueueReceive(uart_server_events, &events, pdMS_TO_TICKS(100));
if (ret != pdTRUE) {
// timeout
if (is_conn_valid) {
ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_BRIDGE_RX, &uart_buf_len));
uart_buf_len = uart_buf_len > UART_BUF_SIZE ? UART_BUF_SIZE : uart_buf_len;
uart_buf_len = uart_read_bytes(UART_BRIDGE_RX, uart_read_buffer, uart_buf_len, pdMS_TO_TICKS(5));
// then send data
netconn_write(uart_netconn, uart_read_buffer, uart_buf_len, NETCONN_COPY);
}
} else if (events.type == NETCONN_EVT_WIFI_DISCONNECTED) { // WIFI disconnected
if (is_conn_valid) {
close_tcp_netconn(uart_netconn);
uart_bridge_reset();
}
} else if (events.nc->state == NETCONN_LISTEN) {
if (is_conn_valid) {
netconn_accept(events.nc, &nc_in);
if (nc_in)
close_tcp_netconn(nc_in);
continue;
}
int err = netconn_accept(events.nc, &nc_in);
if (err != ERR_OK) {
if (nc_in)
netconn_delete(nc_in);
continue;
}
printf("uart bridge accepted\n");
ip_addr_t client_addr; // Address port
uint16_t client_port; // Client port
netconn_peer(nc_in, &client_addr, &client_port);
uart_netconn = nc_in;
is_conn_valid = true;
is_first_time_recv = true;
} else if (events.nc->state != NETCONN_LISTEN) {
// if (events.nc && events.nc->pcb.tcp)
// tcp_nagle_disable(events.nc->pcb.tcp);
uart_netconn = events.nc;
// read data from UART
ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_BRIDGE_RX, &uart_buf_len));
uart_buf_len = uart_buf_len > UART_BUF_SIZE ? UART_BUF_SIZE : uart_buf_len;
uart_buf_len = uart_read_bytes(UART_BRIDGE_RX, uart_read_buffer, uart_buf_len, pdMS_TO_TICKS(5));
// then send data
netconn_write(events.nc, uart_read_buffer, uart_buf_len, NETCONN_COPY);
// try to get data
if ((netconn_recv(events.nc, &netbuf)) == ERR_OK) // data incoming ?
{
do {
netbuf_data(netbuf, (void *)&buffer, &len_buf);
// write to uart
if (is_first_time_recv) { // change bard rate
if (len_buf > 1 && len_buf < 8) {
char tmp_buff[8];
memcpy(tmp_buff, buffer, len_buf);
tmp_buff[len_buf] = '\0';
int baudrate = atoi(tmp_buff);
if (baudrate > 0 && baudrate < 2000000 && num_digits(baudrate) == len_buf) {
ESP_LOGI(UART_TAG, "change baud:%d", baudrate);
uart_set_baudrate(UART_BRIDGE_RX, baudrate);
uart_set_baudrate(UART_BRIDGE_TX, baudrate);
is_first_time_recv = false;
continue;
}
}
is_first_time_recv = false;
}
uart_write_bytes(UART_BRIDGE_TX, (const char *)buffer, len_buf);
} while (netbuf_next(netbuf) >= 0);
netbuf_delete(netbuf);
} else {
if (events.nc->pending_err == ERR_CLSD) {
continue; // The same hacky way to treat a closed connection
}
close_tcp_netconn(events.nc);
uart_bridge_reset();
}
}
}
}

View File

@ -0,0 +1,12 @@
#ifndef _UART_BRIDGE_H_
#define _UART_BRIDGE_H_
#define UART_BRIDGE_PORT 1234
#define UART_BRIDGE_BAUDRATE 74880
void uart_bridge_init();
void uart_bridge_task();
void uart_bridge_close();
#endif

View File

@ -12,6 +12,7 @@
#include "web_server.h"
#include "static_buffer.h"
#include "request_runner.h"
#include "uart_tcp_bridge.h"
#include <assert.h>
@ -33,4 +34,6 @@ void app_main()
// DAP handle task
xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 10, NULL);
xTaskCreate(uart_bridge_task, "uart_server", 4096, NULL, 2, NULL);
}