前言
- 日志对于开发和排错方面有着很重要的影响。
- 通过查看RT-Thread的源码,将日志的打印输出划分到具体的文件和通过宏定义对具体的日志等级进行划分,这样就比较方便。
- 结合此源码的形式将其分离出来,作为自己项目的日志框架进行使用
- 分为日志驱动和从RT-Thread那边移植过来的dbg头文件
相关函数类型定义(根据需要自行选取)
/*------------------------------------------------通用函数类型定义-----------------------------------------------*/
/*基础函数类型定义(无参,无返回)*/
typedef void (*fn_base_def_t)(void);
/*基础函数类型定义(无参,有返回)*/
typedef void *(*fn_base_ret_def_t)(void);
/*基础函数类型定义(有参,无返回)*/
typedef void (*fn_base_par_def_t)(void *data);
/*基础函数类型定义(有参,有返回)*/
typedef void *(*fn_base_par_ret_def_t)(void *data);
/*------------------------------------------------通用函数类型定义----------------------------------------------*/
/*发送数据函数类型定义*/
typedef void (*fn_send_def_t)(void *data, uint16_t len);
/*接收数据函数类型定义*/
typedef uint16_t (*fn_rec_data_def_t)(void *retData);
/*发送数据(带地址)函数类型定义*/
typedef bool (*fn_send_addr_def_t)(uint16_t addr, void *data, uint16_t len);
/*接收数据(带地址)函数类型定义*/
typedef bool (*fn_rec_data_addr_def_t)(uint16_t addr, void *data, uint16_t len);
/*延迟函数类型定义*/
typedef void (*fn_delay_def_t)(uint32_t delay);
/*日志函数类型定义*/
typedef void (*fn_debug_log_def_t)(char *format, ...);
日志驱动(作为具体对接硬件,这里是通过函数回调的方式进行解耦)
头文件
/*******************************************************************************
* Copyright (c) [scl]。保留所有权利。
******************************************************************************/
#ifndef STM32F103VET6_PROJECT_SYS_CORE_LOG_H
#define STM32F103VET6_PROJECT_SYS_CORE_LOG_H
#include "sys_core_conf.h"
#include "sys_core_typedef.h"
/**
* @brief 日志缓存大小
*/
#define LOG_BUFFER_SIZE 512
/**
* @brief 自定义格式化打印输出
* @param format
* @param ...
*/
void os_ps(char *format, ...);
/**
* @brief 源数据记录
* @param data 数据
* @param len 数据长度
*/
void os_log(uint8_t *data, uint16_t len);
/**
* 设置日志回调(如果没有设置,os_ps和os_log不生效)
* @param call
*/
void os_log_call_set(fn_send_def_t call);
/****************************************不能保证输出完整性,则需要设置以下回调***********************************************/
/**
* @brief 设置加锁
* @param lock_call
*/
void os_log_set_lock(fn_base_def_t call);
/**
* @brief 设置解锁
* @param lock_call
*/
void os_log_set_unlock(fn_base_def_t call);
#endif //STM32F103VET6_PROJECT_SYS_CORE_LOG_H
源文件
/*******************************************************************************
* Copyright (c) [scl]。保留所有权利。
******************************************************************************/
#include "sys_core_log.h"
#include <stdio.h>
#include <stdarg.h>
#define log_not_null_run(fn) if(fn!=NULL) fn()
static void (*lock)(void) =NULL;
static void (*unlock)(void) =NULL;
static void (*log_cal)(void *data, uint16_t len) =NULL;
static char os_tx_buf[LOG_BUFFER_SIZE];
void os_ps(char *format, ...) {
log_not_null_run(lock);
if (log_cal != NULL) {
va_list v_args;
va_start(v_args, format);
// 如果成功,则返回写入的字符总数,否则返回一个负数。
int len = vsnprintf((char *) &os_tx_buf[0], (size_t)
sizeof(os_tx_buf), (char const *) format, v_args);
va_end(v_args);
if (len > 0) {
log_cal(os_tx_buf, len);
}
}
log_not_null_run(unlock);
}
void os_log(uint8_t *data, uint16_t len) {
if (log_cal != NULL) {
log_cal(data, len);
}
}
/**
*
* @param call 日志记录回调注册
*/
void os_log_call_set(fn_send_def_t call) {
log_cal = call;
}
/**
* @brief 设置加锁
* @param lock_call
*/
void os_log_set_lock(fn_base_def_t call) {
lock = call;
}
/**
* @brief 设置解锁
* @param lock_call
*/
void os_log_set_unlock(fn_base_def_t call) {
unlock = call;
}
RT-Thread的日志模块
通过 #define PRINTF os_ps 与日志驱动进行绑定,根据需要可以换成自定义的格式输出
头文件
#ifndef STM32_F1XX_TEMPLATE_SYS_DBG_H
#define STM32_F1XX_TEMPLATE_SYS_DBG_H
#include "sys_core_log.h"
#define PRINTF os_ps
#ifdef DBG_ENABLE
#ifdef DBG_LVL
#ifndef DBG_LEVEL
#define DBG_LEVEL DBG_LVL
#endif
#else
/* compatible with old version */
#ifndef DBG_LEVEL
#define DBG_LEVEL DBG_WARNING
#endif
#endif /* DBG_LVL */
/*
* The color for terminal (foreground)
* BLACK 30
* RED 31
* GREEN 32
* YELLOW 33
* BLUE 34
* PURPLE 35
* CYAN 36
* WHITE 37
*/
#ifdef DBG_COLOR
#define _DBG_COLOR(n) PRINTF("\033["#n"m")
#define _DBG_LOG_HDR(lvl_name, color_n) \
PRINTF("\033["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] ")
#define _DBG_LOG_X_END \
PRINTF("\033[0m\n")
#else
#define _DBG_COLOR(n)
#define _DBG_LOG_HDR(lvl_name, color_n) \
PRINTF("[" lvl_name "/" DBG_SECTION_NAME "] ")
#define _DBG_LOG_X_END \
PRINTF("\r\n")
#endif /* DBG_COLOR */
/*
* static debug routine
* NOTE: This is a NOT RECOMMENDED API. Please using LOG_X API.
* It will be DISCARDED later. Because it will take up more resources.
*/
#define dbg_log(level, fmt, ...) \
if ((level) <= DBG_LEVEL) \
{ \
switch(level) \
{ \
case DBG_ERROR: _DBG_LOG_HDR("E", 31); break; \
case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \
case DBG_INFO: _DBG_LOG_HDR("I", 32); break; \
case DBG_LOG: _DBG_LOG_HDR("D", 0); break; \
default: break; \
} \
PRINTF(fmt, ##__VA_ARGS__); \
_DBG_COLOR(0); \
}
#define dbg_here \
if ((DBG_LEVEL) <= DBG_LOG){ \
PRINTF(DBG_SECTION_NAME " Here %s:%d\n",__FUNCTION__, __LINE__);\
}
#define dbg_log_line(lvl, color_n, fmt, ...) \
do \
{ \
_DBG_LOG_HDR(lvl, color_n); \
PRINTF(fmt, ##__VA_ARGS__); \
_DBG_LOG_X_END; \
} \
while (0)
#define dbg_raw(...) PRINTF(__VA_ARGS__);
#else
#define dbg_log(level, fmt, ...)
#define dbg_here
#define dbg_enter
#define dbg_exit
#define dbg_log_line(lvl, color_n, fmt, ...)
#define dbg_raw(...)
#endif /* DBG_ENABLE */
#if (DBG_LEVEL >= DBG_LOG)
#define LOG_D(fmt, ...) dbg_log_line("D", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_D(...)
#endif
#if (DBG_LEVEL >= DBG_INFO)
#define LOG_I(fmt, ...) dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
#else
#define LOG_I(...)
#endif
#if (DBG_LEVEL >= DBG_WARNING)
#define LOG_W(fmt, ...) dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_W(...)
#endif
#if (DBG_LEVEL >= DBG_ERROR)
#define LOG_E(fmt, ...) dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
#else
#define LOG_E(...)
#endif
#define LOG_RAW(...) dbg_raw(__VA_ARGS__)
#endif //STM32_F1XX_TEMPLATE_SYS_DBG_H
示例
/*******************************************************************************
* Copyright (c) [scl]。保留所有权利。
******************************************************************************/
#include "app_conf.h"
#if APP_CONFIG_LOG
#define DBG_ENABLE
#define DBG_SECTION_NAME "log_conf"
#define DBG_LEVEL DBG_LOG
#include "sys_dbg.h"
static void com_send(void *data, uint16_t len) {
HAL_UART_Transmit(com1_handle, data, len, 100);
}
static void init(void) {
bsp_SerialInit(com1_id, 115200);
os_log_call_set(com_send);
}
static void after_init(void) {
UART_HandleTypeDef *ptr = conv_uart_handle_ptr(handle_get_by_id(com1_id));
LOG_D("app start:%lu", ptr->Init.BaudRate);
ptr = conv_uart_handle_ptr(handle_get_by_id(com1_id));
LOG_D("app start:%d", ptr->Init.BaudRate);
}
sys_init_export(app_log, init);
sys_after_init_export(app_log, after_init);
#endif
结果
注意
- 在使用RTOS的框架时,建议设置以下函数
/**
* @brief 设置加锁
* @param lock_call
*/
void os_log_set_lock(fn_base_def_t call);
/**
* @brief 设置解锁
* @param lock_call
*/
void os_log_set_unlock(fn_base_def_t call);