不含stm32 底层的代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
MyStm32Code/DOC/14_EasyLogger.md

7.2 KiB

EasyLogger

源码结构

\easylogger\src\elog.c 核心功能源码 \easylogger\src\elog_async.c 核心功能异步输出模式源码 \easylogger\src\elog_buf.c 核心功能缓冲输出模式源码 \easylogger\src\elog_utils.c EasyLogger常用小工具 \easylogger\port\elog_port.c 不同平台下的EasyLogger移植接口 \easylogger\plugins\ 插件源码目录 \docs\zh\ 所有中文文档目录 \demo\non_os\stm32f10x\ stm32f10x裸机的 demo \demo\os\linux\ linux平台 demo \demo\os\windows\ windows平台 demo \demo\os\rt-thread\stm32f10x\ stm32f10x基于RT-Thread的demo(包含Flash插件demo)

移植

将\easylogger\(里面包含inc、src及port的那个)文件夹拷贝到项目中; 添加\easylogger\src\elog.c、\easylogger\src\elog_utils.c及\easylogger\port\elog_port.c这些文件到项目的编译路径中(elog_async.c 及 elog_buf.c 视情况选择性添加); 添加\easylogger\inc\文件夹到编译的头文件目录列表中;

移植初始化 ElogErrCode elog_port_init(void) //main()

日志输出端口 void elog_port_output(const char *log, size_t size)

void elog_port_output(const char *log, size_t size) {
   /* output to terminal */
   printf("%.*s", size, log);
   /* output to flash */
   elog_flash_write(log, size);
}

void elog_port_output_lock(void) void elog_port_output_unlock(void) const char *elog_port_get_time(void) const char *elog_port_get_t_info(void) const char *elog_port_get_t_info(void)

设置参数

配置时需要修改项目中的elog_cfg.h文件,开启、关闭、修改对应的宏即可。

设置模块启用,只输出某个模块

异步输出

main 调用

elog_init(); /* set EasyLogger log format / elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL); elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME); elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~ELOG_FMT_FUNC); / start EasyLogger */ elog_start(); log_i("elog begin");

noos 使用异步

没有信号量,要在 elog_port.c异步输出要加临界区 #include "critical_section.h" /* enable asynchronous output mode / // #define ELOG_ASYNC_OUTPUT_ENABLE / the highest output level for async mode, other level will sync output / #define ELOG_ASYNC_OUTPUT_LVL ELOG_LVL_ASSERT / buffer size for asynchronous output mode / #define ELOG_ASYNC_OUTPUT_BUF_SIZE (ELOG_LINE_BUF_SIZE * 10) / each asynchronous output's log which must end with newline sign / #define ELOG_ASYNC_LINE_OUTPUT / asynchronous output mode using POSIX pthread implementation */ // #define ELOG_ASYNC_OUTPUT_USING_PTHREAD

按子模块输出

#if !defined(LOG_TAG) #define LOG_TAG "xx" #endif #undef LOG_LVL #if defined(XX_LOG_LVL) #define LOG_LVL XX_LOG_LVL #endif

断言及断言钩子

EasyLogger自带的断言,可以直接用户软件,在断言表达式不成立后会输出断言信息并保持while(1),或者执行断言钩子方法,钩子方法的设定参考 elog_assert_set_hook。 void elog_assert_set_hook(void (hook)(const char expr, const char* func, size_t line))

/* EasyLogger断言钩子方法 */
static void elog_user_assert_hook(const char* ex, const char* func, size_t line) {
    /* 失能异步输出方式(异步输出模块自带方法) */
    elog_async_enabled(false);
    /* 失能日志输出锁 */
    elog_output_lock_enabled(false);
    /* 失能 EasyLogger 的 Flash 插件自带同步锁(Flash 插件自带方法) */
    elog_flash_lock_enabled(false);
    /* 输出断言信息 */
    elog_a("elog", "(%s) has assert failed at %s:%ld.\n", ex, func, line);
    /* 将缓冲区中所有日志保存至 Flash (Flash 插件自带方法) */
    elog_flash_flush();
    while(1);
}

