0
0
Fork 0

feat(uart): Add uart tcp bridge feature

This commit is contained in:
windowsair 2022-01-18 16:48:04 +08:00
parent 7b90b1fe0b
commit eee981dd0f
7 changed files with 287 additions and 36 deletions

View File

@ -297,7 +297,7 @@ We will continue to try to make it work on USB HID. Once the USBIP problem is so
------ ------
# Credit ## Credit
Credits to the following project, people and organizations: Credits to the following project, people and organizations:

View File

@ -46,6 +46,7 @@
#include <string.h> #include <string.h>
#include "main/dap_configuration.h" #include "main/dap_configuration.h"
#include "main/wifi_configuration.h"
#include "main/timer.h" #include "main/timer.h"
#include "components/DAP/include/cmsis_compiler.h" #include "components/DAP/include/cmsis_compiler.h"
@ -617,6 +618,7 @@ It is recommended to provide the following LEDs for status indication:
*/ */
__STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit) __STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit)
{ {
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
if (bit) if (bit)
{ {
//set bit //set bit
@ -627,6 +629,7 @@ __STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit)
//reset bit //reset bit
GPIO.out_w1tc |= (0x1 << PIN_LED_CONNECTED); GPIO.out_w1tc |= (0x1 << PIN_LED_CONNECTED);
} }
#endif
} }
/** /**
@ -700,13 +703,16 @@ __STATIC_INLINE void DAP_SETUP(void)
GPIO_FUNCTION_SET(PIN_TDI); GPIO_FUNCTION_SET(PIN_TDI);
GPIO_FUNCTION_SET(PIN_nTRST); GPIO_FUNCTION_SET(PIN_nTRST);
GPIO_FUNCTION_SET(PIN_nRESET); GPIO_FUNCTION_SET(PIN_nRESET);
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
GPIO_FUNCTION_SET(PIN_LED_CONNECTED); GPIO_FUNCTION_SET(PIN_LED_CONNECTED);
#endif
GPIO_FUNCTION_SET(PIN_LED_RUNNING); GPIO_FUNCTION_SET(PIN_LED_RUNNING);
// Configure: LED as output (turned off) // Configure: LED as output (turned off)
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_CONNECTED); GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_CONNECTED);
#endif
GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_RUNNING); GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_RUNNING);
LED_CONNECTED_OUT(0); LED_CONNECTED_OUT(0);

View File

@ -41,8 +41,6 @@ extern void SWO_Thread();
TaskHandle_t kDAPTaskHandle = NULL; TaskHandle_t kDAPTaskHandle = NULL;
/* FreeRTOS event group to signal when we are connected & ready to make a request */ /* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group; static EventGroupHandle_t wifi_event_group;
@ -51,14 +49,11 @@ const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1; const int IPV6_GOTIP_BIT = BIT1;
#endif #endif
static esp_err_t event_handler(void *ctx, system_event_t *event) {
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
/* For accessing reason codes in case of disconnection */ /* For accessing reason codes in case of disconnection */
system_event_info_t *info = &event->event_info; system_event_info_t *info = &event->event_info;
switch (event->event_id) switch (event->event_id) {
{
case SYSTEM_EVENT_STA_START: case SYSTEM_EVENT_STA_START:
esp_wifi_connect(); esp_wifi_connect();
os_printf("SYSTEM_EVENT_STA_START\r\n"); os_printf("SYSTEM_EVENT_STA_START\r\n");
@ -75,8 +70,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
break; break;
case SYSTEM_EVENT_STA_DISCONNECTED: case SYSTEM_EVENT_STA_DISCONNECTED:
os_printf("Disconnect reason : %d\r\n", info->disconnected.reason); os_printf("Disconnect reason : %d\r\n", info->disconnected.reason);
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
{
/*Switch to 802.11 bgn mode */ /*Switch to 802.11 bgn mode */
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
} }
@ -85,6 +79,10 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
#ifdef CONFIG_EXAMPLE_IPV6 #ifdef CONFIG_EXAMPLE_IPV6
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT); xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
#endif #endif
#if (USE_UART_BRIDGE == 1)
uart_bridge_close();
#endif
break; break;
case SYSTEM_EVENT_AP_STA_GOT_IP6: case SYSTEM_EVENT_AP_STA_GOT_IP6:
#ifdef CONFIG_EXAMPLE_IPV6 #ifdef CONFIG_EXAMPLE_IPV6
@ -100,8 +98,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
return ESP_OK; return ESP_OK;
} }
static void initialise_wifi(void) static void initialise_wifi(void) {
{
tcpip_adapter_init(); tcpip_adapter_init();
#if (USE_STATIC_IP == 1) #if (USE_STATIC_IP == 1)
@ -118,7 +115,6 @@ static void initialise_wifi(void)
tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info); tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
#endif // (USE_STATIC_IP == 1) #endif // (USE_STATIC_IP == 1)
wifi_event_group = xEventGroupCreate(); wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
@ -138,8 +134,7 @@ static void initialise_wifi(void)
ESP_ERROR_CHECK(esp_wifi_start()); ESP_ERROR_CHECK(esp_wifi_start());
} }
static void wait_for_ip() static void wait_for_ip() {
{
#ifdef CONFIG_EXAMPLE_IPV6 #ifdef CONFIG_EXAMPLE_IPV6
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT; uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT;
#else #else
@ -151,7 +146,6 @@ static void wait_for_ip()
os_printf("Connected to AP\r\n"); os_printf("Connected to AP\r\n");
} }
static const char *MDNS_TAG = "server_common"; static const char *MDNS_TAG = "server_common";
void mdns_setup() { void mdns_setup() {
@ -180,9 +174,7 @@ void mdns_setup() {
ESP_LOGI(MDNS_TAG, "mDNS instance name set to: [%s]", MDNS_INSTANCE); ESP_LOGI(MDNS_TAG, "mDNS instance name set to: [%s]", MDNS_INSTANCE);
} }
void app_main() {
void app_main()
{
// struct rst_info *rtc_info = system_get_rst_info(); // struct rst_info *rtc_info = system_get_rst_info();
// os_printf("reset reason: %x\n", rtc_info->reason); // os_printf("reset reason: %x\n", rtc_info->reason);
@ -201,6 +193,11 @@ void app_main()
// } // }
ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(nvs_flash_init());
#if (USE_UART_BRIDGE == 1)
uart_bridge_init();
#endif
initialise_wifi(); initialise_wifi();
wait_for_ip(); wait_for_ip();
DAP_Setup(); DAP_Setup();
@ -238,11 +235,6 @@ void app_main()
xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 10, &kDAPTaskHandle); xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 10, &kDAPTaskHandle);
#if (USE_UART_BRIDGE == 1) #if (USE_UART_BRIDGE == 1)
xTaskCreate(uart_bridge_task, "uart_server", 1024, NULL, 9, NULL); xTaskCreate(uart_bridge_task, "uart_server", 1024, NULL, 2, NULL);
#endif #endif
// SWO Trace Task
#if (SWO_FUNCTION_ENABLE == 1)
xTaskCreate(SWO_Thread, "SWO_Task", 512, NULL, 10, NULL);
#endif
// It seems that the task is overly stressful...
} }

