Files
TCP2UART/App/uart_trans.c
T
gaoro-xiao 31a3da48fa fix(tcp): MUX模式网口失联 — 对端关闭时用tcp_abort替代tcp_close避免TIME_WAIT耗尽pcb池
根因: tcp_close()将对端关闭的pcb推入TIME_WAIT(120s), 占用MEMP_TCP_PCB池(仅4个),
多连接同时断开后pcb池耗尽, tcp_new()返回NULL, 新连接无法建立直到120s超时释放。

核心修复:
- tcp_server/client: 对端关闭(p=NULL)时tcp_abort替代tcp_close, pcb立即释放
- ch390_runtime: PKT_ERR恢复强制OR上RCR_RXEN(与WCH官方一致)
- ch390_runtime: TX连续超时3次自动emergency reset
- ch390_runtime: 每5秒health_check读VID验证芯片存活
- main: App_StartLinksIfNeeded失败时不标记g_links_started, 允许重试
- main: MUX逐帧RTT printf改为#if DEBUG门控, 减少主循环延迟
- uart_trans: MUX帧解析改为先搜0x7E再消费header, 非法帧只丢1字节
2026-04-14 03:44:26 +08:00

389 lines
10 KiB
C

/**
* @file uart_trans.c
* @brief Bare-metal UART DMA/IDLE transport and MUX helpers.
*/
#include "uart_trans.h"
#include "../Core/Inc/usart.h"
#include <string.h>
#define UART_MUX_SYNC 0x7Eu
#define UART_MUX_TAIL 0x7Fu
typedef struct {
UART_HandleTypeDef *huart;
uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE];
uint8_t tx_dma_buffer[UART_TX_DMA_BUFFER_SIZE];
uint8_t rx_ring[UART_RX_RING_BUFFER_SIZE];
uint8_t tx_ring[UART_TX_RING_BUFFER_SIZE];
volatile uint16_t rx_dma_read_index;
volatile uint16_t rx_head;
volatile uint16_t rx_tail;
volatile uint16_t tx_head;
volatile uint16_t tx_tail;
volatile uint16_t tx_dma_len;
volatile bool tx_busy;
uart_config_t config;
uart_stats_t stats;
bool initialized;
bool running;
} uart_channel_ctx_t;
static uart_channel_ctx_t g_channels[UART_CHANNEL_MAX];
static uint16_t ring_used(uint16_t head, uint16_t tail, uint16_t size)
{
return (head >= tail) ? (head - tail) : (size - tail + head);
}
static uint16_t ring_free(uint16_t head, uint16_t tail, uint16_t size)
{
return (uint16_t)(size - ring_used(head, tail, size) - 1u);
}
static int apply_uart_config(uart_channel_t channel)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
if (ctx->huart == NULL) {
return -1;
}
if (ctx->running) {
HAL_UART_DMAStop(ctx->huart);
ctx->running = false;
}
ctx->huart->Init.BaudRate = ctx->config.baudrate;
ctx->huart->Init.WordLength = UART_WORDLENGTH_8B;
ctx->huart->Init.StopBits = UART_STOPBITS_1;
ctx->huart->Init.Parity = UART_PARITY_NONE;
return (HAL_UART_Init(ctx->huart) == HAL_OK) ? 0 : -1;
}
static void process_rx_snapshot(uart_channel_t channel, uint16_t dma_write_index)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
while (ctx->rx_dma_read_index != dma_write_index) {
uint16_t next_head = (uint16_t)((ctx->rx_head + 1u) % UART_RX_RING_BUFFER_SIZE);
if (next_head == ctx->rx_tail) {
ctx->stats.errors++;
break;
}
ctx->rx_ring[ctx->rx_head] = ctx->rx_dma_buffer[ctx->rx_dma_read_index];
ctx->rx_head = next_head;
ctx->rx_dma_read_index = (uint16_t)((ctx->rx_dma_read_index + 1u) % UART_RX_DMA_BUFFER_SIZE);
ctx->stats.rx_bytes++;
}
}
static void kick_tx(uart_channel_t channel)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t available;
uint16_t chunk;
if (!ctx->running || ctx->tx_busy) {
return;
}
available = ring_used(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE);
if (available == 0u) {
return;
}
chunk = available;
if (chunk > UART_TX_DMA_BUFFER_SIZE) {
chunk = UART_TX_DMA_BUFFER_SIZE;
}
for (uint16_t i = 0; i < chunk; ++i) {
ctx->tx_dma_buffer[i] = ctx->tx_ring[ctx->tx_tail];
ctx->tx_tail = (uint16_t)((ctx->tx_tail + 1u) % UART_TX_RING_BUFFER_SIZE);
}
ctx->tx_dma_len = chunk;
ctx->tx_busy = true;
ctx->stats.tx_packets++;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, chunk) != HAL_OK) {
ctx->tx_busy = false;
ctx->stats.errors++;
}
}
int uart_trans_init(void)
{
memset(g_channels, 0, sizeof(g_channels));
g_channels[UART_CHANNEL_U0].huart = &huart2;
g_channels[UART_CHANNEL_U1].huart = &huart3;
g_channels[UART_CHANNEL_U0].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_U1].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_U0].initialized = true;
g_channels[UART_CHANNEL_U1].initialized = true;
return 0;
}
int uart_trans_config(uart_channel_t channel, const uart_config_t *config)
{
if (channel >= UART_CHANNEL_MAX || config == NULL) {
return -1;
}
g_channels[channel].config = *config;
return apply_uart_config(channel);
}
int uart_trans_start(uart_channel_t channel)
{
uart_channel_ctx_t *ctx;
if (channel >= UART_CHANNEL_MAX) {
return -1;
}
ctx = &g_channels[channel];
if (!ctx->initialized || ctx->huart == NULL) {
return -1;
}
ctx->rx_dma_read_index = 0u;
ctx->rx_head = 0u;
ctx->rx_tail = 0u;
ctx->tx_head = 0u;
ctx->tx_tail = 0u;
ctx->tx_dma_len = 0u;
ctx->tx_busy = false;
memset(&ctx->stats, 0, sizeof(ctx->stats));
__HAL_UART_ENABLE_IT(ctx->huart, UART_IT_IDLE);
if (HAL_UART_Receive_DMA(ctx->huart, ctx->rx_dma_buffer, UART_RX_DMA_BUFFER_SIZE) != HAL_OK) {
return -1;
}
ctx->running = true;
return 0;
}
int uart_trans_stop(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return -1;
}
HAL_UART_DMAStop(g_channels[channel].huart);
g_channels[channel].running = false;
g_channels[channel].tx_busy = false;
return 0;
}
void uart_trans_poll(void)
{
kick_tx(UART_CHANNEL_U0);
kick_tx(UART_CHANNEL_U1);
}
uint16_t uart_trans_rx_available(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return 0u;
}
return ring_used(g_channels[channel].rx_head, g_channels[channel].rx_tail, UART_RX_RING_BUFFER_SIZE);
}
uint16_t uart_trans_read(uart_channel_t channel, uint8_t *data, uint16_t max_len)
{
uart_channel_ctx_t *ctx;
uint16_t copied = 0u;
if (channel >= UART_CHANNEL_MAX || data == NULL || max_len == 0u) {
return 0u;
}
ctx = &g_channels[channel];
while (copied < max_len && ctx->rx_tail != ctx->rx_head) {
data[copied++] = ctx->rx_ring[ctx->rx_tail];
ctx->rx_tail = (uint16_t)((ctx->rx_tail + 1u) % UART_RX_RING_BUFFER_SIZE);
}
if (copied > 0u) {
ctx->stats.rx_packets++;
}
return copied;
}
uint16_t uart_trans_write(uart_channel_t channel, const uint8_t *data, uint16_t len)
{
uart_channel_ctx_t *ctx;
uint16_t written = 0u;
if (channel >= UART_CHANNEL_MAX || data == NULL || len == 0u) {
return 0u;
}
ctx = &g_channels[channel];
while (written < len && ring_free(ctx->tx_head, ctx->tx_tail, UART_TX_RING_BUFFER_SIZE) > 0u) {
ctx->tx_ring[ctx->tx_head] = data[written++];
ctx->tx_head = (uint16_t)((ctx->tx_head + 1u) % UART_TX_RING_BUFFER_SIZE);
}
if (written < len) {
ctx->stats.errors++;
}
kick_tx(channel);
return written;
}
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats)
{
if (channel < UART_CHANNEL_MAX && stats != NULL) {
*stats = g_channels[channel].stats;
}
}
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel < UART_CHANNEL_MAX) {
memset(&g_channels[channel].stats, 0, sizeof(g_channels[channel].stats));
}
}
void uart_trans_idle_handler(uart_channel_t channel)
{
UART_HandleTypeDef *huart;
uint16_t dma_write_index;
if (channel >= UART_CHANNEL_MAX) {
return;
}
huart = g_channels[channel].huart;
g_channels[channel].stats.idle_events++;
dma_write_index = (uint16_t)(UART_RX_DMA_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx));
if (dma_write_index >= UART_RX_DMA_BUFFER_SIZE) {
dma_write_index = 0u;
}
process_rx_snapshot(channel, dma_write_index);
}
void uart_trans_rx_half_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
g_channels[channel].stats.rx_half_events++;
process_rx_snapshot(channel, UART_RX_DMA_BUFFER_SIZE / 2u);
}
void uart_trans_rx_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
g_channels[channel].stats.rx_full_events++;
process_rx_snapshot(channel, 0u);
}
void uart_trans_tx_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
g_channels[channel].tx_busy = false;
g_channels[channel].stats.tx_bytes += g_channels[channel].tx_dma_len;
g_channels[channel].tx_dma_len = 0u;
kick_tx(channel);
}
bool uart_mux_try_extract_frame(uart_channel_t channel, uart_mux_frame_t *frame)
{
uint8_t sync_byte;
uint8_t header[4];
uint16_t available;
uint16_t payload_len;
if (channel >= UART_CHANNEL_MAX || frame == NULL) {
return false;
}
available = uart_trans_rx_available(channel);
if (available < 6u) {
return false;
}
/* Scan for SYNC byte (0x7E) — discard non-matching bytes one at a time */
if (uart_trans_read(channel, &sync_byte, 1u) != 1u) {
return false;
}
if (sync_byte != UART_MUX_SYNC) {
return false;
}
/* Need at least: 2(len) + 1(src) + 1(dst) + payload + 1(tail) = 5 + payload */
available = uart_trans_rx_available(channel);
if (available < 4u) {
return false;
}
if (uart_trans_read(channel, header, sizeof(header)) != sizeof(header)) {
return false;
}
payload_len = (uint16_t)(((uint16_t)header[0] << 8) | header[1]);
if (payload_len > sizeof(frame->payload)) {
return false;
}
if (uart_trans_rx_available(channel) < (uint16_t)(payload_len + 1u)) {
return false;
}
frame->src_id = header[2];
frame->dst_mask = header[3];
frame->payload_len = payload_len;
if (payload_len > 0u) {
if (uart_trans_read(channel, frame->payload, payload_len) != payload_len) {
return false;
}
}
{
uint8_t tail = 0u;
if (uart_trans_read(channel, &tail, 1u) != 1u || tail != UART_MUX_TAIL) {
return false;
}
}
return true;
}
bool uart_mux_encode_frame(uint8_t src_id,
uint8_t dst_mask,
const uint8_t *payload,
uint16_t payload_len,
uint8_t *out,
uint16_t *out_len,
uint16_t out_capacity)
{
uint16_t frame_len;
if (out == NULL || out_len == NULL) {
return false;
}
frame_len = (uint16_t)(payload_len + 6u);
if (frame_len > out_capacity) {
return false;
}
out[0] = UART_MUX_SYNC;
out[1] = (uint8_t)(payload_len >> 8);
out[2] = (uint8_t)(payload_len & 0xFFu);
out[3] = src_id;
out[4] = dst_mask;
if (payload_len > 0u && payload != NULL) {
memcpy(&out[5], payload, payload_len);
}
out[5 + payload_len] = UART_MUX_TAIL;
*out_len = frame_len;
return true;
}