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
+253 -450
View File
@@ -1,528 +1,331 @@
/**
* @file uart_trans.c
* @brief UART transparent transmission module implementation
*
* Uses DMA + IDLE interrupt for efficient variable-length data reception.
* Integrates with TCP modules via FreeRTOS StreamBuffers.
* @brief Bare-metal UART DMA/IDLE transport layer.
*/
#include "uart_trans.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include "usart.h"
#include <string.h>
/*---------------------------------------------------------------------------
* Private Definitions
*---------------------------------------------------------------------------*/
/* Channel context structure */
typedef struct {
UART_HandleTypeDef *huart; /* HAL UART handle */
DMA_HandleTypeDef *hdma_rx; /* DMA RX handle */
uint8_t rx_dma_buffer[UART_RX_DMA_BUFFER_SIZE]; /* DMA RX buffer */
uint8_t tx_dma_buffer[UART_TX_DMA_BUFFER_SIZE]; /* DMA TX buffer */
volatile uint16_t rx_read_index; /* Last read position */
volatile bool tx_busy; /* TX in progress flag */
StreamBufferHandle_t rx_stream; /* From TCP (for UART TX) */
StreamBufferHandle_t tx_stream; /* To TCP (from UART RX) */
uart_config_t config; /* UART configuration */
uart_stats_t stats; /* Statistics */
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;
/*---------------------------------------------------------------------------
* Private Variables
*---------------------------------------------------------------------------*/
static uart_channel_ctx_t g_channels[UART_CHANNEL_MAX];
/*---------------------------------------------------------------------------
* Private Functions
*---------------------------------------------------------------------------*/
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 void apply_default_config(uart_channel_ctx_t *ctx)
{
ctx->config.baudrate = UART_DEFAULT_BAUDRATE;
ctx->config.data_bits = UART_DEFAULT_DATA_BITS;
ctx->config.stop_bits = UART_DEFAULT_STOP_BITS;
ctx->config.parity = UART_DEFAULT_PARITY;
}
/**
* @brief Apply UART configuration
*/
static int apply_uart_config(uart_channel_t channel)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
UART_HandleTypeDef *huart = ctx->huart;
if (huart == NULL)
{
if (huart == NULL) {
return -1;
}
/* Stop UART if running */
if (ctx->running)
{
if (ctx->running) {
HAL_UART_DMAStop(huart);
ctx->running = false;
}
/* Update UART parameters */
huart->Init.BaudRate = ctx->config.baudrate;
/* Data bits */
if (ctx->config.data_bits == 9)
{
huart->Init.WordLength = UART_WORDLENGTH_9B;
huart->Init.WordLength = (ctx->config.data_bits == 9u) ? UART_WORDLENGTH_9B : UART_WORDLENGTH_8B;
huart->Init.StopBits = (ctx->config.stop_bits == 2u) ? UART_STOPBITS_2 : UART_STOPBITS_1;
switch (ctx->config.parity) {
case 1:
huart->Init.Parity = UART_PARITY_ODD;
break;
case 2:
huart->Init.Parity = UART_PARITY_EVEN;
break;
default:
huart->Init.Parity = UART_PARITY_NONE;
break;
}
else
{
huart->Init.WordLength = UART_WORDLENGTH_8B;
}
/* Stop bits */
if (ctx->config.stop_bits == 2)
{
huart->Init.StopBits = UART_STOPBITS_2;
}
else
{
huart->Init.StopBits = UART_STOPBITS_1;
}
/* Parity */
switch (ctx->config.parity)
{
case 1:
huart->Init.Parity = UART_PARITY_ODD;
break;
case 2:
huart->Init.Parity = UART_PARITY_EVEN;
break;
default:
huart->Init.Parity = UART_PARITY_NONE;
return (HAL_UART_Init(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;
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++;
}
/* Reinitialize UART */
if (HAL_UART_Init(huart) != HAL_OK)
{
return -1;
}
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_SERVER].huart = &huart2;
g_channels[UART_CHANNEL_CLIENT].huart = &huart3;
apply_default_config(&g_channels[UART_CHANNEL_SERVER]);
apply_default_config(&g_channels[UART_CHANNEL_CLIENT]);
g_channels[UART_CHANNEL_SERVER].initialized = true;
g_channels[UART_CHANNEL_CLIENT].initialized = true;
return 0;
}
static void process_rx_data_from_isr(uart_channel_t channel, uint16_t end_index)
int uart_trans_config(uart_channel_t channel, const uart_config_t *config)
{
uart_channel_ctx_t *ctx = &g_channels[channel];
uint16_t start = ctx->rx_read_index;
uint16_t end = end_index;
uint16_t len;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (start >= UART_RX_DMA_BUFFER_SIZE)
{
start = 0;
if (channel >= UART_CHANNEL_MAX || config == NULL) {
return -1;
}
if (end > UART_RX_DMA_BUFFER_SIZE)
{
end = UART_RX_DMA_BUFFER_SIZE;
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;
}
if (end >= start)
{
len = end - start;
if (len > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
&ctx->rx_dma_buffer[start],
len,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += len;
ctx->stats.rx_packets++;
}
ctx = &g_channels[channel];
if (!ctx->initialized || ctx->huart == NULL) {
return -1;
}
else
{
len = UART_RX_DMA_BUFFER_SIZE - start;
if (len > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
&ctx->rx_dma_buffer[start],
len,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += len;
}
if (end > 0 && ctx->tx_stream != NULL)
{
xStreamBufferSendFromISR(ctx->tx_stream,
ctx->rx_dma_buffer,
end,
&xHigherPriorityTaskWoken);
ctx->stats.rx_bytes += end;
}
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;
__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_get_stats(uart_channel_t channel, uart_stats_t *stats)
{
if (channel >= UART_CHANNEL_MAX || stats == NULL) {
return;
}
*stats = g_channels[channel].stats;
}
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
memset(&g_channels[channel].stats, 0, sizeof(g_channels[channel].stats));
}
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++;
}
ctx->rx_read_index = (end == UART_RX_DMA_BUFFER_SIZE) ? 0 : end;
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
return copied;
}
/*---------------------------------------------------------------------------
* Public Functions
*---------------------------------------------------------------------------*/
/**
* @brief Initialize UART transparent transmission module
*/
int uart_trans_init(void)
uint16_t uart_trans_write(uart_channel_t channel, const uint8_t *data, uint16_t len)
{
/* Initialize Server channel (UART2) */
memset(&g_channels[UART_CHANNEL_SERVER], 0, sizeof(uart_channel_ctx_t));
g_channels[UART_CHANNEL_SERVER].huart = &huart2;
g_channels[UART_CHANNEL_SERVER].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_SERVER].config.data_bits = UART_DEFAULT_DATA_BITS;
g_channels[UART_CHANNEL_SERVER].config.stop_bits = UART_DEFAULT_STOP_BITS;
g_channels[UART_CHANNEL_SERVER].config.parity = UART_DEFAULT_PARITY;
g_channels[UART_CHANNEL_SERVER].initialized = true;
/* Initialize Client channel (UART3) */
memset(&g_channels[UART_CHANNEL_CLIENT], 0, sizeof(uart_channel_ctx_t));
g_channels[UART_CHANNEL_CLIENT].huart = &huart3;
g_channels[UART_CHANNEL_CLIENT].config.baudrate = UART_DEFAULT_BAUDRATE;
g_channels[UART_CHANNEL_CLIENT].config.data_bits = UART_DEFAULT_DATA_BITS;
g_channels[UART_CHANNEL_CLIENT].config.stop_bits = UART_DEFAULT_STOP_BITS;
g_channels[UART_CHANNEL_CLIENT].config.parity = UART_DEFAULT_PARITY;
g_channels[UART_CHANNEL_CLIENT].initialized = true;
return 0;
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;
}
/**
* @brief Configure UART channel parameters
*/
int uart_trans_config(uart_channel_t channel, const uart_config_t *config)
void uart_trans_poll(void)
{
if (channel >= UART_CHANNEL_MAX || config == NULL)
{
return -1;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
memcpy(&ctx->config, config, sizeof(uart_config_t));
/* Apply configuration if already initialized */
if (ctx->initialized)
{
return apply_uart_config(channel);
}
return 0;
kick_tx(UART_CHANNEL_SERVER);
kick_tx(UART_CHANNEL_CLIENT);
}
/**
* @brief Start UART reception
*/
int uart_trans_start(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return -1;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->initialized || ctx->huart == NULL)
{
return -1;
}
/* Reset read index */
ctx->rx_read_index = 0;
ctx->tx_busy = false;
/* Enable IDLE interrupt */
__HAL_UART_ENABLE_IT(ctx->huart, UART_IT_IDLE);
/* Start DMA reception (circular mode) */
HAL_UART_Receive_DMA(ctx->huart, ctx->rx_dma_buffer, UART_RX_DMA_BUFFER_SIZE);
ctx->running = true;
return 0;
}
/**
* @brief Stop UART reception
*/
int uart_trans_stop(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return -1;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (ctx->huart == NULL)
{
return -1;
}
/* Disable IDLE interrupt */
__HAL_UART_DISABLE_IT(ctx->huart, UART_IT_IDLE);
/* Stop DMA */
HAL_UART_DMAStop(ctx->huart);
ctx->running = false;
return 0;
}
/**
* @brief Set StreamBuffer handles
*/
void uart_trans_set_streams(uart_channel_t channel,
void *rx_stream,
void *tx_stream)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
g_channels[channel].rx_stream = (StreamBufferHandle_t)rx_stream;
g_channels[channel].tx_stream = (StreamBufferHandle_t)tx_stream;
}
/**
* @brief Get UART statistics
*/
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats)
{
if (channel >= UART_CHANNEL_MAX || stats == NULL)
{
return;
}
memcpy(stats, &g_channels[channel].stats, sizeof(uart_stats_t));
}
/**
* @brief Reset UART statistics
*/
void uart_trans_reset_stats(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
return;
}
memset(&g_channels[channel].stats, 0, sizeof(uart_stats_t));
}
/**
* @brief UART IDLE interrupt handler
*/
void uart_trans_idle_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
UART_HandleTypeDef *huart;
uint16_t dma_write_index;
if (channel >= UART_CHANNEL_MAX) {
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running || ctx->huart == NULL)
{
return;
}
/* Get current DMA position */
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
/* Process received data */
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
huart = g_channels[channel].huart;
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)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running || ctx->huart == NULL)
{
return;
}
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
}
process_rx_snapshot(channel, UART_RX_DMA_BUFFER_SIZE / 2u);
}
/**
* @brief UART DMA RX complete callback (buffer half/full)
*/
void uart_trans_rx_cplt_handler(uart_channel_t channel)
{
/* In circular mode, this is called when buffer is full */
/* The IDLE handler already processes data continuously */
/* This is a safety handler for high-speed continuous data */
if (channel >= UART_CHANNEL_MAX)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
uart_channel_ctx_t *ctx = &g_channels[channel];
if (!ctx->running)
{
return;
}
uint16_t dma_counter = __HAL_DMA_GET_COUNTER(ctx->huart->hdmarx);
uint16_t current_pos = UART_RX_DMA_BUFFER_SIZE - dma_counter;
if (current_pos != ctx->rx_read_index)
{
process_rx_data_from_isr(channel, current_pos);
}
process_rx_snapshot(channel, 0u);
}
/**
* @brief UART DMA TX complete callback
*/
void uart_trans_tx_cplt_handler(uart_channel_t channel)
{
if (channel >= UART_CHANNEL_MAX)
{
if (channel >= UART_CHANNEL_MAX) {
return;
}
g_channels[channel].tx_busy = false;
}
/**
* @brief Server transparent transmission task (UART2 <-> TCP Server)
*/
void uart_server_trans_task(void *argument)
{
uart_channel_ctx_t *ctx = &g_channels[UART_CHANNEL_SERVER];
uint8_t tx_buffer[128];
size_t len;
(void)argument;
/* Wait for streams to be set */
while (ctx->rx_stream == NULL || ctx->tx_stream == NULL)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
/* Start UART reception */
uart_trans_start(UART_CHANNEL_SERVER);
while (1)
{
/* Check for data from TCP to send to UART */
if (!ctx->tx_busy && ctx->rx_stream != NULL)
{
len = xStreamBufferReceive(ctx->rx_stream, tx_buffer,
sizeof(tx_buffer), pdMS_TO_TICKS(10));
if (len > 0)
{
/* Copy to DMA buffer and send */
memcpy(ctx->tx_dma_buffer, tx_buffer, len);
ctx->tx_busy = true;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, len) != HAL_OK)
{
ctx->tx_busy = false;
ctx->stats.errors++;
}
else
{
ctx->stats.tx_bytes += len;
ctx->stats.tx_packets++;
}
}
}
else
{
/* TX busy or no stream, wait a bit */
vTaskDelay(pdMS_TO_TICKS(1));
}
}
}
/**
* @brief Client transparent transmission task (UART3 <-> TCP Client)
*/
void uart_client_trans_task(void *argument)
{
uart_channel_ctx_t *ctx = &g_channels[UART_CHANNEL_CLIENT];
uint8_t tx_buffer[128];
size_t len;
(void)argument;
/* Wait for streams to be set */
while (ctx->rx_stream == NULL || ctx->tx_stream == NULL)
{
vTaskDelay(pdMS_TO_TICKS(100));
}
/* Start UART reception */
uart_trans_start(UART_CHANNEL_CLIENT);
while (1)
{
/* Check for data from TCP to send to UART */
if (!ctx->tx_busy && ctx->rx_stream != NULL)
{
len = xStreamBufferReceive(ctx->rx_stream, tx_buffer,
sizeof(tx_buffer), pdMS_TO_TICKS(10));
if (len > 0)
{
/* Copy to DMA buffer and send */
memcpy(ctx->tx_dma_buffer, tx_buffer, len);
ctx->tx_busy = true;
if (HAL_UART_Transmit_DMA(ctx->huart, ctx->tx_dma_buffer, len) != HAL_OK)
{
ctx->tx_busy = false;
ctx->stats.errors++;
}
else
{
ctx->stats.tx_bytes += len;
ctx->stats.tx_packets++;
}
}
}
else
{
/* TX busy or no stream, wait a bit */
vTaskDelay(pdMS_TO_TICKS(1));
}
}
g_channels[channel].stats.tx_bytes += g_channels[channel].tx_dma_len;
g_channels[channel].tx_dma_len = 0u;
kick_tx(channel);
}