feat: 保存已验证的CH390网络打通基线

This commit is contained in:
2026-04-17 07:09:55 +08:00
parent 59eecf428f
commit 6aba77df9a
44 changed files with 6428 additions and 3372 deletions
+86 -408
View File
@@ -1,431 +1,109 @@
/**
* @file tcp_client.c
* @brief TCP Client module implementation for transparent transmission with UART3
*/
#include "tcp_client.h"
#include "config.h"
#include "lwip/opt.h"
#include "lwip/tcp.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include "queue.h"
#include "lwip/api.h"
#include "lwip/ip_addr.h"
#include <string.h>
#include "app_runtime.h"
#include "config.h"
#include "route_msg.h"
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
/* Client configuration */
static tcp_client_config_t client_config = {
.server_ip = {192, 168, 1, 100},
.server_port = TCP_CLIENT_DEFAULT_PORT,
.auto_reconnect = true,
.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS
};
/* Client status */
static tcp_client_status_t client_status = {
.state = TCP_CLIENT_STATE_IDLE,
.rx_bytes = 0,
.tx_bytes = 0,
.reconnect_count = 0,
.errors = 0
};
/* Socket descriptor */
static int client_socket = -1;
/* Stream buffers for UART integration */
static StreamBufferHandle_t rx_stream = NULL; /* TCP RX -> UART TX */
static StreamBufferHandle_t tx_stream = NULL; /* UART RX -> TCP TX */
/*---------------------------------------------------------------------------
* Private Functions
*---------------------------------------------------------------------------*/
static int tcp_client_send_all(int sock, const uint8_t *data, uint16_t len)
static void tcp_client_worker(struct netconn *conn, uint8_t link_index)
{
uint16_t total = 0;
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;
while (total < len)
{
int sent = send(sock, data + total, len - total, 0);
if (sent > 0)
{
total += (uint16_t)sent;
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);
(void)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));
} while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
} else if (err != ERR_TIMEOUT) {
break;
}
else
{
return -1;
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;
}
}
}
return (int)total;
}
/**
* @brief Internal connect function
*/
static int tcp_client_do_connect(void)
{
struct sockaddr_in server_addr;
int ret;
if (client_socket >= 0)
{
/* Already connected */
return 0;
}
client_status.state = TCP_CLIENT_STATE_CONNECTING;
/* Create socket */
client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0)
{
client_status.state = TCP_CLIENT_STATE_ERROR;
client_status.errors++;
return -1;
}
/* Prepare server address */
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(client_config.server_port);
server_addr.sin_addr.s_addr = ((uint32_t)client_config.server_ip[0]) |
((uint32_t)client_config.server_ip[1] << 8) |
((uint32_t)client_config.server_ip[2] << 16) |
((uint32_t)client_config.server_ip[3] << 24);
/* Connect to server */
ret = connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
return -1;
}
client_status.state = TCP_CLIENT_STATE_CONNECTED;
return 0;
}
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
/**
* @brief Initialize TCP Client module
*/
int tcp_client_init(const tcp_client_config_t *config)
{
if (config != NULL)
{
memcpy(&client_config, config, sizeof(tcp_client_config_t));
}
/* Create stream buffers */
if (rx_stream == NULL)
{
rx_stream = xStreamBufferCreate(TCP_CLIENT_RX_BUFFER_SIZE, 1);
if (rx_stream == NULL)
{
return -1;
}
}
if (tx_stream == NULL)
{
tx_stream = xStreamBufferCreate(TCP_CLIENT_TX_BUFFER_SIZE, 1);
if (tx_stream == NULL)
{
return -1;
}
}
client_status.state = TCP_CLIENT_STATE_IDLE;
return 0;
}
/**
* @brief Connect to remote server
*/
int tcp_client_connect(void)
{
return tcp_client_do_connect();
}
/**
* @brief Disconnect from server
*/
int tcp_client_disconnect(void)
{
if (client_socket >= 0)
{
close(client_socket);
client_socket = -1;
}
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
return 0;
}
/**
* @brief Send data to server
*/
int tcp_client_send(const uint8_t *data, uint16_t len)
{
int sent;
if (client_socket < 0)
{
return -1;
}
sent = tcp_client_send_all(client_socket, data, len);
if (sent > 0)
{
client_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Connection error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
}
return sent;
}
/**
* @brief Receive data from server
*/
int tcp_client_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms)
{
int received;
struct timeval tv;
if (client_socket < 0)
{
return -1;
}
/* Set receive timeout */
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec = (timeout_ms % 1000) * 1000;
setsockopt(client_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
received = recv(client_socket, data, max_len, 0);
if (received > 0)
{
client_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed by server */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
}
return received;
}
/**
* @brief Check if connected to server
*/
bool tcp_client_is_connected(void)
{
return (client_socket >= 0);
}
/**
* @brief Update server configuration
*/
int tcp_client_set_server(const uint8_t *ip, uint16_t port)
{
if (ip == NULL)
{
return -1;
}
/* Disconnect if connected */
if (client_socket >= 0)
{
tcp_client_disconnect();
}
memcpy(client_config.server_ip, ip, 4);
client_config.server_port = port;
return 0;
}
/**
* @brief Get TCP Client status
*/
void tcp_client_get_status(tcp_client_status_t *status)
{
if (status != NULL)
{
memcpy(status, &client_status, sizeof(tcp_client_status_t));
}
}
/**
* @brief Get RX StreamBuffer handle
*/
void *tcp_client_get_rx_stream(void)
{
return rx_stream;
}
/**
* @brief Get TX StreamBuffer handle
*/
void *tcp_client_get_tx_stream(void)
{
return tx_stream;
}
/**
* @brief TCP Client task
*/
void tcp_client_task(void *argument)
static void tcp_client_task(uint8_t link_index)
{
const device_config_t *cfg;
tcp_client_config_t task_cfg;
uint8_t rx_buffer[256];
uint8_t tx_buffer[256];
int received;
size_t tx_len;
fd_set read_fds;
struct timeval tv;
uint32_t reconnect_timer = 0;
(void)argument;
/* Initialize client */
task_cfg.server_ip[0] = 192;
task_cfg.server_ip[1] = 168;
task_cfg.server_ip[2] = 1;
task_cfg.server_ip[3] = 100;
task_cfg.server_port = TCP_CLIENT_DEFAULT_PORT;
task_cfg.auto_reconnect = true;
task_cfg.reconnect_interval_ms = TCP_CLIENT_RECONNECT_DELAY_MS;
struct netconn *conn;
ip_addr_t remote_ip;
uint32_t delay_ms;
cfg = config_get();
if (cfg != NULL)
{
memcpy(task_cfg.server_ip, cfg->remote_ip, sizeof(task_cfg.server_ip));
if (cfg->remote_port > 0)
{
task_cfg.server_port = cfg->remote_port;
}
if (cfg->reconnect_interval > 0)
{
task_cfg.reconnect_interval_ms = cfg->reconnect_interval;
}
}
tcp_client_init(&task_cfg);
while (1)
{
/* Handle connection state */
if (client_socket < 0)
{
/* Not connected - try to reconnect */
if (client_config.auto_reconnect)
{
if (xTaskGetTickCount() - reconnect_timer >= pdMS_TO_TICKS(client_config.reconnect_interval_ms))
{
if (tcp_client_do_connect() == 0)
{
/* Connected successfully */
client_status.reconnect_count++;
}
reconnect_timer = xTaskGetTickCount();
}
}
/* Wait before retry */
for (;;) {
while (g_netif_ready == pdFALSE) {
vTaskDelay(pdMS_TO_TICKS(100));
}
cfg = config_get();
if (cfg->links[link_index].enabled == 0u) {
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
/* Handle data transfer if connected */
/* Check for data from TCP server */
FD_ZERO(&read_fds);
FD_SET(client_socket, &read_fds);
tv.tv_sec = 0;
tv.tv_usec = 10000; /* 10ms timeout */
if (select(client_socket + 1, &read_fds, NULL, NULL, &tv) > 0)
{
if (FD_ISSET(client_socket, &read_fds))
{
received = recv(client_socket, rx_buffer, sizeof(rx_buffer), 0);
if (received > 0)
{
/* Forward to UART via stream buffer */
xStreamBufferSend(rx_stream, rx_buffer, received, pdMS_TO_TICKS(10));
client_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
reconnect_timer = xTaskGetTickCount();
}
else
{
/* Error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
reconnect_timer = xTaskGetTickCount();
}
}
delay_ms = (cfg->reconnect_interval_ms == 0u) ? 3000u : cfg->reconnect_interval_ms;
conn = netconn_new(NETCONN_TCP);
if (conn == NULL) {
vTaskDelay(pdMS_TO_TICKS(delay_ms));
continue;
}
/* Check for data from UART to send to TCP */
tx_len = xStreamBufferReceive(tx_stream, tx_buffer, sizeof(tx_buffer), 0);
if (tx_len > 0)
{
int sent = tcp_client_send_all(client_socket, tx_buffer, (uint16_t)tx_len);
if (sent > 0)
{
client_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Send error */
close(client_socket);
client_socket = -1;
client_status.state = TCP_CLIENT_STATE_DISCONNECTED;
client_status.errors++;
reconnect_timer = xTaskGetTickCount();
}
if (cfg->links[link_index].local_port != 0u) {
(void)netconn_bind(conn, IP_ADDR_ANY, cfg->links[link_index].local_port);
}
/* Small delay to prevent tight loop */
vTaskDelay(pdMS_TO_TICKS(1));
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]);
if (netconn_connect(conn, &remote_ip, cfg->links[link_index].remote_port) == ERR_OK) {
tcp_client_worker(conn, link_index);
}
netconn_close(conn);
netconn_delete(conn);
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);
}