1、在利用Python和Kvaser进行二次开发时,Kvaser官方提供了可以解析原始CAN报文的Python模块 canlib.kvadblib,使用方法如下:
// python
mydbc = kvadblib.Dbc("mydbc.dbc")
...
frame = ch.read(timeout=int(timeout * 1000))
bmsg = db.interpret(frame)
for bsig in bmsg:
bsig.name # 信号名
bsig.value # 信号物理值
但是,在利用C++进行开发时,我并没有找到可以实现对原始CAN报文进行解析的接口函数(如果您知道相应的接口,还望留言告知),所以自己写了一个。
2、解析原始CAN报文的C++类定义
// 定义原始CAN报文 (沿用Kvaser例程中的定义)
typedef struct {
unsigned char data[8];
unsigned int dlc;
unsigned int flag;
unsigned long time;
long id;
} CanMessage;
// 定义翻译后的CAN报文
struct translatedMsg
{
string id; // 报文的ID
vector<string> can_signals; // 报文中的信号名称列表
vector<double> values; // 与信号名称列表对应的,信号的物理值
};
// 定义DBC文件中的message信息
struct message {
string msgName; // 报文的名称
string ID; // 报文的ID
vector<Signal> can_signals; // 报文中的所有信号
void reset() {
msgName = "";
ID = "";
can_signals = {};
}
};
// 定义message中的Signal
class Signal {
public:
// Parameters
string SigName; // 信号的名称
string Unit; // 单位
uint8 StartBit; // 起始bit位
uint8 BitLength; // 长度
bool ByteOrder; // true: @0 Motorola; false: @1 Intel
bool ValueType; // true: + Unsigned; false: - Signed
double Factor;
double Offset;
double PhyValue;
uint RawValue;
uint8 msb;
uint8 lsb;
// Functions
// 默认构造函数
Signal() = default;
// 利用信号的名称、长度、起始位、byteOrder类型、信号类型(signed/unsigned)、精度、offset等构造Signal对象
Signal(string name, uint8 length, uint8 startBit, bool byteOrder, bool valueType, double factor, double offset);
// 给定原始data数据,翻译出Signal的物理值PhyValue
void getPhyValue(uint8 data[8]);
private:
// Parameters
uint8 StartByte; // startbit所在的Byte,MsbByte或LsbByte
uint8 MsbByte; // MSB所在的Byte
uint8 LsbByte; // LSB所在的Byte
uint8 MsbBit_in_byte; // msb在该Byte中的位置
uint8 LsbBit_in_byte; // lsb在该Byte中的位置
uint8 LSBByteBitUsed; // msb所在Byte中,有MsbBit_in_byte个bit被该Signal占用
uint8 MSBByteBitUsed; // lsb所在Byte中,有LsbBit_in_byte个bit被该Signal占用
// Functions
void getMsbLsb();
uint8 getByteLocation(uint8 bit);
uint getRawValue(uint8 data[8]);
uint8 getBit_inByte(uint8 bitLocation, uint8 byteLocation);
uint8 getByteRaw(uint8 ByteDate, uint8 StartBit, int8 EndBit);
};
// 定义DBC类,该类可以利用给定的DBC文件,对原始的CAN报文进行解析
class DBC : public QThread // DBC继承自QThread,以便在单独的线程中进行报文解析
{
Q_OBJECT // 为了使用Qt的信号和槽机制,必须在定义类的初始位置添加此语句
public:
DBC() = default;
DBC(string File); // File形如"D:\\mydbc.dbc"
string file; // DBC文件的绝对路径,形如"D:\\mydbc.dbc"
void run();
void stopRunning();
void getInfo(); //用于获得DBC文件的信息
string file;
vector<message> Messages; // DBC文件中包含的所有message
translatedMsg tMsg;
public slots:
void translateRawMsg(CanMessage msg); // 槽函数,用于翻译接收到的原始CAN报文
private:
void translate(string id, uint8 data[8], translatedMsg & tMsg); // 内部函数,被槽函数translateRawMsg调用,并将翻译后的CAN信息拷贝给tMsg。
signals:
void sentTranslatedMsg(translatedMsg tMsg); // 该信号,负责将tMsg传递给该信号所连接的槽函数
}