196 lines
6.8 KiB
C
196 lines
6.8 KiB
C
/*
|
||
* 模块名称:Unified Debug Logging
|
||
* 模块功能:提供统一的调试输出宏,支持 DEBUG / INFO / ERROR 三级日志控制
|
||
* 参考 FlashDB FDB_DEBUG/FDB_INFO 设计模式
|
||
* 使用方法:
|
||
* 1. 在 dbg_cfg.h 中定义 DBG_ENABLE(总开关)和 DBG_DEBUG_ENABLE(DEBUG 级别)
|
||
* 2. 每个 .c 文件在包含本文件前定义 DBG_TAG,如:
|
||
* #define DBG_TAG "[CH395]"
|
||
* #include "dbg_log.h"
|
||
* 适用平台:所有 BSP 驱动
|
||
* 作者:王建锋
|
||
* 创建日期:2026-07-18
|
||
* 修改记录:
|
||
* 2026-07-18 王建锋 创建初始版本
|
||
*/
|
||
|
||
#ifndef DBG_LOG_H
|
||
#define DBG_LOG_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdio.h>
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
#include "dbg_cfg.h"
|
||
|
||
#ifdef APP_TIMESTAMP_ENABLE
|
||
#include "sys_clock.h"
|
||
#endif
|
||
|
||
/* 单写者控制台 API:实现见 App/log/console_log.c(2026-09-24 自 HAL 生成文件
|
||
* Src/usart.c 迁出);与 DBG_ENABLE 无关,任何构建都必须可见 */
|
||
#include "console_log.h"
|
||
|
||
/*
|
||
* 总开关:DBG_ENABLE
|
||
* 定义 → 输出 DBG_ERROR / DBG_INFO;若 DBG_DEBUG_ENABLE 也定义则输出 DBG_DEBUG
|
||
* 不定义 → 所有输出宏为空操作(release 版本)
|
||
* 在 net_config.h 或编译器预定义中控制
|
||
*/
|
||
#ifdef DBG_ENABLE
|
||
|
||
/*
|
||
* 行缓冲上限(栈预算旋钮,2026-10-10 加)
|
||
* 默认 = 控制台单行上限 DBG_CON_LINE_MAX(192)。
|
||
* ⚠ 本数组是**在每个日志调用点的栈帧里内联**的,会进 armlink 最坏调用链:
|
||
* 实测存储/配置那条链上 9 个帧各含 192 B 行缓冲 + 32 B 时间戳缓冲
|
||
* → defaultTask 静态最坏链 5312 B 里约 1.5 KB 纯粹是日志行缓冲。
|
||
* 故**深调用链模块**(存储 FTL/NAND、配置引擎、网络驱动、时间同步)应在
|
||
* 包含本文件前显式收紧,例如 `#define DBG_LINE_BUF_MAX 128U`;
|
||
* 取值须 ≥ 该模块最长日志行(含时间戳 20 + 标签 + 正文),否则该行被截断。
|
||
* 核算:scripts/stack_report.py(改前/改后各跑一次)
|
||
*/
|
||
#ifndef DBG_LINE_BUF_MAX
|
||
#define DBG_LINE_BUF_MAX DBG_CON_LINE_MAX
|
||
#endif
|
||
|
||
/*
|
||
* 时间戳文本缓冲上限:sys_clock_get_str() 恒写 "----/--/-- --:--:--" 或
|
||
* "%04d-%02d-%02d %02d:%02d:%02d" = 19 字符 + '\0' → 24 足够(原 32 是随手取整,
|
||
* 每个日志调用点白占 8 B 栈)
|
||
*/
|
||
#define DBG_TS_BUF_MAX 24U
|
||
|
||
/*
|
||
* 有界格式化 + 交单写者控制台(行缓冲由调用方提供,便于与时间戳缓冲共用数组)
|
||
*/
|
||
#define DBG_EMIT(p_line, ...) do { \
|
||
int __con_n = snprintf((p_line), DBG_LINE_BUF_MAX, __VA_ARGS__); \
|
||
if (__con_n > 0) { \
|
||
unsigned __con_len = (__con_n >= (int)DBG_LINE_BUF_MAX) \
|
||
? (unsigned)(DBG_LINE_BUF_MAX - 1u) : (unsigned)__con_n; \
|
||
(void)dbg_console_write_line((p_line), __con_len); \
|
||
} \
|
||
} while (0)
|
||
|
||
/*
|
||
* 可重定向的打印函数,用户可在编译选项或 net_config.h 中预定义
|
||
* #define DBG_PRINT(...) my_printf(__VA_ARGS__)
|
||
* ⚠ 2026-10-10 起:带时间戳的 DBG_ERROR/DBG_INFO/DBG_DEBUG 走 **DBG_EMIT**
|
||
* (与行缓冲共用一个数组,省一帧栈);要整体改道请重定义 `DBG_EMIT(p_line, ...)`
|
||
* ——它是所有日志的唯一落地点。只定义 DBG_PRINT 仅影响不带时间戳的 DBG_PRINT。
|
||
*
|
||
* 默认走单写者控制台(App/log/console_log.c):
|
||
* DBG_EMIT 在调用点用库 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(...) do { \
|
||
char __con_line[DBG_LINE_BUF_MAX]; \
|
||
DBG_EMIT(__con_line, __VA_ARGS__); \
|
||
} while (0)
|
||
#endif
|
||
|
||
/*
|
||
* 模块标签默认值,每个 .c 文件应在包含本文件前定义 DBG_TAG
|
||
* #define DBG_TAG "[CH395]"
|
||
*/
|
||
#ifndef DBG_TAG
|
||
#define DBG_TAG ""
|
||
#endif
|
||
|
||
#ifdef APP_TIMESTAMP_ENABLE
|
||
/*
|
||
* 兼容宏:单独取时间戳文本(当前无调用者;缓冲为复合字面量,仅在本表达式内有效)
|
||
*/
|
||
#define DBG_TS() sys_clock_get_str((char[DBG_TS_BUF_MAX]){0}, DBG_TS_BUF_MAX)
|
||
|
||
/*
|
||
* DBG_ERROR / DBG_INFO / DBG_DEBUG(带时间戳版)
|
||
* 时间戳缓冲与行缓冲**共用一个数组**(每个调用点省一帧 24 B 栈):行文本占前
|
||
* DBG_LINE_BUF_MAX 字节,时间戳文本切片自其后。snprintf 的全部实参先于其执行
|
||
* 求值完毕,故"先写时间戳切片、再格式化行首"不冲突。
|
||
*/
|
||
/*
|
||
* DBG_ERROR - 错误输出,受 DBG_ENABLE + APP_TIMESTAMP_ENABLE 控制
|
||
*/
|
||
#define DBG_ERROR(fmt, ...) do { \
|
||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||
DBG_EMIT(__con_line, "[%s]" "[ERR]" DBG_TAG " " fmt "\r\n", \
|
||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||
##__VA_ARGS__); \
|
||
} while (0)
|
||
|
||
/*
|
||
* DBG_INFO - 信息输出,受 DBG_ENABLE + APP_TIMESTAMP_ENABLE 控制
|
||
*/
|
||
#define DBG_INFO(fmt, ...) do { \
|
||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||
DBG_EMIT(__con_line, "[%s]" DBG_TAG " " fmt "\r\n", \
|
||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||
##__VA_ARGS__); \
|
||
} while (0)
|
||
|
||
/*
|
||
* DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE + APP_TIMESTAMP_ENABLE 同时定义
|
||
*/
|
||
#ifdef DBG_DEBUG_ENABLE
|
||
#define DBG_DEBUG(fmt, ...) do { \
|
||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||
DBG_EMIT(__con_line, "[%s]" DBG_TAG "(%s:%d) " fmt "\r\n", \
|
||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||
__func__, __LINE__, ##__VA_ARGS__); \
|
||
} while (0)
|
||
#else
|
||
#define DBG_DEBUG(fmt, ...)
|
||
#endif
|
||
|
||
#else /* APP_TIMESTAMP_ENABLE not defined */
|
||
|
||
/*
|
||
* DBG_ERROR - 错误输出,受 DBG_ENABLE 控制(无时间戳)
|
||
*/
|
||
#define DBG_ERROR(fmt, ...) do { \
|
||
DBG_PRINT("[ERR]" DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||
} while (0)
|
||
|
||
/*
|
||
* DBG_INFO - 信息输出,受 DBG_ENABLE 控制(无时间戳)
|
||
*/
|
||
#define DBG_INFO(fmt, ...) do { \
|
||
DBG_PRINT(DBG_TAG " " fmt "\r\n", ##__VA_ARGS__); \
|
||
} while (0)
|
||
|
||
/*
|
||
* DBG_DEBUG - 调试输出,需 DBG_ENABLE + DBG_DEBUG_ENABLE 同时定义(无时间戳)
|
||
*/
|
||
#ifdef DBG_DEBUG_ENABLE
|
||
#define DBG_DEBUG(fmt, ...) do { \
|
||
DBG_PRINT(DBG_TAG "(%s:%d) " fmt "\r\n", __func__, __LINE__, ##__VA_ARGS__); \
|
||
} while (0)
|
||
#else
|
||
#define DBG_DEBUG(fmt, ...)
|
||
#endif
|
||
|
||
#endif /* APP_TIMESTAMP_ENABLE */
|
||
|
||
#else /* DBG_ENABLE not defined — all debug output disabled */
|
||
|
||
#define DBG_ERROR(fmt, ...)
|
||
#define DBG_INFO(fmt, ...)
|
||
#define DBG_DEBUG(fmt, ...)
|
||
|
||
#endif /* DBG_ENABLE */
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* DBG_LOG_H */
|