我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

文章目录


前言

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

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


一、Container-I-PDU概念引入

下图为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。

在这里插入图片描述


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

在这里插入图片描述


虽然有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 refile_path = r'C:\Users\Desktop\Demo.arxml'# ============读取Arxml文件============with open(file_path, 'r') as file:    # 读取文件内容    arxml_data = file.read()

三、解析Frame的基本参数

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

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

  • 匹配片段中的../报文名称来获得报文名称;
  • 匹配片段中的帧类型来获得帧类型;
  • 匹配片段中的报文类型来获得报文类型;
  • 匹配片段中的报文ID来获得报文ID;
  <CAN-FRAME-TRIGGERING UUID="09816ea3-a46c-3b48-97f8-d9f3f92799e8"><SHORT-NAME>FrTrDMS_ADCANFD_FrP01</SHORT-NAME><FRAME-PORT-REFS>  <FRAME-PORT-REF DEST="FRAME-PORT">/ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/FramePort_Out</FRAME-PORT-REF>  <FRAME-PORT-REF DEST="FRAME-PORT">/VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/framePort_ac33e765d8d23aa9</FRAME-PORT-REF></FRAME-PORT-REFS><FRAME-REF DEST="CAN-FRAME">/Communication/Frame/DMS_ADCANFD_FrP01</FRAME-REF><PDU-TRIGGERINGS>  <PDU-TRIGGERING-REF-CONDITIONAL>    <PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/PduTrDMS_ADCANFD_050ms_Container01</PDU-TRIGGERING-REF>  </PDU-TRIGGERING-REF-CONDITIONAL></PDU-TRIGGERINGS><CAN-ADDRESSING-MODE>STANDARD</CAN-ADDRESSING-MODE><CAN-FRAME-TX-BEHAVIOR>CAN-FD</CAN-FRAME-TX-BEHAVIOR><IDENTIFIER>554</IDENTIFIER>  </CAN-FRAME-TRIGGERING>

正则表达式处理数据

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

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

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

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

  • 匹配片段中的../报文名称来获得报文名称;
  • 匹配片段中的../PDU名称来获取PDU名称;
  <CAN-FRAME-TRIGGERING UUID="09816ea3-a46c-3b48-97f8-d9f3f92799e8"><SHORT-NAME>FrTrDMS_ADCANFD_FrP01</SHORT-NAME><FRAME-PORT-REFS>  <FRAME-PORT-REF DEST="FRAME-PORT">/ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/FramePort_Out</FRAME-PORT-REF>  <FRAME-PORT-REF DEST="FRAME-PORT">/VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/framePort_ac33e765d8d23aa9</FRAME-PORT-REF></FRAME-PORT-REFS><FRAME-REF DEST="CAN-FRAME">/Communication/Frame/DMS_ADCANFD_FrP01</FRAME-REF><PDU-TRIGGERINGS>  <PDU-TRIGGERING-REF-CONDITIONAL>    <PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/PduTrDMS_ADCANFD_050ms_Container01</PDU-TRIGGERING-REF>  </PDU-TRIGGERING-REF-CONDITIONAL></PDU-TRIGGERINGS><CAN-ADDRESSING-MODE>STANDARD</CAN-ADDRESSING-MODE><CAN-FRAME-TX-BEHAVIOR>CAN-FD</CAN-FRAME-TX-BEHAVIOR><IDENTIFIER>554</IDENTIFIER>  </CAN-FRAME-TRIGGERING>

正则表达式处理数据

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

#设置PDU的匹配规则:报文名称:, PDU名称:PDUS_pattern = r'(.*?)|(.*?)'Frame_Pdus_Data = []Pdus_data = []#匹配FrameName和PDUfor 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']}]