View File

@ -162,7 +162,7 @@ void tcp_netconn_task()
ip_addr_t client_addr; // Address port ip_addr_t client_addr; // Address port
uint16_t client_port; // Client port uint16_t client_port; // Client port
netconn_peer(nc_in, &client_addr, &client_port); netconn_peer(nc_in, &client_addr, &client_port);
// tcp_nagle_disable(events.nc->pcb.tcp); // tcp_nagle_disable(events.nc->pcb.tcp); // crash! DO NOT USE
} }
else if (events.nc->state != NETCONN_LISTEN) // If netconn is the client and receive data else if (events.nc->state != NETCONN_LISTEN) // If netconn is the client and receive data
{ {

View File

@ -0,0 +1,250 @@
/*
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 <stdatomic.h>
#include "main/wifi_configuration.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netbuf.h"
#include "lwip/api.h"
#include "lwip/tcp.h"
#include <lwip/netdb.h>
#if (USE_UART_BRIDGE == 1)
#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
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;
}
/*
* 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:%u\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};
uart_param_config(UART_NUM_0, &uart_config);
uart_param_config(UART_NUM_1, &uart_config);
uart_driver_install(UART_NUM_0, UART_BUF_SIZE, 0, 0, NULL, 0); // RX only
uart_driver_install(UART_NUM_1, 0, UART_BUF_SIZE, 0, NULL, 0); // TX only
}
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_NUM_0, &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_NUM_0, 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;
}
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;
} 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_NUM_0, &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_NUM_0, 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
uart_write_bytes(UART_NUM_1, (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();
}
}
}
}
#endif // (USE_UART_BRIDGE == 1)

View File

@ -1,6 +1,10 @@
#ifndef _UART_BRIDGE_H_ #ifndef _UART_BRIDGE_H_
#define _UART_BRIDGE_H_ #define _UART_BRIDGE_H_
void uart_bridge_init();
void uart_bridge_task(); void uart_bridge_task();
void uart_bridge_close();
#endif #endif

View File

@ -13,7 +13,6 @@
#define WIFI_SSID "DAP" #define WIFI_SSID "DAP"
#define WIFI_PASS "12345678" #define WIFI_PASS "12345678"
#define USE_MDNS 1 #define USE_MDNS 1
// Use the address "dap.local" to access the device // Use the address "dap.local" to access the device
#define MDNS_HOSTNAME "dap" #define MDNS_HOSTNAME "dap"
@ -29,9 +28,9 @@
#define USE_OTA 1 #define USE_OTA 1
#define USE_UART_BRIDGE 1
#define USE_UART_BRIDGE 0
#define UART_BRIDGE_PORT 1234 #define UART_BRIDGE_PORT 1234
#define UART_BRIDGE_BAUDRATE 74880
// //
#define USE_TCP_NETCONN 0 #define USE_TCP_NETCONN 0