当写的程序越复杂,其中需要打印的东西会越多,但是当我们写了很多条调试信息时,但是又不想删除,并且可以给后面程序遇到bug继续留着调试使用,我们就可以使用如下的方法:
/*
* mat_log.h
*
* Created on: 2022-8-16
*
*/
#ifndef MAT_LOG_H
#define MAT_LOG_H
#include "tl_common.h"
#define DEBUG 1
#define ERR 1
#define INFO 1
#if INFO
#define LOG_INFO(str, ...) printf("[INFO]:"str "\r\n", ##__VA_ARGS__)
#else
#define LOG_INFO(str, ...)
#endif
#if ERR
#define LOG_ERR(str, ...) printf("[ERR]:"str "\r\n", ##__VA_ARGS__)
#else
#define LOG_ERR(str, ...)
#endif
#if DEBUG
#define LOG_DEBUG(str, ...) printf("[DEBUG]:"str "\r\n", ##__VA_ARGS__)
#else
#define LOG_DEBUG(str, ...)
#endif
#endif
这里面我也有借鉴别人的,但是已经找不到那位兄弟的链接了,我只是在他的基础上增加了条件编译,让我们的设计更加的灵活。
__VA_ARGS__是C语言预处理器中的宏定义,用于表示可变参数列表。在使用可变参数的宏定义中,__VA_ARGS__可以代替可变参数列表,使得代码更加简洁和灵活。
例如,以下宏定义实现了一个简单的打印函数:
#define PRINT(...) printf(__VA_ARGS__)
使用这个宏定义时,可以像下面这样传入任意数量的参数:
PRINT("Hello, world!\n");
PRINT("The value of x is %d\n", x);
PRINT("The sum of %d and %d is %d\n", a, b, a + b);
在这些例子中,__VA_ARGS__会被替换成传入的可变参数列表。
接下来来看nordic蓝牙工程中关于打印的等级的设置,似乎有点复杂,还是没有上面的那种好用
#define NRF_LOG_ERROR(...) NRF_LOG_INTERNAL_ERROR(__VA_ARGS__)
#define NRF_LOG_WARNING(...) NRF_LOG_INTERNAL_WARNING( __VA_ARGS__)
#define NRF_LOG_INFO(...) NRF_LOG_INTERNAL_INFO( __VA_ARGS__)
#define NRF_LOG_DEBUG(...) NRF_LOG_INTERNAL_DEBUG( __VA_ARGS__)
#define NRF_LOG_INTERNAL_ERROR(...) \
NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_ERROR, NRF_LOG_SEVERITY_ERROR,__VA_ARGS__)
#define NRF_LOG_INTERNAL_WARNING(...) \
NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_WARNING, NRF_LOG_SEVERITY_WARNING,__VA_ARGS__)
#define NRF_LOG_INTERNAL_INFO(...) \
NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_INFO, NRF_LOG_SEVERITY_INFO, __VA_ARGS__)
#define NRF_LOG_INTERNAL_DEBUG(...) \
NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_DEBUG, NRF_LOG_SEVERITY_DEBUG, __VA_ARGS__)
#define NRF_LOG_INTERNAL_MODULE(level, level_id, ...) \
if (NRF_LOG_ENABLED && (NRF_LOG_LEVEL >= level) && \
(level <= NRF_LOG_DEFAULT_LEVEL)) \
{ \
if (NRF_LOG_FILTER >= level) \
{ \
LOG_INTERNAL(LOG_SEVERITY_MOD_ID(level_id), __VA_ARGS__); \
} \
}
2024/4/23:
调试过程中, 我们需要打印数据, 一种是编译的时候进行设置, 一种是运行过程中进行设置.接下来就对这两种方式进行设置:
#ifndef LOG_H
#define LOG_H
#include "stdio.h"
#define USE_MACRO_CTRL 0
#if USE_MACRO_CTRL
#define ERR 1
#define WRN 1
#define INFO 1
#define DB 1
#define log_printf(str, ...) printf(str "\r\n", ##__VA_ARGS__)
#if ERR
#define log_err(str, ...) printf("[ERR]:"str "\r\n", ##__VA_ARGS__)
#else
#define log_err(str, ...)
#endif
#if WRN
#define log_wrn(str, ...) printf("[ERR]:"str "\r\n", ##__VA_ARGS__)
#else
#define log_wrn(str, ...)
#endif
#if INFO
#define log_info(str, ...) printf("[INFO]:"str "\r\n", ##__VA_ARGS__)
#else
#define log_info(str, ...)
#endif
#if DB
#define log_db(str, ...) printf("[DEBUG]:"str "\r\n", ##__VA_ARGS__)
#else
#define log_db(str, ...)
#endif
#else
typedef enum {
LOGPRI_NONE = 0,
LOGPRI_ERR,
LOGPRI_WRN,
LOGPRI_INFO,
LOGPRI_DB,
LOGPRI_MAX,
} loglevel_t;
void log_print(loglevel_t level, const char *fmt, ...);
#define log_printf(str, ...) log_print(LOGPRI_NONE, str "\r\n", ##__VA_ARGS__)
#define log_err(str, ...) log_print(LOGPRI_ERR, "[ERR]:"str "\r\n", ##__VA_ARGS__)
#define log_wrn(str, ...) log_print(LOGPRI_WRN, "[WRN]:"str "\r\n", ##__VA_ARGS__)
#define log_info(str, ...) log_print(LOGPRI_INFO, "[INFO]:"str "\r\n", ##__VA_ARGS__)
#define log_db(str, ...) log_print(LOGPRI_DB, "[DB]:"str "\r\n", ##__VA_ARGS__)
#endif
#endif
#include "LOG/log.h"
#include "bsp.h"
#include "stdarg.h"
#include "AT/cmd.h"
#include "stdlib.h"
#if (!USE_MACRO_CTRL)
loglevel_t log_level = LOGPRI_INFO;
void log_print(loglevel_t level, const char *fmt, ...)
{
#define BUF_SIZE 100
va_list argptr;
static char buff[BUF_SIZE]; /* 如果是裸机可以使用临时变量 */
int len = 0;
if(level <= log_level)
{
va_start(argptr, fmt);
len = vsnprintf(buff, BUF_SIZE, fmt, argptr);
va_end(argptr);
if(drv_ram.uart)
{
drv_ram.uart->SendBuf(buff, len);
}
}
}
static void set_log_level(char *param)
{
if(*param != '\0')
{
loglevel_t level;
level = (loglevel_t)(atoi(param));
if(level < LOGPRI_MAX)
{
log_level = level;
log_printf("current level: %d", level);
}
}
}
ADD_CMD("loglevel", set_log_level);
#endif