H7-TOOL的CANFD Trace全解析功能制作完成,历时一个月(2023-04-28)

Posted 嵌入式系统

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H7-TOOL的CANFD Trace全解析功能制作完成,历时一个月(2023-04-28)相关的知识,希望对你有一定的参考价值。

为了完成这个功能,差不多耗费了一个月时间,精神状态基本已经被磨平了。

当前已经支持:
1、LUA小程序控制,使用灵活。
2、采用SWD接口直接访问目标板芯片的CANFD外设寄存器和CANFD RAM区实现,支持USB,以太网和WiFi方式以及内网和外网访问。
3、可以解析CANFD工作模式,波特率,采样点和是时钟误差率。
4、可以解析所有标准ID过滤器配置和所有扩展ID过滤器配置。
5、可以解析CANFD接收的Rx Buffer,Rx FIFO0和Rx FIFO1数据。
6、通过监测Tx Event FIFO解析Tx Buffer, TxFIFO/Queue的发送事件序列。
7、监测ECR错误计数器和PSR协议状态寄存器。
8、CANFD兼容经典CAN,CANFD用于经典CAN模式也是可以正常解析的。
9、CANFD基本都是采用博世的IP核,所以大家可以方便的修正移植到其他厂家的CANFD芯片监测。

这几天将正式发布分享给大家,同时带来第2期CAN/CANFD/CANopen专题视频教程,将把CANFD的工作机制做个详细的说明

扩展ID过滤器和标准ID过滤器解析均正常

接收消息Rx FIFO 0和Rx FIFO 1也没问题了

Rx Buffer的读取没问题了

发送解析也没问题了,Tx Event里面可以记录Tx Buffer/TxFIFO的发送事件。

 

概念,原理,到例子,全解析logback ,学会日志系统

不管是游戏还是其他的web开发,日志都是非常重要的组件,是解决问题的关键,今天聊聊日志组件Logback。
在业务系统开发中,一般使用的日志框架有 Commons logging 、 Log4j 、 Slf4j 、 Logback 、 Log4j 2 等。
业务日志一般分为trace 、 debug 、 warn、 info 和 error 级别等,线上系统根据其特点进行的相应设置也不同,有的设置为 debug 级别,有的设置为 info 、error 级别在刚上线且不稳定的项目中通常设置为 debug 级别,便于查找问题;在线上系统稳定后使用 error级别即可,这样能够有效地提高效率。避免一些不必要的日志影响解决问题。废话不多说,开始吧。

1、slf4j 和logback的绑定

1、SLF4J和logback 原理

SLF4J是简单的日志外观模式框架,抽象了各种日志框架例如Logback、Log4j、Commons-logging和JDK自带的logging实现接口。它使得用户可以在部署时使用自己想要的日志框架。SLF4J没有替代任何日志框架,它仅仅是标准日志框架的外观模式。如果在类路径下除了SLF4J再没有任何日志框架,那么默认状态是在控制台输出日志。
概念,原理,到例子,全解析logback ,学会日志系统
1、slf4j是java的一个日志门面,实现了日志框架一些通用的api,log4j和logback是具体的日志框架。
2、他们可以单独的使用,也可以绑定slf4j一起使用。
单独使用,分别调用框架自己的方法来输出日志信息。绑定slf4j一起使用。调用slf4j的api来输入日志信息,具体使用与底层日志框架无关(需要底层框架的配置文件)。显然不推荐单独使用日志框架。假设项目中已经使用了log4j,而我们此时加载了一个类库,而这个类库依赖另一个日志框架。这个时候我们就需要维护两个日志框架,这是一个非常麻烦的事情。而使用了slf4j就不同了,由于应用调用的抽象层的api,与底层日志框架是无关的,因此可以任意更换日志框架。

2、源码解析

起点:LoggerFactory.getLogger(App.class),一步一步跟着往下点就可以了。
概念,原理,到例子,全解析logback ,学会日志系统

获取日志factory,如果没初始化,需要初始化
概念,原理,到例子,全解析logback ,学会日志系统
开始进行绑定。
概念,原理,到例子,全解析logback ,学会日志系统
查找StaticLoggerBinder 的实现类
概念,原理,到例子,全解析logback ,学会日志系统
查找系统资源的实现
概念,原理,到例子,全解析logback ,学会日志系统
调用classloader 的接口查找资源,注意路径为 org/slf4j/impl/StaticLoggerBinder.class(这是规则)
概念,原理,到例子,全解析logback ,学会日志系统
getResources() 接口的翻译:查找所有的给定的资源名的资源,资源可以是 图片,声音,文本等等。或者可以被访问的类的代码。
资源的路径是用/ 分割的。
总结:slf4j 在启动的时候查找当前需要的logger,会找到实现的StaticLoggerBinder。
也就是说logback需要在包内实现 org/slf4j/impl/StaticLoggerBinder,然后就会slf4j 和logback 进行绑定
注意:找到实现是通过classLoader.getResource 进行实现的。可以跨越jar包查询

