diff --git a/README.md b/README.md index b630220..58b8f37 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/components/DAP/config/DAP_config.h b/components/DAP/config/DAP_config.h index cc1d1f4..ec67197 100644 --- a/components/DAP/config/DAP_config.h +++ b/components/DAP/config/DAP_config.h @@ -46,6 +46,7 @@ #include #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); diff --git a/main/main.c b/main/main.c index 2e15cfb..9e2a316 100644 --- a/main/main.c +++ b/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... } diff --git a/main/tcp_netconn.c b/main/tcp_netconn.c index 1c58e83..3fe77f3 100644 --- a/main/tcp_netconn.c +++ b/main/tcp_netconn.c @@ -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 { diff --git a/main/uart_bridge.c b/main/uart_bridge.c index e69de29..fa0e658 100644 --- a/main/uart_bridge.c +++ b/main/uart_bridge.c @@ -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 +#include +#include +#include + +#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 + +#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) \ No newline at end of file diff --git a/main/uart_bridge.h b/main/uart_bridge.h index 4da1e31..df3ae09 100644 --- a/main/uart_bridge.h +++ b/main/uart_bridge.h @@ -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 \ No newline at end of file diff --git a/main/wifi_configuration.h b/main/wifi_configuration.h index 4a37598..64575f8 100644 --- a/main/wifi_configuration.h +++ b/main/wifi_configuration.h @@ -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)