控制台改单写者发送:defaultTask唯一发串口其余任务写环形缓冲,杜绝日志交错与脏指针入UART;溢出钩子加指针窗口校验、崩溃上报改显式长度

This commit is contained in:
2026-09-24 23:47:23 +08:00
parent c075cfa076
commit 3763e699dc
8 changed files with 346 additions and 34 deletions
+10 -1
View File
@@ -3,10 +3,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "dbg_log.h"
void lftpd_log_internal(const char* level, const char* format, ...) {
static char buffer[256]; /* static: called at depth in ftpTask, keep off-stack */
static char line[288]; /* static: 组装含前缀的整行,交给控制台单写者 */
va_list args;
va_start(args, format);
int err = vsnprintf(buffer, sizeof(buffer), format, args);
@@ -14,5 +16,12 @@ void lftpd_log_internal(const char* level, const char* format, ...) {
if (err >= sizeof(buffer)) {
return;
}
printf("%s %s\n", level, buffer);
/* 走控制台单写者(Src/usart.c):整行一次入缓冲,避免逐字符 fputc 交错 */
int n = snprintf(line, sizeof(line), "%s %s\r\n", level, buffer);
if (n > 0) {
if (n > (int)sizeof(line) - 1) {
n = (int)sizeof(line) - 1;
}
(void)dbg_console_write_line(line, (unsigned)n);
}
}
+6
View File
@@ -77,6 +77,12 @@ HAL_StatusTypeDef rs485_transmit(rs485_handle_t *p_handle,
timeout = RS485_TIMEOUT_DEFAULT;
}
/* 防御性边界(2026-09-24,UART 缓冲遍历类 HardFault 加固):
* 长度必须非零且不超过收发缓冲上限——脏长度交给 HAL 会变成"按长度遍历整片内存" */
if ((p_data == NULL) || (len == 0U) || (len > RS485_TX_MAX_LEN)) {
return HAL_ERROR;
}
RS485_DIR_TX(p_handle);
/* DE 建立延时:HAL 时基为 1ms 粒度,1ms 已充分覆盖收发器驱动使能稳定时间 */
+1
View File
@@ -25,6 +25,7 @@ extern "C" {
*/
#define RS485_TIMEOUT_DEFAULT 1000U /* 默认发送超时(ms) */
#define RS485_RX_BUF_SIZE 256U /* 接收缓冲区大小 */
#define RS485_TX_MAX_LEN 256U /* 单帧发送长度上限(防御脏长度进 UART,2026-09-24 加固) */
/*
* RS-485 句柄结构体
+34 -1
View File
@@ -23,12 +23,30 @@ extern "C" {
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include "dbg_cfg.h"
#ifdef APP_TIMESTAMP_ENABLE
#include "sys_clock.h"
#endif
/*
* 单写者控制台 API(实现见 Src/usart.c;与 DBG_ENABLE 无关,任何构建都必须可见):
* dbg_console_write_line - 生产者入口:调用方已格式化好的整行文本一次入环形缓冲
* (刻意**不用**自研可变参数函数——规范 S12 7.6 禁止;格式化在
* DBG_PRINT 宏内用库 snprintf 完成)
* dbg_console_write_raw - 异常/早期路径:有界单次直发(不加锁)
* dbg_console_writer_attach- 写者任务(defaultTask)注册自己为唯一发送者
* dbg_console_drain - 写者任务排空缓冲并发送
* dbg_console_dropped - 因缓冲满丢弃的行数(诊断)
*/
#define DBG_CON_LINE_MAX 192U /* 单行文本上限(与 Src/usart.c 内部口径一致) */
int dbg_console_write_line(const char *line, unsigned len);
void dbg_console_write_raw(const char *buf, unsigned len);
void dbg_console_writer_attach(void);
void dbg_console_drain(void);
uint32_t dbg_console_dropped(void);
/*
* 总开关:DBG_ENABLE
* 定义 → 输出 DBG_ERROR / DBG_INFO;若 DBG_DEBUG_ENABLE 也定义则输出 DBG_DEBUG
@@ -40,9 +58,24 @@ extern "C" {
/*
* 可重定向的打印函数,用户可在编译选项或 net_config.h 中预定义
* #define DBG_PRINT(...) my_printf(__VA_ARGS__)
*
* 默认走单写者控制台(Src/usart.c):
* DBG_PRINT 在调用点用库 snprintf 有界格式化整行,再一次性交给 dbg_console_write_line
* 入环形缓冲,由 defaultTask 唯一发送——
* ① 行与行不会字符级交错(旧 printf→fputc 每字符一次 HAL_UART_Transmit 会交错);
* ② 进 UART 的缓冲恒为控制台内部缓冲,调用方脏指针到不了 UART
* (2026-09-24 HardFault:BFAR=CCM 末尾+1 即在 UART 缓冲读取处)。
*/
#ifndef DBG_PRINT
#define DBG_PRINT(...) printf(__VA_ARGS__)
#define DBG_PRINT(...) do { \
char __con_line[DBG_CON_LINE_MAX]; \
int __con_n = snprintf(__con_line, sizeof(__con_line), __VA_ARGS__); \
if (__con_n > 0) { \
unsigned __con_len = (__con_n >= (int)sizeof(__con_line)) \
? (unsigned)(sizeof(__con_line) - 1u) : (unsigned)__con_n; \
(void)dbg_console_write_line(__con_line, __con_len); \
} \
} while (0)
#endif
/*