汽车架构解析:python解析Autosar架构的ARXML

文章目录

  • 前言
  • 一、Container-I-PDU概念引入
  • 二、以文本形式读取ARXML文件
  • 三、解析Frame的基本参数
  • 四、解析Frame中的PDU
  • 五、解析PDU中的Signals
  • 六、解析Signal中的初始值和长度
  • 七、解析Signal中的起始位置
  • 八、解析Signal中的枚举值或公式
  • 九、解析ARXML总结

前言

  • Autosar架构下arxml文件作为通用数据库文件,在数据传输和存储中起到关键作用。行业上其实有一些arxml的工具可以将arxml转换成dbc,再将dbc转换成自己想要的数据,但是拿到的数据是不完整的,arxml有一些数据dbc是没有的,也根据缺少的数据直接到ARXML拿,不用硬解ARXML。
  • 想要解析ARXML的最好的方法就是对原始数据进行处理。网上有一些python的库推荐,如xml.etree.ElementTree等,我试用了下,arxml的层级关系太多了感觉处理起来不太自由。
  • 于是我决定用python的正则表达式来解析,因为知道了所需数据存放的结构体,就可以通过正则表达式快速定位获取数据,而且可以自由的获取arxml的任意数据片段,按照自己的规则解析。

正则表达式相关学习点这里


一、Container-I-PDU概念引入

1、下图为autosar的协议栈,可以看出具备多种类型的PDU:Dcm-I-PDU、General-Purpose-PDU、General-Purpose-I-PDU、I-Signal-I-PDU、Multiplexed-I-PDU、NM-PDU、N-PDU、User-Defined-PDU、User-Defined-I-PDU、XCP-PDU、J1939-Dcm-I-PDU 和 Secured-I-PDU。

在这里插入图片描述


2、而Container-I-PDU 是一种在 AUTOSAR 中使用的数据单元,用于封装其他类型的 PDU(Protocol Data Unit)。它是一种容器,可以包含不同类型的 PDU 作为其成员。Container-I-PDU 的主要目的是将多个 PDU 组合成一个逻辑单元进行传输。通过将多个 PDU 打包到一个 Container-I-PDU 中,可以减少通信开销,并提高通信效率。

在这里插入图片描述


3、虽然有Container-I-PDU的概念,但是不代表I-PDU就一定需要通过Container-I-PDU去传输,因此也有两种传输方式。

1)通过Container-I-PDU打包传输:

在这里插入图片描述

在这里插入图片描述

如果是通过Container-I-PDU打包发出则需要先找到Container-I-PDU,再找到I-PDU,最后才能找到Signal。

2)不通过Container-I-PDU打包传输:

在这里插入图片描述

在这里插入图片描述

如果是直接通过I-PDU发出,则直接找到I-PDU,再找到Signal。

二、以文本形式读取ARXML文件

import re
file_path = r'C:\Users\Desktop\Demo.arxml'
# ============读取Arxml文件============
with open(file_path, 'r') as file:
    # 读取文件内容
    arxml_data = file.read()

三、解析Frame的基本参数

1、下面是arxml的片段其中就包括了CAN报文的名称DMS_ADCANFD_FrP01,寻址模式STANDARD,通讯协议CAN-FD,以及报文ID554;

2、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的../报文名称来获得报文名称;
  • 匹配片段中的帧类型来获得帧类型;
  • 匹配片段中的报文类型来获得报文类型;
  • 匹配片段中的报文ID来获得报文ID;
  
	FrTrDMS_ADCANFD_FrP01
	
	  /ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/FramePort_Out
	  /VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/framePort_ac33e765d8d23aa9
	
	/Communication/Frame/DMS_ADCANFD_FrP01
	
	  
	    /VehicleTopology/ADCANFD/PhCnADCANFD/PduTrDMS_ADCANFD_050ms_Container01
	  
	
	STANDARD
	CAN-FD
	554
  

3、正则表达式处理数据

python代码:

#找出所有frame的数据片段
CANFrameNode_pattern  = r'(.*?)'
CANFrameNodes_List = re.findall(CANFrameNode_pattern, arxml_data, re.DOTALL) # 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符

#设置CANFrame的匹配规则:报文名称:(.*?),寻址模式:,报文类型CAN/CANFD:,报文标识ID:
CANFrame_pattern = r'(.*?).*?(.*?).*?(.*?).*?(.*?)'