下面是arxml的片段其中就包括了PDU的名称CCP_ADCANFD_020ms_Container11,Container-I-PDU中的I-PDUPduTrCCP_020ms_PDU00_ADPduTrCCP_020ms_PDU02_ADNewPduTriggering_a1955a2b08c2a3bb

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

  • 匹配片段中的PDU名称来获得报文名称;
  • 匹配片段中的../IPDU名称来获取PDU名称,I-PDU可能存在多个;
<CONTAINER-I-PDU UUID="84de9d07-cf25-4a32-8cc4-92fd8eabcc93"> <SHORT-NAME>CCP_ADCANFD_020ms_Container11</SHORT-NAME> <LENGTH>64</LENGTH> <CONTAINED-PDU-TRIGGERING-REFS>   <CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/PduTrCCP_020ms_PDU00_AD</CONTAINED-PDU-TRIGGERING-REF>   <CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/PduTrCCP_020ms_PDU02_AD</CONTAINED-PDU-TRIGGERING-REF>   <CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/NewPduTriggering_a1955a2b08c2a3bb</CONTAINED-PDU-TRIGGERING-REF> </CONTAINED-PDU-TRIGGERING-REFS> <CONTAINER-TIMEOUT>0</CONTAINER-TIMEOUT> <CONTAINER-TRIGGER>DEFAULT-TRIGGER</CONTAINER-TRIGGER> <HEADER-TYPE>SHORT-HEADER</HEADER-TYPE> <RX-ACCEPT-CONTAINED-I-PDU>ACCEPT-CONFIGURED</RX-ACCEPT-CONTAINED-I-PDU> <THRESHOLD-SIZE>0</THRESHOLD-SIZE></CONTAINER-I-PDU>

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;

<NM-PDU UUID="f07d063e-61af-47b8-aee2-5118e0a44392"> <SHORT-NAME>NmPDU_ADCANFD_DMS</SHORT-NAME> <LENGTH>8</LENGTH> <I-SIGNAL-TO-I-PDU-MAPPINGS>   <I-SIGNAL-TO-I-PDU-MAPPING UUID="006c991f-1d37-3873-92ab-c3387a927208">     <SHORT-NAME>isDMS_NM_BSMtoRMS_mtx</SHORT-NAME>     <I-SIGNAL-REF DEST="I-SIGNAL">/Communication/ISignal/isDMS_NM_BSMtoRMS</I-SIGNAL-REF>     <PACKING-BYTE-ORDER>MOST-SIGNIFICANT-BYTE-FIRST</PACKING-BYTE-ORDER>     <START-POSITION>16</START-POSITION>     <TRANSFER-PROPERTY>TRIGGERED</TRANSFER-PROPERTY>   </I-SIGNAL-TO-I-PDU-MAPPING> </I-SIGNAL-TO-I-PDU-MAPPINGS> <NM-VOTE-INFORMATION>false</NM-VOTE-INFORMATION> <UNUSED-BIT-PATTERN>255</UNUSED-BIT-PATTERN></NM-PDU>

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

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

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

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

  • 匹配片段中的PDU中Signal名称来获得PDU中Mapping Signal name名称;
  • 匹配片段中的../RealSignal名称来获取Real Signal name名称;
<I-SIGNAL-TRIGGERINGS>  <I-SIGNAL-TRIGGERING UUID="24208cb2-a384-3cb4-b090-989665b8c45e">  <SHORT-NAME>ISTrisDMSAdoWrnngDspCmd_0</SHORT-NAME>  <I-SIGNAL-PORT-REFS>    <I-SIGNAL-PORT-REF DEST="I-SIGNAL-PORT">/ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/SignalPort_Out</I-SIGNAL-PORT-REF>    <I-SIGNAL-PORT-REF DEST="I-SIGNAL-PORT">/VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/SP_b097681ed4394b359291806d796936a3_Rx</I-SIGNAL-PORT-REF>  </I-SIGNAL-PORT-REFS>  <I-SIGNAL-REF DEST="I-SIGNAL">/Communication/ISignal/isDMSAdoWrnngDspCmd</I-SIGNAL-REF></I-SIGNAL-TRIGGERING>

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的相关参数。


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

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

  • 匹配片段中的PDU名称来获得PDU名称;
  • 匹配片段中的../Mapping Signal name名称来获取Mapping Signal name名称;
