refactor: 完成R8裸机lwIP移植并更新文档

This commit is contained in:
2026-03-30 18:08:54 +08:00
parent 68c64959c7
commit 9efa2cdc59
24 changed files with 1845 additions and 3619 deletions
+165 -324
View File
@@ -1,405 +1,246 @@
/**
* @file tcp_server.c
* @brief TCP Server module implementation for transparent transmission with UART2
* @brief lwIP RAW TCP server for the UART2 bridge.
*/
#include "tcp_server.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 "lwip/pbuf.h"
#include "lwip/tcp.h"
#include <string.h>
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
typedef struct {
struct tcp_pcb *listen_pcb;
struct tcp_pcb *client_pcb;
uint8_t rx_ring[TCP_SERVER_RX_BUFFER_SIZE];
uint16_t rx_head;
uint16_t rx_tail;
tcp_server_config_t config;
tcp_server_status_t status;
} tcp_server_ctx_t;
/* Server configuration */
static tcp_server_config_t server_config = {
.port = TCP_SERVER_DEFAULT_PORT,
.auto_reconnect = true
};
static tcp_server_ctx_t g_server;
/* Server status */
static tcp_server_status_t server_status = {
.state = TCP_SERVER_STATE_IDLE,
.rx_bytes = 0,
.tx_bytes = 0,
.connections = 0,
.errors = 0
};
/* Socket descriptors */
static int listen_socket = -1;
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 */
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
static int tcp_server_send_all(int sock, const uint8_t *data, uint16_t len)
static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
{
uint16_t total = 0;
return (head >= tail) ? (uint16_t)(size - head + tail - 1u) : (uint16_t)(tail - head - 1u);
}
while (total < len)
{
int sent = send(sock, data + total, len - total, 0);
if (sent > 0)
{
total += (uint16_t)sent;
static err_t tcp_server_on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
struct pbuf *q;
if (err != ERR_OK) {
if (p != NULL) {
pbuf_free(p);
}
else
{
return -1;
return err;
}
if (p == NULL) {
ctx->client_pcb = NULL;
ctx->status.state = TCP_SERVER_STATE_LISTENING;
return ERR_OK;
}
for (q = p; q != NULL; q = q->next) {
const uint8_t *src = (const uint8_t *)q->payload;
for (uint16_t i = 0; i < q->len; ++i) {
if (ring_free(ctx->rx_head, ctx->rx_tail, TCP_SERVER_RX_BUFFER_SIZE) == 0u) {
ctx->status.errors++;
break;
}
ctx->rx_ring[ctx->rx_head] = src[i];
ctx->rx_head = (uint16_t)((ctx->rx_head + 1u) % TCP_SERVER_RX_BUFFER_SIZE);
ctx->status.rx_bytes++;
}
}
return (int)total;
tcp_recved(pcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
}
static err_t tcp_server_on_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
(void)pcb;
ctx->status.tx_bytes += len;
return ERR_OK;
}
static void tcp_server_on_err(void *arg, err_t err)
{
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
(void)err;
ctx->client_pcb = NULL;
ctx->status.state = TCP_SERVER_STATE_LISTENING;
ctx->status.errors++;
}
static err_t tcp_server_on_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
tcp_server_ctx_t *ctx = (tcp_server_ctx_t *)arg;
if (err != ERR_OK) {
return err;
}
if (ctx->client_pcb != NULL) {
tcp_abort(newpcb);
return ERR_ABRT;
}
ctx->client_pcb = newpcb;
ctx->status.state = TCP_SERVER_STATE_CONNECTED;
ctx->status.connections++;
tcp_arg(newpcb, ctx);
tcp_recv(newpcb, tcp_server_on_recv);
tcp_sent(newpcb, tcp_server_on_sent);
tcp_err(newpcb, tcp_server_on_err);
return ERR_OK;
}
/**
* @brief Initialize TCP Server module
*/
int tcp_server_init(const tcp_server_config_t *config)
{
if (config != NULL)
{
memcpy(&server_config, config, sizeof(tcp_server_config_t));
memset(&g_server, 0, sizeof(g_server));
g_server.config.port = TCP_SERVER_DEFAULT_PORT;
g_server.config.auto_reconnect = true;
g_server.status.state = TCP_SERVER_STATE_IDLE;
if (config != NULL) {
g_server.config = *config;
}
/* Create stream buffers */
if (rx_stream == NULL)
{
rx_stream = xStreamBufferCreate(TCP_SERVER_RX_BUFFER_SIZE, 1);
if (rx_stream == NULL)
{
return -1;
}
}
if (tx_stream == NULL)
{
tx_stream = xStreamBufferCreate(TCP_SERVER_TX_BUFFER_SIZE, 1);
if (tx_stream == NULL)
{
return -1;
}
}
server_status.state = TCP_SERVER_STATE_IDLE;
return 0;
}
/**
* @brief Start TCP Server
*/
int tcp_server_start(void)
{
struct sockaddr_in server_addr;
int opt = 1;
if (listen_socket >= 0)
{
/* Already started */
struct tcp_pcb *pcb;
err_t err;
if (g_server.listen_pcb != NULL) {
return 0;
}
/* Create socket */
listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket < 0)
{
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
if (pcb == NULL) {
g_server.status.errors++;
return -1;
}
/* Set socket options */
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
/* Bind to port */
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(server_config.port);
if (bind(listen_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
close(listen_socket);
listen_socket = -1;
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
err = tcp_bind(pcb, IP_ANY_TYPE, g_server.config.port);
if (err != ERR_OK) {
tcp_abort(pcb);
g_server.status.errors++;
return -1;
}
/* Start listening */
if (listen(listen_socket, TCP_SERVER_MAX_CONNECTIONS) < 0)
{
close(listen_socket);
listen_socket = -1;
server_status.state = TCP_SERVER_STATE_ERROR;
server_status.errors++;
g_server.listen_pcb = tcp_listen_with_backlog(pcb, 1);
if (g_server.listen_pcb == NULL) {
g_server.status.errors++;
return -1;
}
server_status.state = TCP_SERVER_STATE_LISTENING;
tcp_arg(g_server.listen_pcb, &g_server);
tcp_accept(g_server.listen_pcb, tcp_server_on_accept);
g_server.status.state = TCP_SERVER_STATE_LISTENING;
return 0;
}
/**
* @brief Stop TCP Server
*/
int tcp_server_stop(void)
{
if (client_socket >= 0)
{
close(client_socket);
client_socket = -1;
if (g_server.client_pcb != NULL) {
tcp_arg(g_server.client_pcb, NULL);
tcp_recv(g_server.client_pcb, NULL);
tcp_sent(g_server.client_pcb, NULL);
tcp_err(g_server.client_pcb, NULL);
tcp_abort(g_server.client_pcb);
g_server.client_pcb = NULL;
}
if (listen_socket >= 0)
{
close(listen_socket);
listen_socket = -1;
if (g_server.listen_pcb != NULL) {
tcp_arg(g_server.listen_pcb, NULL);
tcp_accept(g_server.listen_pcb, NULL);
tcp_close(g_server.listen_pcb);
g_server.listen_pcb = NULL;
}
server_status.state = TCP_SERVER_STATE_IDLE;
g_server.status.state = TCP_SERVER_STATE_IDLE;
return 0;
}
/**
* @brief Send data to connected client
*/
int tcp_server_send(const uint8_t *data, uint16_t len)
{
int sent;
if (client_socket < 0)
{
err_t err;
if (g_server.client_pcb == NULL || data == NULL || len == 0u) {
return -1;
}
sent = tcp_server_send_all(client_socket, data, len);
if (sent > 0)
{
server_status.tx_bytes += sent;
if (tcp_sndbuf(g_server.client_pcb) < len) {
return 0;
}
else if (sent < 0)
{
/* Connection error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
err = tcp_write(g_server.client_pcb, data, len, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) {
g_server.status.errors++;
return -1;
}
return sent;
err = tcp_output(g_server.client_pcb);
if (err != ERR_OK) {
g_server.status.errors++;
return -1;
}
return (int)len;
}
/**
* @brief Receive data from connected client
*/
int tcp_server_recv(uint8_t *data, uint16_t max_len, uint32_t timeout_ms)
{
int received;
struct timeval tv;
if (client_socket < 0)
{
uint16_t copied = 0u;
(void)timeout_ms;
if (data == NULL || max_len == 0u) {
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)
{
server_status.rx_bytes += received;
while (copied < max_len && g_server.rx_tail != g_server.rx_head) {
data[copied++] = g_server.rx_ring[g_server.rx_tail];
g_server.rx_tail = (uint16_t)((g_server.rx_tail + 1u) % TCP_SERVER_RX_BUFFER_SIZE);
}
else if (received == 0)
{
/* Connection closed by client */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
}
else if (received < 0)
{
/* Timeout or error - check errno */
/* For timeout, just return 0 */
}
return received;
return (int)copied;
}
/**
* @brief Check if client is connected
*/
bool tcp_server_is_connected(void)
{
return (client_socket >= 0);
return g_server.client_pcb != NULL;
}
/**
* @brief Get TCP Server status
*/
void tcp_server_get_status(tcp_server_status_t *status)
{
if (status != NULL)
{
memcpy(status, &server_status, sizeof(tcp_server_status_t));
if (status != NULL) {
*status = g_server.status;
}
}
/**
* @brief Get RX StreamBuffer handle
*/
void *tcp_server_get_rx_stream(void)
{
return rx_stream;
return NULL;
}
/**
* @brief Get TX StreamBuffer handle
*/
void *tcp_server_get_tx_stream(void)
{
return tx_stream;
return NULL;
}
/**
* @brief TCP Server task
*/
void tcp_server_task(void *argument)
{
const device_config_t *cfg;
tcp_server_config_t task_cfg;
struct sockaddr_in client_addr;
socklen_t addr_len;
uint8_t rx_buffer[256];
uint8_t tx_buffer[256];
int received;
size_t tx_len;
fd_set read_fds;
struct timeval tv;
int max_fd;
(void)argument;
/* Initialize server */
task_cfg.port = TCP_SERVER_DEFAULT_PORT;
task_cfg.auto_reconnect = true;
cfg = config_get();
if (cfg != NULL && cfg->server_port > 0)
{
task_cfg.port = cfg->server_port;
}
tcp_server_init(&task_cfg);
/* Start server */
while (tcp_server_start() != 0)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
while (1)
{
/* Check if we need to accept a new connection */
if (client_socket < 0 && listen_socket >= 0)
{
/* Use select with timeout to check for incoming connections */
FD_ZERO(&read_fds);
FD_SET(listen_socket, &read_fds);
tv.tv_sec = 0;
tv.tv_usec = 100000; /* 100ms timeout */
if (select(listen_socket + 1, &read_fds, NULL, NULL, &tv) > 0)
{
addr_len = sizeof(client_addr);
client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &addr_len);
if (client_socket >= 0)
{
server_status.state = TCP_SERVER_STATE_CONNECTED;
server_status.connections++;
}
}
}
/* Handle data transfer if connected */
if (client_socket >= 0)
{
/* Check for data from TCP client */
FD_ZERO(&read_fds);
FD_SET(client_socket, &read_fds);
max_fd = client_socket;
tv.tv_sec = 0;
tv.tv_usec = 10000; /* 10ms timeout */
if (select(max_fd + 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));
server_status.rx_bytes += received;
}
else if (received == 0)
{
/* Connection closed */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
}
else
{
/* Error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
}
}
}
/* 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_server_send_all(client_socket, tx_buffer, (uint16_t)tx_len);
if (sent > 0)
{
server_status.tx_bytes += sent;
}
else if (sent < 0)
{
/* Send error */
close(client_socket);
client_socket = -1;
server_status.state = TCP_SERVER_STATE_LISTENING;
server_status.errors++;
}
}
}
/* Small delay to prevent tight loop */
vTaskDelay(pdMS_TO_TICKS(1));
}
}