#开始匹配上述参数
for CANFrameNodes in CANFrameNodes_List:
    CANFrames_match = re.findall(CANFrame_pattern, CANFrameNodes, re.DOTALL)  # 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符
    if CANFrames_match:
        for CANFrame in CANFrames_match:
            CAN_FrameData_dict = {"FrameName":"","AdressingMode":'',"Frametype":"","CanId":"","signals":[]}
            CAN_FrameData_dict["FrameName"] = CANFrame[0].split("/")[-1]
            CAN_FrameData_dict["AdressingMode"] = CANFrame[1]
            CAN_FrameData_dict["Frametype"] = CANFrame[2]
            CAN_FrameData_dict["CanId"] = CANFrame[3]
            CAN_matrix.append(CAN_FrameData_dict)
print(CAN_matrix)

打印结果:

#打印结果只列举一个
[{'FrameName': 'DMS_ADCANFD_FrP01', 'AdressingMode': 'STANDARD', 'Frametype': 'CAN-FD', 'CanId': '554', 'signals': []}]

四、解析Frame中的PDU

1、这里举例解析Frame中的Container-I-PDU和Signal-I-PDU,这里强调必须注意是否存在Container-I-PDU,因为匹配的方法不太一样。

2、下面是arxml的片段其中就包括了CAN报文的名称DMS_ADCANFD_FrP01,PDU名称PduTrDMS_ADCANFD_050ms_Container01;

3、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的../报文名称来获得报文名称;
  • 匹配片段中的../PDU名称来获取PDU名称;
  
	FrTrDMS_ADCANFD_FrP01
	
	  /ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/FramePort_Out
	  /VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/framePort_ac33e765d8d23aa9
	
	/Communication/Frame/DMS_ADCANFD_FrP01
	
	  
	    /VehicleTopology/ADCANFD/PhCnADCANFD/PduTrDMS_ADCANFD_050ms_Container01
	  
	
	STANDARD
	CAN-FD
	554
  

4、正则表达式处理数据

python代码:

这里的参数不和上述的《三、解析Frame的基本参数》一起匹配的原因是Frame中的Container-I-PDU的数量可能不唯一,用贪婪匹配可以匹配多个结果。

#设置PDU的匹配规则:报文名称:, PDU名称:
PDUS_pattern = r'(.*?)|(.*?)'

Frame_Pdus_Data = []
Pdus_data = []
#匹配FrameName和PDU
for CANFrameNode in CANFrameNodes_List:
    Frame_Pdus_dict = {"FrameName":"","pduname":""}
    PDUS_match = re.findall(PDUS_pattern, CANFrameNode,re.DOTALL)
    Framepdu = [match[0].split("/")[-1] or match[1].split("/")[-1] for match in PDUS_match if match[0] or match[1]]
    Frame_Pdus_dict["FrameName"] = Framepdu[0]
    Frame_Pdus_dict["pduname"] = Framepdu[1:]
    Frame_Pdus_Data.append(Frame_Pdus_dict)

print(Frame_Pdus_Data)

打印结果:

#打印结果只列举一个
[{'FrameName': 'DMS_ADCANFD_FrP01', 'pduname': ['PduTrDMS_ADCANFD_050ms_Container01']}]

5、下面是arxml的片段其中就包括了PDU的名称CCP_ADCANFD_020ms_Container11,Container-I-PDU中的I-PDUPduTrCCP_020ms_PDU00_AD,PduTrCCP_020ms_PDU02_AD,NewPduTriggering_a1955a2b08c2a3bb;

6、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的PDU名称来获得报文名称;
  • 匹配片段中的../IPDU名称来获取PDU名称,I-PDU可能存在多个;
 CCP_ADCANFD_020ms_Container11
 64
 
   /VehicleTopology/ADCANFD/PhCnADCANFD/PduTrCCP_020ms_PDU00_AD
   /VehicleTopology/ADCANFD/PhCnADCANFD/PduTrCCP_020ms_PDU02_AD
   /VehicleTopology/ADCANFD/PhCnADCANFD/NewPduTriggering_a1955a2b08c2a3bb
 
 0
 DEFAULT-TRIGGER
 SHORT-HEADER
 ACCEPT-CONFIGURED
 0

python代码

匹配CONTAINER-I-PDU中的PDU

#============找出CONTAINER-I-PDU中的PDU===========
Container_PDUS_pattern = r'(.*?)'

