Files
STM32F4-Base/Drivers/BSP/dbg_log.h
T

196 lines
6.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称: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 */