解析 .dbc 文件并生成 C++ 代码以表示每个消息的类/结构(对于目标 ECU)
Posted
技术标签:
【中文标题】解析 .dbc 文件并生成 C++ 代码以表示每个消息的类/结构(对于目标 ECU)【英文标题】:Parse the .dbc file and generate C++ code to represent classes/struct for each message( for target ECU ) 【发布时间】:2021-02-01 06:55:38 【问题描述】:我正在尝试从 .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++ 代码。消息名称将成为类名称,所有信号都应与数据类型一起成为该类的成员。
//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 解析器和代码生成工具?
【问题讨论】:
【参考方案1】:这是我发现的最接近的东西: https://github.com/astand/c-coderdbc 它似乎生成的代码格式与您想要的大致相同。
还有一个与之相关的网站: https://coderdbc.com/ccoder/uploaddbc
还有这个其他类似的项目: https://github.com/xR3b0rn/dbcppp 但我个人不喜欢生成的代码,因为它不会为每个 CAN 消息创建结构,而是单独解析每个信号。这种方法可能效果很好,但并不是您想要的。
【讨论】:
感谢@Ian 回答这个问题。我还不能用上面提到的项目生成代码,但它看起来很有希望。短期溶胶。我能够想出一个解析 dbc 文件并生成 C++ 代码的 python 脚本。我将分享溶胶。几天后。谢谢。【参考方案2】:这是一个生成 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;
【讨论】:
以上是关于解析 .dbc 文件并生成 C++ 代码以表示每个消息的类/结构(对于目标 ECU)的主要内容,如果未能解决你的问题,请参考以下文章