#匹配具体参数获得I-PDU参数
Container_PDUS_match = re.findall(Container_PDUS_pattern, arxml_data, re.DOTALL)  # 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符
ISignal_PDUS_pattern = r'(.*?)|(.*?)'

Container_PDUS = []
for Container_PDU in Container_PDUS_match:
    ISignal_PDUS = []
    ISignal_PDUS_match = re.findall(ISignal_PDUS_pattern, Container_PDU, re.DOTALL)
    for ISignal_PDU in ISignal_PDUS_match:
        a = [PDU.split("/")[-1] for PDU in ISignal_PDU if PDU !=""]
        ISignal_PDUS.extend([PDU.split("/")[-1] for PDU in ISignal_PDU if PDU !=""])
    Container_PDUS.append(ISignal_PDUS)

将Container-I-PDU中的iI-PDU成员整合到Frame中

#填充CONTAINER-I-PDU数据到字典
for Frame_Pdus in Frame_Pdus_Data:
    for pdname in Frame_Pdus['pduname']:
        for Container_PDU in Container_PDUS: 
            if any( element in pdname for element in Container_PDU) is True:
                for Cp in Container_PDU:
                    PduData_dict = {"FrameName":"","pduname":""}
                    PduData_dict["FrameName"] = Frame_Pdus["FrameName"]                       
                    PduData_dict["pduname"] = Cp
                    Pdus_data.append(PduData_dict)
print(Pdus_data)

打印结果:

#这里只举例一个结果
[{'FrameName': 'CCP_ADCANFD_FrP02', 'pduname': 'CCP_ADCANFD_020ms_Container11'}, {'FrameName': 'CCP_ADCANFD_FrP02', 'pduname': 'PduTrCCP_020ms_PDU00_AD'}, {'FrameName': 'CCP_ADCANFD_FrP02', 'pduname': 'PduTrCCP_020ms_PDU02_AD'}, {'FrameName': 'CCP_ADCANFD_FrP02', 'pduname': 'NewPduTriggering_a1955a2b08c2a3bb'}]

7、拓展:假设有其他PDU,但是又不经过Container-I-PDU打包传输怎么办?直接在Frame中匹配到N-PDU或者I-Signal-PDUd等等,这种情况也很常见,大家在匹配PDU部分的时候一定要特别注意不要在Frame中匹配Container-I-PDU;

 NmPDU_ADCANFD_DMS
 8
 
   
     isDMS_NM_BSMtoRMS_mtx
     /Communication/ISignal/isDMS_NM_BSMtoRMS
     MOST-SIGNIFICANT-BYTE-FIRST
     16
     TRIGGERED
   
 
 false
 255

python代码:

NM_PDUS_Pattern = r'.*?(.*?).*?'
NM_PDUs = re.findall(N_PDUS_pattern,arxml_data,re.DOTALL)

打印结果

#这里只举例一个结果
NmPDU_ADCANFD_DMS

可以直接查找有Frame中的PDU,而且PDU里面直接有signal参数,后面会正式一起匹配Signal的参数。


五、解析PDU中的Signals

1、匹配Signal名称的mapping关系,因为PDU中的Signal名称只是Mapping Signal name,真正的名称在其他arxml片段,我也不知道autosar为什么需要这么设计,还是按照他的规则办事吧。

2、下面是arxml的片段其中就包括了PDU中Signal的名称ISTrisDMSAdoWrnngDspCmd_0,以及真实用到的RealSignal名称isDMSAdoWrnngDspCmd;

3、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的PDU中Signal名称来获得PDU中Mapping Signal name名称;
  • 匹配片段中的../RealSignal名称来获取Real Signal name名称;
  
  ISTrisDMSAdoWrnngDspCmd_0
  
    /ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/SignalPort_Out
    /VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/SP_b097681ed4394b359291806d796936a3_Rx
  
  /Communication/ISignal/isDMSAdoWrnngDspCmd

python代码

#因为PDU中的部分Signal名称有Mapping关系,所以需要拿到Real signal name名称
signalTrig_pattern = r'(.*?)'
signalTrig_match = re.findall(signalTrig_pattern,arxml_data,re.DOTALL)
signalTrig_str = ""

#存在的片段,才具有Mapping属性,仅有一个
for signalTrig in signalTrig_match:
    if '' in signalTrig:
        signalTrig_str= signalTrig

