Files
433_STM32/Core/Src/uart3_passthrough.c

269 lines
7.8 KiB
C
Raw Permalink Normal View History

/**
******************************************************************************
* @file uart3_passthrough.c
* @brief UART3透传引擎模块实现
* @author Application Layer
* @version 1.0
******************************************************************************
* @attention
* UART3智能数据路由与透传功能开发计划 3.2
*
*
* UART3接收的透传数据转发至UART1
*
* 3.2.3
* 1.
* 2. UART1是否可发送
* 3.
* 4.
* 5.
*
*
* - UART1 TX完成中断驱动连续发送
* - 使
******************************************************************************
*/
#include "uart3_passthrough.h"
#include "uart3_smart_router_config.h"
#include "multi_uart_router.h"
#include "uart2_print.h"
#include <string.h>
/*==============================================================================
*
*============================================================================*/
#if DEBUG_PASSTHROUGH_ENGINE
#define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[PTX] " fmt "\r\n", ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...)
#endif
/*==============================================================================
*
* 3.2.2
*============================================================================*/
/**
* @brief
* @note
*/
passthrough_context_t g_passthrough_ctx;
/*==============================================================================
*
* 3.2.1
*============================================================================*/
/**
* @brief
* @note
*/
void Passthrough_Init(void)
{
memset(&g_passthrough_ctx, 0, sizeof(g_passthrough_ctx));
for (uint8_t i = 0; i < PASSTHROUGH_MAX_NODES; i++) {
g_passthrough_ctx.queue.nodes[i].valid = false;
g_passthrough_ctx.queue.nodes[i].length = 0;
g_passthrough_ctx.queue.nodes[i].offset = 0;
}
g_passthrough_ctx.queue.write_index = 0;
g_passthrough_ctx.queue.read_index = 0;
g_passthrough_ctx.queue.pending_count = 0;
g_passthrough_ctx.stats.total_bytes_sent = 0;
g_passthrough_ctx.stats.total_packets = 0;
g_passthrough_ctx.stats.overflow_count = 0;
g_passthrough_ctx.stats.busy_count = 0;
g_passthrough_ctx.initialized = true;
DEBUG_LOG("Passthrough engine initialized, buffer size: %d bytes", PASSTHROUGH_TOTAL_BUFFER);
}
/**
* @brief
* @note
* @param byte:
* @retval bool: true=false=
*/
bool Passthrough_PushByte(uint8_t byte)
{
passthrough_context_t *ctx = &g_passthrough_ctx;
if (!ctx->initialized) {
return false;
}
uint8_t next_index = (ctx->queue.write_index + 1) % PASSTHROUGH_MAX_NODES;
if (next_index == ctx->queue.read_index && ctx->queue.pending_count > 0) {
ctx->stats.overflow_count++;
DEBUG_LOG("Buffer full, overflow count: %d", ctx->stats.overflow_count);
return false;
}
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.write_index];
if (!node->valid || node->length >= PASSTHROUGH_NODE_SIZE) {
if (node->valid) {
ctx->queue.write_index = next_index;
node = &ctx->queue.nodes[ctx->queue.write_index];
}
node->length = 0;
node->offset = 0;
node->valid = true;
}
node->data[node->length++] = byte;
ctx->queue.pending_count++;
return true;
}
/**
* @brief
* @note
* @param data:
* @param length:
* @retval uint16_t:
*/
uint16_t Passthrough_PushBuffer(const uint8_t *data, uint16_t length)
{
if (data == NULL || length == 0) {
return 0;
}
passthrough_context_t *ctx = &g_passthrough_ctx;
uint16_t written = 0;
for (uint16_t i = 0; i < length; i++) {
uint8_t next_index = (ctx->queue.write_index + 1) % PASSTHROUGH_MAX_NODES;
if (next_index == ctx->queue.read_index && ctx->queue.pending_count > 0) {
ctx->stats.overflow_count++;
DEBUG_LOG("Buffer overflow at byte %d/%d", i, length);
break;
}
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.write_index];
if (!node->valid || node->length >= PASSTHROUGH_NODE_SIZE) {
if (node->valid) {
ctx->queue.write_index = next_index;
node = &ctx->queue.nodes[ctx->queue.write_index];
}
node->length = 0;
node->offset = 0;
node->valid = true;
}
node->data[node->length++] = data[i];
ctx->queue.pending_count++;
written++;
}
if (written > 0) {
ctx->stats.total_packets++;
DEBUG_LOG("Pushed %d bytes to buffer, pending: %d", written, ctx->queue.pending_count);
}
return written;
}
/**
* @brief
* @note
* UART1 TX完成中断实现连续发送
*/
void Passthrough_Task(void)
{
passthrough_context_t *ctx = &g_passthrough_ctx;
if (!ctx->initialized) {
return;
}
if (ctx->queue.pending_count == 0) {
return;
}
if (!Passthrough_CanSend()) {
ctx->stats.busy_count++;
return;
}
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.read_index];
if (!node->valid || node->offset >= node->length) {
if (node->valid) {
node->valid = false;
}
ctx->queue.read_index = (ctx->queue.read_index + 1) % PASSTHROUGH_MAX_NODES;
return;
}
uint8_t byte = node->data[node->offset++];
MultiUART_Send(PORT_UART1, &byte, 1);
ctx->queue.pending_count--;
ctx->stats.total_bytes_sent++;
DEBUG_LOG("Sent byte 0x%02X, pending: %d", byte, ctx->queue.pending_count);
}
/**
* @brief UART1发送完成回调
* @note HAL_UART_TxCpltCallback中调用
*/
void Passthrough_OnTxComplete(void)
{
Passthrough_Task();
}
/**
* @brief UART1是否可发送
* @note UART1发送缓冲区是否有空间
* @retval bool: true=false=
*/
bool Passthrough_CanSend(void)
{
return (MultiUART_GetTxAvailable(PORT_UART1) > 0) &&
(g_passthrough_ctx.queue.pending_count > 0);
}
/**
* @brief
* @note
* @param stats:
*/
void Passthrough_GetStats(passthrough_stats_t *stats)
{
if (stats != NULL) {
memcpy(stats, &g_passthrough_ctx.stats, sizeof(passthrough_stats_t));
}
}
/**
* @brief
* @note
*/
void Passthrough_ResetStats(void)
{
passthrough_context_t *ctx = &g_passthrough_ctx;
ctx->stats.total_bytes_sent = 0;
ctx->stats.total_packets = 0;
ctx->stats.overflow_count = 0;
ctx->stats.busy_count = 0;
DEBUG_LOG("Stats reset");
}
/**
* @brief
* @note
* @retval uint16_t:
*/
uint16_t Passthrough_GetPendingCount(void)
{
return g_passthrough_ctx.queue.pending_count;
}