feat(uart): Add uart tcp bridge feature
This commit is contained in:
parent
7b90b1fe0b
commit
eee981dd0f
|
@ -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:
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "main/dap_configuration.h"
|
||||
#include "main/wifi_configuration.h"
|
||||
#include "main/timer.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)
|
||||
{
|
||||
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
|
||||
if (bit)
|
||||
{
|
||||
//set bit
|
||||
|
@ -627,6 +629,7 @@ __STATIC_INLINE void LED_CONNECTED_OUT(uint32_t bit)
|
|||
//reset bit
|
||||
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_nTRST);
|
||||
GPIO_FUNCTION_SET(PIN_nRESET);
|
||||
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
|
||||
GPIO_FUNCTION_SET(PIN_LED_CONNECTED);
|
||||
#endif
|
||||
GPIO_FUNCTION_SET(PIN_LED_RUNNING);
|
||||
|
||||
|
||||
// Configure: LED as output (turned off)
|
||||
|
||||
#if (!defined USE_UART_BRIDGE || USE_UART_BRIDGE == 0)
|
||||
GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_CONNECTED);
|
||||
#endif
|
||||
GPIO_SET_DIRECTION_NORMAL_OUT(PIN_LED_RUNNING);
|
||||
|
||||
LED_CONNECTED_OUT(0);
|
||||
|
|
40
main/main.c
40
main/main.c
|
@ -41,8 +41,6 @@ extern void SWO_Thread();
|
|||
|
||||
TaskHandle_t kDAPTaskHandle = NULL;
|
||||
|
||||
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
|
@ -51,14 +49,11 @@ const int IPV4_GOTIP_BIT = BIT0;
|
|||
const int IPV6_GOTIP_BIT = BIT1;
|
||||
#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 */
|
||||
system_event_info_t *info = &event->event_info;
|
||||
|
||||
switch (event->event_id)
|
||||
{
|
||||
switch (event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
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;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
os_printf("Disconnect reason : %d\r\n", info->disconnected.reason);
|
||||
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT)
|
||||
{
|
||||
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_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
|
||||
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
|
||||
#endif
|
||||
|
||||
#if (USE_UART_BRIDGE == 1)
|
||||
uart_bridge_close();
|
||||
#endif
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STA_GOT_IP6:
|
||||
#ifdef CONFIG_EXAMPLE_IPV6
|
||||
|
@ -100,8 +98,7 @@ static esp_err_t event_handler(void *ctx, system_event_t *event)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
static void initialise_wifi(void) {
|
||||
tcpip_adapter_init();
|
||||
|
||||
#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);
|
||||
#endif // (USE_STATIC_IP == 1)
|
||||
|
||||
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
static void wait_for_ip()
|
||||
{
|
||||
static void wait_for_ip() {
|
||||
#ifdef CONFIG_EXAMPLE_IPV6
|
||||
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT;
|
||||
#else
|
||||
|
@ -151,7 +146,6 @@ static void wait_for_ip()
|
|||
os_printf("Connected to AP\r\n");
|
||||
}
|
||||
|
||||
|
||||
static const char *MDNS_TAG = "server_common";
|
||||
|
||||
void mdns_setup() {
|
||||
|
@ -180,9 +174,7 @@ void mdns_setup() {
|
|||
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();
|
||||
|
||||
// os_printf("reset reason: %x\n", rtc_info->reason);
|
||||
|
@ -201,6 +193,11 @@ void app_main()
|
|||
// }
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
#if (USE_UART_BRIDGE == 1)
|
||||
uart_bridge_init();
|
||||
#endif
|
||||
|
||||
initialise_wifi();
|
||||
wait_for_ip();
|
||||
DAP_Setup();
|
||||
|
@ -238,11 +235,6 @@ void app_main()
|
|||
xTaskCreate(DAP_Thread, "DAP_Task", 2048, NULL, 10, &kDAPTaskHandle);
|
||||
|
||||
#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
|
||||
// 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...
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ void tcp_netconn_task()
|
|||
ip_addr_t client_addr; // Address port
|
||||
uint16_t client_port; // 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
|
||||
{
|
||||
|
|
|
@ -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)
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef _UART_BRIDGE_H_
|
||||
#define _UART_BRIDGE_H_
|
||||
|
||||
|
||||
void uart_bridge_init();
|
||||
void uart_bridge_task();
|
||||
void uart_bridge_close();
|
||||
|
||||
|
||||
#endif
|
|
@ -13,8 +13,7 @@
|
|||
#define WIFI_SSID "DAP"
|
||||
#define WIFI_PASS "12345678"
|
||||
|
||||
|
||||
#define USE_MDNS 1
|
||||
#define USE_MDNS 1
|
||||
// Use the address "dap.local" to access the device
|
||||
#define MDNS_HOSTNAME "dap"
|
||||
#define MDNS_INSTANCE "DAP mDNS"
|
||||
|
@ -27,20 +26,20 @@
|
|||
#define DAP_IP_NETMASK 255, 255, 255, 0
|
||||
//
|
||||
|
||||
#define USE_OTA 1
|
||||
#define USE_OTA 1
|
||||
|
||||
|
||||
#define USE_UART_BRIDGE 0
|
||||
#define UART_BRIDGE_PORT 1234
|
||||
#define USE_UART_BRIDGE 1
|
||||
#define UART_BRIDGE_PORT 1234
|
||||
#define UART_BRIDGE_BAUDRATE 74880
|
||||
//
|
||||
|
||||
#define USE_TCP_NETCONN 0
|
||||
|
||||
// DO NOT CHANGE
|
||||
#define PORT 3240
|
||||
#define PORT 3240
|
||||
#define CONFIG_EXAMPLE_IPV4 1
|
||||
#define USE_KCP 0
|
||||
#define MTU_SIZE 1500
|
||||
#define USE_KCP 0
|
||||
#define MTU_SIZE 1500
|
||||
//
|
||||
|
||||
#if (USE_TCP_NETCONN == 1 && USE_KCP == 1)
|
||||
|
|
Loading…
Reference in New Issue