2.3、自己实现:(技术点)


 
   
   
 
public class App {
   public static void main(String[] args) throws IOException {

       Enumeration<URL> resources = App.class.getClassLoader().getResources("org/slf4j/impl/StaticLoggerBinder.class");
       while(resources.hasMoreElements()) {
           URL path = resources.nextElement();
           System.out.println(path);
      }
  }
}
运行结果如下:
可以看到我们加载到了logback的实现类。

2、logback的概念

1、配置文件的加载顺序

logback允许多配置文件,其加载时读取配置文件的顺序如下:
  1. 在classpath查找logback-test.xml(一般classpath为src/test/resources)
  2. 如果该文件不存在,logback尝试寻找logback.groovy
  3. 如果该文件不存在,logback尝试寻找logback.xml
  4. 如果该文件不存在,logback会在META-INF下查找 [com.qos.logback.classic.spi.Configurator](http://logback.qos.ch/xref/ch/qos/logback/classic/spi/Configurator.html)接口的实现
  5. 如果依然找不到,则会使用默认的BasicConfigurator,导致日志直接打印到控制台,日志等级为DEBUG,日志的格式为 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n

2、配置详解

2.1、configuration

  • scan : 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
  • scanPeriod : 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
  • debug : 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。

2.2 root标签

  root标签要求在配置中必须声明一次,root标签其实定义的是root logger的配置信息,它的默认的日志级别为debug。 所有的logger的最终的父logger一定是root logger。
root标签实质是 <logger> 标签,不过其是根标签;若 <logger > <appender> 标签为设置输出级别时就会默认继承该标签设置的级别!
 
   
   
 
<!-- 日志输出级别 -->
   <root level="INFO">
       <appender-ref ref="STDOUT" />
       <appender-ref ref="FILE" />
   </root>

2.3 appender

appender 让我们的应用知道怎么打、打印到哪里、打印成什么样;而 logger 则是告诉应用哪些可以这么打。例如某个类下的日志可以使用这个 appender 打印或者某个包下的日志可以这么打印。
  • ConsoleAppender:把日志添加到控制台
  • FileAppender:把日志添加到文件
  • RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件。它是FileAppender的子
  • additivity 属性为false,表示此logger的打印信息不再向上级传递(注:该值默认为true,logger的日志信息会依次向上级传递,最高级logger为root,如果不加则至少打印2次,本身一次,root一次)-
  • level :用来设置打印级别( TRACE , DEBUG , INFO , WARN , ERROR , ALL OFF ),还有一个值 INHERITED 或者同义词 NULL ,代表强制执行上级的级别。如果没有设置此属性,那么当前 logger 将会继承上级的级别。
  • filter :过滤器可以通过 LevelFilter 过滤器设置日志最低的打印级别
  • encoder :可用通过 Pattern 标签设置日志格式,通过 charset 设置日志的字符集
       
         
         
       
       <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
           <encoder charset="UTF-8">
               <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
               <charset>UTF-8</charset>
           </encoder>
       </appender>

2.4 变量

用来定义变量值,它有两个属性name和value,通过定义的值会被插入到logger上下文中,可以使“${}”来使用变量。
  • name :变量的名称
  • value :变量的值

3、logback实例

springboot 默认使用的日志框架是 logback,其由三个组件组成
  • logback-core
  • logback-classic
  • logback-access
 
   
   
 
<!-- Slf4j 依赖 -->
       <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-api</artifactId>
           <version>1.7.30</version>
       </dependency>
       <!-- logback 依赖 -->
       <dependency>
           <groupId>ch.qos.logback</groupId>
           <artifactId>logback-classic</artifactId>
           <version>1.2.3</version>
       </dependency>
注:可以换成最新版本
 
   
   
 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

   <!--自定义控制台日志格式-->
   <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
       <encoder charset="UTF-8">
           <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
           <charset>UTF-8</charset>
       </encoder>
   </appender>

   <!--系统INFO级别日志-滚动记录日志-->
   <appender name="SYS_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <!--被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值-->
       <File>sys_info.log</File>
       <!--如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。-->
       <append>true</append>
       <!--级别过滤器(LevelFilter),此处只打INFO级别的日志-->
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>INFO</level>
           <!--下面2个属性表示匹配规定level的接受打印,不匹配的(即非INFO)拒绝打印-->
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
       <!-- 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动-->
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <!--设置滚动文件规则,如果直接使用 %d,默认格式是 yyyy-MM-dd-->
           <fileNamePattern>sys_info.log.%d</fileNamePattern>
           <!--保留30天的日志-->
           <maxHistory>30</maxHistory>
       </rollingPolicy>

       <encoder charset="UTF-8">
           <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
           <charset>UTF-8</charset>
       </encoder>
   </appender>

   <!--系统ERROR级别日志-滚动记录日志-->
   <appender name="SYS_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <File>sys_error.log</File>
       <append>true</append>
       <!--此处只打ERROR级别的日志-->
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>ERROR</level>
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>sys_error.log.%d</fileNamePattern>
           <maxHistory>12</maxHistory>
       </rollingPolicy>

       <encoder charset="UTF-8">
           <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
           <charset>UTF-8</charset>
       </encoder>
   </appender>

   <!--不同业务逻辑的日志打印到不同文件,见下面2种业务日志-->

   <!--业务逻辑日志-->
   <appender name="game_Appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <File>D:/log/yj-test/b1.log</File>
       <append>true</append>
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>INFO</level>
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>D:/log/yj-test/b1.log.%d</fileNamePattern>
           <maxHistory>12</maxHistory>
       </rollingPolicy>
       <encoder charset="UTF-8">
           <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
           <charset>UTF-8</charset>
       </encoder>
   </appender>

   <!--战斗日志-->
   <appender name="fight_Appender" class="ch.qos.logback.core.rolling.RollingFileAppender">
       <File>D:/log/yj-test/b2.log</File>
       <append>true</append>
       <filter class="ch.qos.logback.classic.filter.LevelFilter">
           <level>INFO</level>
           <onMatch>ACCEPT</onMatch>
           <onMismatch>DENY</onMismatch>
       </filter>
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
           <fileNamePattern>D:/log/yj-test/b2.log.%d</fileNamePattern>
           <maxHistory>12</maxHistory>
       </rollingPolicy>
       <encoder charset="UTF-8">
           <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %file:%line - %msg%n</pattern>
           <charset>UTF-8</charset>
       </encoder>
   </appender>

   <!-- additivity属性为false,表示此logger的打印信息不再向上级传递(注:该值默认为true,logger的日志信息会依次向上级传递,最高级logger为root,如果不加则至少打印2次,本身一次,root一次)-->
   <logger name="game" additivity="false" level="INFO">
       <appender-ref ref="CONSOLE"/>
   </logger>
   <logger name="fight" additivity="false" level="INFO">
       <appender-ref ref="fight_Appender"/>
   </logger>


   <!--info和error分开打印,注:ERROR > WARN > INFO > DEBUG > TRACE-->
   <root level="INFO">
       <appender-ref ref="CONSOLE"/>
       <appender-ref ref="SYS_INFO"/>
       <appender-ref ref="SYS_ERROR"/>
   </root>

</configuration>
测试代码:
 
   
   
 
package com.pdool.logdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LogDemoApplication {

   public static void main(String[] args) {
       SpringApplication.run(LogDemoApplication.class, args);
       Logger logger = LoggerFactory.getLogger(LogDemoApplication.class);
       Logger gameLogger = LoggerFactory.getLogger("game");
       logger.error("ccccccccccccccc");
       gameLogger.error("bbbbbbbbbbb");
  }

}

4、总结

日志组件要做的就是:
1、公用的变量统一定义 = property
1、日志需要什么什么样的格式输出到什么地方 = appender
2、定义不同的级别 = level
3、不同的日志输出口径 = logger
<property> :定义变量
<appender> :定义日志记录器
<filter> :定义日志过滤器
<rollingPolicy> :定义滚动策略
<springProfile> :定义日志适配的环境
<root> :根日志记录器


以上是关于H7-TOOL的CANFD Trace全解析功能制作完成,历时一个月(2023-04-28)的主要内容,如果未能解决你的问题,请参考以下文章

《安富莱嵌入式周报》第311期:300V可调节全隔离USB PD电源,开源交流负载分析仪,CANFD Trace,6位半多斜率精密ADC设计,开源数学库

H7-TOOL的WiFi版基本成形,无线烧录,无线RTT,无线串口,无线CAN/CANFD,无线LUA小程序,无线示波器等,且支持局域网和外网

H7-TOOL发布固件V2.17, 脱机烧录增加泰为,华大和复旦微新系列以及串口和CANFD接口脱机烧录,LUA小程序实现JSCope HSS模式波形

H7-TOOL发布固件V2.17, 脱机烧录增加泰为,华大和复旦微新系列以及串口和CANFD接口脱机烧录,LUA小程序实现JSCope HSS模式波形

H7-TOOL发布V2.20带来原创RTOS Trace,截图,Scope功能,脱机烧录增加PSoC6, 中颖, 笙泉, 韦斯佰瑞, nRF9160, 杰发科技新系列等

H7-TooL高速 DAPLINK仿真器,含全功能版 RTT Viewer