本次重构完成了 433MHz 全链路协议统一:实现了 AA TYPE LEN ID PAYLOAD SUM 统一帧格式;引入了基于 AUX 的 LBT 避让与 TX 优先调度,确保高频发送稳定;完成了端口语义化重命名;并成功集成了 IO 监控、RS485 及 W5500 以太网 的标准化打包转发,实现了多源数据的高效、稳定透传。
This commit is contained in:
@ -113,7 +113,7 @@ static uint32_t g_routed_count = 0;
|
||||
* @brief 当前正在解析的端口ID
|
||||
* @note 用于在多端口环境下跟踪当前处理哪个端口的数据
|
||||
*/
|
||||
static uint8_t g_current_parsing_port = PORT_UART2;
|
||||
static uint8_t g_current_parsing_port = PORT_DEBUG;
|
||||
|
||||
/**
|
||||
* @brief 接收原始字节日志缓冲区
|
||||
@ -275,7 +275,7 @@ static void cmd_parser_response_callback(uint8_t source_port, const char *respon
|
||||
* 1. 重置所有端口的解析状态
|
||||
* 2. 清零所有日志缓冲区
|
||||
* 3. 重置统计计数器
|
||||
* 4. 设置默认解析端口为PORT_UART2
|
||||
* 4. 设置默认解析端口为PORT_DEBUG
|
||||
* 5. 注册响应回调函数到解析器
|
||||
*/
|
||||
void CmdRouter_Init(void)
|
||||
@ -299,7 +299,7 @@ void CmdRouter_Init(void)
|
||||
g_response_handler = NULL;
|
||||
g_processed_count = 0;
|
||||
g_routed_count = 0;
|
||||
g_current_parsing_port = PORT_UART2;
|
||||
g_current_parsing_port = PORT_DEBUG;
|
||||
|
||||
/*----------------------------------------------------------
|
||||
* 注册响应回调函数
|
||||
@ -348,7 +348,7 @@ void CmdRouter_Task(void)
|
||||
* 第一阶段:UART1处理(保持原有逻辑)
|
||||
*----------------------------------------------------------*/
|
||||
{
|
||||
port_id_t port_id = PORT_UART1;
|
||||
port_id_t port_id = PORT_433;
|
||||
|
||||
uint16_t rx_count = MultiUART_GetRxCount(port_id);
|
||||
|
||||
@ -380,11 +380,11 @@ void CmdRouter_Task(void)
|
||||
LOG_DEBUG("UART3", "Protocol state: %d", UART3_Protocol_GetState());
|
||||
uint8_t byte;
|
||||
|
||||
while (MultiUART_ReadByte(PORT_UART3, &byte) > 0) {
|
||||
while (MultiUART_ReadByte(PORT_RS485, &byte) > 0) {
|
||||
route_result_t route = UART3_Protocol_FeedByte(byte, current_tick);
|
||||
switch (route) {
|
||||
case ROUTE_CMD:
|
||||
CmdParser_SetSourcePort(PORT_UART3);
|
||||
CmdParser_SetSourcePort(PORT_RS485);
|
||||
CmdParser_FeedByte(byte, current_tick);
|
||||
LOG_DEBUG("UART3", "CMD byte: 0x%02X", byte);
|
||||
break;
|
||||
@ -422,7 +422,7 @@ void CmdRouter_Task(void)
|
||||
int appended = snprintf(msg + msg_len, sizeof(msg) - msg_len, "*%02X\r\n", cs);
|
||||
LOG_DEBUG("UART3", "Constructed message: %s", msg);
|
||||
// 发送ASCII消息
|
||||
MultiUART_SendString(PORT_UART1, msg);
|
||||
MultiUART_SendString(PORT_433, msg);
|
||||
LOG_INFO("UART3", "PASSTHROUGH: %d bytes sent as ASCII message", (int)length);
|
||||
} else {
|
||||
LOG_DEBUG("UART3", "No passthrough data");
|
||||
@ -433,7 +433,7 @@ void CmdRouter_Task(void)
|
||||
}
|
||||
#else
|
||||
{
|
||||
port_id_t port_id = PORT_UART3;
|
||||
port_id_t port_id = PORT_RS485;
|
||||
|
||||
uint16_t rx_count = MultiUART_GetRxCount(port_id);
|
||||
|
||||
@ -461,7 +461,7 @@ void CmdRouter_Task(void)
|
||||
* 第三阶段:检查各端口日志缓冲区的超时状态
|
||||
*----------------------------------------------------------*/
|
||||
for (port_id_t port_id = 0; port_id < PORT_COUNT; port_id++) {
|
||||
if (port_id == PORT_UART2) {
|
||||
if (port_id == PORT_DEBUG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -112,6 +112,146 @@ void DebugLog_EnableModule(const char *module, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
void DebugLog_Output(log_level_t level, const char *module, const char *fmt, ...)
|
||||
{
|
||||
if (level < g_current_level) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_module_enabled(module)) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[256];
|
||||
int len = 0;
|
||||
|
||||
len += snprintf(buffer + len, sizeof(buffer) - len, "[%s][%s] ",
|
||||
g_level_str[level], module ? module : "MAIN");
|
||||
|
||||
if (len < (int)sizeof(buffer) - 1) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
len += vsnprintf(buffer + len, sizeof(buffer) - len, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
if (len > 0 && len < (int)sizeof(buffer)) {
|
||||
buffer[len++] = '\r';
|
||||
if (len < (int)sizeof(buffer)) {
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file debug_log.c
|
||||
* @brief 增强型调试日志系统实现
|
||||
* @author Application Layer
|
||||
* @version 1.0
|
||||
******************************************************************************
|
||||
* @attention
|
||||
* 本模块实现增强型调试日志系统
|
||||
* 设计依据:多通信接口统一指令处理系统开发计划 第3.4节
|
||||
*
|
||||
* 日志格式:[LEVEL][MODULE] message
|
||||
* 示例:[INFO][CMD] Command received: RL
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "debug_log.h"
|
||||
#include "uart2_print.h"
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "multi_uart_router.h"
|
||||
#define MAX_MODULES 16
|
||||
#define MODULE_NAME_LEN 16
|
||||
|
||||
typedef struct {
|
||||
char name[MODULE_NAME_LEN];
|
||||
bool enabled;
|
||||
} module_config_t;
|
||||
|
||||
static log_level_t g_current_level = LOG_LEVEL_DEBUG;
|
||||
static module_config_t g_modules[MAX_MODULES];
|
||||
static bool g_modules_initialized = false;
|
||||
|
||||
static const char *const g_level_str[] = {
|
||||
[LOG_LEVEL_DEBUG] = "DEBUG",
|
||||
[LOG_LEVEL_INFO] = "INFO ",
|
||||
[LOG_LEVEL_WARN] = "WARN ",
|
||||
[LOG_LEVEL_ERROR] = "ERROR",
|
||||
};
|
||||
|
||||
static void init_modules(void)
|
||||
{
|
||||
if (g_modules_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_MODULES; i++) {
|
||||
g_modules[i].name[0] = '\0';
|
||||
g_modules[i].enabled = false;
|
||||
}
|
||||
|
||||
g_modules_initialized = true;
|
||||
}
|
||||
|
||||
static bool is_module_enabled(const char *module)
|
||||
{
|
||||
if (module == NULL || module[0] == '\0') {
|
||||
return true;
|
||||
}
|
||||
|
||||
init_modules();
|
||||
|
||||
for (int i = 0; i < MAX_MODULES; i++) {
|
||||
if (g_modules[i].name[0] != '\0' &&
|
||||
strncmp(g_modules[i].name, module, MODULE_NAME_LEN - 1) == 0) {
|
||||
return g_modules[i].enabled;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebugLog_Init(void)
|
||||
{
|
||||
g_current_level = LOG_LEVEL_DEBUG;
|
||||
init_modules();
|
||||
|
||||
UART2_Print_String("[LOG] Debug log system initialized\r\n");
|
||||
}
|
||||
|
||||
void DebugLog_SetLevel(log_level_t level)
|
||||
{
|
||||
g_current_level = level;
|
||||
}
|
||||
|
||||
log_level_t DebugLog_GetLevel(void)
|
||||
{
|
||||
return g_current_level;
|
||||
}
|
||||
|
||||
void DebugLog_EnableModule(const char *module, bool enable)
|
||||
{
|
||||
if (module == NULL || module[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
init_modules();
|
||||
|
||||
for (int i = 0; i < MAX_MODULES; i++) {
|
||||
if (g_modules[i].name[0] == '\0') {
|
||||
strncpy(g_modules[i].name, module, MODULE_NAME_LEN - 1);
|
||||
g_modules[i].name[MODULE_NAME_LEN - 1] = '\0';
|
||||
g_modules[i].enabled = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp(g_modules[i].name, module, MODULE_NAME_LEN - 1) == 0) {
|
||||
g_modules[i].enabled = enable;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DebugLog_Output(log_level_t level, const char *module, const char *fmt, ...)
|
||||
{
|
||||
if (level < g_current_level) {
|
||||
@ -144,6 +284,6 @@ void DebugLog_Output(log_level_t level, const char *module, const char *fmt, ...
|
||||
|
||||
if (len > 0) {
|
||||
UART2_Print_Send((const uint8_t *)buffer, len);
|
||||
MultiUART_Send(PORT_UART3, (const uint8_t *)buffer, len); /* 增加:同时将日志发给 UART3 */
|
||||
MultiUART_Send(PORT_RS485, (const uint8_t *)buffer, len); /* 增加:同时将日志发给 RS485 */
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ static void send_di_event(uint8_t channel, uint8_t state)
|
||||
memcpy(&rf_tx_buf[2], msg, msg_len); // 把真正的 DI 消息塞到第 2 个字节后面
|
||||
|
||||
/* 将带 ID 的完整包裹发送给 433 模块 */
|
||||
MultiUART_Send(PORT_UART1, rf_tx_buf, msg_len + 2);
|
||||
MultiUART_Send(PORT_433, rf_tx_buf, msg_len + 2);
|
||||
/* ========================================================== */
|
||||
|
||||
DEBUG_LOG("RF433 TX: \"%s\"", msg);
|
||||
@ -261,8 +261,8 @@ void IO_Monitor_Init(void)
|
||||
|
||||
/* 初始化扫描时间戳为0,确保首次扫描立即执行 */
|
||||
last_scan_tick = 0;
|
||||
/* 使能自动上报功能 */
|
||||
report_enabled = true;
|
||||
/* 禁用旧的自动上报功能,改用 main.c 中的新协议上报 */
|
||||
report_enabled = false;
|
||||
|
||||
/* 输出初始化完成日志,显示初始各通道状态掩码 */
|
||||
DEBUG_LOG("Init OK, initial states: 0x%02X", IO_Monitor_GetAllStates());
|
||||
|
||||
209
Core/Src/main.c
209
Core/Src/main.c
@ -85,11 +85,89 @@ static uint8_t u1_rx_buffer[256];
|
||||
static volatile uint16_t u1_rx_len = 0;
|
||||
static volatile uint32_t u1_last_rx_time = 0;
|
||||
|
||||
/* === 485 设备的接收缓存 (UART3) 增加这三行!=== */
|
||||
/* === 485 设备的接收缓存 (UART3) === */
|
||||
static uint8_t u3_rx_buffer[512];
|
||||
static volatile uint16_t u3_rx_len = 0;
|
||||
static volatile uint32_t u3_last_rx_time = 0;
|
||||
static volatile uint32_t u3_ignore_until = 0;
|
||||
|
||||
/* === 协议处理全局变量 === */
|
||||
static uint16_t g_hb_seq = 0; /* 心跳序列号 */
|
||||
static uint32_t g_last_hb_tick = 0; /* 上次心跳时间 */
|
||||
static uint8_t g_last_io_state = 0xFF; /* 上次记录的 IO 状态,用于变化检测 */
|
||||
|
||||
/* === W5500 外部变量声明 === */
|
||||
#if USE_W5500
|
||||
extern uint16_t local_port;
|
||||
extern uint8_t ethernet_buf[];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 判断单片机与 433 模块连接的串口是否正忙于传输
|
||||
* @return bool: true=串口引擎忙(需避让), false=串口空闲
|
||||
*/
|
||||
bool RF433_UART_Is_Busy(void)
|
||||
{
|
||||
// 仅查询 UART1 的引擎状态,不关心模块 AUX
|
||||
return MultiUART_IsBusy(PORT_433);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算并发送 RF433 协议数据包
|
||||
|
||||
* @param type: 协议类型 (0x10, 0x55, 0x48, 0xAA)
|
||||
* @param payload: 载荷数据指针
|
||||
* @param len: 载荷长度
|
||||
*/
|
||||
void RF433_SendPacket(uint8_t type, const uint8_t *payload, uint8_t len)
|
||||
{
|
||||
uint8_t frame[260];
|
||||
uint16_t frame_idx = 0;
|
||||
uint8_t checksum = 0;
|
||||
|
||||
frame[frame_idx++] = PROTO_START_BYTE; // AA
|
||||
frame[frame_idx++] = type; // TYPE
|
||||
frame[frame_idx++] = (uint8_t)(len + 1); // LEN (ID + Payload)
|
||||
frame[frame_idx++] = MY_DEVICE_ID; // ID
|
||||
|
||||
if (len > 0 && payload != NULL) {
|
||||
memcpy(&frame[frame_idx], payload, len);
|
||||
frame_idx += len;
|
||||
}
|
||||
|
||||
/* 计算校验和 (Sum8) */
|
||||
for (uint16_t i = 0; i < frame_idx; i++) {
|
||||
checksum += frame[i];
|
||||
}
|
||||
frame[frame_idx++] = checksum;
|
||||
|
||||
/* 通过 MultiUART 发送 */
|
||||
MultiUART_Send(PORT_433, frame, frame_idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查 433 无线信道是否忙碌 (发送保护区)
|
||||
* @return bool: true=忙碌(需避让), false=空闲
|
||||
*/
|
||||
bool RF433_Is_Air_Busy(void)
|
||||
{
|
||||
return (HAL_GPIO_ReadPin(AUX_GPIO_Port, AUX_Pin) == GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取当前 4 路 DI 的合并状态
|
||||
* @return uint8_t: Bit0-3 对应 DI1-4
|
||||
*/
|
||||
uint8_t IO_Get_Current_State(void)
|
||||
{
|
||||
uint8_t state = 0;
|
||||
if (HAL_GPIO_ReadPin(MCU_DI1_GPIO_Port, MCU_DI1_Pin) == GPIO_PIN_SET) state |= (1 << 0);
|
||||
if (HAL_GPIO_ReadPin(MCU_DI2_GPIO_Port, MCU_DI2_Pin) == GPIO_PIN_SET) state |= (1 << 1);
|
||||
if (HAL_GPIO_ReadPin(MCU_DI3_GPIO_Port, MCU_DI3_Pin) == GPIO_PIN_SET) state |= (1 << 2);
|
||||
if (HAL_GPIO_ReadPin(MCU_DI4_GPIO_Port, MCU_DI4_Pin) == GPIO_PIN_SET) state |= (1 << 3);
|
||||
return state;
|
||||
}
|
||||
|
||||
/* W5500 variables */
|
||||
#if USE_W5500
|
||||
#define SOCKET_ID 0
|
||||
@ -240,74 +318,36 @@ int main(void)
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
/* === 1. 恢复系统的核心驱动引擎 === */
|
||||
/* === 1. 核心通信驱动引擎 (最高优先级) === */
|
||||
UART2_Print_Task();
|
||||
MultiUART_Task();
|
||||
IO_Monitor_Task();
|
||||
|
||||
/* === 2. 网络轮询任务 === */
|
||||
#if USE_W5500
|
||||
loopback_udps(SOCKET_ID, ethernet_buf, local_port);
|
||||
#endif
|
||||
|
||||
/* === 3. 极速无乱码透传 === */
|
||||
|
||||
/* === 方案 A:从 433 收到无线数据 -> 给上位机解析 === */
|
||||
/* === 2. 无线接收透传 (433 -> 485/Debug) === */
|
||||
#if (RF433_MODE == RF433_MODE_RX) || (RF433_MODE == RF433_MODE_BOTH)
|
||||
// 如果 433 收到无线数据,直接透传输出,不进行解码
|
||||
if (u1_rx_len > 0 && (HAL_GetTick() - u1_last_rx_time > 20))
|
||||
{
|
||||
static uint8_t temp_buf1[256];
|
||||
__disable_irq();
|
||||
__disable_irq();
|
||||
uint16_t len = u1_rx_len;
|
||||
memcpy(temp_buf1, (uint8_t*)u1_rx_buffer, len);
|
||||
u1_rx_len = 0;
|
||||
u1_rx_len = 0;
|
||||
__enable_irq();
|
||||
|
||||
MultiUART_Send(PORT_RS485, (uint8_t*)u1_rx_buffer, len);
|
||||
MultiUART_Send(PORT_DEBUG, (uint8_t*)u1_rx_buffer, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 🚀 终极上位机协议:[0xAA帧头] + [设备ID] + [来源接口] + [数据长度] + [纯净数据] */
|
||||
if (len >= 2 && temp_buf1[0] == 0xAA)
|
||||
{
|
||||
uint8_t sender_id = temp_buf1[1];
|
||||
uint16_t payload_len = len - 2;
|
||||
uint8_t* payload_data = &temp_buf1[2];
|
||||
|
||||
/* 默认 0x03 为 RS485 透传数据 */
|
||||
uint8_t source_type = 0x03;
|
||||
|
||||
/* 判断是不是 $DI 标签 */
|
||||
if (payload_len >= 3 && payload_data[0] == '$' && payload_data[1] == 'D' && payload_data[2] == 'I')
|
||||
{
|
||||
source_type = 0x01; /* 也是 DI 口数据,但不砍标签了,直接全发过去 */
|
||||
}
|
||||
/* 判断是不是网口 [NET] 标签 */
|
||||
else if (payload_len >= 5 && payload_data[0] == '[' && payload_data[1] == 'N' && payload_data[2] == 'E' && payload_data[3] == 'T' && payload_data[4] == ']')
|
||||
{
|
||||
source_type = 0x02; /* 0x02 代表是 网络口 收到的数据 */
|
||||
payload_data += 5; /* 砍掉 "[NET]" 标签 */
|
||||
payload_len -= 5;
|
||||
}
|
||||
/* ========================================================== */
|
||||
/* === 3. 核心发送保护区 (TX 优先调度) === */
|
||||
// 只有当我们单片机正在往 433 模块灌数时,才进行避让
|
||||
// 只要单片机串口引擎一空闲,主循环就立刻开始处理后续采集任务
|
||||
if (RF433_UART_Is_Busy()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (payload_len > 0) {
|
||||
/* 重新组装终极协议帧 */
|
||||
uint8_t upper_buf[260];
|
||||
upper_buf[0] = 0xAA; // Byte 0: 魔法帧头
|
||||
upper_buf[1] = sender_id; // Byte 1: 发送设备 ID
|
||||
upper_buf[2] = source_type; // Byte 2: 数据来源 (1=DI, 2=NET, 3=485)
|
||||
upper_buf[3] = (uint8_t)payload_len; // Byte 3: 真实数据长度
|
||||
memcpy(&upper_buf[4], payload_data, payload_len); // Byte 4~末尾: 绝对纯净的数据
|
||||
|
||||
/* 发送给 485 和电脑上位机 */
|
||||
MultiUART_Send(PORT_UART3, upper_buf, payload_len + 4);
|
||||
MultiUART_Send(PORT_UART2, upper_buf, payload_len + 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 普通无帧头干扰数据,按原样透传 */
|
||||
MultiUART_Send(PORT_UART3, temp_buf1, len);
|
||||
MultiUART_Send(PORT_UART2, temp_buf1, len);
|
||||
}
|
||||
|
||||
/* === 方案 B:从 485 收到设备数据 -> 穿上包装(附加ID) -> 通过 433 无线发射 === */
|
||||
/* === 4. 实时数据采集与上报 (仅在非发射状态运行) === */
|
||||
|
||||
// (A) 485 来源数据处理 (Type 0x48)
|
||||
#if USE_RS485
|
||||
if (u3_rx_len > 0 && (HAL_GetTick() - u3_last_rx_time > 20))
|
||||
{
|
||||
static uint8_t temp_buf3[512];
|
||||
@ -317,20 +357,45 @@ int main(void)
|
||||
u3_rx_len = 0;
|
||||
__enable_irq();
|
||||
|
||||
/* 🚀 制作“快递包”:在最前面加上 [0xAA] 和 [本机ID] */
|
||||
static uint8_t rf_tx_buf[515];
|
||||
rf_tx_buf[0] = 0xAA; // 贴上魔法帧头
|
||||
rf_tx_buf[1] = MY_DEVICE_ID; // 贴上本机的身份证号
|
||||
memcpy(&rf_tx_buf[2], temp_buf3, len); // 把 485 收到的真实数据塞进后面
|
||||
|
||||
/* 把带有身份证的完整包裹,通过 433 发射到空气中 */
|
||||
MultiUART_Send(PORT_UART1, rf_tx_buf, len + 2);
|
||||
RF433_SendPacket(PROTO_TYPE_485, temp_buf3, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
// (B) I/O 状态监控与变化上报 (Type 0x10)
|
||||
#if USE_IO_MONITOR
|
||||
IO_Monitor_Task(); // 执行去抖扫描
|
||||
uint8_t current_io = IO_Monitor_GetAllStates();
|
||||
if (current_io != g_last_io_state) {
|
||||
if (g_last_io_state == 0xFF) {
|
||||
g_last_io_state = current_io;
|
||||
} else {
|
||||
g_last_io_state = current_io;
|
||||
RF433_SendPacket(PROTO_TYPE_IO, ¤t_io, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// (C) 30秒系统心跳包 (Type 0xAA)
|
||||
#if USE_IO_MONITOR
|
||||
if (HAL_GetTick() - g_last_hb_tick >= 30000) {
|
||||
g_last_hb_tick = HAL_GetTick();
|
||||
uint8_t hb_payload[3];
|
||||
hb_payload[0] = IO_Monitor_GetAllStates();
|
||||
hb_payload[1] = (uint8_t)(g_hb_seq >> 8);
|
||||
hb_payload[2] = (uint8_t)(g_hb_seq & 0xFF);
|
||||
g_hb_seq++;
|
||||
|
||||
RF433_SendPacket(PROTO_TYPE_HB, hb_payload, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
// (D) W5500 以太网轮询处理 (Type 0x55)
|
||||
#if USE_W5500
|
||||
loopback_udps(SOCKET_ID, ethernet_buf, local_port);
|
||||
#endif
|
||||
|
||||
/* USER CODE END WHILE */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
@ -433,7 +498,7 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
||||
if (huart->Instance == USART1)
|
||||
{
|
||||
/* 调用多UART路由器的UART1发送完成回调 */
|
||||
MultiUART_TxCpltCallback(PORT_UART1);
|
||||
MultiUART_TxCpltCallback(PORT_433);
|
||||
}
|
||||
else if (huart->Instance == USART2)
|
||||
{
|
||||
@ -444,7 +509,7 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
||||
{
|
||||
|
||||
/* 调用多UART路由器的UART3发送完成回调 */
|
||||
MultiUART_TxCpltCallback(PORT_UART3);
|
||||
MultiUART_TxCpltCallback(PORT_RS485);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,14 +16,15 @@
|
||||
* 4. 响应路由表
|
||||
*
|
||||
* 端口映射:
|
||||
* - PORT_UART1: 连接RF433无线模块(用于无线数据收发)
|
||||
* - PORT_UART2: 调试串口(用于日志和调试输出)
|
||||
* - PORT_UART3: 预留扩展端口
|
||||
* - PORT_433: 连接RF433无线模块(用于无线数据收发)
|
||||
* - PORT_DEBUG: 调试串口(用于日志和调试输出)
|
||||
* - PORT_RS485: 预留扩展端口
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "multi_uart_router.h"
|
||||
#include "uart2_print.h"
|
||||
#include "main.h"
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@ -57,9 +58,9 @@ static uart_port_context_t g_port_ctx[PORT_COUNT];
|
||||
* 使用常量初始化,在编译时确定,无运行时开销
|
||||
*/
|
||||
static UART_HandleTypeDef *const g_port_uart_map[PORT_COUNT] = {
|
||||
[PORT_UART1] = &huart1, /**< RF433无线模块 */
|
||||
[PORT_UART2] = &huart2, /**< 调试串口 */
|
||||
[PORT_UART3] = &huart3, /**< 预留扩展 */
|
||||
[PORT_433] = &huart1, /**< RF433无线模块 */
|
||||
[PORT_DEBUG] = &huart2, /**< 调试串口 */
|
||||
[PORT_RS485] = &huart3, /**< 预留扩展 */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -67,9 +68,9 @@ static UART_HandleTypeDef *const g_port_uart_map[PORT_COUNT] = {
|
||||
* @note 用于调试日志输出,快速获取端口的可读名称
|
||||
*/
|
||||
static const char *const g_port_name_map[PORT_COUNT] = {
|
||||
[PORT_UART1] = "UART1", /**< RF433无线模块 */
|
||||
[PORT_UART2] = "UART2", /**< 调试串口 */
|
||||
[PORT_UART3] = "UART3", /**< 预留扩展 */
|
||||
[PORT_433] = "UART1", /**< RF433无线模块 */
|
||||
[PORT_DEBUG] = "UART2", /**< 调试串口 */
|
||||
[PORT_RS485] = "UART3", /**< 预留扩展 */
|
||||
};
|
||||
|
||||
/*==============================================================================
|
||||
@ -234,6 +235,15 @@ static void tx_kickoff(port_id_t port_id)
|
||||
|
||||
__disable_irq();
|
||||
if (!ring->is_sending && ring->count > 0) {
|
||||
/* --- 核心修复:针对 RF433 (UART1) 执行包级 LBT 检查 --- */
|
||||
if (port_id == PORT_433) {
|
||||
// 如果 AUX 为低电平,说明信道忙(接收中或正在发送前一包),暂缓起步
|
||||
if (HAL_GPIO_ReadPin(AUX_GPIO_Port, AUX_Pin) == GPIO_PIN_RESET) {
|
||||
__enable_irq();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 取出下一个待发送字节 */
|
||||
byte = ring->buffer[ring->tail];
|
||||
ring->tail = (ring->tail + 1) % UART_TX_BUFFER_SIZE;
|
||||
@ -344,7 +354,7 @@ void MultiUART_FeedByte(port_id_t port_id, uint8_t byte)
|
||||
* 接收处理由中断完成(MultiUART_FeedByte),此函数仅处理发送
|
||||
*
|
||||
* 端口跳过说明:
|
||||
* - 跳过PORT_UART2(调试串口),由UART2_Print模块独立处理
|
||||
* - 跳过PORT_DEBUG(调试串口),由UART2_Print模块独立处理
|
||||
*
|
||||
* 调用时机:
|
||||
* 建议在主循环中周期性调用(如10ms定时)
|
||||
@ -360,7 +370,7 @@ void MultiUART_Task(void)
|
||||
}
|
||||
|
||||
/* 跳过调试串口(UART2) */
|
||||
if (i == PORT_UART2) {
|
||||
if (i == PORT_DEBUG) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -379,7 +389,7 @@ void MultiUART_Task(void)
|
||||
* @return 无
|
||||
*
|
||||
* 特殊处理:
|
||||
* - PORT_UART2直接调用UART2_Print_Send,由调试模块处理
|
||||
* - PORT_DEBUG直接调用UART2_Print_Send,由调试模块处理
|
||||
* - 其他端口使用本模块的环形缓冲区机制
|
||||
*
|
||||
* 发送流程:
|
||||
@ -400,7 +410,7 @@ void MultiUART_Send(port_id_t port_id, const uint8_t *data, uint16_t len)
|
||||
* 调试串口(UART2)特殊处理
|
||||
* 调试打印不走环形缓冲区,直接发送
|
||||
*----------------------------------------------------------*/
|
||||
if (port_id == PORT_UART2) {
|
||||
if (port_id == PORT_DEBUG) {
|
||||
UART2_Print_Send(data, len);
|
||||
return;
|
||||
}
|
||||
@ -487,7 +497,7 @@ void MultiUART_SendFmt(port_id_t port_id, const char *fmt, ...)
|
||||
* @return 无
|
||||
*
|
||||
* 特殊处理:
|
||||
* - PORT_UART2调用UART2_Print_TxCpltCallback处理
|
||||
* - PORT_DEBUG调用UART2_Print_TxCpltCallback处理
|
||||
*
|
||||
* 发送驱动逻辑:
|
||||
* 1. 清除is_sending标志
|
||||
@ -504,7 +514,7 @@ void MultiUART_TxCpltCallback(port_id_t port_id)
|
||||
}
|
||||
|
||||
/* 调试串口(UART2)特殊处理 */
|
||||
if (port_id == PORT_UART2) {
|
||||
if (port_id == PORT_DEBUG) {
|
||||
UART2_Print_TxCpltCallback();
|
||||
return;
|
||||
}
|
||||
@ -660,3 +670,22 @@ uint32_t MultiUART_GetOverflowCount(port_id_t port_id)
|
||||
return g_port_ctx[port_id].rx_ring.overflow_count +
|
||||
g_port_ctx[port_id].tx_ring.overflow_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查指定端口是否正忙于发送
|
||||
* @param port_id: 端口ID
|
||||
* @return bool: true=忙碌(有待发数据或硬件发送中), false=空闲
|
||||
*/
|
||||
bool MultiUART_IsBusy(uint8_t port_id)
|
||||
{
|
||||
if (port_id >= PORT_COUNT) return false;
|
||||
|
||||
// 调试串口特殊处理
|
||||
if (port_id == PORT_UART2) {
|
||||
// UART2_Print 使用单独的标志位,这里简单兼容
|
||||
return false;
|
||||
}
|
||||
|
||||
// 直接读取状态,不屏蔽中断,追求极致性能
|
||||
return (g_port_ctx[port_id].tx_ring.count > 0 || g_port_ctx[port_id].tx_ring.is_sending);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user