前言
磨刀不误砍柴工,前面的非阻塞串口打印,shell命令行交互都是为了方便后面USB开发的调试。现在开始正是开始砍柴了。第一步我们就是实现比较灵活的LOG输出。主要考虑以下几点需求
- 非阻塞,前面已经实现了相关的接口
- 可配置日志输出等级,因为调试输出可能很多,所以根据等级过滤会方便查看
- 可配置日子类型,结合上述等级可控制,进一步能控制不同类型(TAG)的日志的不同等级的使能,这样可以更精确的分类输出。
- 可动态命令行配置,基于前面的shell可以动态修改不同TAG的不同等级的日志的使能控制。
- 可以根据不同等级显示不通的颜色,方便屠户显示错误。
过程
添加debug.c和debug.h
使能配置如下,一个数组记录每个TAG的当前使能等级
static uint8_t debug_level_enabled[DEBUG_TAG_MAX] = {
};
void debug_toggle_level(debug_level_t tag)
{
if (tag >= DEBUG_TAG_MAX)
return;
debug_level_enabled[tag] ^= 0x80;
}
void debug_set_level(debug_tag_t tag, debug_level_t level)
{
if (level >= DEBUG_LEVEL_MAX)
return;
if (tag >= DEBUG_TAG_MAX)
return;
if(level == DEBUG_LEVEL_OFF)
{
debug_level_enabled[tag] = 0;
}
else
{
debug_level_enabled[tag] = level | 0x80;
}
}
debug_level_t debug_get_level(debug_tag_t tag)
{
if (tag >= DEBUG_TAG_MAX)
return DEBUG_LEVEL_OFF;
return debug_level_enabled[tag];
}
根据不同等级打印不同颜色
void debug_set_color(debug_color_t color) {
unsigned int color_code, modifier_code;
switch (color & COLOR_MASK_COLOR) {
case COLOR_BLACK:
color_code = 30; break;
case COLOR_RED:
color_code = 31; break;
case COLOR_GREEN:
color_code = 32; break;
case COLOR_YELLOW:
color_code = 33; break;
case COLOR_BLUE:
color_code = 34; break;
case COLOR_MAGENTA:
color_code = 35; break;
case COLOR_CYAN:
color_code = 36; break;
case COLOR_WHITE:
color_code = 37; break;
case COLOR_RESET:
default:
color_code = 0; break;
}
switch (color & COLOR_MASK_MODIFIER) {
case COLOR_BOLD:
modifier_code = 1; break;
case COLOR_UNDERLINE:
modifier_code = 2; break;
case COLOR_BLINK:
modifier_code = 3; break;
case COLOR_HIDE:
modifier_code = 4; break;
case COLOR_NORMAL:
default:
modifier_code = 0; break;
}
printf("\033[%u;%um", modifier_code, color_code);
}
打印接口
void do_debug(debug_tag_t tag, debug_level_t level, const char *format, ...)
{
int color = COLOR_RESET;
va_list args;
/* Don't print anything if log level is disabled */
if(((debug_level_enabled[tag] & 0x80) == 0) || ((debug_level_enabled[tag] & 0x7F) > level))
return;
switch(level) {
case DEBUG_LEVEL_INFO:
color = COLOR_GREEN | COLOR_BOLD;
break;
case DEBUG_LEVEL_ERROR:
color = COLOR_RED | COLOR_BOLD;
break;
case DEBUG_LEVEL_WARN:
color = COLOR_YELLOW | COLOR_BOLD;
break;
default:
return;
}
va_start(args, format);
/* If csp_debug_hook symbol is defined, pass on the message.
* Otherwise, just print with pretty colors ... */
if (debug_hook_func) {
debug_set_color((debug_color_t)color);
debug_hook_func((debug_color_t)color, format, args);
debug_set_color(COLOR_RESET);
} else {
debug_set_color((debug_color_t)color);
vprintf(format, args);
printf("\r\n");
debug_set_color(COLOR_RESET);
}
va_end(args);
}
添加命令行
shell_func.c中#include "debug.h"
shell_cmd_list添加一行
{ (const uint8_t*)"debug", DebugFun, "debug tag level"},
添加实现函数
void DebugFun(unsigned char* param)
{
int tag;
int level;
if(2 == sscanf((const char*)param, "%*s %d %d", &tag, &tag))
{
debug_set_level(tag, level);
}
}
shell_func.c中
void DebugFun(unsigned char* param);
可以看到添加的命令
测试
Main.c中
#include "debug.h"
使能颜色主题
输入
debug 0 1
debug 1 1
debug 2 1
使能所有TAG的所有等级输出
输入
debug 0 3
debug 1 3
debug 2 3
使能所有TAG的ERROR等级输出
则只输出ERROR
debug 0 0
关闭TAG0输出则只剩下如下两个TAG输出
代码
Debug.c
#include <stdio.h>
#include "debug.h"
/* Custom debug function */
debug_hook_func_t debug_hook_func = NULL;
/* Debug levels */
static uint8_t debug_level_enabled[DEBUG_TAG_MAX] = {
};
/* Some compilers do not support weak symbols, so this function
* can be used instead to set a custom debug hook */
void csp_debug_hook_set(debug_hook_func_t f)
{
debug_hook_func = f;
}
void debug_set_color(debug_color_t color) {
unsigned int color_code, modifier_code;
switch (color & COLOR_MASK_COLOR) {
case COLOR_BLACK:
color_code = 30; break;
case COLOR_RED:
color_code = 31; break;
case COLOR_GREEN:
color_code = 32; break;
case COLOR_YELLOW:
color_code = 33; break;
case COLOR_BLUE:
color_code = 34; break;
case COLOR_MAGENTA:
color_code = 35; break;
case COLOR_CYAN:
color_code = 36; break;
case COLOR_WHITE:
color_code = 37; break;
case COLOR_RESET:
default:
color_code = 0; break;
}
switch (color & COLOR_MASK_MODIFIER) {
case COLOR_BOLD:
modifier_code = 1; break;
case COLOR_UNDERLINE:
modifier_code = 2; break;
case COLOR_BLINK:
modifier_code = 3; break;
case COLOR_HIDE:
modifier_code = 4; break;
case COLOR_NORMAL:
default:
modifier_code = 0; break;
}
printf("\033[%u;%um", modifier_code, color_code);
}
void do_debug(debug_tag_t tag, debug_level_t level, const char *format, ...)
{
int color = COLOR_RESET;
va_list args;
/* Don't print anything if log level is disabled */
if(((debug_level_enabled[tag] & 0x80) == 0) || ((debug_level_enabled[tag] & 0x7F) > level))
return;
switch(level) {
case DEBUG_LEVEL_INFO:
color = COLOR_GREEN | COLOR_BOLD;
break;
case DEBUG_LEVEL_ERROR:
color = COLOR_RED | COLOR_BOLD;
break;
case DEBUG_LEVEL_WARN:
color = COLOR_YELLOW | COLOR_BOLD;
break;
default:
return;
}
va_start(args, format);
/* If csp_debug_hook symbol is defined, pass on the message.
* Otherwise, just print with pretty colors ... */
if (debug_hook_func) {
debug_set_color((debug_color_t)color);
debug_hook_func((debug_color_t)color, format, args);
debug_set_color(COLOR_RESET);
} else {
debug_set_color((debug_color_t)color);
vprintf(format, args);
printf("\r\n");
debug_set_color(COLOR_RESET);
}
va_end(args);
}
void debug_toggle_level(debug_level_t tag)
{
if (tag >= DEBUG_TAG_MAX)
return;
debug_level_enabled[tag] ^= 0x80;
}
void debug_set_level(debug_tag_t tag, debug_level_t level)
{
if (level >= DEBUG_LEVEL_MAX)
return;
if (tag >= DEBUG_TAG_MAX)
return;
if(level == DEBUG_LEVEL_OFF)
{
debug_level_enabled[tag] = 0;
}
else
{
debug_level_enabled[tag] = level | 0x80;
}
}
debug_level_t debug_get_level(debug_tag_t tag)
{
if (tag >= DEBUG_TAG_MAX)
return DEBUG_LEVEL_OFF;
return debug_level_enabled[tag];
}
Debug.h
#ifndef DEBUG_H
#define DEBUG_H
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Debug levels */
typedef enum {
DEBUG_LEVEL_OFF = 0,
DEBUG_LEVEL_INFO = 1,
DEBUG_LEVEL_WARN = 2,
DEBUG_LEVEL_ERROR = 3,
DEBUG_LEVEL_MAX = 4,
} debug_level_t;
/** Debug tags */
typedef enum {
DEBUG_TAG_SETUP = 0,
DEBUG_TAG_INT = 1,
DEBUG_TAG_STATE = 2,
DEBUG_TAG_MAX = 3,
} debug_tag_t;
#define COLOR_MASK_COLOR 0x0F
#define COLOR_MASK_MODIFIER 0xF0
typedef enum {
/* Colors */
COLOR_RESET = 0xF0,
COLOR_BLACK = 0x01,
COLOR_RED = 0x02,
COLOR_GREEN = 0x03,
COLOR_YELLOW = 0x04,
COLOR_BLUE = 0x05,
COLOR_MAGENTA = 0x06,
COLOR_CYAN = 0x07,
COLOR_WHITE = 0x08,
/* Modifiers */
COLOR_NORMAL = 0x0F,
COLOR_BOLD = 0x10,
COLOR_UNDERLINE = 0x20,
COLOR_BLINK = 0x30,
COLOR_HIDE = 0x40,
} debug_color_t;
typedef void (*debug_hook_func_t)(debug_color_t color, const char *format, va_list args);
void csp_debug_hook_set(debug_hook_func_t f);
/* Extract filename component from path */
#define BASENAME(_file) ((strrchr(_file, '/') ? : (strrchr(_file, '\\') ? : _file)) + 1)
#ifndef NDEBUG
#define debug_assert(exp) \
do { \
if (!(exp)) { \
char *assertion = #exp; \
const char *file = BASENAME(__FILE__); \
int line = __LINE__; \
printf("\E[1;31m Assertion \'%s\' failed in %s:%d\E[0m\r\n", \
assertion, file, line);} \
} while (0)
#else
#define debug_assert(...) do {} while (0)
#endif
#ifdef DEBUG
#define debug(tag, level, format, ...) do { do_debug(tag, level, CONSTSTR(format), ##__VA_ARGS__); } while(0)
#else
#define debug(...) do {} while (0)
#endif
/**
* This function should not be used directly, use log_<level>() macro instead
* @param tag
* @param level
* @param format
*/
void do_debug(debug_tag_t tag, debug_level_t level, const char *format, ...);
/**
* Toggle debug level on/off
* @param tag Tag to toggle
*/
void debug_toggle_level(debug_level_t tag);
/**
* Set debug level
* @param tag Tag value to get
* @param level Level to set
*/
void debug_set_level(debug_tag_t tag, debug_level_t level);
/**
* Get current debug level value
* @param tag Tag value to get
* [url=home.php?mod=space&uid=784970]@return[/url] Level value
*/
debug_level_t debug_get_level(debug_tag_t tag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
总结
以上实现了比较灵活可配置的LOG输出,可配置TAG和指定TAG的输出等级,
方便后面USB调试动态修改条数输出。