qinyunti 发表于 2023-10-30 17:37

【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" >&nbsp;</p>

<h1 ><b>过程</b></h1>

<p >添加debug.c和debug.h</p>

<p >&nbsp;</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 &gt;= DEBUG_TAG_MAX)

return;

debug_level_enabled ^= 0x80;

}





void debug_set_level(debug_tag_t tag, debug_level_t level)

{

if (level &gt;= DEBUG_LEVEL_MAX)

return;

if (tag &gt;= 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 &gt;= DEBUG_TAG_MAX)

return DEBUG_LEVEL_OFF;

return debug_level_enabled;

}</code></pre>

<p >&nbsp;</p>

<p >根据不同等级打印不同颜色</p>

<pre>
<code class="language-cpp">void debug_set_color(debug_color_t color) {



unsigned int color_code, modifier_code;

switch (color &amp; 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 &amp; 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 >&nbsp;</p>

<p >&nbsp;</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 &amp; 0x80) == 0) || ((debug_level_enabled &amp; 0x7F) &gt; 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 &quot;debug.h&quot;</p>

<p >&nbsp;</p>

<p >shell_cmd_list添加一行</p>

<p >&nbsp;&nbsp;{ (const uint8_t*)&quot;debug&quot;, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DebugFun, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;debug tag level&quot;},</p>

<p >&nbsp;</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", &amp;tag, &amp;tag))

  {

debug_set_level(tag, level);

}

}</code></pre>

<p >&nbsp;</p>

<p >shell_func.c中</p>

<p >void DebugFun(unsigned char* param);</p>

<p >&nbsp;</p>

<p >可以看到添加的命令</p>

<p > &nbsp;</p>

<p >&nbsp;</p>

<div style="page-break-after:always"><span style="display: none;">&nbsp;</span></div>

<p>&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<p >&nbsp;</p>

<h2 ><b>测试</b></h2>

<p >Main.c中</p>

<p >#include &quot;debug.h&quot;</p>

<p >&nbsp;</p>

<div style="page-break-after:always"><span style="display: none;">&nbsp;</span></div>

<p>&nbsp;</p>

<p >&nbsp;</p>

<p >使能颜色主题</p>

<p > &nbsp;</p>

<p >输入</p>

<p >debug 0 1</p>

<p >debug 1 1</p>

<p >debug 2 1</p>

<p >使能所有TAG的所有等级输出</p>

<p > &nbsp;</p>

<p >&nbsp;</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 > &nbsp;</p>

<p >&nbsp;</p>

<p >debug 0 0</p>

<p >关闭TAG0输出则只剩下如下两个TAG输出</p>

<p > &nbsp;</p>

<p >&nbsp;</p>

<h2 ><b>代码</b></h2>

<p >Debug.c</p>

<pre>
<code class="language-cpp">#include &lt;stdio.h&gt;
#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 &amp; 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 &amp; 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 &amp; 0x80) == 0) || ((debug_level_enabled &amp; 0x7F) &gt; 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 &gt;= DEBUG_TAG_MAX)
                return;
        debug_level_enabled ^= 0x80;
}


void debug_set_level(debug_tag_t tag, debug_level_t level)
{
        if (level &gt;= DEBUG_LEVEL_MAX)
                return;
        if (tag &gt;= 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 &gt;= 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 &lt;stdint.h&gt;
#include &lt;inttypes.h&gt;
#include &lt;string.h&gt;
#include &lt;stdarg.h&gt;

#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_&lt;level&gt;() 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 >&nbsp;</p>

<p >&nbsp;</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]
查看完整版本: 【ST多款开发板返场测评】STM32F767 Nucleo-144 灵活可配的LOG日志输出实现