使能日志

过滤日志

void elog_set_filter_lvl(uint8_t level) void elog_set_filter_tag(const char *tag) 默认过滤标签为空字符串(""),即不过滤。 当前输出日志的标签会与过滤标签做字符串匹配,日志的标签包含过滤标签,则该输出该日志。 void elog_set_filter_kw(const char *keyword) void elog_set_filter(uint8_t level, const char *tag, const char *keyword) void elog_set_filter_tag_lvl(const char *tag, uint8_t level);

缓冲日志

void elog_buf_enabled(bool enabled) void elog_flush(void) 在判断出错前 ,或执行下个重要动作前执行

异步shuchu

void elog_async_enabled(bool enabled) size_t elog_async_get_log(char *log, size_t size) size_t elog_async_get_line_log(char *log, size_t size)

elog_port.c文件 加critical_section.h

elog_async_output_notice() 引入临界区

void elog_async_output_notice(void) {
    int descriptor;
    descriptor=critical_section_enter();
    flag_output++;
    critical_section_exit(descriptor);
}

elog_async_output 预留的接口,外部实现

void elog_async_output(uint8_t level, const char *log, size_t size) {
    /* this function must be implement by user when ELOG_ASYNC_OUTPUT_USING_PTHREAD is not defined */
    extern void elog_async_output_notice(void);

添加函数 void async_output(void); 头文件 elog.h 实体添加到 elog_port.c, 其他文件就不需要修改了

思路就是,通过进入临界区,判断输出日志窗口的状态。决定是否输出日志。 在main 函数, while底部调用

void async_output(void){
    size_t get_log_size=0;
    int descriptor;
    static char poll_get_buf[ELOG_LINE_BUF_SIZE];
    descriptor=critical_section_enter();
    if(descriptor<0){
        return;
    }
    if(flag_output==0 || rs485_isbusy(&rs485_menu) || menu_get_state(&menu)){
        critical_section_exit(descriptor);
        return;
    }
    flag_output--;
    critical_section_exit(descriptor);
#ifdef ELOG_ASYNC_LINE_OUTPUT
    get_log_size = elog_async_get_line_log(poll_get_buf,ELOG_LINE_BUF_SIZE);
#else
    get_log_size = elog_async_get_log(poll_get_buf, ELOG_ASYNC_POLL_GET_LOG_BUF_SIZE);
#endif
    if(get_log_size){
        elog_port_output(poll_get_buf,get_log_size);
    }
}

ITM通道

ITM_SendChar( ) core_cm4.c 里函数

临界区代码

#ifndef CRITICAL_SECTION_H_
#define CRITICAL_SECTION_H_
#include <stdint.h>
#include <stdlib.h>
struct critical_section
{
    uint32_t flag;
    uint8_t con;
};
int critical_section_enter(void);
void critical_section_exit(int descriptor);
#endif
#include "critical_section.h"
#include "stm32f4xx.h"
static struct critical_section cs={
    .flag=0,
    .con=0
};
/**
 * @brief 进入临界区
 * 
 * @return int 成功:临界区描述符 失败:负值
 */
int critical_section_enter(void)
{
    int tmp;
    if(((cs.flag>>cs.con)&1)!=0){
        return -2;
    }
    if(cs.flag==0){
        __disable_irq();
    }
    cs.flag|=(uint32_t)1<<cs.con;
    tmp=cs.con++;
    cs.con&=0x1f;
    return tmp;
}
/**
 * @brief 退出临界区
 * 
 * @param descriptor 临界区描述符
 */
void critical_section_exit(int descriptor)
{
    if(descriptor>=32){
        return;
    }
    cs.flag&=~((uint32_t)1<<descriptor);
    if(cs.flag==0){
        __enable_irq();
    }
}