• 如何在S32K144中优雅地输出调试信息


    1.前言

    前两天在CSDN上面刷到一些介绍开源项目log.c的文章,称赞log.c是一款轻量级日志库,使用简单。笔者怀着兴趣去log.c的github仓库学习了一下,地址如下:

    GitHub - rxi/log.c: A simple logging library implemented in C99

    log.c的源码看,非常适合用在嵌入式Linux系统中,但是在MCU中却没法直接使用。因此,笔者对log.c的源码进行修改,使其能够用在MCU中,并保留原本log.c开源项目的大部分功能,下文称此项目为log.c for mcu

    2.功能

    log.c for mcu主要实现的功能如下:

    • 基础log输出功能
    • 增加颜色识别
    • 增加log输出静默功能
    • 增加低等级log输出屏蔽功能
    • 增加查询log等级对应的字符串名称的功能

    2.1 基础打印功能

    原本的log.c项目实现了六种log输出等级,如下所示,本质上都是对void log_log(int level, const char *file, int line, const char *fmt, ...)的简单封装,log.c for mcu也要实现该功能。

    #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
    #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
    #define log_info(...)  log_log(LOG_INFO,  __FILE__, __LINE__, __VA_ARGS__)
    #define log_warn(...)  log_log(LOG_WARN,  __FILE__, __LINE__, __VA_ARGS__)
    #define log_error(...) log_log(LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
    #define log_fatal(...) log_log(LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    其中,

    • __FILE__ 代表log输出函数所在的文件
    • __LINE__ 代表log输出函数所在的行号
    • __VA_ARGS__ 传输log_trace(...)等宏的括号内的字符串或者可变参数

    2.2 增加颜色识别

    log.c中增加宏定义LOG_USE_COLOR即可实现几种log以不同颜色输出,显示效果如下:

    受宏定义LOG_USE_COLOR影响的主要代码如下:

    #ifdef LOG_USE_COLOR
    static const char *level_colors[] = {
      "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"
    };
    #endif
    
    static void stdout_callback(log_Event *ev) {
      char buf[16];
      buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
    #ifdef LOG_USE_COLOR
      fprintf(
        ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
        buf, level_colors[ev->level], level_strings[ev->level],
        ev->file, ev->line);
    #else
      fprintf(
        ev->udata, "%s %-5s %s:%d: ",
        buf, level_strings[ev->level], ev->file, ev->line);
    #endif
      vfprintf(ev->udata, ev->fmt, ev->ap);
      fprintf(ev->udata, "\n");
      fflush(ev->udata);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这段代码使用的fprintf函数以及vfprintf函数在MCU中并不实用,在log.c for mcu中会修改成printf函数和vprintf函数。

    需要注意的是,"\x1b[94m"这些配置打印信息显示不同颜色的方式,只有在putty这些终端工具才能产生效果,普通的串口工具如sscom不会产生效果。

    2.3 增加log输出静默功能

    log.c使用函数void log_set_quiet(bool enable)进行静默使能,按如下方式调用即可关闭log输出功能。

    log_set_quiet(true);
    
    • 1

    2.4 增加低等级log输出屏蔽功能

    log.c使用函数void log_set_level(int level)进行低等级log输出屏蔽,低于该函数设置的等级的log输出会被屏蔽。默认屏蔽等级设置为LOG_TRACE,即最低的等级0,所以所有log函数都可以输出。

    2.5 增加查询log等级对应的字符串名称的功能

    log.c使用函数const char* log_level_string(int level)返回log等级对应的字符串名称,可以方便的了解LOG_DEBUG等字符串对应的log等级,和函数void log_set_level(int level)配合使用。

    2.6 其他功能

    log.c还有三个功能函数,在MCU裸机中没有用武之地,所以就不移植了。

    int log_add_callback(log_LogFn fn, void *udata, int level);
    int log_add_fp(FILE *fp, int level);
    void log_set_lock(log_LockFn fn, void *udata);
    
    • 1
    • 2
    • 3

    3.源代码修改

    3.1 修改

    1. 对结构体log_Event进行删减,剔除不需要用的成员;同时删除不需要用的typedef自定义的数据类型。
    2. 删除用不到的函数

    3.2 修改

    1. 删除不需要用的typedef自定义的数据类型,对结构体L进行删减。
    2. 修改函数static void stdout_callback(log_Event *ev)的内部实现,使其能够在MCU中运行使用。
    3. 修改函数void log_log(int level, const char *file, int line, const char *fmt, ...)的内部实现,和第2点是主要的修改点。
    4. 删除如下不需要使用的函数。
    • static void file_callback(log_Event *ev)
    • static void lock(void)
    • static void unlock(void)
    • void log_set_lock(log_LockFn fn, void *udata)
    • int log_add_callback(log_LogFn fn, void *udata, int level)
    • int log_add_fp(FILE *fp, int level)
    • static void init_event(log_Event *ev, void *udata)

    4.测试

    将上述章节描述的修改之后的log.c和log.h文件添加到实现串口标准打印输出的程序,同时在main函数中调用相关函数即可,最后基于S32K144EVB-Q100开发板进行测试。

    关于实现串口标准打印输出的程序,可以参考如下文章的1.3.3章节。

    基于S32K144平台实现两种软件定时器_Auto FAE进阶之路的博客-CSDN博客

    4.1 测试基础log输出功能

    4.1.1 main函数编写

    基础功能的main函数编写如下:

    4.1.2 测试情况

    使用普通串口工具打印的信息如下:

    4.2 测试颜色识别功能

    4.2.1 代码修改

    中增加如下宏定义:

    #define LOG_USE_COLOR
    
    • 1
    4.2.2 测试情况

    使用putty终端工具打印的信息如下:

    4.3 测试log输出静默功能

    因为正常情况下,MCU串口打印很少使用putty,所以后面的功能演示会取消颜色识别功能。

    4.3.1 main函数编写

    注释宏定义LOG_USE_COLOR,并修改main函数如下:

    4.3.2 测试情况

    使用普通串口工具打印的信息如下:

    4.4 测试低等级log输出屏蔽功能

    4.4.1 main函数编写

    main函数修改如下:

    4.4.2 测试情况

    使用普通串口工具打印的信息如下:

    4.5 测试查询log等级对应的字符串名称的功能

    4.5.1 main函数编写

    main函数修改如下:

    4.5.2 测试情况

    使用普通串口工具打印的信息如下:

    5.例程分享

    相关例程已上传百度网盘,链接如下:

    • 链接:https://pan.baidu.com/s/1aSYqoXwDROoX0gMfQvBHtQ
    • 提取码:j3av

    如果觉得文章对您有用,帮忙点个关注!!!

  • 相关阅读:
    信息学奥赛一本通:1307:【例1.3】高精度乘法
    c语言进阶篇:指针(五)
    Flink1.17 DataStream API
    523. 连续的子数组和 (前缀和 + 同余性质+哈希)
    编曲学习:钢琴编写 人性化、逻辑预制 工程音频导出
    基于PHP+MySql的酒店信息管理系统的设计与实现
    (学习笔记)SpringCloud微服务快速入门实战课程【2020版】
    JavaScript 字符串连接的工作原理——“+”运算符与“+=”运算符
    VLAN通讯
    2022年8月总结
  • 原文地址:https://blog.csdn.net/bjxdbz/article/details/127411277