您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 
 订阅
汽车架构解析:python解析Autosar架构的ARXML
 
 
  458  次浏览      18 次
 2023-11-16
 
编辑推荐:
本文主要介绍了汽车架构解析: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'
# ============读取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代码:

#找出所有frame的数据片段
CANFrameNode_pattern  = r'<CAN-FRAME-TRIGGERING.
*?>(.*?)</CAN-FRAME-TRIGGERING>'
CANFrameNodes_List = re.findall(
CANFrameNode_pattern, arxml_data, re.DOTALL)
# 使用 re.DOTALL 标志使 . 匹配任意字符,包括换行符
#设置CANFrame的匹配规则:报文名称:<FRAME-REF
DEST="CAN-FRAME">(.*?)</FRAME-REF>,寻址模式
:<CAN-ADDRESSING-MODE>,报文类型CAN/CANFD:
<CAN-FRAME-TX-BEHAVIOR>,报文标识ID:<IDENTIFIER>
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)
# 使用 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的数量可能不唯一,用贪婪匹配可以匹配多个结果。

#设置PDU的匹配规则:报文名称:
<FRAME-REF DEST="CAN-FRAME">,
PDU名称:<PDU-
TRIGGERING-REF DEST="PDU-TRIGGERING">
PDUS_pattern = r'<FRAME-REF DEST
="CAN-FRAME">(.*?)</FRAME-REF>|
<PDU-TRIGGERING-REF
DEST="PDU-TRIGGERING">
(.*?)</PDU-TRIGGERING-REF>'
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、我们查找报文相关的参数就可以通过查找<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-I-PDU中的PDU===========
Container_PDUS_pattern
=
r'<CONTAINER-I-PDU
(?: UUID="[^"]+")?>(.*?)<
/CONTAINER-I-PDU>'
#匹配具体参数获得I-PDU参数 Container_PDUS_match = re.findall(
Container_PDUS_pattern, arxml_data, re.
DOTALL) # 使用 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-I-PDU中的PDU===========
Container_PDUS_pattern
= r'<CONTAINER-I-PDU
(?: UUID="[^"]+")?>
(.*?)</CONTAINER-I-PDU>'
#匹配具体参数获得I-PDU参数 Container_PDUS_match = re.findall
(
Container_PDUS_pattern, arxml_data,
re.DOTALL) # 使用 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)

 

打印结果

#这里只举例一个结果
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、我们查找报文相关的参数就可以通过查找<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代码

#因为PDU中的部分Signal名称有Mapping关系
,所以需要拿到Real signal name名称
signalTrig_pattern = r'<I-SIGNAL-
TRIGGERINGS>(.*?)</I-SIGNAL-TRIGGERINGS>'
signalTrig_match = re.findall(
signalTrig_pattern,arxml_data,re.DOTALL) signalTrig_str = "" #存在<I-SIGNAL-REF DEST="I-SIGNAL">的
<I-SIGNAL-TRIGGERINGS>片段,
才具有Mapping属性,仅有一个
for signalTrig in signalTrig_match: if '<I-SIGNAL-REF DEST="I-SIGNAL">' in signalTrig: signalTrig_str= signalTrig #匹配signal name的Mapping关系 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代码

 #========匹配PDU Name和signals name========
 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':[]} #开始查找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、我们查找报文相关的参数就可以通过查找<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代码

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

 #匹配<I-SIGNAL></I-SIGNAL>或
者<I-SIGNAL UUID=""></I-SIGNAL>中的文本
iSignals_pattern = r'<I-SIGNAL(?: UUID
="[^"]+")?>(.*?)</I-SIGNAL>'
iSignals_match = re.findall(
iSignals_pattern,arxml_data,re.DOTALL) #匹配signal的初始值和长度的数据 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] #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、我们查找报文相关的参数就可以通过查找<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代码

 #匹配<I-SIGNAL-TO-PDU-MAPPINGS></
I-SIGNAL-TO-PDU-MAPPINGS>中的内容
,signal的START-POSITION在其中
signal2PDUs_pattern =
r'<I-SIGNAL-TO-PDU-MAPPINGS>
(.*?)</I-SIGNAL-TO-PDU-MAPPINGS>'
signal2PDUs_match = re.findall(
signal2PDUs_pattern,arxml_data,re.DOTALL) #匹配signal的真实名称和signal的start position 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) #每个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、我们查找报文相关的参数就可以通过查找<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代码

#匹配<COMPU-METHOD></COMPU-METHOD>或者
<COMPU-METHOD UUID=""></COMPU-METHOD>中的文本
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>'
#匹配TEXTTABLE中的枚举值<COMPU-SCALE>,
每个<COMPU-SCALE>中有一个枚举值和枚举文本
compuScale_pattern = r'<COMPU-SCALE>
(.*?)</COMPU-SCALE>'
#匹配<COMPU-SCALE>中的枚举值和枚举文本 compuScaleEnum_pattern = r'<LOWER-LIMIT
(?: INTERVAL-TYPE="CLOSED")?>(.*?)</
LOWER-LIMIT>.*?<VT>(.*?)</VT>'
#匹配<COMPU-SCALE>值的范围 compuScaleLimit_pattern = r'<LOWER-LIMIT
(?: INTERVAL-TYPE="CLOSED")?>
(.*?)</LOWER-LIMIT>.*?<UPPER-LIMIT
(?: INTERVAL-TYPE="CLOSED")?>(.*?)</UPPER-LIMIT>'
#匹配<COMPU-SCALE>值的计算公式 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: #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矩阵中去。

 
   
458 次浏览       18
相关文章

中央计算的软件定义汽车架构设计
汽车电子控制系统中的软件开发过程
一文读懂汽车芯片-有线通信芯片
OTA在汽车上有哪些难点痛点?
相关文档

汽车设计-汽车的整体结构及动力系统
自动驾驶汽车软件计算框架
SysML在汽车领域的应用实践
电子电气架构-大陆汽车系统架构平台
相关课程

AutoSAR原理与实践
功能安全管理体系(基于ISO26262)
MBSE(基于模型的系统工程)
基于SOA的汽车电子架构设计与开发

最新活动计划
MBSE(基于模型的系统工程)4-18[北京]
自然语言处理(NLP) 4-25[北京]
基于 UML 和EA进行分析设计 4-29[北京]
以用户为中心的软件界面设计 5-16[北京]
DoDAF规范、模型与实例 5-23[北京]
信息架构建模(基于UML+EA)5-29[北京]
 
 
最新文章
中央计算的软件定义汽车架构设计方案解析
汽车电子控制系统中的软件开发过程
一文读懂汽车芯片-有线通信芯片
OTA在汽车上有哪些难点痛点?
智能汽车车用基础软件的内核和中间件
最新课程
Auto SAR原理与实践
MBSE(基于模型的系统工程)
基于SOA的汽车电子架构设计与开发(域控模式)
人工智能助力汽车行业升级
基于UML和EA进行系统分析设计
SysML和EA进行系统设计建模
更多...   
成功案例
奇瑞商用车 购买建模工具EA完全版
航空发动机研究院 购买建模工具EA完全版
联创汽车 购买建模工具EA完全版
江淮汽车 购买建模工具EA
更多...