【ST多款开发板返场测评】STM32F767 Nucleo-144 灵活可配的LOG日志输出实现
<div class='showpostmsg'><h1><b>前言</b></h1><p >磨刀不误砍柴工,前面的非阻塞串口打印,shell命令行交互都是为了方便后面USB开发的调试。现在开始正是开始砍柴了。第一步我们就是实现比较灵活的LOG输出。主要考虑以下几点需求</p>
<ol>
<li >非阻塞,前面已经实现了相关的接口</li>
<li >可配置日志输出等级,因为调试输出可能很多,所以根据等级过滤会方便查看</li>
<li >可配置日子类型,结合上述等级可控制,进一步能控制不同类型(TAG)的日志的不同等级的使能,这样可以更精确的分类输出。</li>
<li >可动态命令行配置,基于前面的shell可以动态修改不同TAG的不同等级的日志的使能控制。</li>
<li >可以根据不同等级显示不通的颜色,方便屠户显示错误。</li>
</ol>
<p align="justify" > </p>
<h1 ><b>过程</b></h1>
<p >添加debug.c和debug.h</p>
<p > </p>
<p >使能配置如下,一个数组记录每个TAG的当前使能等级</p>
<pre>
<code class="language-cpp">static uint8_t debug_level_enabled = {
};
void debug_toggle_level(debug_level_t tag)
{
if (tag >= DEBUG_TAG_MAX)
return;
debug_level_enabled ^= 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 = 0;
}
else
{
debug_level_enabled = 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;
}</code></pre>
<p > </p>
<p >根据不同等级打印不同颜色</p>
<pre>
<code class="language-cpp">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);
}</code></pre>
<p > </p>
<p > </p>
<p >打印接口</p>
<pre>
<code class="language-cpp">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 & 0x80) == 0) || ((debug_level_enabled & 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);
}</code></pre>
<h2 ><b>添加命令行</b></h2>
<p >shell_func.c中#include "debug.h"</p>
<p > </p>
<p >shell_cmd_list添加一行</p>
<p > { (const uint8_t*)"debug", DebugFun, "debug tag level"},</p>
<p > </p>
<p >添加实现函数</p>
<pre>
<code class="language-cpp">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);
}
}</code></pre>
<p > </p>
<p >shell_func.c中</p>
<p >void DebugFun(unsigned char* param);</p>
<p > </p>
<p >可以看到添加的命令</p>
<p > </p>
<p > </p>
<div style="page-break-after:always"><span style="display: none;"> </span></div>
<p> </p>
<p > </p>
<p > </p>
<p > </p>
<h2 ><b>测试</b></h2>
<p >Main.c中</p>
<p >#include "debug.h"</p>
<p > </p>
<div style="page-break-after:always"><span style="display: none;"> </span></div>
<p> </p>
<p > </p>
<p >使能颜色主题</p>
<p > </p>
<p >输入</p>
<p >debug 0 1</p>
<p >debug 1 1</p>
<p >debug 2 1</p>
<p >使能所有TAG的所有等级输出</p>
<p > </p>
<p > </p>
<p >输入</p>
<p >debug 0 3</p>
<p >debug 1 3</p>
<p >debug 2 3</p>
<p >使能所有TAG的ERROR等级输出</p>
<p >则只输出ERROR</p>
<p > </p>
<p > </p>
<p >debug 0 0</p>
<p >关闭TAG0输出则只剩下如下两个TAG输出</p>
<p > </p>
<p > </p>
<h2 ><b>代码</b></h2>
<p >Debug.c</p>
<pre>
<code class="language-cpp">#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 = {
};
/* 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 & 0x80) == 0) || ((debug_level_enabled & 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 ^= 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 = 0;
}
else
{
debug_level_enabled = 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;
}
</code></pre>
<p >Debug.h</p>
<pre>
<code class="language-cpp">#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
* @return Level value
*/
debug_level_t debug_get_level(debug_tag_t tag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif</code></pre>
<p > </p>
<p > </p>
<h1 ><b>总结</b></h1>
<p >以上实现了比较灵活可配置的LOG输出,可配置TAG和指定TAG的输出等级,</p>
<p >方便后面USB调试动态修改条数输出。</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页:
[1]