精华内容
下载资源
问答
  • DBC解析

    2021-01-25 16:50:16
    DBC文件描述单个CAN网络的通信。这个信息足以监测和分析网络并模拟不是物理可用的节点(剩余的总线模拟)。 DBC文件也可以用来开发电子控制单元的通信软件,该控制单元应该是CAN网络的一部分。 DBC文件不处理ECU...

    关于DBC文件的格式解析

     

    摘要

            在之前的文章里,我们通过一条报文示例展示了创建dbc文件的操作步骤。通过记事本打开在“关于DBC文件的创建”一文中创建的dbc文件,此时界面如下图所示:
    在这里插入图片描述
    如上图所示,一般dbc文件中包含了如下的8种信息:
    1、版本与新符号
    2、波特率定义
    3、网络节点的定义
    4、报文帧的定义
    5、信号的定义
    6、注解部分
    7、属性定义部分
    8、数值表部分

    其中第2点、第3点是必须项,缺少这两项的dbc文件是不能用CANdb++ Editor软件打开的;接下来我们结合例子对dbc文件的这几项信息进行逐步解析介绍。

    1、版本与新符号

            如下图,Dbc文件头部包含着”version”与”new symbol”的信息;
            (1)、 ”version”信息可以为空,也可以由用户自定定义;
            (2)、 ”new symbol”信息在我们创建dbc文件时就已经自动生成;
    所以这一部分的信息我们无需过多留意,一般默认即可。
    在这里插入图片描述

    2、波特率定义

            格式如下:
                            BS_:[baudrate:BTR1,BTR2];
            其中BS_为关键字,用于定义CAN网络的波特率;[ ]内容表示为可选部分,可以省略(如下图例子中即把该部分省略了);但关键字”BS_:”必须存在,省略则会出错

    在这里插入图片描述

    3、网络节点的定义

            格式如下:
                            BU_:Nodename1 Nodename2 Nodename3 ……
            其中BU_为关键字,表示网络节点,格式中的Nodename1、Nodename2表示定义的网络节点名字,由用户自己定义;但需保证节点命名的唯一性。

            如示例中的BU_: AVNT ACU HUD :表示定义了AVNT、ACU、HUD这三个网络节点

    4、报文帧的定义

            格式如下:
                            BO_ MessageId(10进制数表示) MessageName: MessageSize Transmitter

            (1)、BO_为关键字,表示报文;
            (2)、MessageId为定义的报文ID,是以10进制数表示的;如例子中的996,代表报文ID为0x3E4;
            (3)、MessageName表示该报文的名字,命名规则和C语言变量相同;
            (4)、MessageSize表示该报文数据域字节数,为无符号整型数据;
            (5)、Transmitter表示发送该报文的网络节点;如果该报文没有指定发送节点,则该值需设置为” Vector__XXX”。

            如示例中的BO_ 996 HUD_1_B: 8 HUD:表示定义了一条由HUD这个节点发送,数据域长度为8字节,ID为996(0x3E4),名字命名为HUD_1_B的报文

    5、信号的定义

            格式如下:
                            SG_ SignalName : StartBit|SignalSize@ByteOrder ValueType (Factor,Offset) [Min|Max] Unit Receiver

            (1)、SG_为关键字,表示信号;
            (2)、SignalName、 StartBit、 SignalSize分别表示该信号的名字、起始位、信号长度;
            (3)、ByteOrder表示信号的字节顺序:0代表Motorola格式,1代表Inter格式
            (4)、 ValueType 表示该信号的数值类型:+表示无符号数,-表示有符号数
            (5)、Factor表示因子,Offset表示偏移量;这两个值于该信号的原始值与物理值之间的转换。
            转换如下:物理值=原始值*因子+偏移量;
            (6)、Min|Max表示该信号的最小值和最大值,即指定了该信号值的范围;这两个值为double类型;
            (7)、Unit表示该信号的单位,为字符串类型;
            (8)、Receiver表示该信号的接收节点;若该信号没有指定的接收节点,则必须设置为” Vector__XXX”。

            如示例中的 SG_ HUD_BrightnessLv : 15|4@0+ (1,0) [0|15] “lv” ACU,AVNT
    表示定义了一个命名为HUD_BrightnessLv的信号,其起始位是第15位,信号长度4个位;信号是Motorola格式,数值类型为无符号类型数;因子为1,偏移量为0;信号取值范围为0到15;信号单位为字符串”lv”;该信号接收节点为ACU、AVNT这两个节点。

    6、注解部分

            格式如下:
                            CM_ Object MessageId/NodeName “Comment”

            (1)、 CM_为关键字,表示注解信息;
            (2)、 Object表示进行注解的对象类型,可以是节点“BU_”、报文“BO_”、消息”SG_”;
            (3)、 MessageId/NodeName 表示进行注解的对象,若前面的对象类型是信号或者报文,则这里的值应为报文的ID(10进制数表示);若前面的对象类型为节点,则这里的值应为节点的名字;
            (4)、 Comment表示进行注解的文本信息;

            如示例中的 CM_ SG_ 996 HUD_HeightLv “Control hud height level”;
    表示对ID为996(0x3E4)这条报文下的名为”HUD_HeightLv ”的信号进行注解说明,说明的内容为"Control hud height level"。

            又如 CM_ BU_ HUD “Head Up Display";表示对HUD这个节点进行注解说明,说明的内容为" Head Up Display "。

    7、属性定义部分

            格式如下:
                            BA_DEF_ Object AttributeName ValueType Min Max;
                            BA_DEF_DEF_ AttributeName DefaultValue;

            (1)、 BA_DEF_为关键字,表示属性定义;
            (2)、 Object表示属性定义的对象类型,可以是节点“BU_”、报文“BO_”、消息”SG_”、网络节点” ”(用空格表示)等;
            (3)、 AttributeName表示进行定义的属性名字;
            (4)、 ValueType表示属性值的类型,可以是整型、字符串、浮点型、枚举类型等;
            (5)、Min/Max表示属性值的上下最值,即指定了取值范围(字符串类型没有此项)。
            (6)、 BA_DEF_DEF_为关键字,表示定义属性的初始值;
            (7)、 DefaultValue表示该属性的初始值。

            如示例中的 BA_DEF_ SG_ “MyTry” INT 0 11;
                                 BA_DEF_DEF_ “MyTry” 0;
            表示对定义了一个针对信号类型的属性,属性名为”MyTry”,属性值是整型数据,取值范围在0到11之间,初始值为0。

    8、数值表部分

            格式如下:
                            VAL_ MessageId SignalName N “DefineN” …… 0 “Define0”;

            (1)、VAL_为关键字,表示数值表定义;
            (2)、 MessageId表示该信号所属的报文ID(10进制数表示);
            (3)、 SignalName表示信号名;
            (4)、 N “DefineN” …… 0 “Define0”表示定义的数值表内容,即该信号的有效值分别用什么符号表示 。

            如示例中的 VAL_ 996 HUD_OffSt 1 “Active” 0 “Not Active”;
            表示对ID为996(0x3E4)的这条报文下的,一个命名为”HUD_OffSt”的信号,进行其数值表的定义;用”Active”取代1;用”Not Active”取代0。

    小结

            本文通过示例将常见dbc文件的格式分成了以下八点进行了阐述介绍。
            1、版本与新符号
            2、波特率定义
            3、网络节点的定义
            4、报文帧的定义
            5、信号的定义
            6、注解部分
            7、属性定义部分
            8、数值表部分

            其中第2点、第3点是必须项,其他项不一定都有。当我们对dbc文件的结构比较熟悉之后,可以在文本模式下直接对dbc文件进行修改编辑;例如直接拷贝数值表进行修改定义等操作,会比在"CANdb ++ Editor"界面下操作更方便。

     

    1 引言

    DBC文件描述单个CAN网络的通信。这个信息足以监测和分析网络并模拟不是物理可用的节点(剩余的总线模拟)。

     

    DBC文件也可以用来开发电子控制单元的通信软件,该控制单元应该是CAN网络的一部分。 DBC文件不处理ECU的功能行为。

     

    2一般定义

    本文档中使用以下常规元素:

     

    unsigned_integer:一个无符号整数

     

    signed_integer:一个有符号的整数

     

    double:双精度浮点数

     

    char_string:除双连字符('“')以外的任何可打印字符组成的任意字符串。

     

    C_identifier:一个有效的C_identifier。 C_identifiers必须以字母字符或下划线开始,并可能进一步包含

     

    字母数字字符和下划线。 C_identifier =(alpha_char |'_'){alpha_num_char | '_'}

     

    DBC文件中使用的C标识符最多可以有128个字符。为了与旧工具兼容,长度不应超过32个字符。

     

    DBC文件中使用的其他字符串可能是任意长度。

     

    在DBC文件中使用的关键字o标识一个对象的类型在下表中给出:

     

     

    关键字     对象类型

     

    BU_           网络节点

     

    BO_           消息

     

    SG_           信号

     

    EV_           环境变量

     

     

     

     

    语法使用扩展的BNF符号(Backus-Naur-Format)进行描述。

     

     

    符号含义

     

    =使用右侧的语法(语法规则)定义=的左侧的名称。

     

     

    ;分号终止一个定义。

     

    |竖条表示替代方案。

     

    [...]括号内的定义是可选的(零次或一次出现)。

     

    {...}大括号内的定义重复(零次或多次出现)

     

    (...)括号定义分组元素。

     

    '...'连字符中的文本必须按照定义出现。

     

    (* ... *)评论。

     

     

     

    3 DBC文件的结构

    DBC文件格式具有以下总体结构:

     

    DBC_file =

        version

        new_symbols

        bit_timing(*过时但需要*)

        nodes

        value_tables

        messages

        message_transmitters

        environment_variables

        environment_variables_data

        signal_types

        comments

        attribute_definitions

        sigtype_attr_list

        attribute_defaults

        attribute_values

        value_descriptions

        category_definitions(*过时*)

        categories(*过时*)

        filter(*过时*)

        signal_type_refs

        signal_groups

        signal_extended_value_type_list;

     

    描述CAN网络基本通信的DBC文件包括以下部分:

     

             •       Bit_timing

                       这部分是必需的,但通常是空的。

             •       nodes

                       这部分是必需的,并定义了网络节点。

     

             •       messages

                       本节定义了消息和信号。

     

    以下部分不在正常的DBC文件中使用。它们只是为了完整而定义在这里:

     

             •       signal_types

             •       sigtype_attr_list

             •       category_definitions

             •       category

             •       filter

             •       signal_type_refs

             •       signal_extended_value_type_list

     

    描述CAN通信的DBC文件,不定义系统或剩余总线仿真的任何附加数据,不包括环境变量。

     

    4版本和新符号规范

    DBC文件包含一个包含版本和新符号条目的头文件。版本或者是空的,或者是CANdb编辑器使用的字符串。

     

    version = ['VERSION''''{CANdb_version_string}'“'];

     

    new_symbols = ['NS_'':'['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_']];

     

    5位定时定义

    位定时部分定义了波特率和网络的BTR寄存器的设置这部分已经过时,不再使用。尽管如此,他的关键字'BS_'必须出现在DBC文件中。

     

    bit_timing ='BS_:'[baudrate':'BTR1','BTR2];

     

    baudrate = unsigned_integer; BTR1 = unsigned_integer;

     

    BTR2 = unsigned_integer;

     

    6节点定义

    节点部分定义所有参与节点的名称,本节中定义的名称在本节中必须是唯一的。

     

    nodes ='BU_:'{node_name};

     

    node_name = C_identifier;

     

    7值表定义

    值表部分定义了全局值表。值表中的值描述定义了信号原始值的值编码。在常用的DBC文件中,不使用全局值表,而是分别为每个信号定义值描述。

     

    value_tables  =  {value_table} ;

     

    value_table  = 'VAL_TABLE_'  value_table_name  {value_description} ';'  ;

     

    value_table_name  =  C_identifier;

     

    7.1值描述(值编码)

     

    值描述为单个值定义文本描述。该值可以是在总线上传输的信号原始值,也可以是剩余总线(虚拟节点)模拟中环境变量的值。

     

    value_description = double char_string;

     

    8消息定义

    消息部分定义了集群中所有帧的名称以及它们的属性和在这些帧上传输的信号。

     

    messages = {message};

     

    message = BO_  message_id  message_name':'message_size  trans-mitter  {signal} ;

     

    message_id = unsigned_integer;

     

    该消息的CAN-ID。 CAN-ID在DBC文件中必须是唯一的。如果CAN-ID的最高有效位被设置,则该ID是扩展的CAN ID。扩展的CAN ID可以通过用掩码0xCFFFFFFF屏蔽掉最高有效位来确定。

     

        message_name = C_identifier ;

     

    在这个部分定义的名字在这组消息中必须是唯一的。

     

             message_size = unsigned_integer;

     

    message_size以字节为单位指定消息的大小。

     

             transmitter = node_name | 'Vector__XXX';

     

    发送者名称指定发送消息的节点的名称。发件人名称必须在节点部分的节点名称集中定义。如果消息没有发送者,则必须在这里给出字符串Vector__XXX。

     

    8.1信号定义

     

    消息的信号部分列出消息中放置的所有信号,消息数据字段中的位置及其属性。

     

    signal = 'SG_' signal_name multiplexer_indicator ':' start_bit '|' signal_size '@' byte_order value_type '(' factor ',' offset ')' '[' minimum '|' maximum ']' unit receiver {',' receiver} ;

     

    signal_name = C_identifier ;

     

    这里定义的名称对于单个消息的信号必须是唯一的。

     

    multiplexer_indicator = ' ' | 'M' | m multiplexer_switch_value ;

     

    多路复用器指示器定义信号是正常信号、多路复用信号的多路开关,还是多路复用信号。 “M”(大写)字符将信号定义为多路复用器开关。多路复用器交换机中只能有一个信号内的信号。一个“m”(小写)字符,后跟一个无符号整数,将信号定义为复用器开关复用的信号。如果多路复用器信号的开关值等于其multiplexer_switch_value,则多路复用信号被传送到消息中。

     

    start_bit = unsigned_integer ;

     

    start_bit值指定帧的数据字段内信号的位置。对于字节顺序为英特尔(little endian)的信号给出了最低有效位的位置。对于具有字节顺序Motorola(big endian)的信号,给出最高有效位的位置。这些位以锯齿形方式计数。起始位必须在0到(8 * message_size - 1)的范围内。

     

             signal_size = unsigned_integer;

     

             signal_size以位为单位指定信号的大小

     

             byte_order ='0'| '1'; (* 0 =小端,1 =大端*)

     

    如果信号的字节顺序是Intel(小端),则byte_format是0;如果字节顺序是Motorola(大端),则byte_format是1。(这里可能有错误,从其他渠道获取的消息是1=intel ,0=Motorola)

     

             value_type ='+'| ' - '; (* + =无符号, - =有符号*)

     

    value_type将信号定义为unsigned( - )或signed( - )类型。

     

             factor = double;

     

             offset = double;

     

    系数和偏移定义了线性转换规则,将信号原始值转换为信号的物理值,反之亦然:

     

             physical_value = raw_value * factor + offset

     

             raw_value =(physical_value - offset)/ factor

     

    从转换规则公式中可以看出,该因子不能为0。

     

        minimum = double ;

        maximum = double ;

     

    最小值和最大值定义信号有效物理值的范围。

     

             unit = char_string;

     

             receiver = node_name | 'Vector__XXX';

     

    接收者名称指定信号的接收者。接收者名称必须在节点部分的一组节点名称中定义。如果信号没有

    接收器,字符串'Vector__XXX'必须在这里给出。

     

     

    值为“float”和“double”的信号在sig-nal_valtype_list部分有附加条目。

     

        signal_extended_value_type_list = 'SIG_VALTYPE_' message_id signal_

           name signal_extended_value_type ';' ;

        signal_extended_value_type = '0' | '1' | '2' | '3' ; (* 0=signed or

           unsigned integer, 1=32-bit IEEE-float, 2=64-bit IEEE-double *)

    8.2消息发送器的定义

     

    消息发送器部分使得能够定义单个节点的多个发送器节点。这用于描述更高层协议的通信数据。这不用于定义CAN二层通信。

     

        message_transmitters = {message_transmitter} ;

     

        Message_transmitter = 'BO_TX_BU_' message_id ':' {transmitter} ';' ;

     

    8.3信号值描述(值编码)

     

    信号值描述定义了特定信号原始值的编码。

     

        value_descriptions = { value_descriptions_for_signal |

           value_descriptions_for_env_var } ;

     

        value_descriptions_for_signal = 'VAL_' message_id signal_name

           { value_description } ';' ;

    9环境变量定义

    在环境变量部分中定义了用于系统仿真和剩余总线仿真工具的环境变量。

     

        environment_variables = {environment_variable}

     

        environment_variable = 'EV_' env_var_name ':' env_var_type '[' minimum

           '|' maximum ']' unit initial_value ev_id access_type access_

           node {',' access_node } ';' ;

     

        env_var_name = C_identifier ;

     

        env_var_type = '0' | '1' | '2' ; (* 0=integer, 1=float, 2=string *)

     

        minimum = double ;

     

        maximum = double ;

     

        initial_value = double ;

     

        ev_id = unsigned_integer ; (* obsolete *)

        access_type = 'DUMMY_NODE_VECTOR0' | 'DUMMY_NODE_VECTOR1' |

           'DUMMY_NODE_VECTOR2' | 'DUMMY_NODE_VECTOR3' ; (*

           0=unrestricted, 1=read, 2=write, 3=readWrite *)

     

        access_node = node_name | 'VECTOR_XXX' ;

     

    环境变量数据部分中的条目将此处列出的环境定义为数据类型“数据”。这种类型的环境变量可以存储给定长度的任意二进制数据。长度以字节为单位给出。

     

        environment_variables_data = environment_variable_data ;

     

        environment_variable_data = 'ENVVAR_DATA_' env_var_name ':'

           data_size ';' ;

     

        data_size = unsigned_integer ;

     

    9.1环境变量值描述

     

    环境变量的值描述提供了变量特定值的文本表示。

     

        value_descriptions_for_env_var = 'VAL_' env_var_aname

           { value_description } ';' ;

     

    10信号类型和信号组定义

     

    信号类型用于定义几个信号的公共属性。它们通常不用于DBC文件。

     

        signal_types = {signal_type} ;

     

        signal_type = 'SGTYPE_' signal_type_name ':' signal_size '@'

           byte_order value_type '(' factor ',' offset ')' '[' minimum '|'

           maximum ']' unit default_value ',' value_table ';' ;

     

        signal_type_name = C_identifier ;

     

        default_value = double ;

     

        value_table = value_table_name ;

     

     

        signal_type_refs = {signal_type_ref} ;

     

        signal_type_ref = 'SGTYPE_' message_id signal_name ':' signal_

           type_name ';' ;

    信号组被用来定义消息内的一组信号,例如,以确定一个组的信号必须共同更新。

     

        signal_groups = 'SIG_GROUP_' message_id signal_group_name repetitions

           ':' { signal_name } ';' ;

     

        signal_group_name = C_identifier ;

     

        repetitions = unsigned_integer ;

     

    11注释定义

     

    注释部分包含对象注释。对于每个有注释的对象,本节定义了一个带有对象类型标识的条目。

     

        comments = {comment} ;

     

        comment = 'CM_' (char_string |

           'BU_' node_name char_string |

           'BO_' message_id char_string |

           'SG_' message_id signal_name char_string |

           'EV_' env_var_name char_string)

           ';' ;

     

    12用户定义的属性定义

    用户定义的属性是扩展DBC文件的对象属性的一种手段。这些附加属性必须使用具有属性默认值的属性定义进行定义。对于每个具有为该属性定义的值的对象,都必须定义一个属性值条目。如果没有为对象定义属性值条目,则该对象的属性值是该属性的默认值。

     

    12.1属性定义

     

        attribute_definitions = { attribute_definition } ;

     

        attribute_definition = 'BA_DEF_' object_type attribute_name attribute_

           value_type ';' ;

     

        object_type = '' | 'BU_' | 'BO_' | 'SG_' | 'EV_' ;

     

        attribute_name = '"' C_identifier '"' ;

     

        attribute_value_type = 'INT' signed_integer signed_integer |

           'HEX' signed_integer signed_integer |

           'FLOAT' double double |

           'STRING' |

           'ENUM' [char_string {',' char_string}]

     

     

        attribute_defaults = { attribute_default } ;

     

        attribute_default = 'BA_DEF_DEF_' attribute_name attribute_value

           ';' ;

     

        attribute_value = unsigned_integer | signed_integer | double |

            char_string ;

     

    12.2属性值

     

        attribute_values = { attribute_value_for_object } ;

     

        attribute_value_for_object = 'BA_' attribute_name (attribute_value |

           'BU_' node_name attribute_value |

           'BO_' message_id attribute_value |

           'SG_' message_id signal_name attribute_value |

           'EV_' env_var_name attribute_value)

    13         Examples

     

    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_       

    BS_:        

     

    BU_: Engine Gateway       

     

    BO_ 100 EngineData: 8 Engine        

      SG_ PetrolLevel : 24|8@1+ (1,0) [0|255] "l"   Gateway   

      SG_ EngPower : 48|16@1+ (0.01,0) [0|150]  "kW"   Gateway   

      SG_ EngForce : 32|16@1+ (1,0) [0|0] "N"   Gateway   

      SG_ IdleRunning : 23|1@1+ (1,0) [0|0] ""  Gateway   

      SG_ EngTemp : 16|7@1+ (2,-50) [-50|150] "degC"  Gateway 

      SG_ EngSpeed : 0|16@1+ (1,0) [0|8000] "rpm"   Gateway   

     

     

    CM_ "CAN communication matrix for power train electronics *******************************************************

     

    implemented: turn lights, warning lights, windows";

     

    VAL_ 100 IdleRunning 0 "Running" 1 "Idle" ;

    展开全文
  • 周立功DBC解析模块库资料,用周立功硬件产品解析DBC文件
  • 类型:PDF文档。 版本:Version 01/2007。 描述:DBC File Format Documentation。 详情:Vertor官方DBC文件描述。
  • 支持asc,cvs,txt等等等格式方便好用,离线曲线解析更方便,CAN报文自动解析工具,只需要加载协议以及报文,即可实现自动解析报文信息。
  • CAN DBC解析自动生成C 信号 API代码

    千次阅读 2019-04-08 16:54:34
    众所周知,Python的脚本解析最近非常流行,Python入门是非常友好的,... 目标:通过Python对CAN DBC文件进行解析,并把帧解析为具体的信号。 实现过程:方法一,Python读取DBC====》对DBC完成信号提取====》生成...

        众所周知,Python的脚本解析最近非常流行,Python入门是非常友好的,如果有C语言基础,一周基本就入门了。

        一直想写一下DBC自动生成代码的小工具,正好借助小工具的编写,学习一下Python。

        目标:通过Python对CAN DBC文件进行解析,并把帧解析为具体的信号。

        实现过程:方法一,Python读取DBC====》对DBC完成信号提取====》生成对应的信号API接口

                          方法二,通过Matlab CAN Unpack也可实现

                          方法一更加灵活,方便代码集成,故采用方法一

    生成脚本

    dbc_demo.py -i 243.dbc -s IO > IO.txt
    :pause
    choice /t 20 /d y /n >nul

    生成代码

    
    #ifndef __GENEARTED_DBC_PARSER
    #define __GENERATED_DBC_PARSER
    #include <stdbool.h>
    #include <stdint.h>
    #include <stdlib.h>
    
    
    
    /// Extern function needed for dbc_encode_and_send()
    extern bool dbc_app_send_can_msg(uint32_t mid, uint8_t dlc, uint8_t bytes[8]);
    
    /// Missing in Action structure
    typedef struct {
        uint32_t is_mia : 1;          ///< Missing in action flag
        uint32_t mia_counter_ms : 31; ///< Missing in action counter
    } dbc_mia_info_t;
    
    /// CAN message header structure
    typedef struct { 
        uint32_t mid; ///< Message ID of the message
        uint8_t  dlc; ///< Data length of the message
    } dbc_msg_hdr_t; 
    
    static const dbc_msg_hdr_t DBC_TEST1_HDR =                        { 0x1f4, 8 };
    static const dbc_msg_hdr_t DBC_TEST2_HDR =                        { 0x1f5, 8 };
    static const dbc_msg_hdr_t DBC_TEST3_HDR =                        { 0x1f6, 8 };
    // static const dbc_msg_hdr_t DRIVER_HEARTBEAT_HDR =                 { 0x64, 1 };
    // static const dbc_msg_hdr_t MOTOR_CMD_HDR =                        { 0x65, 1 };
    static const dbc_msg_hdr_t MOTOR_STATUS_HDR =                     { 0x190, 3 };
    static const dbc_msg_hdr_t SENSOR_SONARS_HDR =                    { 0xc8, 8 };
    static const dbc_msg_hdr_t DBC_TEST4_HDR =                        { 0x1f7, 8 };
    
    
    
    
    /// Message: DBC_TEST1 from 'IO', DLC: 8 byte(s), MID: 0x1f4
    typedef struct {
        uint32_t DBC_TEST1_unsigned1 : 8;         ///< B7:0   Destination: DBG
        uint32_t DBC_TEST1_unsigned_minmax : 8;   ///< B15:8  Min: 0 Max: 100   Destination: DBG
        uint32_t DBC_TEST1_enum : 8;              ///< B39:32   Destination: DBG
        uint32_t DBC_TEST1_float : 8;             ///< B47:40   Destination: DBG
        uint32_t DBC_TEST1_float_signed : 16;     ///< B63:48  Min: 0 Max: 65.535   Destination: DBG
    
        // No dbc_mia_info_t for a message that we will send
    } DBC_TEST1_t;
    
    
    /// Message: DBC_TEST2 from 'IO', DLC: 8 byte(s), MID: 0x1f5
    typedef struct {
        uint32_t DBC_TEST2_real_signed1 : 12;     ///< B17:6   Destination: DBG
        uint32_t DBC_TEST2_real_signed2 : 18;     ///< B35:18   Destination: DBG
        uint32_t DBC_TEST2_signed : 8;            ///< B43:36   Destination: DBG
        uint32_t DBC_TEST2_signed_minmax : 16;    ///< B59:44  Min: -32768 Max: 32767   Destination: DBG
    
        // No dbc_mia_info_t for a message that we will send
    } DBC_TEST2_t;
    
    
    /// Message: DBC_TEST3 from 'IO', DLC: 8 byte(s), MID: 0x1f6
    typedef struct {
        uint32_t DBC_TEST3_real_signed1 : 4;      ///< B5:2   Destination: DBG
        uint32_t DBC_TEST3_real_signed2 : 8;      ///< B15:8   Destination: DBG
    
        // No dbc_mia_info_t for a message that we will send
    } DBC_TEST3_t;
    
    
    /// Message: MOTOR_STATUS from 'MOTOR', DLC: 3 byte(s), MID: 0x190
    typedef struct {
        uint32_t MOTOR_STATUS_wheel_error : 1;    ///< B0:0   Destination: DRIVER,IO
        uint32_t MOTOR_STATUS_speed_kph : 16;     ///< B23:8   Destination: DRIVER,IO
    
        dbc_mia_info_t mia_info;
    } MOTOR_STATUS_t;
    
    /// @{ MUX'd message: SENSOR_SONARS
    
    /// Struct for MUX: m0 (used for transmitting)
    typedef struct {
        uint32_t SENSOR_SONARS_err_count : 12;    ///< B15:4   Destination: DRIVER,IO
        uint32_t SENSOR_SONARS_left : 12;         ///< B27:16   Destination: DRIVER,IO
        uint32_t SENSOR_SONARS_middle : 12;       ///< B39:28   Destination: DRIVER,IO
        uint32_t SENSOR_SONARS_right : 12;        ///< B51:40   Destination: DRIVER,IO
        uint32_t SENSOR_SONARS_rear : 12;         ///< B63:52   Destination: DRIVER,IO
    
        dbc_mia_info_t mia_info;
    } SENSOR_SONARS_m0_t;
    
    /// Struct for MUX: m1 (used for transmitting)
    typedef struct {
        uint32_t SENSOR_SONARS_err_count : 12;    ///< B15:4   Destination: DRIVER,IO
        uint32_t SENSOR_SONARS_no_filt_left : 12; ///< B27:16   Destination: DBG
        uint32_t SENSOR_SONARS_no_filt_middle : 12; ///< B39:28   Destination: DBG
        uint32_t SENSOR_SONARS_no_filt_right : 12; ///< B51:40   Destination: DBG
        uint32_t SENSOR_SONARS_no_filt_rear : 12; ///< B63:52   Destination: DBG
    
        dbc_mia_info_t mia_info;
    } SENSOR_SONARS_m1_t;
    
    /// Struct with all the child MUX'd signals (Used for receiving)
    typedef struct {
        SENSOR_SONARS_m0_t m0; ///< MUX'd structure
        SENSOR_SONARS_m1_t m1; ///< MUX'd structure
    } SENSOR_SONARS_t;
    /// @} MUX'd message
    
    
    /// Message: DBC_TEST4 from 'IO', DLC: 8 byte(s), MID: 0x1f7
    typedef struct {
        uint32_t DBC_TEST4_real_signed1 : 32;     ///< B31:0   Destination: DBG
        uint32_t DBC_TEST4_real_signed2 : 16;     ///< B47:32  Min: -32768 Max: 32767   Destination: DBG
        uint32_t DBC_TEST4_real_overflow : 16;    ///< B63:48   Destination: DBG
    
        // No dbc_mia_info_t for a message that we will send
    } DBC_TEST4_t;
    
    
    /// @{ These 'externs' need to be defined in a source file of your project
    extern const uint32_t                             MOTOR_STATUS__MIA_MS;
    extern const MOTOR_STATUS_t                       MOTOR_STATUS__MIA_MSG;
    extern const uint32_t                             SENSOR_SONARS_m0__MIA_MS;
    extern const SENSOR_SONARS_m0_t                   SENSOR_SONARS_m0__MIA_MSG;
    extern const uint32_t                             SENSOR_SONARS_m1__MIA_MS;
    extern const SENSOR_SONARS_m1_t                   SENSOR_SONARS_m1__MIA_MSG;
    /// @}
    
    
    /// Encode IO's 'DBC_TEST1' message
    /// @returns the message header of this message
    static inline dbc_msg_hdr_t dbc_encode_DBC_TEST1(uint8_t frame[8], DBC_TEST1_t *msg)
    {
        uint32_t raw;
        frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:0BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 0, 8, msg->DBC_TEST1_unsigned1);
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:8BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 8, 8, msg->DBC_TEST1_unsigned_minmax);
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:32BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 32, 8, msg->DBC_TEST1_enum);
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:40BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 40, 8, msg->DBC_TEST1_float);
    
        // Stuff a SIG into the DBC 16-bit signal
        ///<  bit(s) starting from BBitStart:48BitSize:16
        set_frame_data(frame, MOTOROLA_MSB, 48, 16, msg->DBC_TEST1_float_signed);
    
        return DBC_TEST1_HDR;
    }
    
    /// Encode and send for dbc_encode_DBC_TEST1() message
    static inline bool dbc_encode_and_send_DBC_TEST1(DBC_TEST1_t *from)
    {
        uint8_t bytes[8];
        const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST1(bytes, from);
        return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
    }
    
    
    
    /// Encode IO's 'DBC_TEST2' message
    /// @returns the message header of this message
    static inline dbc_msg_hdr_t dbc_encode_DBC_TEST2(uint8_t frame[8], DBC_TEST2_t *msg)
    {
        uint32_t raw;
        frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;
    
        // Stuff a SIG into the DBC 12-bit signal
        ///<  bit(s) starting from BBitStart:6BitSize:12
        set_frame_data(frame, MOTOROLA_MSB, 6, 12, msg->DBC_TEST2_real_signed1);
    
        // Stuff a SIG into the DBC 18-bit signal
        ///<  bit(s) starting from BBitStart:18BitSize:18
        set_frame_data(frame, MOTOROLA_MSB, 18, 18, msg->DBC_TEST2_real_signed2);
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:36BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 36, 8, msg->DBC_TEST2_signed);
    
        // Stuff a SIG into the DBC 16-bit signal
        ///<  bit(s) starting from BBitStart:44BitSize:16
        set_frame_data(frame, MOTOROLA_MSB, 44, 16, msg->DBC_TEST2_signed_minmax);
    
        return DBC_TEST2_HDR;
    }
    
    /// Encode and send for dbc_encode_DBC_TEST2() message
    static inline bool dbc_encode_and_send_DBC_TEST2(DBC_TEST2_t *from)
    {
        uint8_t bytes[8];
        const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST2(bytes, from);
        return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
    }
    
    
    
    /// Encode IO's 'DBC_TEST3' message
    /// @returns the message header of this message
    static inline dbc_msg_hdr_t dbc_encode_DBC_TEST3(uint8_t frame[8], DBC_TEST3_t *msg)
    {
        uint32_t raw;
        frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;
    
        // Stuff a SIG into the DBC 4-bit signal
        ///<  bit(s) starting from BBitStart:2BitSize:4
        set_frame_data(frame, MOTOROLA_MSB, 2, 4, msg->DBC_TEST3_real_signed1);
    
        // Stuff a SIG into the DBC 8-bit signal
        ///<  bit(s) starting from BBitStart:8BitSize:8
        set_frame_data(frame, MOTOROLA_MSB, 8, 8, msg->DBC_TEST3_real_signed2);
    
        return DBC_TEST3_HDR;
    }
    
    /// Encode and send for dbc_encode_DBC_TEST3() message
    static inline bool dbc_encode_and_send_DBC_TEST3(DBC_TEST3_t *from)
    {
        uint8_t bytes[8];
        const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST3(bytes, from);
        return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
    }
    
    
    
    /// Not generating code for dbc_encode_DRIVER_HEARTBEAT() since the sender is DRIVER and we are IO
    
    /// Not generating code for dbc_encode_MOTOR_CMD() since the sender is DRIVER and we are IO
    
    /// Not generating code for dbc_encode_MOTOR_STATUS() since the sender is MOTOR and we are IO
    
    /// Not generating code for dbc_encode_SENSOR_SONARS() since the sender is SENSOR and we are IO
    
    /// Encode IO's 'DBC_TEST4' message
    /// @returns the message header of this message
    static inline dbc_msg_hdr_t dbc_encode_DBC_TEST4(uint8_t frame[8], DBC_TEST4_t *msg)
    {
        uint32_t raw;
        frame[0]=frame[1]=frame[2]=frame[3]=frame[4]=frame[5]=frame[6]=frame[7]=0;
    
        // Stuff a SIG into the DBC 32-bit signal
        ///<  bit(s) starting from BBitStart:0BitSize:32
        set_frame_data(frame, MOTOROLA_MSB, 0, 32, msg->DBC_TEST4_real_signed1);
    
        // Stuff a SIG into the DBC 16-bit signal
        ///<  bit(s) starting from BBitStart:32BitSize:16
        set_frame_data(frame, MOTOROLA_MSB, 32, 16, msg->DBC_TEST4_real_signed2);
    
        // Stuff a SIG into the DBC 16-bit signal
        ///<  bit(s) starting from BBitStart:48BitSize:16
        set_frame_data(frame, MOTOROLA_MSB, 48, 16, msg->DBC_TEST4_real_overflow);
    
        return DBC_TEST4_HDR;
    }
    
    /// Encode and send for dbc_encode_DBC_TEST4() message
    static inline bool dbc_encode_and_send_DBC_TEST4(DBC_TEST4_t *from)
    {
        uint8_t bytes[8];
        const dbc_msg_hdr_t hdr = dbc_encode_DBC_TEST4(bytes, from);
        return dbc_app_send_can_msg(hdr.mid, hdr.dlc, bytes);
    }
    
    
    
    /// Not generating code for dbc_decode_DBC_TEST1() since 'IO' is not the recipient of any of the signals
    
    /// Not generating code for dbc_decode_DBC_TEST2() since 'IO' is not the recipient of any of the signals
    
    /// Not generating code for dbc_decode_DBC_TEST3() since 'IO' is not the recipient of any of the signals
    
    /// Not generating code for dbc_decode_DRIVER_HEARTBEAT() since 'IO' is not the recipient of any of the signals
    
    /// Not generating code for dbc_decode_MOTOR_CMD() since 'IO' is not the recipient of any of the signals
    
    /// Decode MOTOR's 'MOTOR_STATUS' message
    /// @param hdr  The header of the message to validate its DLC and MID; this can be NULL to skip this check
    static inline bool dbc_decode_MOTOR_STATUS(MOTOR_STATUS_t *msg, const uint8_t frame[8], const dbc_msg_hdr_t *hdr)
    {
        const bool success = true;
        // If msg header is provided, check if the DLC and the MID match
        if (NULL != hdr && (hdr->dlc != MOTOR_STATUS_HDR.dlc || hdr->mid != MOTOR_STATUS_HDR.mid)) {
            return !success;
        }
    
        uint32_t raw;
        // Stuff a SIG from the DBC 1-bit signal
        ///<  bit(s) starting from BBitStart:0BitSize:1
        get_frame_data(frame, MOTOROLA_MSB, 0, 1, msg->MOTOR_STATUS_wheel_error);
        // Stuff a SIG from the DBC 16-bit signal
        ///<  bit(s) starting from BBitStart:8BitSize:16
        get_frame_data(frame, MOTOROLA_MSB, 8, 16, msg->MOTOR_STATUS_speed_kph);
    
        msg->mia_info.mia_counter_ms = 0; ///< Reset the MIA counter
    
        return success;
    }
    
    
    /// Decode SENSOR's 'SENSOR_SONARS' message
    /// @param hdr  The header of the message to validate its DLC and MID; this can be NULL to skip this check
    static inline bool dbc_decode_SENSOR_SONARS(SENSOR_SONARS_t *msg, const uint8_t frame[8], const dbc_msg_hdr_t *hdr)
    {
        const bool success = true;
        // If msg header is provided, check if the DLC and the MID match
        if (NULL != hdr && (hdr->dlc != SENSOR_SONARS_HDR.dlc || hdr->mid != SENSOR_SONARS_HDR.mid)) {
            return !success;
        }
    
        uint32_t raw;
        // Decode the MUX
        uint8_t MUX = 0;    // Stuff a SIG from the DBC 4-bit signal
        ///<  bit(s) starting from BBitStart:0BitSize:4
        get_frame_data(frame, MOTOROLA_MSB, 0, 4, &MUX);
    
        if (0 == MUX) {
            // Non Muxed signals (part of all MUX'd structures)
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:4BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 4, 12, &msg->m0.SENSOR_SONARS_err_count);
    
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:16BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 16, 12, &msg->m0.SENSOR_SONARS_left);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:28BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 28, 12, &msg->m0.SENSOR_SONARS_middle);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:40BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 40, 12, &msg->m0.SENSOR_SONARS_right);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:52BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 52, 12, &msg->m0.SENSOR_SONARS_rear);
    
            msg->m0.mia_info.mia_counter_ms = 0; ///< Reset the MIA counter
        }
        else if (1 == MUX) {
            // Non Muxed signals (part of all MUX'd structures)
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:4BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 4, 12, &msg->m1.SENSOR_SONARS_err_count);
    
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:16BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 16, 12, &msg->m1.SENSOR_SONARS_no_filt_left);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:28BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 28, 12, &msg->m1.SENSOR_SONARS_no_filt_middle);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:40BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 40, 12, &msg->m1.SENSOR_SONARS_no_filt_right);
            // Stuff a SIG from the DBC 12-bit signal
            ///<  bit(s) starting from BBitStart:52BitSize:12
            get_frame_data(frame, MOTOROLA_MSB, 52, 12, &msg->m1.SENSOR_SONARS_no_filt_rear);
    
            msg->m1.mia_info.mia_counter_ms = 0; ///< Reset the MIA counter
        }
        else {
            return !success;
        }
    
        return success;
    }
    
    
    /// Not generating code for dbc_decode_DBC_TEST4() since 'IO' is not the recipient of any of the signals
    
    /// Handle the MIA for MOTOR's MOTOR_STATUS message
    /// @param   time_incr_ms  The time to increment the MIA counter with
    /// @returns true if the MIA just occurred
    /// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
    static inline bool dbc_handle_mia_MOTOR_STATUS(MOTOR_STATUS_t *msg, uint32_t time_incr_ms)
    {
        bool mia_occurred = false;
        const dbc_mia_info_t old_mia = msg->mia_info;
        msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= MOTOR_STATUS__MIA_MS);
    
        if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
            msg->mia_info.mia_counter_ms += time_incr_ms;
        }
        else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
            // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
            *msg = MOTOR_STATUS__MIA_MSG;
            msg->mia_info.mia_counter_ms = MOTOR_STATUS__MIA_MS;
            msg->mia_info.is_mia = true;
            mia_occurred = true;
        }
    
        return mia_occurred;
    }
    
    /// Handle the MIA for SENSOR's SENSOR_SONARS for MUX "m0" message
    /// @param   time_incr_ms  The time to increment the MIA counter with
    /// @returns true if the MIA just occurred
    /// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
    static inline bool dbc_handle_mia_SENSOR_SONARS_m0(SENSOR_SONARS_m0_t *msg, uint32_t time_incr_ms)
    {
        bool mia_occurred = false;
        const dbc_mia_info_t old_mia = msg->mia_info;
        msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= SENSOR_SONARS_m0__MIA_MS);
    
        if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
            msg->mia_info.mia_counter_ms += time_incr_ms;
        }
        else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
            // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
            *msg = SENSOR_SONARS_m0__MIA_MSG;
            msg->mia_info.mia_counter_ms = SENSOR_SONARS_m0__MIA_MS;
            msg->mia_info.is_mia = true;
            mia_occurred = true;
        }
    
        return mia_occurred;
    }
    
    /// Handle the MIA for SENSOR's SENSOR_SONARS for MUX "m1" message
    /// @param   time_incr_ms  The time to increment the MIA counter with
    /// @returns true if the MIA just occurred
    /// @post    If the MIA counter reaches the MIA threshold, MIA struct will be copied to *msg
    static inline bool dbc_handle_mia_SENSOR_SONARS_m1(SENSOR_SONARS_m1_t *msg, uint32_t time_incr_ms)
    {
        bool mia_occurred = false;
        const dbc_mia_info_t old_mia = msg->mia_info;
        msg->mia_info.is_mia = (msg->mia_info.mia_counter_ms >= SENSOR_SONARS_m1__MIA_MS);
    
        if (!msg->mia_info.is_mia) { // Not MIA yet, so keep incrementing the MIA counter
            msg->mia_info.mia_counter_ms += time_incr_ms;
        }
        else if(!old_mia.is_mia)   { // Previously not MIA, but it is MIA now
            // Copy MIA struct, then re-write the MIA counter and is_mia that is overwriten
            *msg = SENSOR_SONARS_m1__MIA_MSG;
            msg->mia_info.mia_counter_ms = SENSOR_SONARS_m1__MIA_MS;
            msg->mia_info.is_mia = true;
            mia_occurred = true;
        }
    
        return mia_occurred;
    }
    
    #endif

    Python片段

    def main(argv):
        dbcfile = '243.dbc'  # Default value unless overriden
        self_node = 'DRIVER'  # Default value unless overriden
        gen_all = False
        muxed_signal = False
        mux_bit_width = 0
        msg_ids_used = []
        try:
            opts, args = getopt.getopt(argv, "i:s:a", ["ifile=", "self=", "all"])
        except getopt.GetoptError:
            print('dbc_parse.py -i <dbcfile> -s <self_node> <-a>')
            sys.exit(2)
        for opt, arg in opts:
            if opt == '-h':
                print('dbc_parse.py -i <dbcfile> -s <self_node> <-a> <-b>')
                sys.exit()
            elif opt in ("-i", "--ifile"):
                dbcfile = arg
            elif opt in ("-s", "--self"):
                self_node = arg
            elif opt in ("-a", "--all"):
                gen_all = True
    
        # Parse the DBC file
        dbc = DBC(dbcfile, self_node, gen_all)
        f = open(dbcfile, "r")
        last_mid = -1
        validFile = True
        while 1:
            line = f.readline()
            if not line:
                break
    
            # Nodes in the DBC file
            if line.startswith("BU_:"):
                nodes = line.strip("\n").split(' ')
                dbc.nodes = (nodes[1:])
                if self_node not in dbc.nodes:
                    print('/// ERROR /')
                    print('#error "Self node: ' + self_node + ' not found in _BU nodes in the DBC file"')
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error "Self node: ' + self_node + ' not found in _BU nodes in the DBC file"')
    
            # Start of a message
            # BO_ 100 DRIVER_HEARTBEAT: 1 DRIVER
            if line.startswith("BO_ "):
                muxed_signal = False
                mux_bit_width = 0
                tokens = line.split(' ')
                msg_id = hex(int(tokens[1],10))
                msg_name = tokens[2].strip(":")
                dbc.messages[msg_id] = Message(msg_id, msg_name, tokens[3], tokens[4].strip("\n"))
                msg_length = tokens[3]
                last_mid = msg_id
                fixed_mux_signal = False
                fixed_signal_end = 0
                prev_signal_end = 0
                prev_mux_index = 0
    
                if (int(msg_id, 16) < 0) or (int(msg_id, 16) > 536870911):
                    print('/// ERROR /')
                    print('#error msg id '+ tokens[1] + ' is out of bounds')
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error msg id '+ tokens[1] + ' is out of bounds for 29-bit msgID')
    
                if msg_id not in msg_ids_used:
                    msg_id = msg_ids_used.append(msg_id)
                else:
                    print('/// ERROR /')
                    print('#error '+ tokens[1] + ' has already been used')
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error msg id '+ msg_id + ' has already been used')
    
                if (int(msg_length) > 8) or (int(msg_length) < 0):
                    print('/// ERROR /')
                    print('#error ' + str(tokens[1]) + ' has an incorrect number of bytes. It must be between 0 and 8 bytes.')
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error msg id ' + str(tokens[1]) + ' has an incorrect number of bytes. It must be between 0 and 8 bytes.')
    
            # Signals: SG_ IO_DEBUG_test_signed : 16|8@1+ (1,-128) [0|0] "" DBG
            if line.startswith(" SG_ "):
                t = line[1:].split(' ')
    
                # If this is a MUX'd symbol
                mux = ''
                if t[3] == ":":
                    mux = t[2]
                    line = line.replace(mux + " ", '')
                    t = line[1:].split(' ')
    
                # Split the bit start and the bit size
                s = re.split('[|@]', t[3])
                bit_start = s[0]
                bit_size = s[1]
    
                if mux == 'M':
                    muxed_signal = True
                    mux_bit_width = int(bit_size)
    
                if not muxed_signal:
                    if (int(bit_start) < prev_signal_end):
                        print('/// ERROR /')
                        print('#error ' + t[1] + ' start bit overwrites previous signal')
                        print('/// ERROR /')
                        print('')
                        raise ValueError('#error ' + t[1] + ' start bit overwrites previous signal')
                    prev_signal_end = int(bit_start) + int(bit_size)
                # Ensure a mux index
                if muxed_signal:
                    if mux == '':
                        fixed_mux_signal = True
                        fixed_signal_end = mux_bit_width + int(bit_size)
                    elif mux[0] == 'm':
                        fixed_mux_signal = False
                        if int(mux[1:]) != prev_mux_index:
                            prev_signal_end = fixed_signal_end
    
                    if fixed_mux_signal:
                        if int(bit_start) < mux_bit_width:
                            print('/// ERROR /')
                            print('#error ' + t[1] + ' start bit overwrites mux index')
                            print('/// ERROR /')
                            print('')
                            raise ValueError('#error ' + t[1] + ' start bit overwrites mux index')
                    else:
                        if mux != 'M':
                            # Do not allow the signal to use the indexing bits
                            if int(bit_start) < fixed_signal_end:
                                print('/// ERROR /')
                                print('#error ' + t[1] + ' start bit overwrites mux index')
                                print('/// ERROR /')
                                print('')
                                raise ValueError('#error ' + t[1] + ' start bit overwrites previous fixed signal')
                            if mux[0] == 'm':
                            # Check for mux index out of bounds
                                if (int(mux[1:]) >= pow(2,mux_bit_width)) or (int(mux[1:]) < 0):
                                    print('/// ERROR /')
                                    print('#error ' + t[1] + ' mux index out of bounds.')
                                    print('/// ERROR /')
                                    print('')
                                    raise ValueError('#error ' + t[1] + ' mux index out of bounds.')
    
                                if int(bit_start) < prev_signal_end:
                                    print('/// ERROR /')
                                    print('#error ' + t[1] + ' start bit overwrites previous signal')
                                    print('/// ERROR /')
                                    print('')
                                    raise ValueError('#error ' + t[1] + ' start bit overwrites previous signal')
                                prev_signal_end = int(bit_start) + int(bit_size)
                            prev_mux_index = int(mux[1:])
    
                # If we have an invalid message length then invalidate the DBC and print the offending signal
                # Signal bit width is <= 0
                if (int(bit_size) <= 0):
                    print('/// ERROR /')
                    print('#error ' + t[1] + ' has invalid size. Signal bit width is: ' + str(int(bit_size)))
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error ' + t[1] + ' has invalid size. Signal bit width is: ' + str(int(bit_size)))
    
                # Signal is too wide for message
                if (int(bit_start) + int(bit_size)) > (int(msg_length) * 8):
                    print('/// ERROR /')
                    print('#error ' + t[1] + ' too large. Message needs ' + str(int(bit_start) + int(bit_size)) + ' bits.')
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error ' + t[1] + ' too large. Message needs ' + str(int(bit_start) + int(bit_size)) + ' bits.')
    
                endian_and_sign = s[2]
                # Split (0.1,1) to two tokens by removing the ( and the )
                s = t[4][1:-1].split(',')
                scale = s[0]
                offset = s[1]
    
                # Split the [0|0] to min and max
                s = t[5][1:-1].split('|')
                min_val = s[0]
                max_val = s[1]
    
                signal_min = 0
                signal_max = (float(scale) * pow(2,int(bit_size)))
                if '-' in t[3]:
                    signal_min = -(float(scale) * pow(2,int(bit_size))) / 2
                    signal_max = (float(scale) * pow(2,int(bit_size)) / 2)
                # If our min / max values are incorrect then clamping will not work correctly.
                # Invalidate the DBC and print out the offending signal.
                signal_min = signal_min + float(offset)
                signal_max = signal_max + float(offset) - float(scale)
    
                # Min for signal is too low.
                if (float(min_val) != 0) and (float(min_val) < float(signal_min)):
                    print('/// ERROR /')
                    print('#error ' + t[1] + ' min value too low. Min value is: ' + str(signal_min))
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error ' + t[1] + ' min value too low. Min value is: ' + str(signal_min))
    
                # Max for signal is too high
                if (float(max_val) != 0) and (float(max_val)) > (float(signal_max)):
                    print('/// ERROR /')
                    print('#error ' + t[1] + ' max value too high. Max value is: ' + str(signal_max))
                    print('/// ERROR /')
                    print('')
                    raise ValueError('#error ' + t[1] + ' max value too high. Max value is: ' + str(signal_max))
    
                recipients = t[7].strip('\n').split(',')
    
                # Add the signal the last message object
                sig = Signal(t[1], bit_start, bit_size, endian_and_sign, scale, offset, min_val, max_val, recipients, mux, signal_min, signal_max)
                dbc.messages[last_mid].add_signal(sig)
    
            # Parse the "FieldType" which is the trigger to use enumeration type for certain signals
            if line.startswith('BA_ "FieldType"'):
                t = line[1:].split(' ')  # BA_ "FieldType" SG_ 123 Some_sig "Some_sig";
                sig_mid = t[3]
                sig_name = t[4]
    
                # Locate the message and the signal whom this "FieldType" type belongs to
                if sig_mid in dbc.messages:
                    if sig_name in dbc.messages[sig_mid].signals:
                        dbc.messages[sig_mid].signals[sig_name].has_field_type = True
    
            # Enumeration types
            # VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" ;
            if line.startswith("VAL_ "):
                t = line[1:].split(' ')
                sig_mid = t[1]
                enum_name = t[2]
                pairs = {}
                t = t[3:]
                for i in range(0, int(len(t) / 2)):
                    pairs[t[i * 2 + 1].replace('"', '').replace(';\n', '')] = t[i * 2]
    
                # Locate the message and the signal whom this enumeration type belongs to
                if sig_mid in dbc.messages:
                    if enum_name in dbc.messages[sig_mid].signals:
                        if dbc.messages[sig_mid].signals[enum_name].has_field_type:
                            dbc.messages[sig_mid].signals[enum_name].enum_info = pairs
    
        # If there were errors in parsing the DBC file then do not continue with generation.
        if not validFile:
            sys.exit(-1)
        
        print(HeadCode)
        print(dbc.gen_file_header())
        print("\n")
    
        # Generate the application send extern function
        print("/// Extern function needed for dbc_encode_and_send()")
        print("extern bool dbc_app_send_can_msg(uint32_t mid, uint8_t dlc, uint8_t bytes[8]);")
        print("")
    
        # Generate header structs and MIA struct
        print(dbc.gen_mia_struct())
        print(dbc.gen_msg_hdr_struct())
        print(dbc.gen_msg_hdr_instances())
        print(dbc.gen_enum_types())
    
        # Generate converted struct types for each message
        for mid in dbc.messages:
            m = dbc.messages[mid]
            if not gen_all and not m.is_recipient_of_at_least_one_sig(self_node) and m.sender != self_node:
                code = ("\n// Not generating '" + m.get_struct_name() + "' since we are not the sender or a recipient of any of its signals")
            else:
                print(m.gen_converted_struct(self_node, gen_all))
    
        # Generate MIA handler "externs"
        print("\n/// @{ These 'externs' need to be defined in a source file of your project")
        for mid in dbc.messages:
            m = dbc.messages[mid]
            if gen_all or m.is_recipient_of_at_least_one_sig(self_node):
                if m.contains_muxed_signals():
                    muxes = m.get_muxes()
                    for mux in muxes[1:]:
                        print(str("extern const uint32_t ").ljust(50) + (m.name + "_" + mux + "__MIA_MS;"))
                        print(str("extern const " + m.get_struct_name()[:-2] + "_" + mux + "_t").ljust(49) + " " + (
                        m.name + "_" + mux + "__MIA_MSG;"))
                else:
                    print(str("extern const uint32_t ").ljust(50) + (m.name + "__MIA_MS;"))
                    print(str("extern const " + m.get_struct_name()).ljust(49) + " " + (m.name + "__MIA_MSG;"))
        print("/// @}\n")
    
        # Generate encode methods
        for mid in dbc.messages:
            m = dbc.messages[mid]
            if not gen_all and m.sender != self_node:
                print ("\n/// Not generating code for dbc_encode_" + m.get_struct_name()[:-2] + "() since the sender is " + m.sender + " and we are " + self_node)
            else:
                print(m.get_encode_code())
    
        # Generate decode methods
        for mid in dbc.messages:
            m = dbc.messages[mid]
            if not gen_all and not m.is_recipient_of_at_least_one_sig(self_node):
                print ("\n/// Not generating code for dbc_decode_" + m.get_struct_name()[:-2] + "() since '" + self_node + "' is not the recipient of any of the signals")
            else:
                print(m.get_decode_code())
    
        print(dbc.gen_mia_funcs())
        print("#endif")
    
    
    if __name__ == "__main__":
        main(sys.argv[1:])

    有了这个工具,我们的程序员就可以省下点时间好好喝杯茶了。

    展开全文
  • 通常在有CAN通讯的项目开发中,当收到客户的“通讯矩阵”和对应的.dbc后,就要立马着手进行信号的解析和计算,等程序写好了紧接着做测试,如果期间又有比较多的需求变更,改动起来是比较费劲的。常规的这种开发过程...

    在这里插入图片描述


    1. 背景


    通常在有CAN通讯的项目开发中,当收到客户的“通讯矩阵”和对应的.dbc后,就要立马着手进行信号的解析和计算,等程序写好了紧接着做测试,如果期间又有比较多的需求变更,改动起来是比较费劲的。常规的这种开发过程效率并不高,限于个人能力通常代码质量也并不高。通过模型,自动生成解析代码,完美解决开发痛点。


    2. 参考资料


    【1】CANMatrix代码自动生成实践笔记

    展开全文
  • CAN DBC解析复用帧信号

    千次阅读 2018-11-06 15:58:20
    当我们用一帧信号上报很多信息的时候会把帧中的一个字节作为帧序号,然后根据不同的帧序号进行不同的解析 BYTE0|BYTE1|BYTE2|BYTE3|BYTE4|BYTE5|BYTE6|BYTE7 当BYTE7等于0时BYTE1解析为SIG1 当BYTE7等于1时BYTE1...

    当我们用一帧信号上报很多信息的时候会把帧中的一个字节作为帧序号,然后根据不同的帧序号进行不同的解析

    BYTE0|BYTE1|BYTE2|BYTE3|BYTE4|BYTE5|BYTE6|BYTE7

    当BYTE7等于0时BYTE1解析为SIG1

    当BYTE7等于1时BYTE1解析为SIG2

    帮助搜索关键字Mutiplex

     

    展开全文
  • 环境:操作系统。 语言:C++/C# 版本:V1.04。 描述:CAN、DBC解析与收发、多帧传输。 详情:周立功官方的DBC解析模块接口案例。
  • DBC文件解析,基于致远电子DBC_demo

    万次阅读 热门讨论 2018-10-19 14:49:50
    致远电子官网上有DBC文件解析的demo,不过是用C++做的,...致远电子网上还有一个can数据收发的demo,有C#的例子,那我想就参考这个例子用C#做个DBC解析的软件好了,反正公司的软件也是用C#做的。 其实LibDBCManager.d...
  • DBC signal解析思路

    千次阅读 2019-07-03 19:26:57
    DBC解析思路 首先,打开 DBC文件(如果无法打开可以先安装CANoe),打开的文件如下所示: 下面以一个message为例理解DBC,首先,括号里面的为该message的ID,如下所示: 双击该message,可以查看详情信息。...
  • DBC的C++解析源码

    2018-11-28 09:38:10
    DBC是描述CAN网络节点间的数据通讯的文件,本源码是基于周立功的USBCAN盒的C++解析上位机源码,可修改为自己的DBC解析模块使用。
  • 官网资料解析DBC

    2019-02-17 14:53:14
    比较实用的周立功官方网站的DBC解析资料,里面包好原始VI和DEMO测试程序,已测试OK
  • DBC文件解析——基于DBCView工具

    千次阅读 2018-01-22 11:22:19
    汽车电子少不了使用dbc文件,这里我们用DBCView这个工具来解析DBC文件 ——基于DBCView工具 DBCView由5个部分构成:1)菜单和工具。...1)DBC解析---网络节点 如图所示:CAN BUS上挂了三个节点:NMNo...
  • DBC文件解析CAN信息》由会员分享,可在线阅读,更多相关《DBC文件解析CAN信息(15页珍藏版)》请在人人文库网上搜索。1、DBCCAN数据包-基于CANAPE,打开CANape,新建一个工程,如右图所示,如图示过程,建立新的...
  • DBC文件解析 ——基于DBCView工具

    千次阅读 2018-01-22 11:44:10
    1)DBC解析---网络节点 DBC是描述CAN网络节点间的数据通讯的文件: 例如下面的3.dbc文件,包括了6个节点连接在CAN网络上 2)DBC解析---节点收发MSG dbc文件中会为每个节点定义发送消息和接收消息 例如下图所示:...
  • DBC文件解析——基于DBCVIew3.1(中文版) DBCView由5个部分构成:1)...1)DBC解析—网络节点 如图所示:CAN BUS上挂了三个节点:NMNode,BCM,PTG。 2)DBC解析—MSG内部Signal排版 NMNode发送了一个Message...
  • DBC文件解析

    2021-01-07 14:28:15
    这里写自定义目录标题1、基础介绍2、DBC文件2.1、开头是Version 和 new_symbols两个Tag。2.2、波特率定义2.3、网络节点的定义2.4、报文帧的定义2.5、信号的定义2.6、注解部分2.7、特征(属性)定义部分:2.8、数值表...
  • CANas分析软件,DBC文件解析,仿CANoe曲线显示

    千次阅读 热门讨论 2020-09-12 14:56:32
    1、CAN连接,支持周立功CAN及PCAN ...2、DBC解析与生成 3、历史报文解析,支持asc,csv,blf等格式 4、曲线生成,仿CANOE的曲线显示 下载地址:https://download.csdn.net/download/amw2738/12833259
  • JAVA解析DBC文件

    2019-04-17 20:39:59
    用JAVA解析DBC文件,考虑大小端,生成文件内容跟Vector CANDB++相同。
  • 解析dbc文件

    2018-05-07 17:38:39
    简洁明了,可以为相关人员提供一个解析文件的思路,没有复杂的代码,比较容易理解
  • 1.可以根据DBC文件自动解析实时收发的CAN数据 2.可以把cantest软件保存的CAN数据(txt文件)进行解析后导出保存 3.可以自定义选取某个帧内容显示实时曲线 4.可以保存已接收的数据帧 5.可以主动发送单个数据或导入文件...
  • Labview 用DBC文件解析CAN报文以及DBC格式发送CAN 载入DBC格式文件,解析数据,修改后可以发送,调用的dll有使用说明。 参考程序后续可以自己改动 复制这条消息后,打开闲鱼€1y5gcYErL74€后打开闲鱼 ...
  • can-dbc用Rust的nom解析器组合器库编写的CAN-dbc格式解析器。 1.示例读取dbc文件并基于mes can-dbc生成Rust结构。一个用Rust的nom解析器组合器库编写的CAN-dbc格式解析器。 1.示例读取dbc文件并根据dbc中定义的消息/...
  • 使用CANoe对DBC的深入解析
  • DBC文件源码解析

    千次阅读 2020-03-16 19:04:39
    DBC文件源码解析   DBC(data base CAN)文件是由德国Victor公司发布的,它被用来描述单一CAN网络中各逻辑节点信息,依据该文件可以开发出来监视和分析CAN网络中所有逻辑节点的运行状态。DBC是一种文件格式,.dbc...
  • 功能:读取DBC文件,将Bo_、SG_解析封装到实体类里,方便下一步的开发。
  • 正则解析 DBC

    2019-12-06 10:00:34
    MessagePattern = "^BO_[ ]+(\\d+)[ ]+(\\w+):[ ]+(\\d+)[ ]+(\\w+)$"; SignalPattern = "^SG_[ ]+(\\w+)[ ]+(((m)(\\d+[ ]+))|(M[ ]+))?:[ ]+(\\d+)\\|(\\d+)@([0|1])([+|-])[ ]+\\((-?\\d+(\\.\\d+)?...
  • CAN通讯进阶-基于Python使用DBC文件解析CAN数据配置环境1.环境配置1.1安装CAN通讯需要的包1.2 安装kvaser_drivers以及Kvaser CanKing2.使用DBC文件解析CAN帧2.1DBC文件2.2本博客布局3.DBC文件的创建3.1创建DBC文件...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,259
精华内容 1,303
关键字:

dbc解析