<PDU-TRIGGERING UUID="64059ffd-36c8-3905-b0e5-8a9a874e2957"> <SHORT-NAME>PduTrDMS_050ms_PDU00</SHORT-NAME>   <I-PDU-PORT-REFS>     <I-PDU-PORT-REF DEST="I-PDU-PORT">/ECUSystem/DMS/DMSC/DMSCCfg/DMSCCfg/ADCANFD/IPduPort_Out</I-PDU-PORT-REF>     <I-PDU-PORT-REF DEST="I-PDU-PORT">/VectorAutosarExplorerGeneratedObjects/ECU_INSTANCES/OtherNodes/Connector_OtherNodes_64e0f3f0db5999fe/PP_01fa4447d4724b9298c6e01a29830d3a_Rx</I-PDU-PORT-REF>   </I-PDU-PORT-REFS>   <I-PDU-REF DEST="I-SIGNAL-I-PDU">/Communication/Pdu/DMS_050ms_PDU00</I-PDU-REF>   <I-SIGNAL-TRIGGERINGS>     <I-SIGNAL-TRIGGERING-REF-CONDITIONAL>       <I-SIGNAL-TRIGGERING-REF DEST="I-SIGNAL-TRIGGERING">/VehicleTopology/ADCANFD/PhCnADCANFD/ISTrisDMSAdoWrnngDspCmd_0</I-SIGNAL-TRIGGERING-REF>     </I-SIGNAL-TRIGGERING-REF-CONDITIONAL>   </I-SIGNAL-TRIGGERINGS></PDU-TRIGGERING>

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

python代码

 #============匹配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中的初始值和长度

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

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

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的初始值来获取Signal的初始值InitValue;
  • 匹配片段中的长度来获取Signal的长度Length;
<I-SIGNAL UUID="5db6edd8-2ae7-3c89-9d92-3eecde037ea6">  <SHORT-NAME>isDMSAdoWrnngDspCmd</SHORT-NAME>  <DATA-TYPE-POLICY>OVERRIDE</DATA-TYPE-POLICY>  <INIT-VALUE>    <NUMERICAL-VALUE-SPECIFICATION>      <VALUE>2</VALUE>    </NUMERICAL-VALUE-SPECIFICATION>  </INIT-VALUE>  <LENGTH>2</LENGTH>  <NETWORK-REPRESENTATION-PROPS>    <SW-DATA-DEF-PROPS-VARIANTS>      <SW-DATA-DEF-PROPS-CONDITIONAL>        <BASE-TYPE-REF DEST="SW-BASE-TYPE">/DataType/DataTypeSemantics/SwBaseTypes/UINT2</BASE-TYPE-REF>        <COMPU-METHOD-REF DEST="COMPU-METHOD">/DataType/DataTypeSemantics/DMSAdoWrnngDspCmd</COMPU-METHOD-REF>      </SW-DATA-DEF-PROPS-CONDITIONAL>    </SW-DATA-DEF-PROPS-VARIANTS>  </NETWORK-REPRESENTATION-PROPS>  <SYSTEM-SIGNAL-REF DEST="SYSTEM-SIGNAL">/Signal/DMSAdoWrnngDspCmd</SYSTEM-SIGNAL-REF></I-SIGNAL>

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中的起始位置

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

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

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的起始位来获取Signal的起始位StartPosition;
<I-SIGNAL-TO-PDU-MAPPINGS> <I-SIGNAL-TO-I-PDU-MAPPING UUID="212b6d36-3fbb-3ecc-b3c7-7be45a4c75ff">   <SHORT-NAME>isDMSAdoWrnngDspCmd_mtx</SHORT-NAME>   <I-SIGNAL-REF DEST="I-SIGNAL">/Communication/ISignal/isDMSAdoWrnngDspCmd</I-SIGNAL-REF>   <PACKING-BYTE-ORDER>MOST-SIGNIFICANT-BYTE-FIRST</PACKING-BYTE-ORDER>   <START-POSITION>63</START-POSITION> </I-SIGNAL-TO-I-PDU-MAPPING></I-SIGNAL-TO-PDU-MAPPINGS>

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中的枚举值或公式

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

