223 lines
6.1 KiB
C
223 lines
6.1 KiB
C
/**
|
|
******************************************************************************
|
|
* @file cmd_router.c
|
|
* @brief 指令路由与响应分发模块实现
|
|
* @author Application Layer
|
|
* @version 1.0
|
|
******************************************************************************
|
|
* @attention
|
|
* 本模块实现指令路由与响应分发功能
|
|
* 设计依据:多通信接口统一指令处理系统开发计划 第3.2节
|
|
*
|
|
* 核心职责:
|
|
* - 从各UART端口读取数据并喂入解析器
|
|
* - 根据指令来源端口路由响应
|
|
* - 管理响应路由表
|
|
*
|
|
* 工作流程:
|
|
* 1. 中断中将接收字节写入对应端口的环形缓冲区
|
|
* 2. 主循环中CmdRouter_Task轮询各端口缓冲区
|
|
* 3. 读取字节喂入CmdParser解析器
|
|
* 4. 解析完成后通过回调发送响应到源端口
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "cmd_router.h"
|
|
#include "multi_uart_router.h"
|
|
#include "cmd_parser.h"
|
|
#include "uart2_print.h"
|
|
#include "debug_log.h"
|
|
#include <string.h>
|
|
|
|
#define DEBUG_CMD_ROUTER 1
|
|
|
|
#if DEBUG_CMD_ROUTER
|
|
#define ROUTER_LOG(fmt, ...) UART2_Print_Printf("[ROUTER] " fmt "\r\n", ##__VA_ARGS__)
|
|
#else
|
|
#define ROUTER_LOG(fmt, ...)
|
|
#endif
|
|
|
|
#define RX_LOG_BUFFER_SIZE 128
|
|
|
|
typedef struct {
|
|
uint8_t source_port;
|
|
uint32_t last_feed_tick;
|
|
uint32_t rx_count;
|
|
bool active;
|
|
} port_parser_state_t;
|
|
|
|
static port_parser_state_t g_port_states[PORT_COUNT];
|
|
|
|
static cmd_response_handler_t g_response_handler = NULL;
|
|
|
|
static uint32_t g_processed_count = 0;
|
|
static uint32_t g_routed_count = 0;
|
|
|
|
static uint8_t g_current_parsing_port = PORT_UART2;
|
|
|
|
static uint8_t g_rx_log_buffer[PORT_COUNT][RX_LOG_BUFFER_SIZE];
|
|
static uint16_t g_rx_log_len[PORT_COUNT];
|
|
static uint32_t g_rx_log_last_tick[PORT_COUNT];
|
|
#define RX_LOG_TIMEOUT_MS 50
|
|
|
|
static void flush_rx_log(port_id_t port_id)
|
|
{
|
|
if (g_rx_log_len[port_id] == 0) {
|
|
return;
|
|
}
|
|
|
|
UART2_Print_Printf("[ROUTER] %s RX: \"", MultiUART_GetPortName(port_id));
|
|
|
|
for (uint16_t i = 0; i < g_rx_log_len[port_id]; i++) {
|
|
uint8_t c = g_rx_log_buffer[port_id][i];
|
|
if (c >= 0x20 && c < 0x7F) {
|
|
UART2_Print_Send(&c, 1);
|
|
} else if (c == '\r') {
|
|
UART2_Print_Send((const uint8_t *)"\\r", 2);
|
|
} else if (c == '\n') {
|
|
UART2_Print_Send((const uint8_t *)"\\n", 2);
|
|
} else {
|
|
char hex[4];
|
|
snprintf(hex, sizeof(hex), "\\x%02X", c);
|
|
UART2_Print_Send((const uint8_t *)hex, 4);
|
|
}
|
|
}
|
|
|
|
UART2_Print_String("\"\r\n");
|
|
|
|
g_rx_log_len[port_id] = 0;
|
|
}
|
|
|
|
static void append_rx_log(port_id_t port_id, uint8_t byte)
|
|
{
|
|
if (g_rx_log_len[port_id] < RX_LOG_BUFFER_SIZE) {
|
|
g_rx_log_buffer[port_id][g_rx_log_len[port_id]++] = byte;
|
|
}
|
|
g_rx_log_last_tick[port_id] = HAL_GetTick();
|
|
}
|
|
|
|
static void cmd_parser_response_callback(uint8_t source_port, const char *response)
|
|
{
|
|
if (g_response_handler != NULL) {
|
|
g_response_handler((port_id_t)source_port, response, strlen(response));
|
|
g_routed_count++;
|
|
} else {
|
|
MultiUART_SendString((port_id_t)source_port, response);
|
|
g_routed_count++;
|
|
}
|
|
|
|
LOG_INFO("ROUTER", "TX[%s]: %s",
|
|
MultiUART_GetPortName((port_id_t)source_port), response);
|
|
}
|
|
|
|
void CmdRouter_Init(void)
|
|
{
|
|
for (port_id_t i = 0; i < PORT_COUNT; i++) {
|
|
g_port_states[i].source_port = i;
|
|
g_port_states[i].last_feed_tick = 0;
|
|
g_port_states[i].rx_count = 0;
|
|
g_port_states[i].active = false;
|
|
|
|
g_rx_log_len[i] = 0;
|
|
g_rx_log_last_tick[i] = 0;
|
|
}
|
|
|
|
g_response_handler = NULL;
|
|
g_processed_count = 0;
|
|
g_routed_count = 0;
|
|
g_current_parsing_port = PORT_UART2;
|
|
|
|
CmdParser_SetResponseCallback(cmd_parser_response_callback);
|
|
|
|
ROUTER_LOG("Init OK, %d ports registered", PORT_COUNT);
|
|
}
|
|
|
|
void CmdRouter_Task(void)
|
|
{
|
|
uint32_t current_tick = HAL_GetTick();
|
|
|
|
for (port_id_t port_id = 0; port_id < PORT_COUNT; port_id++) {
|
|
if (port_id == PORT_UART2) {
|
|
continue;
|
|
}
|
|
|
|
if (g_rx_log_len[port_id] > 0 &&
|
|
(current_tick - g_rx_log_last_tick[port_id]) >= RX_LOG_TIMEOUT_MS) {
|
|
flush_rx_log(port_id);
|
|
}
|
|
}
|
|
|
|
for (port_id_t port_id = 0; port_id < PORT_COUNT; port_id++) {
|
|
if (port_id == PORT_UART2) {
|
|
continue;
|
|
}
|
|
|
|
uint16_t rx_count = MultiUART_GetRxCount(port_id);
|
|
|
|
if (rx_count == 0) {
|
|
continue;
|
|
}
|
|
|
|
g_current_parsing_port = port_id;
|
|
CmdParser_SetSourcePort(port_id);
|
|
|
|
uint8_t byte;
|
|
while (MultiUART_ReadByte(port_id, &byte) > 0) {
|
|
append_rx_log(port_id, byte);
|
|
CmdParser_FeedByte(byte, HAL_GetTick());
|
|
g_port_states[port_id].rx_count++;
|
|
}
|
|
|
|
if (CmdParser_HasCompleteFrame(NULL)) {
|
|
flush_rx_log(port_id);
|
|
g_processed_count++;
|
|
g_port_states[port_id].active = true;
|
|
}
|
|
}
|
|
|
|
CmdParser_Task();
|
|
}
|
|
|
|
void CmdRouter_SetResponseHandler(cmd_response_handler_t handler)
|
|
{
|
|
g_response_handler = handler;
|
|
ROUTER_LOG("Response handler %s", handler ? "set" : "cleared");
|
|
}
|
|
|
|
void CmdRouter_SendResponse(port_id_t port, const char *response, uint16_t len)
|
|
{
|
|
if (port >= PORT_COUNT || response == NULL || len == 0) {
|
|
return;
|
|
}
|
|
|
|
MultiUART_Send(port, (const uint8_t *)response, len);
|
|
g_routed_count++;
|
|
|
|
LOG_INFO("ROUTER", "SendResponse[%s]: %.*s",
|
|
MultiUART_GetPortName(port), len, response);
|
|
}
|
|
|
|
void CmdRouter_BroadcastResponse(const char *response, uint16_t len)
|
|
{
|
|
if (response == NULL || len == 0) {
|
|
return;
|
|
}
|
|
|
|
for (port_id_t port = 0; port < PORT_COUNT; port++) {
|
|
MultiUART_Send(port, (const uint8_t *)response, len);
|
|
g_routed_count++;
|
|
}
|
|
|
|
LOG_INFO("ROUTER", "Broadcast: %.*s", len, response);
|
|
}
|
|
|
|
uint32_t CmdRouter_GetProcessedCount(void)
|
|
{
|
|
return g_processed_count;
|
|
}
|
|
|
|
uint32_t CmdRouter_GetRoutedCount(void)
|
|
{
|
|
return g_routed_count;
|
|
}
|