编辑推荐: |
本文主要介绍了汽车架构解析:python解析Autosar架构的ARXML相关知识。希望对你的学习有帮助。
本文来自于CSDN,由火龙果软件Linda编辑,推荐。 |
|
前言
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'
with open(file_path, 'r') as file:
arxml_data = file.read()
|
三、解析Frame的基本参数
1、下面是arxml的片段其中就包括了CAN报文的名称DMS_ADCANFD_FrP01,寻址模式STANDARD,通讯协议CAN-FD,以及报文ID554;
2、我们查找报文相关的参数就可以通过查找<CAN-FRAME-TRIGGERING...>数据片段</CAN-FRAME-TRIGGERING>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<FRAME-REF DEST="CAN-FRAME">../报文名称</FRAME-REF>来获得报文名称;
匹配片段中的<CAN-ADDRESSING-MODE>帧类型</CAN-ADDRESSING-MODE>来获得帧类型;
匹配片段中的<CAN-FRAME-TX-BEHAVIOR>报文类型</CAN-FRAME-TX-BEHAVIOR>来获得报文类型;
匹配片段中的<IDENTIFIER>报文ID</IDENTIFIER>来获得报文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>
|
3、正则表达式处理数据
python代码:
CANFrameNode_pattern = r'<CAN-FRAME-TRIGGERING. *?>(.*?)</CAN-FRAME-TRIGGERING>'
CANFrameNodes_List = re.findall( CANFrameNode_pattern, arxml_data, re.DOTALL)
CANFrame_pattern = r'<FRAME-REF DEST="CAN-FRAME"> (.*?)</FRAME-REF>.*?<CAN-ADDRESSING-MODE> (.*?)</CAN-ADDRESSING-MODE>.*?<CAN-FRAME- \wX-BEHAVIOR>(.*?)</CAN-FRAME-\wX-BEHAVIOR>. *?<IDENTIFIER>(.*?)</IDENTIFIER>'
for CANFrameNodes in CANFrameNodes_List:
CANFrames_match = re.findall (CANFrame_pattern, CANFrameNodes, 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_dic ["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、我们查找报文相关的参数就可以通过查找<CAN-FRAME-TRIGGERING...>数据片段</CAN-FRAME-TRIGGERING>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<FRAME-REF DEST="CAN-FRAME">../报文名称</FRAME-REF>来获得报文名称;
匹配片段中的<PDU-TRIGGERING-REF DEST="PDU-TRIGGERING" >../PDU名称</PDU-TRIGGERING-REF>来获取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>
|
4、正则表达式处理数据
python代码:
这里的参数不和上述的《三、解析Frame的基本参数》一起匹配的原因是Frame中的Container-I-PDU的数量可能不唯一,用贪婪匹配可以匹配多个结果。
PDUS_pattern = r'<FRAME-REF DEST ="CAN-FRAME">(.*?)</FRAME-REF>| <PDU-TRIGGERING-REF DEST="PDU-TRIGGERING"> (.*?)</PDU-TRIGGERING-REF>'
Frame_Pdus_Data = []
Pdus_data = []
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、我们查找报文相关的参数就可以通过查找<CONTAINER-I-PDU...>数据片段</CONTAINER-I-PDU>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>PDU名称</SHORT-NAME>来获得报文名称;
匹配片段中的<CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING" >../IPDU名称</CONTAINED-PDU- TRIGGERING-REF>来获取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_PDUS_pattern = r'<CONTAINER-I-PDU (?: UUID="[^"]+")?>(.*?)< /CONTAINER-I-PDU>'
Container_PDUS_match = re.findall( Container_PDUS_pattern, arxml_data, re. DOTALL)
ISignal_PDUS_pattern = r'<SHORT-NAME>(.*?)< /SHORT-NAME>|<CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">(.*?)</CONTAINED -PDU-TRIGGERING-REF>'
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_PDUS_pattern = r'<CONTAINER-I-PDU (?: UUID="[^"]+")?> (.*?)</CONTAINER-I-PDU>'
Container_PDUS_match = re.findall (Container_PDUS_pattern, arxml_data, re.DOTALL)
ISignal_PDUS_pattern = r'<SHORT-NAME>(.*?)< /SHORT-NAME>|<CONTAINED-PDU-TRIGGERING-REF DEST="PDU-TRIGGERING">(.*?)< /CONTAINED-PDU-TRIGGERING-REF>'
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)
|
打印结果:
[{'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-PDU (?: UUID="[^"]+")?>.*?<SHORT-NAME >(.*?)</SHORT-NAME>.*?</NM-PDU>'
NM_PDUs = re.findall(N_PDUS_pattern, arxml_data,re.DOTALL)
|
打印结果
可以直接查找有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、我们查找报文相关的参数就可以通过查找<I-SIGNAL-TRIGGERINGS>数据片段</I-SIGNAL-TRIGGERING>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>PDU中Signal名称</SHORT-NAME>来获得PDU中Mapping
Signal name名称;
匹配片段中的<I-SIGNAL-REF DEST="I-SIGNAL">../RealSignal名称</I-SIGNAL-REF>来获取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_64e0 f3f0db5999fe/SP_b097681ed4394b35929180 6d796936a3_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代码
signalTrig_pattern = r'<I-SIGNAL- TRIGGERINGS>(.*?)</I-SIGNAL-TRIGGERINGS>'
signalTrig_match = re.findall( signalTrig_pattern,arxml_data,re.DOTALL)
signalTrig_str = ""
for signalTrig in signalTrig_match:
if '<I-SIGNAL-REF DEST="I-SIGNAL">' in signalTrig:
signalTrig_str= signalTrig
signalRealName_pattern = r'<SHORT-NAME> (.*?)</SHORT-NAME>|<I-SIGNAL(?:-GROUP)?- REF DEST="I-SIGNAL(?:-GROUP)?"> (.*?)</I-SIGNAL(?:-GROUP)?-REF>'
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 = signalReal Name_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、我们查找报文相关的参数就可以通过查找<PDU-TRIGGERING(?: UUID="[^"]+")?>数据片段</PDU-TRIGGERING>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>PDU名称</SHORT-NAME>来获得PDU名称;
匹配片段中的<I-SIGNAL-TRIGGERING-REF DEST=" I-SIGNAL-TRIGGERING">../Mapping
Signal name名称< /I-SIGNAL-TRIGGERING-REF>来获取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_01fa4447d4724b9298 c6e01a29830d3a_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>
|
6、匹配完Mapping Signal Name之后,顺便替换成Real Signal Name;
python代码
signals_pattern = r'<SHORT-NAME>(.*?)< /SHORT-NAME>|<I-SIGNAL-TRIGGERING-REF \b.*?>(.*?)</I-SIGNAL-TRIGGERING-REF>'
PDUSignals_data = []
for PDUSignals in PDUSignals_match:
PDU_signals = []
PDU_signals_dict = {'pduname':'','signals':[]}
signals_match = re.findall(signals_pattern, PDUSignals, 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:
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、我们查找报文相关的参数就可以通过查找<I-SIGNAL(?: UUID="[^"]+")?>数据片段</I-SIGNAL>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>Signal Name名称</SHORT-NAME>来获得Signal
Name;
匹配片段中的<VALUE>初始值</VALUE>来获取Signal的初始值InitValue;
匹配片段中的<LENGTH>长度</LENGTH>来获取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'<I-SIGNAL(?: UUID ="[^"]+")?>(.*?)</I-SIGNAL>'
iSignals_match = re.findall( iSignals_pattern,arxml_data,re.DOTALL)
iSignalsPara_pattern = r'<SHORT-NAME>(.*?)< /SHORT-NAME>|<VALUE>(.*?)</ VALUE>|<LENGTH>(.*?)</LENGTH>'
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]
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、我们查找报文相关的参数就可以通过查找<I-SIGNAL-TO-PDU-MAPPINGS>片段数据</I-SIGNAL-TO-PDU-MAPPINGS>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>Signal Name名称</SHORT-NAME>来获得Signal
Name;
匹配片段中的<START-POSITION>起始位</START-POSITION>来获取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代码
signal2PDUs_pattern = r'<I-SIGNAL-TO-PDU-MAPPINGS> (.*?)</I-SIGNAL-TO-PDU-MAPPINGS>'
signal2PDUs_match = re.findall( signal2PDUs_pattern,arxml_data,re.DOTALL)
startPosition_pattern = r'<I-SIGNAL(?:-GROUP)?-REF DEST="I-SIGNAL(?:-GROUP)?">(.*?)< /I-SIGNAL(?:-GROUP)?-REF>| <START-POSITION>(.*?)</START-POSITION>'
iSignalSPos_data = []
for signal2PDU in signal2PDUs_match:
signalSPos_match = re.findall( startPosition_pattern,signal2PDU,re.DOTALL)
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():
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、我们查找报文相关的参数就可以通过查找<COMPU-METHOD(?: UUID="[^"]+")?>数据片段</COMPU-METHOD>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>Signal Name名称</SHORT-NAME>来获得Signal
Name;
匹配片段中的<LOWER-LIMIT(?: INTERVAL-TYPE=" CLOSED")?>LIMIT值区域</LOWER-LIMIT>来获得Signal值得区域范围;
匹配片段中的<VT>枚举值</VT>来获取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类型
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、我们查找报文相关的参数就可以通过查找<COMPU-METHOD(?: UUID="[^"]+")?>数据片段</COMPU-METHOD>来获取arxml中的数据片段,再进行更详细的匹配获取其余数据。
匹配片段中的<SHORT-NAME>Signal Name名称</SHORT-NAME>来获得Signal
Name;
匹配片段中的<LOWER-LIMIT(?: INTERVAL-TYPE= "CLOSED")?>Signal值区域</LOWER-LIMIT>来获得Signal值得区域范围;
匹配片段中的 <COMPU-NUMERATOR><V> Offset分子</V><V>Factor分子</V></COMPU-NUMERATOR>来获取分子;
匹配片段中的<COMPU-DENOMINATOR><V> 分母</V></COMPU-DENOMINATOR>来获得分母;
<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'<COMPU-METHOD (?: UUID="[^"]+")?>(.*?)</COMPU-METHOD>'
compuMethod_match = re.findall (compuMethod_pattern,arxml_data,re.DOTALL)
compuMethodPara_pattern = r'<SHORT-NAME> (.*?)</SHORT-NAME>|<CATEGORY> (.*?)</CATEGORY>|<COMPU-SCALES>(.*?)</COMPU-SCALES>'
compuScale_pattern = r'<COMPU-SCALE> (.*?)</COMPU-SCALE>'
compuScaleEnum_pattern = r'<LOWER-LIMIT (?: INTERVAL-TYPE="CLOSED")?>(.*?)</ LOWER-LIMIT>.*?<VT>(.*?)</VT>'
compuScaleLimit_pattern = r'<LOWER-LIMIT (?: INTERVAL-TYPE="CLOSED")?> (.*?)</LOWER-LIMIT>.*?<UPPER-LIMIT (?: INTERVAL-TYPE="CLOSED")?>(.*?)</UPPER-LIMIT>'
compuScaleFormula_pattern = r'<V>(.*?)</V>'
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:
compuMethodPara_dic['signalname' ] = compuMethodPara_match[0][0]
category = compuMethodPara_match[1][1]
compuMethodPara_dic['category'] = category
compuScales_text = compuMethodPara_match[2][2]
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
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矩阵中去。
|