TEXTTABLE:
在这里插入图片描述
LINEAR:
在这里插入图片描述

因此匹配方法有两种情况

情况一:TEXTTABLE类型

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

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

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的LIMIT值区域来获得Signal值得区域范围;
  • 匹配片段中的枚举值来获取Signal的枚举值;
<COMPU-METHOD UUID="26578eb7-6133-4ca0-8764-932f674899e2">  <SHORT-NAME>DMSAdoWrnngDspCmd</SHORT-NAME>  <CATEGORY>TEXTTABLE</CATEGORY>  <COMPU-INTERNAL-TO-PHYS>    <COMPU-SCALES>      <COMPU-SCALE>        <LOWER-LIMIT INTERVAL-TYPE="CLOSED">0</LOWER-LIMIT>        <UPPER-LIMIT INTERVAL-TYPE="CLOSED">0</UPPER-LIMIT>        <COMPU-CONST>          <VT>DMSAdoWrnngDspCmd_0_Unavailable</VT>        </COMPU-CONST>      </COMPU-SCALE>      <COMPU-SCALE>        <LOWER-LIMIT INTERVAL-TYPE="CLOSED">1</LOWER-LIMIT>        <UPPER-LIMIT INTERVAL-TYPE="CLOSED">1</UPPER-LIMIT>        <COMPU-CONST>          <VT>DMSAdoWrnngDspCmd_1_Off</VT>        </COMPU-CONST>      </COMPU-SCALE>      <COMPU-SCALE>        <LOWER-LIMIT INTERVAL-TYPE="CLOSED">2</LOWER-LIMIT>        <UPPER-LIMIT INTERVAL-TYPE="CLOSED">2</UPPER-LIMIT>        <COMPU-CONST>          <VT>DMSAdoWrnngDspCmd_2_On</VT>        </COMPU-CONST>      </COMPU-SCALE>      <COMPU-SCALE>        <LOWER-LIMIT INTERVAL-TYPE="CLOSED">3</LOWER-LIMIT>        <UPPER-LIMIT INTERVAL-TYPE="CLOSED">3</UPPER-LIMIT>        <COMPU-CONST>          <VT>DMSAdoWrnngDspCmd_3_laststatus</VT>        </COMPU-CONST>      </COMPU-SCALE>    </COMPU-SCALES>  </COMPU-INTERNAL-TO-PHYS></COMPU-METHOD>

情况二:LINEAR类型

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

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

  • 匹配片段中的Signal Name名称来获得Signal Name;
  • 匹配片段中的Signal值区域来获得Signal值得区域范围;
  • 匹配片段中的 Offset分子Factor分子来获取分子;
  • 匹配片段中的分母来获得分母;
<COMPU-METHOD UUID="60cf4d04-1640-4e96-a021-f6d2137d0faf"> <SHORT-NAME>VehSpdAvg</SHORT-NAME> <CATEGORY>LINEAR</CATEGORY> <COMPU-INTERNAL-TO-PHYS>   <COMPU-SCALES>     <COMPU-SCALE>       <LOWER-LIMIT INTERVAL-TYPE="CLOSED">0</LOWER-LIMIT>       <UPPER-LIMIT INTERVAL-TYPE="CLOSED">32767</UPPER-LIMIT>       <COMPU-RATIONAL-COEFFS>         <COMPU-NUMERATOR>           <V>0</V>           <V>0.015625</V>         </COMPU-NUMERATOR>         <COMPU-DENOMINATOR>           <V>1</V>         </COMPU-DENOMINATOR>       </COMPU-RATIONAL-COEFFS>     </COMPU-SCALE>   </COMPU-SCALES> </COMPU-INTERNAL-TO-PHYS></COMPU-METHOD>

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总结

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

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

