#include "tcp_client.h" #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "lwip/api.h" #include "lwip/ip_addr.h" #include "lwip/tcp.h" #include "lwip/tcpip.h" #include "app_runtime.h" #include "config.h" #include "debug_log.h" #include "ethernetif.h" #include "route_msg.h" #define TCP_CLIENT_CONNECT_TIMEOUT_MS 5000 static void tcp_client_abort_and_delete(struct netconn *conn, uint8_t link_index) { struct tcp_pcb *pcb; if (conn == NULL) { return; } pcb = conn->pcb.tcp; if (pcb != NULL) { LOCK_TCPIP_CORE(); pcb = conn->pcb.tcp; if (pcb != NULL) { tcp_abort(pcb); conn->pcb.tcp = NULL; conn->state = NETCONN_NONE; debug_log_printf("[CLI] idx=%u abort-close\r\n", (unsigned int)link_index); } UNLOCK_TCPIP_CORE(); } netconn_delete(conn); } static err_t tcp_client_worker(struct netconn *conn, uint8_t link_index) { struct netbuf *buf; const device_config_t *cfg = config_get(); uint8_t uart_endpoint = config_uart_index_to_endpoint(cfg->links[link_index].uart); uint8_t src_endpoint = config_link_index_to_endpoint(link_index); err_t err; route_msg_t *tx_msg; route_send_result_t route_result; netconn_set_recvtimeout(conn, 10); for (;;) { err = netconn_recv(conn, &buf); if (err == ERR_OK) { do { void *data; uint16_t len; netbuf_data(buf, &data, &len); route_result = route_send(xTcpRxQueue, src_endpoint, uart_endpoint, (link_index == CONFIG_LINK_C1) ? ROUTE_CONN_C1 : ROUTE_CONN_C2, (const uint8_t *)data, len, pdMS_TO_TICKS(10)); if (route_result != ROUTE_SEND_OK) { debug_log_printf("[CLI] idx=%u rx-route-fail rc=%s len=%u\r\n", (unsigned int)link_index, route_send_result_to_str(route_result), (unsigned int)len); netbuf_delete(buf); return ERR_CLSD; } } while (netbuf_next(buf) >= 0); netbuf_delete(buf); } else if (err != ERR_TIMEOUT) { return err; } while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) { err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY); route_msg_free(tx_msg); if (err != ERR_OK) { return err; } } } } static void tcp_client_task(uint8_t link_index) { const device_config_t *cfg; struct netconn *conn; ip_addr_t remote_ip; uint32_t delay_ms; err_t err; uint8_t first_connect_deferred; netconn_thread_init(); first_connect_deferred = (link_index == CONFIG_LINK_C1) ? 1u : 0u; for (;;) { while ((g_netif_ready == pdFALSE) || (ethernetif_link_is_up() == 0u)) { vTaskDelay(pdMS_TO_TICKS(100)); } cfg = config_get(); if (cfg->links[link_index].enabled == 0u) { vTaskDelay(pdMS_TO_TICKS(500)); continue; } delay_ms = (cfg->reconnect_interval_ms == 0u) ? 3000u : cfg->reconnect_interval_ms; if (first_connect_deferred != 0u) { first_connect_deferred = 0u; debug_log_write("[CLI] C1 first-connect defer\r\n"); vTaskDelay(pdMS_TO_TICKS(delay_ms)); continue; } conn = netconn_new(NETCONN_TCP); if (conn == NULL) { vTaskDelay(pdMS_TO_TICKS(delay_ms)); continue; } if (cfg->links[link_index].local_port != 0u) { err = netconn_bind(conn, IP_ADDR_ANY, cfg->links[link_index].local_port); if (err != ERR_OK) { debug_log_printf("[CLI] idx=%u bind-fail err=%d lport=%u\r\n", (unsigned int)link_index, (int)err, (unsigned int)cfg->links[link_index].local_port); netconn_delete(conn); vTaskDelay(pdMS_TO_TICKS(delay_ms)); continue; } } IP_ADDR4(&remote_ip, cfg->links[link_index].remote_ip[0], cfg->links[link_index].remote_ip[1], cfg->links[link_index].remote_ip[2], cfg->links[link_index].remote_ip[3]); netconn_set_recvtimeout(conn, TCP_CLIENT_CONNECT_TIMEOUT_MS); err = netconn_connect(conn, &remote_ip, cfg->links[link_index].remote_port); if (err == ERR_OK) { debug_log_printf("[CLI] idx=%u connect-ok\r\n", (unsigned int)link_index); (void)tcp_client_worker(conn, link_index); } else { if (err == ERR_TIMEOUT) { debug_log_printf("[CLI] idx=%u connect-timeout ms=%u rip=%u.%u.%u.%u rport=%u\r\n", (unsigned int)link_index, (unsigned int)TCP_CLIENT_CONNECT_TIMEOUT_MS, (unsigned int)cfg->links[link_index].remote_ip[0], (unsigned int)cfg->links[link_index].remote_ip[1], (unsigned int)cfg->links[link_index].remote_ip[2], (unsigned int)cfg->links[link_index].remote_ip[3], (unsigned int)cfg->links[link_index].remote_port); } else { debug_log_printf("[CLI] idx=%u connect-fail err=%d rip=%u.%u.%u.%u rport=%u\r\n", (unsigned int)link_index, (int)err, (unsigned int)cfg->links[link_index].remote_ip[0], (unsigned int)cfg->links[link_index].remote_ip[1], (unsigned int)cfg->links[link_index].remote_ip[2], (unsigned int)cfg->links[link_index].remote_ip[3], (unsigned int)cfg->links[link_index].remote_port); } } tcp_client_abort_and_delete(conn, link_index); vTaskDelay(pdMS_TO_TICKS(delay_ms)); } } void TcpCliTask_C1(void *argument) { (void)argument; tcp_client_task(CONFIG_LINK_C1); } void TcpCliTask_C2(void *argument) { (void)argument; tcp_client_task(CONFIG_LINK_C2); }