最近在项目中,同事遇到了一个dbc数据库解析错误的问题:基于ekuiper 对can报文解析,发现实际输出结果与预期差距较大。当时他第一反应是ekuiper的解析规则有误,因此就没有跟踪下去了。因为之前我用过ekuiper的CAN报文解析功能,是没有问题的。因此我更倾向于是他的dbc数据库有问题,于是研究了一下DBC文件解析的规则,并实际验证。过程中也踩了一些坑,在此记录。希望能帮助到有需要的人。
DBC是vector公司定义的can网络通信文件格式。网上介绍的文章很多,有兴趣的朋友可以去搜索一下。本文的主要核心是解析DBC信号部分,对于相关信息进行简略描述。
dbc文件一般包含了如下信息:
这两个参数一般在文件的开头,tag为VERSION
和NS_
。其中VERSION
可以为空或自定义,NS_
一般固定,不需要修改。如下:
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
格式为BS_:[baudrate:BTR1,BTR2];
含义如下:
BS_
为关键字,用于定义CAN网络的波特率;[ ]
内容表示为可选部分,可以省略;BS_:
必须存在,省略则会出错。如下:BS_:
格式为BU_: Nodename1 Nodename2 Nodename3 ……
含义如下:。
BU_
为关键字,表示网络节点;Nodename1、Nodename2
表示网络节点名字,由用户自己定义。通过网络节点方便地进行CAN网络的设计、开发和测试。如下:BU_: EOCM_F_FO Dummy_FO
格式为BO_ MessageId MessageName: MessageSize Transmitter
含义如下:
BO_
,为关键字,表示报文;MessageId
,报文ID,是以10进制数表示的;MessageName
,报文的名字,命名规则和C语言变量相同;MessageSize
,报文数据域字节数,为无符号整型数据,CAN 2.0为最大8字节,CAN FD 最大64字节;Transmitter
,该报文的网络节点;如果该报文没有指定发送节点,则该值需设置为” Vector__XXX”。BO_ 1414 RVB_TVR_Debug2_FO: 7 EOCM_F_FO
格式为:SG_ SignalName (SigTypeDefinition) : StartBit|SignalSize@ByteOrder ValueType (Factor,Offset) [Min|Max] Unit Receiver
含义如下:
SG_
为关键字,表示信号;SignalName
表示该信号的名字;StartBit、 SignalSize
表示该信号起始位、信号长度,不同的字节序,StartBit含义不同;ByteOrder
表示信号的字节顺序:0代表Motorola格式,1代表Inter格式;ValueType
表示该信号的数值类型:+表示无符号数,-表示有符号数;Factor,Offset
表示因子,偏移量;这两个值用于信号的原始值与物理值之间的转换。转换如:物理值=原始值*因子+偏移量
;Min|Max
表示该信号的最小值和最大值,即指定了该信号值的范围;这两个值为double类型;Unit
表示该信号的物理单位,为字符串类型;Receiver
表示该信号的接收节点;若该信号没有指定的接收节点,则必须设置为” Vector__XXX”。如下:定义了一个VBTOSLonPstn
的普通信号,它的起始值在bit7
,长度为12
。字节序为Motorola
,有符号
。因子为0.125
,偏移为0
。数值的范围为-256~255.875
,单位是m
,由Dummy_FO
网络节点接收。
SG_ VBTOSLonPstn : 7|12@0- (0.125,0) [-256|255.875] "m" Dummy_FO
注解部分,特征部分,数值表部分在dbc文件中属于非必须部分,本文不再进一步介绍。综上所述,我们得到最小的dbc文件,后续基于该文件进行解析。
VERSION ""
NS_ :
NS_DESC_
CM_
BA_DEF_
BA_
VAL_
CAT_DEF_
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_
ENVVAR_DATA_
SGTYPE_
SGTYPE_VAL_
BA_DEF_SGTYPE_
BA_SGTYPE_
SIG_TYPE_REF_
VAL_TABLE_
SIG_GROUP_
SIG_VALTYPE_
SIGTYPE_VALTYPE_
BO_TX_BU_
BA_DEF_REL_
BA_REL_
BA_DEF_DEF_REL_
BU_SG_REL_
BU_EV_REL_
BU_BO_REL_
SG_MUL_VAL_
BS_:
BU_: EOCM_F_FO Dummy_FO
BO_ 1414 RVB_TVR_Debug2_FO: 7 EOCM_F_FO
SG_ VBBrkCntlAccel : 45|12@0- (0.01,0) [-20.48|20.47] "m/s^2" Dummy_FO
SG_ VBTOSObjID : 35|6@0+ (1,0) [0|63] "" Dummy_FO
SG_ VBTOSTTC : 31|12@0+ (0.025,0) [0|102.375] "s" Dummy_FO
SG_ VBTOSLatPstn : 11|11@0- (0.125,0) [-128|127.875] "m" Dummy_FO
SG_ VBTOSLonPstn : 7|12@0- (0.125,0) [-256|255.875] "m" Dummy_FO
根据上面的dbc文件,我们进行如下示例分析。向can0网卡发送数据 cansend can0 586#d465737400000000
,ekuiper输出以下结果:
[
{
"VBBrkCntlAccel": 0,
"VBTOSLatPstn": 87.125,
"VBTOSLonPstn": -87.25,
"VBTOSObjID": 0,
"VBTOSTTC": 46.400000000000009
}
]
我们尝试通过对dbc数据库文件的理解进行分析,看看是否与ekuiper的计算结果一致。在分析前,我们需要了解几点内容:
比如:二进制数11010100
,若比特序为大端msb
,则最高有效比特位在高位,最低有效比特位在低位,那么它代表的值为0xd4
;若比特序为lsb
,则最高有效比特位在低位,最低有效比特位在高位,那么它代表的值为0x2b
。CAN 总线协议中规定,位序都是大端模式,即 msb
。
ByteOrder
表示信号的字节顺序。分别为inter和Motorola两种格式。分析:
586#d465737400000000
表示报文ID为0x586
=1414,与RVB_TVR_Debug2_FO
报文匹配。其中d465737400000000
则为该报文的数据部分。RVB_TVR_Debug2_FO
报文长度仅有7Byte。VBBrkCntlAccel
信号的起始位bit45,且为Motorola字节序,则bit45是信号VBBrkCntlAccel
最高有效比特位,因此信号内容如下。即信号原始值为000000000000
,物理值=原始值*(0.01)+0 = 0;VBTOSObjID
原始值为000000
,物理值=0*1+0=0;VBTOSTTC
原始值为011101000000
,物理值=1856*0.025+0=46.4。至于最终的打印结果为什么是46.400000000000009
,可以参考我的博客flaot 数据类型的一些坑(大数吃小数)。VBTOSLatPstn
原始值为01010111001
,物理值=697*0.125+0=87.125。VBTOSLonPstn
原始值为110101000110
。</font color=blue>因为该信号为有符号数,因此最高位1,则表示该值为负。其原始值的补码为110101000110
,则原始值为101010111010
=-698。物理值=-698*0.125+0=-87.25。同样的dbc文件,若由CANdb++进行解析,如下。可知Startbit与dbc文件不一致。因为CANdb++默认是Motorola_LSB表达方式。
若我的内容对您有所帮助,还请关注我的公众号。不定期分享干活,剖析案例,也可以一起讨论分享。
我的宗旨:
踩完您工作中的所有坑并分享给您,让你的工作无bug,人生尽是坦途。
经过两天的查阅资料,以及咨询同事,算是熟悉了dbc数据库的解析规则。希望本篇文章,能够帮助到各位小伙伴。