本文介绍基于python对dbc文件定义的各个参数的CAN报文进行解析。
首先根据dbc文件创建以下格式内容的xls文件:
ID | Name | ByteOrder | StartBit | Length | Factor | Offset | ValueType | ValueTable |
0x355 | TemValVaild | Motorola_LSB | 0 | 1 | 1 | 0 | Bool_t | 0x0-False; 0x1-True |
0x504 | Count | Intel | 88 | 16 | 1 | 0 | Uint32_t | NA |
然后根据文档格式编写python代码读取xls文档内容:
import os
from xlrd import open_workbook
def xlsProtocolFile_Handle(infile, sheet_idx):
ProtocolData_list = list()
if (True == os.path.exists(infile)):
workbook = open_workbook(infile)
sheetData_table = workbook.sheet_by_index(sheet_idx)
row_idx = 1
while (row_idx < sheetData_table.nrows):
tableLineData_dict = { }
tableLineData_dict["Index"] = row_idx
tableLineData_dict["ID"] = hex(int(sheetData_table.cell(row_idx, 0).value, 16))
tableLineData_dict["Name"] = sheetData_table.cell(row_idx, 1).value
tableLineData_dict["ByteOrder"] = sheetData_table.cell(row_idx, 2).value
tableLineData_dict["StartBit"] = sheetData_table.cell(row_idx, 3).value
tableLineData_dict["Length"] = sheetData_table.cell(row_idx, 4).value
tableLineData_dict["Factor"] = sheetData_table.cell(row_idx, 5).value
tableLineData_dict["Offset"] = sheetData_table.cell(row_idx, 6).value
tableLineData_dict["ValueType"] = sheetData_table.cell(row_idx, 7).value
tableLineData_dict["ValueTable"] = ParamValueTable_Disassemble(sheetData_table.cell(row_idx, 8).value)
ProtocolData_list.append(tableLineData_dict)
row_idx += 1
else:
row_idx = 1
return ProtocolData_list
代码中,”infile“为上述定义的xls文件,记住只能是xls文件,不能是xlsx文件,因为xlrd 1.2.0之后的版本不支持.xlsx文件;”sheet_idx“表示xls里的sheet值,默认填0;
该函数返回一个列表,列表里是由一个个字典组成;字典内容及数据格式如下:
key | type | decription |
'Index' | int() | |
'ID' | hex() | |
'Name' | str() | |
'ByteOrder' | str() | Intel/Motorola_MSB/Motorola_LSB |
'StartBit' | float() | |
'Length' | float() | |
'Factor' | float() | |
'Offset' | float() | |
'ValueType' | str() | Bool_t, Uint32_t, Float32_t |
'ValueTable' | dict(num: str()) |
其中“ValueTable”是定义变量的值的内容,其具体解析函数如下:
def ParamValueTable_Disassemble(strValueTab):
value_list = strValueTab.strip().split(';\n') # 格式为:0x0-Normal
if ((len(value_list) > 1) and (('NA' != strValueTab) or ('' != strValueTab))):
valueTab_dict = { }
for n, strValue in enumerate(value_list):
strItem = strValue.strip().split('-')
valueTab_dict[int(strItem[0], 16)] = strItem[1]
return valueTab_dict
else:
return 'NA'
知道数据解析的参数定义后,接下来就是对接收的报文进行计算,主要实现代码如下:
def ExtPhyValFromDict(rxData_dict, sigAttri_dict):
Msg_Index = rxData_dict['Index']
Msg_ID = rxData_dict['ID']
Msg_dataList = rxData_dict['Data']
Attri_ID = sigAttri_dict['ID']
Attri_Name = sigAttri_dict['Name']
Attri_byteOrder = sigAttri_dict['ByteOrder']
Attri_valueType = sigAttri_dict['ValueType']
Attri_startBit = sigAttri_dict['StartBit']
Attri_bitLen = sigAttri_dict['Length']
Attri_factor = sigAttri_dict['Factor']
Attri_offset = sigAttri_dict['Offset']
if (Attri_ID == Msg_ID):
# ==== initSignal ====
if (Attri_byteOrder == 'Intel'):
byteIdx_lsb = int(Attri_startBit // BYTE_BITLEN)
bitIdxInByte_lsb = int(Attri_startBit % BYTE_BITLEN)
cntBytes = int(((Attri_bitLen + bitIdxInByte_lsb) + (BYTE_BITLEN - 1))// BYTE_BITLEN)
byteIdx_msb = int((byteIdx_lsb + cntBytes) - 1)
bitIdxInByte_msb = int((Attri_bitLen + bitIdxInByte_lsb - 1) - (cntBytes - 1) * BYTE_BITLEN)
elif (Attri_byteOrder == 'Motorola_MSB'):
byteIdx_msb = int(Attri_startBit // BYTE_BITLEN)
bitIdxInByte_msb = int(Attri_startBit % BYTE_BITLEN)
cntBytes = int(((Attri_bitLen + ((BYTE_BITLEN - 1) - bitIdxInByte_msb)) + (BYTE_BITLEN - 1)) // BYTE_BITLEN)
byteIdx_lsb = int((byteIdx_msb + cntBytes) - 1)
bitIdxInByte_lsb = int((((cntBytes - 1) * BYTE_BITLEN) + (bitIdxInByte_msb + 1)) - Attri_bitLen)
elif (Attri_byteOrder == 'Motorola_LSB'):
byteIdx_lsb = int(Attri_startBit // BYTE_BITLEN)
bitIdxInByte_lsb = int(Attri_startBit % BYTE_BITLEN)
cntBytes = int(((Attri_bitLen + bitIdxInByte_lsb) + (BYTE_BITLEN - 1)) // BYTE_BITLEN)
byteIdx_msb = int((byteIdx_lsb + 1) - cntBytes)
bitIdxInByte_msb = int((Attri_bitLen + bitIdxInByte_lsb - 1) - (cntBytes - 1) * BYTE_BITLEN)
else:
return
# ==== extractRawData ====
reserveMask = (1 << (bitIdxInByte_msb + 1)) - 1
u64Data = (Msg_dataList[byteIdx_msb] & reserveMask)
# Intel
if (Attri_byteOrder == 'Intel'):
if (cntBytes <= 8):
for i in range(1, cntBytes):
u64Data = u64Data << BYTE_BITLEN
u64Data = u64Data + Msg_dataList[byteIdx_msb - i]
u64Data = u64Data >> bitIdxInByte_lsb
else:
for i in range(1, (cntBytes - 1)):
u64Data = u64Data << BYTE_BITLEN
u64Data = u64Data + Msg_dataList[byteIdx_msb - i]
u64Data = u64Data << (BYTE_BITLEN - bitIdxInByte_lsb)
u8Qac = Msg_dataList[byteIdx_lsb] >> bitIdxInByte_lsb
u64Data = u64Data | u8Qac
# Motorola_MSB/Motorola_LSB
elif ((Attri_byteOrder == 'Motorola_MSB') or (Attri_byteOrder == 'Motorola_LSB')):
if (cntBytes <= 8):
for i in range(1, cntBytes):
u64Data = u64Data << BYTE_BITLEN
u64Data = u64Data + Msg_dataList[byteIdx_msb + i]
u64Data = u64Data >> bitIdxInByte_lsb
else:
for i in range(1, (cntBytes - 1)):
u64Data = u64Data << BYTE_BITLEN
u64Data = u64Data + Msg_dataList[byteIdx_msb + i]
u64Data = u64Data << (BYTE_BITLEN - bitIdxInByte_lsb)
u8Qac = Msg_dataList[byteIdx_lsb] >> bitIdxInByte_lsb
u64Data = u64Data | u8Qac
else:
return
# ==== Data out ====
if ((Attri_valueType == 'Bool_t') or (Attri_valueType == 'Uint32_t')):
SigPhyVal = int((u64Data * Attri_factor + Attri_offset))
elif (Attri_valueType == 'Float32_t'):
SigPhyVal = round((u64Data * Attri_factor + Attri_offset), 2)
return SigPhyVal
上述函数中,“rxData_dict”表示接收到的CAN报文的数据内容,其为一个字典,内容如下:
key | type |
'Index' | int() |
'ID' | hex() |
'Data' | [int(), ...] |
转换的过程会根据xls文件定义参数的字节序,分Intel、Motorola_MSB、Motorola_LSB,这3种字节序有何差别,请上网搜索学习。