来源地址:https://blog.csdn.net/zataji/article/details/131465764

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Hadoop架构解析

Hadoop是一个开源的分布式存储和处理大数据的框架,它的架构主要包括以下几个核心组件:Hadoop Distributed File System(HDFS):HDFS是Hadoop的分布式文件系统,它将大文件分成多个块并存储在多台机器上
Hadoop架构解析
2024-02-29

怎样解析Kafka架构

本篇文章给大家分享的是有关怎样解析Kafka架构,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Kafka是一个开源的、分布式的、可分区的、可复制的基于日志提交的发布订阅消息系统
2023-06-19

CRM功能架构图解析

CRM(CustomerRelationshipManagement)是企业管理和客户关系管理的核心概念,它通过集成各种技术手段,帮助企业管理客户数据、与客户沟通和交流,以提高客户满意度和忠诚度。本文将介绍CRM的功能架构图,并对其各个组件进行详细说明。详细说明:CRM功能架构图:CRM功能架构图通常包括以下几个主要组
CRM功能架构图解析
2024-01-16

如何解析Linux 驱动架构

今天就跟大家聊聊有关如何解析Linux 驱动架构,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先,需要熟悉操作系统的设计与实现,推荐大家看 MINIX作者的那部书,同时把MINIX
2023-06-28

如何解析.NET三层架构

如何解析.NET三层架构,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。所谓三层架构,是在客户端与数据库之间加入了一个“中间层”,也叫组件层。这里所说的三层体系,
2023-06-17

微前端架构ModuleFederationPlugin源码解析

这篇文章主要为大家介绍了微前端架构ModuleFederationPlugin源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

面向数据架构内部解析

面向数据主要是指面向数据解析(DOP,Data-oriented parsing),也称为面向数据编程(data-oriented processing),是一种形式主义概率语法的计算语言学。编程学习网教育
面向数据架构内部解析
2024-04-23

PHP框架的奥秘:架构、性能、安全全解析

php框架的核心要素:架构:遵循mvc模式,分离模型、视图和控制器(例如:laravel采用eloquent orm、blade模板引擎)性能:优化应用程序性能,采用标准化处理(例如:symfony的psr-7标准)、内存管理(例如:zen
PHP框架的奥秘:架构、性能、安全全解析
2024-05-23

亚马逊云服务器架构图解析

VPC:Vpc是一个虚拟的网络,用于将各个云服务器之间的数据流隔离开来。Vpc可以通过不同的路由器和交换机实现,可以是一个专用的VPC,也可以是多个公有云服务提供商共用一个Vpc。子网:子网是由一个或多个主机和服务器组成的小型网络。子网可以被用于分布式存储和计算,以实现更高的灵活性和性能。私有网络:私有网络是一种只有特定的用户才能访问的网络,用于保护数据和应用程序。私有网络通常只在特定的云服务提供商之间共...
2023-10-27

如何解析Linux系统架构中的内核

如何解析Linux系统架构中的内核,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。概述Linux系统一般有4个主要部分组成,内核、shell、文件系统和应用程序。内核、shell
2023-06-16

数据中台全景架构及模块解析!一文入门中台架构师!

回顾一下,第一篇文章大白话 六问数据中台!你想知道的都在这了!。把数据中台是什么?为什么?有什么价值?说的明明白白。数据中台是企业级能力复用平台,目标是让数据持续用起来,通过数据中台提供的工具、方法和运行机制,把数据变为一种服务能力,让数据更方便地被业务所使用
数据中台全景架构及模块解析!一文入门中台架构师!
2021-01-26

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录