#匹配signal name的Mapping关系
signalRealName_pattern = r'(.*?)|(.*?)'
signalRealName_match = re.findall(signalRealName_pattern,signalTrig_str,re.DOTALL)
signalsname_map = []
for num in range(0,len(signalRealName_match),2):
    signalname_dict = {"MappingName":"","RealName":""}
    signalRealName = signalRealName_match[num:num+2]
    signalname_dict["MappingName"] = signalRealName[0][0]
    signalname_dict["RealName"] = signalRealName[1][1].split("/")[-1]
    signalsname_map.append(signalname_dict)
    
print(signalsname_map)

打印结果

#这里只举例一个结果
[{'MappingName': 'ISTrisDMSAdoWrnngDspCmd_0', 'RealName': 'isDMSAdoWrnngDspCmd'}]

匹配完Signal名称的Mapping关系之后,需要开始匹配PDU中的Mapping Signal name名称,并且替换Mapping Signal name为Real Signal name,因为只能通过真实的Real Signal name才能找到Signal的相关参数。


4、下面是arxml的片段其中就包括了PDU的名称PduTrDMS_050ms_PDU00,以及Mapping Signal name名称ISTrisDMSAdoWrnngDspCmd_0;

5、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的PDU名称来获得PDU名称;
  • 匹配片段中的../Mapping Signal name名称来获取Mapping Signal name名称;
 PduTrDMS_050ms_PDU00
   
     /ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/IPduPort_Out
     /VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/PP_01fa4447d4724b9298c6e01a29830d3a_Rx
   
   /Communication/Pdu/DMS_050ms_PDU00
   
     
       /VehicleTopology/ADCANFD/PhCnADCANFD/ISTrisDMSAdoWrnngDspCmd_0
     
   

6、匹配完Mapping Signal Name之后,顺便替换成Real Signal Name;

python代码

 #============匹配PDU中的Signal信息==============
 PDUSignals_pattern = r'(.*?)'
 PDUSignals_match = re.findall(PDUSignals_pattern, arxml_data, re.DOTALL)  # 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符

 #============匹配PDU Name和signals name=============
 signals_pattern = r'(.*?)|(.*?)'
 PDUSignals_data = []
 for PDUSignals in PDUSignals_match:
     PDU_signals = []
     PDU_signals_dict = {'pduname':'','signals':[]}
     #开始查找signal的信息
     signals_match = re.findall(signals_pattern, PDUSignals, re.DOTALL)  # 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符
     for cntr,signal_match in enumerate(signals_match):
         signalsdata_dict = {"signalname":"","signaldata":[]}
         if cntr == 0:
             PDU_signals_dict['pduname'] = signal_match[0]
         else:
             signal_name = signal_match[1].split("/")[-1]
             for signalname_map in signalsname_map:
                 #开始替换signal的名称
                 if signal_name in signalname_map["MappingName"]:
                     signalsdata_dict["signalname"] = signalname_map["RealName"]
                     PDU_signals.append(signalsdata_dict)

     PDU_signals_dict['signals'] = PDU_signals
     PDUSignals_data.append(PDU_signals_dict)
     
 print(PDUSignals_data)

打印结果

