📘前言
-
🍅 在汽车电子系统测试中,离不开对报文周期的测试,如果系统比较复杂,要处理成千上万个报文,如果纯手动测试,会耗费人力,在CAPL脚本的基础上,通过python 解析 arxml 文件中的Flxeray 和 dbc 文件中的 CAN报文。形成自动化的测试脚本。
-
🍅演示软硬件环境 Win10 x64 ; CANoe 11 SP2 x64
📗 分析并提取Flexray 报文
- 1️⃣ 通过xml marker 工具打开 flexray.arxml 报文矩阵,分析后,得知flexray的报文结构如下图,
- 2️⃣ 明确我们测试周期需要的参数,Flexray 报文我们需要提取
报文名字和报文周期时间
,而报文周期时间由调度表参数(Slot,Base,Repetition)
决定,所以我们需要提取总共4个参数,Name ,Slot,Base,Repetition
,具体代码如下:
from lxml import etree
import re
import os
class cycleTimeTest():
def __init__(self, *args, **kwargs): # real signature unknown
self.frames_name = []
self.slot_ID = []
self.base_cycle = []
self.cycle_repetition = []
def arxml(self):
html = etree.parse('./files/test.arxml')#just have one arxmal file
if html:
root = html.getroot()
print(root.tag) # 开始认为返回的root tag 应该是 ’AUTOSAR‘ ,结果却是 ’{http://autosar.org/schema/r4.0}AUTOSAR ‘
AR_PACKAGES =root.findall("./%sAR-PACKAGES//%sAR-PACKAGE"%(base_tag,base_tag))
# print(AR_PACKAGES)
frames = AR_PACKAGES[1].findall(".//%sFLEXRAY-CLUSTER//%sFLEXRAY-FRAME-TRIGGERING"%(base_tag,base_tag))# 得到所有的 flexray 报文
# print(Frames)
for frame in frames:
name = frame.find(".//%sFRAME-REF"%(base_tag)).text.split(r'/')[-1]
if re.match('FlcFLC_FlexrayFr', name):#这里有个过滤的动作,因为我们只需要测试ECU发过来的报文,而ECU的报文名字都有'FlcFLC_FlexrayFr'
self.frames_name.append(name)
slot = frame.find(".//%sSLOT-ID"%(base_tag)).text # 得到flexray 报文 slot 参数
self.slot_ID.append(slot)
cycle = frame.find(".//%sCYCLE-REPETITION//%sBASE-CYCLE"%(base_tag,base_tag)).text # 得到flexray 报文 base cycle 参数
self.base_cycle.append(cycle)
repetition = frame.find(".//%sCYCLE-REPETITION//%sCYCLE-REPETITION"%(base_tag,base_tag)).text.split(r'-')[-1] # 得到flexray 报文 cycle repetition 参数
self.cycle_repetition.append(repetition)
print(self.frames_name)
print(self.slot_ID)
print(self.base_cycle)
print(self.cycle_repetition)
else:
print("parse file failed!")
if __name__ == '__main__':
c = cycleTimeTest()
c.arxml()
- 3️⃣ 测试结果如下,总共有195个满足测试条件的Flexray报文:
📗 分析提取can报文
- 1️⃣ 通过notepad 打开 .dbc文件。可以分析出dbc文件的结果如下图
- 以第一行为例解释下报文的格式: BO_ 是开始标识,80 是报文ID,紧接着字符串是报文名字,8是报文长度,FLC是报文发出者
- 报文下面SG开头的,是这个报文的信号参数,包括信号的长度,起始终止位等。
- 我们明确Can报文周期测试我们需要提取的参数是什么
下图,红色 笔着色的是 报文 cycle参数,比如 BA_ “GenMsgCycleTime” BO_ 80 10; 就表明
ID为80的报文cycle 是10ms
.
- 2️⃣ 解析代码
from lxml import etree
import re
import os
class cycleTimeTest():
def __init__(self, *args, **kwargs): # real signature unknown
#flexray
self.frames_name = []
self.slot_ID = []
self.base_cycle = []
self.cycle_repetition = []
#can
self.can_mesages_name = []
self.can_mesages_id = []
self.can_mesages_peried = []
def get_abspath(self,file_suffix):
'''
@这个函数根据文件后缀,选出所有符合条件的文件
'''
self.root_path = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
self.root_path = os.path.join(self.root_path, "files")
self.fileList = os.listdir(self.root_path)
self.get_files = []
for file in self.fileList:
if file.split(".")[-1] == file_suffix:
self.get_files.append(os.path.join(self.root_path, file))
return self.get_files
def arxml(self):
html = etree.parse('./files/test.arxml')#just have one arxmal file
if html:
root = html.getroot()
print(root.tag) # 开始认为返回的root tag 应该是 ’AUTOSAR‘ ,结果却是 ’{http://autosar.org/schema/r4.0}AUTOSAR ‘
base_tag = "{http://autosar.org/schema/r4.0}"
AR_PACKAGES =root.findall("./%sAR-PACKAGES//%sAR-PACKAGE"%(base_tag,base_tag))
# print(AR_PACKAGES)
frames = AR_PACKAGES[1].findall(".//%sFLEXRAY-CLUSTER//%sFLEXRAY-FRAME-TRIGGERING"%(base_tag,base_tag))# 得到所有的 flexray 报文
# print(Frames)
for frame in frames:
name = frame.find(".//%sFRAME-REF"%(base_tag)).text.split(r'/')[-1]
if re.match('FlcFLC_FlexrayFr', name):#这里有个过滤的动作,因为我们只需要测试ECU发过来的报文,而ECU的报文名字都有'FlcFLC_FlexrayFr'
self.frames_name.append(name)
slot = frame.find(".//%sSLOT-ID"%(base_tag)).text # 得到flexray 报文 slot 参数
self.slot_ID.append(int(slot))
cycle = frame.find(".//%sCYCLE-REPETITION//%sBASE-CYCLE"%(base_tag,base_tag)).text # 得到flexray 报文 base cycle 参数
self.base_cycle.append(int(cycle))
repetition = frame.find(".//%sCYCLE-REPETITION//%sCYCLE-REPETITION"%(base_tag,base_tag)).text.split(r'-')[-1] # 得到flexray 报文 cycle repetition 参数
self.cycle_repetition.append(int(repetition))
print(self.frames_name)
print(self.slot_ID)
print(self.base_cycle)
print(self.cycle_repetition)
return 1
else:
print("parse file failed!")
def dbc(self):
self.dbcfiles = self.get_abspath('dbc')
if self.dbcfiles:
for i in range(len(self.dbcfiles)):
print(self.get_files[i])
self.get_can_message_name_and_id(self.dbcfiles[i])
print(self.can_mesages_name)
print(self.can_mesages_id)
print(self.can_mesages_peried)
def get_can_message_name_and_id(self,filename):
f = open(filename)
if f:
line = f.readline() # read next line
while line: # read by line
message_search_obj = re.search(message_pattern, line.strip()) # 匹配到message
# print(message_search_obj)
if message_search_obj:
id = message_search_obj.group(1) # message id
name = message_search_obj.group(2)# message name
cycle = self.get_can_message_cycle(filename,id) # message cycle
if cycle: #如果读取的cycle 为None, 这样的 报文不需要测
self.can_mesages_id.append(int(id))
self.can_mesages_name.append(name)
self.can_mesages_peried.append(cycle)
line = f.readline()
f.close()
else:
print("open file :%s failed"%filename)
def get_can_message_cycle(self,filename,id):
f = open(filename)
if f:
line = f.readline()
while line:
# eg:BA_ "GenMsgCycleTime" BO_ 72 10 cycle is 10ms ;
cycle_pattern = re.compile(r'''BA_ "GenMsgCycleTime" BO_ %s (.*?);''' % id,re.S) # 报文的周期 需要根据报文ID获取
message_search_obj = re.search(cycle_pattern, line.strip())
if message_search_obj:
cycle = int(float(message_search_obj.group(1)))
f.close()
return cycle
line = f.readline()
f.close()
else:
print("open file :%s failed"%filename)
if __name__ == '__main__':
c = cycleTimeTest()
c.arxml()
c.dbc()
- 3️⃣ 测试结果如下图,虽然穿进去3个dbc文件,但是目标ECU 发出的有效的报文就只有8个报文:
🌎总结
- 🚩要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!
- 🚩 有微信的小伙伴可以关注下浪哥车载诊断,一个行业内小小圈子,群里有
网盘资料
,源码
,还有各路大神
闲时交流交流技术,聊聊工作机会啥的。
- 🚩如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。