python应用笔记之CAN报文解析详解

本文介绍基于python对dbc文件定义的各个参数的CAN报文进行解析。

 

首先根据dbc文件创建以下格式内容的xls文件:

IDNameByteOrderStartBitLengthFactorOffsetValueTypeValueTable
0x355TemValVaildMotorola_LSB0110Bool_t0x0-False;
0x1-True
0x504Count Intel 881610Uint32_tNA

 

然后根据文档格式编写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;

        该函数返回一个列表,列表里是由一个个字典组成;字典内容及数据格式如下:

keytypedecription

'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报文的数据内容,其为一个字典,内容如下:

keytype

'Index'

int()

'ID'

hex()

'Data'

[int(), ...]

转换的过程会根据xls文件定义参数的字节序,分Intel、Motorola_MSB、Motorola_LSB,这3种字节序有何差别,请上网搜索学习。

  • 26
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡尔二叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值