#这里只举例一个结果
[{'pduname': 'PduTrDMS_050ms_PDU00', 'signals': [{'signalname': 'isDMSAdoWrnngDspCmd', 'signaldata': []}]

六、解析Signal中的初始值和长度

1、下面是arxml的片段其中就包括了Signal NameisDMSAdoWrnngDspCmd,初始值InitValue2,和长度Length2;

2、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的初始值来获取Signal的初始值InitValue;
  • 匹配片段中的长度来获取Signal的长度Length;
  isDMSAdoWrnngDspCmd
  OVERRIDE
  
    
      2
    
  
  2
  
    
      
        /DataType/DataTypeSemantics/SwBaseTypes/UINT2
        /DataType/DataTypeSemantics/DMSAdoWrnngDspCmd
      
    
  
  /Signal/DMSAdoWrnngDspCmd

python代码

有些信号是不存在初始值的,解析的时候要注意

 #匹配或者中的文本
 iSignals_pattern = r'(.*?)'
 iSignals_match = re.findall(iSignals_pattern,arxml_data,re.DOTALL)
 #匹配signal的初始值和长度的数据
 iSignalsPara_pattern = r'(.*?)|(.*?)|(.*?)'
 iSignalsPara_data = []

 for iSignals in iSignals_match:
     signal_dict = {'signalname':'','initvalue':None,'length':0 }
     iSignal_match = re.findall(iSignalsPara_pattern,iSignals,re.DOTALL)

     if len(iSignal_match) == 3:

         signal_dict['signalname'] = iSignal_match[0][0]
         signal_dict['initvalue'] = iSignal_match[1][1]
         signal_dict['length'] = iSignal_match[2][2]
     
     #iSignal_match长度为2,说明没有匹配到initvalue
     elif len(iSignal_match) == 2:

         signal_dict['signalname'] = iSignal_match[0][0]
         signal_dict['length'] = iSignal_match[1][2]

     iSignalsPara_data.append(signal_dict)
     
print(iSignalsPara_data)

打印结果

#这里只举例一个结果
[{'signalname': 'isDMSAdoWrnngDspCmd', 'initvalue': '2', 'length': '2'}]

七、解析Signal中的起始位置

1、下面是arxml的片段其中就包括了Signal NameisDMSAdoWrnngDspCmd_mtx,初始值StartPosition63;

2、我们查找报文相关的参数就可以通过查找片段数据来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的起始位来获取Signal的起始位StartPosition;
 
   isDMSAdoWrnngDspCmd_mtx
   /Communication/ISignal/isDMSAdoWrnngDspCmd
   MOST-SIGNIFICANT-BYTE-FIRST
   63
 

python代码

 #匹配中的内容,signal的START-POSITION在其中
 signal2PDUs_pattern = r'(.*?)'
 signal2PDUs_match = re.findall(signal2PDUs_pattern,arxml_data,re.DOTALL)

 #匹配signal的真实名称和signal的start position
 startPosition_pattern = r'(.*?)|(.*?)'
 iSignalSPos_data = []

 for signal2PDU in signal2PDUs_match:
     #开始匹配
     signalSPos_match = re.findall(startPosition_pattern,signal2PDU,re.DOTALL)
     #每个signal有2个参数,signal名称,start position
     for num in range(0,len(signalSPos_match),2):
         signalSPos_dict = {'signalname':'','startposition': 0}
         signalPara = signalSPos_match[num:num+2]
         try:
             signalname = signalPara[0][0].split("/")[-1]
             if "PDU" not in signalname.upper():
                 #处理signalName,因为signal是路径加名称../signalName
                 signalSPos_dict['signalname'] = signalPara[0][0].split("/")[-1]
                 signalSPos_dict['startposition'] = signalPara[1][1]
                 iSignalSPos_data.append(signalSPos_dict)
         except IndexError:
             print("无法找到参数")

 print(iSignalSPos_data)

打印结果

#这里只举例一个结果
[{'signalname': 'isDMSAdoWrnngDspCmd', 'startposition': '63'}]

八、解析Signal中的枚举值或公式

1、每个信号都有Internal-To-phys,有些类型是TEXTTABLE,有些是LINEAR;

TEXTTABLE:

在这里插入图片描述

LINEAR:

在这里插入图片描述

因此匹配方法有两种情况

情况一:TEXTTABLE类型

2、下面是arxml的片段其中就包括了Signal NameDMSAdoWrnngDspCmd,Internal-To-phys类型TEXTTABLE,值的范围0-0,枚举值DMSAdoWrnngDspCmd_0_Unavailable/DMSAdoWrnngDspCmd_1_Off/DMSAdoWrnngDspCmd_2_On/DMSAdoWrnngDspCmd_3_laststatus;

3、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的LIMIT值区域来获得Signal值得区域范围;
  • 匹配片段中的枚举值来获取Signal的枚举值;
  DMSAdoWrnngDspCmd
  TEXTTABLE
  
    
      
        0
        0
        
          DMSAdoWrnngDspCmd_0_Unavailable
        
      
      
        1
        1
        
          DMSAdoWrnngDspCmd_1_Off
        
      
      
        2
        2
        
          DMSAdoWrnngDspCmd_2_On
        
      
      
        3
        3
        
          DMSAdoWrnngDspCmd_3_laststatus
        
      
    
  

情况二:LINEAR类型

4、下面是arxml的片段其中就包括了Signal NameVehSpdAvg,Internal-To-phys类型LINEAR,值的范围0-32767,Offset分子0,Factor分子0.015625,Offset和Factor分母1,最终需要组合成(0-32767): (0.015625*raw) / 1;

5、我们查找报文相关的参数就可以通过查找数据片段来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的Signal值区域来获得Signal值得区域范围;
  • 匹配片段中的 Offset分子Factor分子来获取分子;
  • 匹配片段中的分母来获得分母;
 VehSpdAvg
 LINEAR
 
   
     
       0
       32767
       
         
           0
           0.015625
         
         
           1
         
       
     
   
 

python代码

#匹配或者中的文本
compuMethod_pattern = r'(.*?)'
compuMethod_match = re.findall(compuMethod_pattern,arxml_data,re.DOTALL)

#匹配信号名和对应的值,有枚举值或者线性值
compuMethodPara_pattern = r'(.*?)|(.*?)|(.*?)'

#匹配TEXTTABLE中的枚举值,每个中有一个枚举值和枚举文本
compuScale_pattern = r'(.*?)'

#匹配中的枚举值和枚举文本
compuScaleEnum_pattern = r'(.*?).*?(.*?)'

#匹配值的范围
compuScaleLimit_pattern = r'(.*?).*?(.*?)'

#匹配值的计算公式
compuScaleFormula_pattern = r'(.*?)'

compuMethodPara_data = []
for compuMethod in compuMethod_match:
    enumrate = []
    compuMethodPara_dic = {'signalname':'','category':'','TEXTTABLE':[],'formula':''}
    #匹配信号名和对应的值,有枚举值或者线性值
    compuMethodPara_match = re.findall(compuMethodPara_pattern,compuMethod,re.DOTALL)

    if len(compuMethodPara_match) == 3:
        #signalname
        compuMethodPara_dic['signalname'] = compuMethodPara_match[0][0]

        #值的类型,是TEXTTABLE或者LINEAR
        category = compuMethodPara_match[1][1]
        compuMethodPara_dic['category'] = category

        #compuScales含有多个枚举的值和文本
        compuScales_text = compuMethodPara_match[2][2]
        #signal有枚举值
        if category == "TEXTTABLE":
            compuScales = re.findall(compuScale_pattern,compuScales_text,re.DOTALL)

            for compuScale in compuScales:
                #查找枚举值和枚举文本
                compuScalePara = re.findall(compuScaleEnum_pattern,compuScale,re.DOTALL)
                #字典形式存放枚举值和枚举文本
                try:
                    enumrate_dict = {compuScalePara[0][0]:compuScalePara[0][1]}
                    enumrate.append(enumrate_dict)
                except IndexError:
                    print(compuScalePara)
                    
            compuMethodPara_dic['TEXTTABLE'] = enumrate
            
        #信号有factor和offset
        elif category == "LINEAR":
            Limit = re.findall(compuScaleLimit_pattern,compuMethod,re.DOTALL)
            formula = re.findall(compuScaleFormula_pattern,compuMethod,re.DOTALL)
            
            if len(Limit) == 1 and len(formula) ==3:
                Limit_str = '('+Limit[0][0]+'-'+Limit[0][1]+'):'
                formula_str = '('+'phys=raw'+'*'+formula[1]+'+'+formula[0]+')'+'/'+formula[2]
                compuMethodPara_dic['formula'] = Limit_str + formula_str

        compuMethodPara_data.append(compuMethodPara_dic)

print(compuMethodPara_data)

打印结果

[{'signalname': 'DMSAdoWrnngDspCmd', 'category': 'TEXTTABLE', 'TEXTTABLE': [{'0': 'DMSAdoWrnngDspCmd_0_Unavailable'}, {'1': 'DMSAdoWrnngDspCmd_1_Off'}, {'2': 'DMSAdoWrnngDspCmd_2_On'}, {'3': 'DMSAdoWrnngDspCmd_3_laststatus'}], 'formula': ''},{'signalname': 'VehSpdAvg', 'category': 'LINEAR', 'TEXTTABLE': [], 'formula': '(0-32767):(phys=raw*0.015625+0)/1'}]

九、解析ARXML总结

1、注意这不是完整版的ARXML解析代码,只是提供一种方法给大家参考,还有大量的参数需要大家去学习解读autosar规范,本人也是利用下班时间自己学习,如果有什么问题请大家指出。

2、另外正则表达式并不是行业内推荐的方法,大家在操作前可以先看看Python的库matrix,我更建议使用matrix将ARXML转换成DBC,然后缺少哪些数据再去ARXML拿,拿完之后再匹配到DBC矩阵中去。

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/ae86b234ac.html