解析 .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++ 是微不足道的。
我正在尝试从 .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++ 是微不足道的。