feat: save stable CH390 bridge baseline
This commit is contained in:
+113
-82
@@ -1,14 +1,17 @@
|
||||
/**
|
||||
* @file uart_trans.c
|
||||
* @brief Bare-metal UART DMA/IDLE transport layer.
|
||||
* @brief Bare-metal UART DMA/IDLE transport and MUX helpers.
|
||||
*/
|
||||
|
||||
#include "uart_trans.h"
|
||||
|
||||
#include "usart.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];
|
||||
@@ -40,55 +43,23 @@ 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;
|
||||
}
|
||||
|
||||
static int apply_uart_config(uart_channel_t channel)
|
||||
{
|
||||
uart_channel_ctx_t *ctx = &g_channels[channel];
|
||||
UART_HandleTypeDef *huart = ctx->huart;
|
||||
uint32_t word_length;
|
||||
uint32_t parity;
|
||||
|
||||
if (huart == NULL) {
|
||||
if (ctx->huart == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->running) {
|
||||
HAL_UART_DMAStop(huart);
|
||||
HAL_UART_DMAStop(ctx->huart);
|
||||
ctx->running = false;
|
||||
}
|
||||
|
||||
huart->Init.BaudRate = ctx->config.baudrate;
|
||||
huart->Init.StopBits = (ctx->config.stop_bits == 2u) ? UART_STOPBITS_2 : UART_STOPBITS_1;
|
||||
|
||||
switch (ctx->config.parity) {
|
||||
case 1:
|
||||
parity = UART_PARITY_ODD;
|
||||
break;
|
||||
case 2:
|
||||
parity = UART_PARITY_EVEN;
|
||||
break;
|
||||
default:
|
||||
parity = UART_PARITY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (parity == UART_PARITY_NONE) {
|
||||
word_length = (ctx->config.data_bits == 9u) ? UART_WORDLENGTH_9B : UART_WORDLENGTH_8B;
|
||||
} else {
|
||||
word_length = (ctx->config.data_bits >= 8u) ? UART_WORDLENGTH_9B : UART_WORDLENGTH_8B;
|
||||
}
|
||||
|
||||
huart->Init.WordLength = word_length;
|
||||
huart->Init.Parity = parity;
|
||||
|
||||
return (HAL_UART_Init(huart) == HAL_OK) ? 0 : -1;
|
||||
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)
|
||||
@@ -96,9 +67,7 @@ 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);
|
||||
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;
|
||||
@@ -149,16 +118,12 @@ static void kick_tx(uart_channel_t channel)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -167,7 +132,6 @@ 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);
|
||||
}
|
||||
@@ -208,29 +172,16 @@ 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)
|
||||
void uart_trans_poll(void)
|
||||
{
|
||||
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));
|
||||
kick_tx(UART_CHANNEL_U0);
|
||||
kick_tx(UART_CHANNEL_U1);
|
||||
}
|
||||
|
||||
uint16_t uart_trans_rx_available(uart_channel_t channel)
|
||||
@@ -238,7 +189,6 @@ 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);
|
||||
}
|
||||
|
||||
@@ -256,11 +206,9 @@ uint16_t uart_trans_read(uart_channel_t channel, uint8_t *data, uint16_t max_len
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -287,10 +235,18 @@ uint16_t uart_trans_write(uart_channel_t channel, const uint8_t *data, uint16_t
|
||||
return written;
|
||||
}
|
||||
|
||||
void uart_trans_poll(void)
|
||||
void uart_trans_get_stats(uart_channel_t channel, uart_stats_t *stats)
|
||||
{
|
||||
kick_tx(UART_CHANNEL_SERVER);
|
||||
kick_tx(UART_CHANNEL_CLIENT);
|
||||
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)
|
||||
@@ -301,14 +257,12 @@ void uart_trans_idle_handler(uart_channel_t channel)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -317,7 +271,6 @@ 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);
|
||||
}
|
||||
@@ -327,7 +280,6 @@ 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);
|
||||
}
|
||||
@@ -337,9 +289,88 @@ 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 header[5];
|
||||
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;
|
||||
}
|
||||
|
||||
if (uart_trans_read(channel, header, sizeof(header)) != sizeof(header)) {
|
||||
return false;
|
||||
}
|
||||
if (header[0] != UART_MUX_SYNC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
payload_len = (uint16_t)(((uint16_t)header[1] << 8) | header[2]);
|
||||
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[3];
|
||||
frame->dst_mask = header[4];
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user