解析 .dbc 文件并生成 C++ 代码以表示每个消息的 classes/struct(针对目标 ECU)

Parse the .dbc file and generate C++ code to represent classes/struct for each message( for target ECU )

我正在尝试从 .dbc 文件生成 C++ 代码。

例如在 .dbc 文件

中定义了一条消息,如下所示
BO_ 500 IO_DEBUG: 5 IO
 SG_ IO_DEBUG_test_unsigned : 0|8@1+ (1,0) [0|0] "" DBG
 SG_ IO_DEBUG_test_signed : 8|8@1- (1,-128) [0|0] "" DBG
 SG_ IO_DEBUG_test_float1 : 16|8@1+ (0.1,0) [0|0] "" DBG
 SG_ IO_DEBUG_test_float2 : 24|12@1+ (0.01,-20.48) [-20.48|20.47] "" DBG
 SG_ IO_DEBUG_test_enum : 38|2@1+ (1,0) [0|0] "" DBG

BA_ "FieldType" SG_ 500 IO_DEBUG_test_enum "IO_DEBUG_test_enum";
VAL_ 500 IO_DEBUG_test_enum 2 "IO_DEBUG_test2_enum_two" 1 "IO_DEBUG_test2_enum_one" ;

我正在尝试生成类似这样的 C++ 代码。消息名称将成为 Class 名称,所有信号都应成为 class 的成员以及数据类型。

//IoDebug.h -- ProcessMessageInterface 是一个接口。

class IoDebug : public ProcessMessageInterface {
pubic:
   // ProcessMessageInterface implementation
   void processMessage();


private:
   uint8_t testUnSigned;
   int8_t  testSigned;
   float   testFloat1;
   float   testFloat2; 
   IO_DEBUG_test_enum testEnum;
};

//IoDebug.cpp

#include "IoDebug.h"

IoDebug::processMessage() 
{
   
}

是否存在可以生成上述代码的 dbc 解析器和代码生成工具?

这是我找到的最接近的东西: https://github.com/astand/c-coderdbc
它生成的代码格式似乎与您想要的格式大致相同。

还有一个与之关联的网站: https://coderdbc.com/ccoder/uploaddbc

还有这个类似的项目: https://github.com/xR3b0rn/dbcppp
但我个人不喜欢生成的代码,因为它不会为每个 CAN 消息创建结构,而是单独解析每个信号。这种方法可能效果很好,但并不是您想要的。

这是一个生成 C++ 代码的 python 脚本。您需要按照脚本将 cantools 软件包安装到 运行。

import cantools
import math

def build_name(name):
    nodes = name.split("_")
    nodes[0] = nodes[0].title()
    return "".join(nodes)

def signal_variable_name(signal_name):
    return "m_" + build_name(signal_name)

def isFloat(signal):
    return True if isinstance(signal.scale, float) else False

def signal_data_type(signal):
    if not signal.choices:
        if isFloat(signal):
            return "float"
        else:
            return "int" if signal.is_signed else "uint" + str((math.floor((signal.length - 1) / 8) + 1) * 8) + "_t"
    else:
        return signal.name

def initial_signal_value(signal):
    initial = 0
    if signal.initial:
        initial = signal.initial
    print("initial: "+str(initial))
    print(signal.choices)
    if signal.choices:
        return signal.name + "_" + signal.choices[initial]
    else:
        return initial

cpp_template = """
#include <string>

#include "{messagename}.h"

using namespace std;

{messagename}::{messagename}()
{{
}}

"""
header_template = """
#ifndef {message_h}
#define {message_h}

#include <stdint.h>
#include <iostream>

class {messagename} : public {messageparent} {{
public:
    {messagename}();

    bool processMessage();

private:
"""

# dbc file 
db = cantools.database.load_file("path_to_dummy.dbc")

# We can grow following list, add those messages for which we want to generate the code. 
messages_list=["IO_DEBUG"]

for message_name in messages_list:
    # massaging message_name here. 
    good_message_name = build_name(message_name)
    message = db.get_message_by_name(message_name)
    message_cpp_file = good_message_name+".cpp"
    context = {"messagename": good_message_name, "dbc_message_name": message_name}

    # writing code for C++ file.
    f = open(message_cpp_file, "w")
    f.write(cpp_template.format(**context))
    f.write("bool {}::processMessage() {{\n    return true;\n}}\n".format(good_message_name))
    # we can add more code here to auto-generate code inside above fucntion to process the signals.
    f.close()

    # writing code for header file.
    message_header_file = good_message_name+".h"
    f = open(message_header_file, "w")
    context["message_h"] = message_name.upper()+"_H"
    context["messageparent"] = "ProcessMessageInterface"
    f.write(header_template.format(**context))

    for signal in message.signals:
        f.write("    {} {};\n".format(signal_data_type(signal), signal_variable_name(signal.name)))

    f.write("\n};\n\n#endif // " + context["message_h"])
    f.write("\n")
    f.close()

运行 等于

python3 script.py

以上脚本将生成以下头文件和 cpp 文件。

IoDEBUG.h

#ifndef IO_DEBUG_H
#define IO_DEBUG_H

#include <stdint.h>
#include <iostream>

class IoDEBUG : public ProcessMessageInterface {
public:
    IoDEBUG();

    bool processMessage();

private:
    uint8_t m_IoDEBUGtestunsigned;
    int m_IoDEBUGtestsigned;
    float m_IoDEBUGtestfloat1;
    float m_IoDEBUGtestfloat2;
    IO_DEBUG_test_enum m_IoDEBUGtestenum;

};

#endif // IO_DEBUG_H

IoDEBUG.cpp

#include <string>

#include "IoDEBUG.h"

using namespace std;

IoDEBUG::IoDEBUG()
{
}

bool IoDEBUG::processMessage() {
    return true;
}

也请看看 Soureforge 的 comFramework。它可能接近您的需要。这里的概念是让输出受模板控制;强大的模板引擎 StringTemplate V4 提供解析后的 DBC 文件。您几乎可以将 DBC 中的所有内容带入 C/C++(消息、信号、属性、枚举、节点名称等)。不幸的是,所有示例仍然生成 C。然而,迁移到 C++ 是微不足道的。

https://sourceforge.net/projects/comframe/