CANoe自动生成CAPL脚本:利用Python读取DBC文件批量生成测试脚本和VXT文件
第一步读取.dbc文件,获取带E2E校验的报文,生成excel表格,目标生成结果如下
因为E2E报文都是含有CRC和counter的信号,我们可以以此作为依据筛选,然后再获取目标报文的关键信息填到表格中
import cantools
from openpyxl import Workbook
import re
def GetSigDataId(filePath):
fileList = []
with open(filePath, 'r', encoding='utf-8') as f:
fileList = f.readlines()
sigDataIdMap = {}
for line in fileList:
result = re.match(r'BA_\s+"E2EDataId"\s+SG_\s+\d+\s+(\w+)\s+(\d+);', line)
if (result):
sigName = result.group(1)
dataId = result.group(2)
sigDataIdMap[sigName] = dataId
return sigDataIdMap
def find_messages_with_crc_and_counter(dbc_file_path, excel_file_path, sigDataIdMap):
try:
# 载入 DBC 文件
db = cantools.database.load_file(dbc_file_path)
except FileNotFoundError:
print(f"错误:找不到位于 {dbc_file_path} 的 DBC 文件")
return
for message in db.messages:
has_crc_signal = any("CRC" in signal.name for signal in message.signals)
crc_signal_names = [signal.name for signal in message.signals if "CRC" in signal.name]
has_counter_signal = any("Counter" in signal.name for signal in message.signals)
counter_signal_names = [signal.name for signal in message.signals if "Counter" in signal.name]
if has_crc_signal and has_counter_signal:
sending_node = message.senders[0] if message.senders else 'N/A'
message_period = message.cycle_time if message.cycle_time is not None else 'N/A'
dataId = sigDataIdMap[counter_signal_names[0]]
dataId=int(dataId)
ws.append([dbc_file_path, message.name, ', '.join(crc_signal_names), ', '.join(counter_signal_names), hex(dataId), sending_node, hex(message.frame_id), message_period, message.length])
processed_messages.add(message)
if __name__ == "__main__":
dbc_file_paths = ["CAN4.dbc","CAN5.dbc"]
excel_file_path = "messagewithE2E.xlsx"
wb = Workbook()
ws = wb.active
# 写入表头
ws.append(["DBC 文件", "报文名称", "CRC 信号", "Counter 信号", "E2E_DATAID", "发送节点","报文标识", "报文周期 (毫秒)","报文长度","检测变量","是否TX"])
# 将 DBC 数据写入 Excel,包含同时具有 CRC 和 Counter 信号的报文
processed_messages = set() # 记录处理过的报文
for dbc_file_path in dbc_file_paths:
sigDataIdMap = GetSigDataId(dbc_file_path)
find_messages_with_crc_and_counter(dbc_file_path, excel_file_path, sigDataIdMap)
# 保存 Excel 文件
wb.save(excel_file_path)
print(f"已保存同时具有 CRC 和 Counter 信号的报文至 {excel_file_path}")
第二步,我们用for循环,读取excel的关键内容,批量生成case,vxt
import openpyxl
def generate_test_cases_vxt(excel_file, can_file, vxt_file):
wb = openpyxl.load_workbook(excel_file)
ws = wb.active
# Assuming the first row contains column headers
headers = [cell.value for cell in ws[1]]
# Get the column indices for required data
dbc_index = headers.index('DBC 文件')
msg_name_index = headers.index('报文名称')
a2lvaliable_index = headers.index('检测变量')
# Initialize variables to store test case content and names
test_cases_content = ""
test_cases_names = ""
test_vxt=""
# Iterate through rows starting from the second row
for row in ws.iter_rows(min_row=2, values_only=True):
dbc_file = row[dbc_index]
msg_name = row[msg_name_index]
a2lvaliable =row[a2lvaliable_index]
# Generate test case content
test_case_content = f"testcase TC1_RX_{msg_name}_msg()\n"
test_case_content += "{\n"
test_case_content += f" Start_Logging('TC1_RX_{msg_name}_msg');\n"
test_case_content += f" //赋中间值\n"
test_case_content += f" testStep(\"Info\",\"Set Signalvalue = middlevalue\");\n"
test_case_content += f" for(i = 2; i < 54; i++ )\n"
test_case_content += " {\n"
test_case_content += f" {msg_name}_msg.byte(i) = 0x88;\n"
test_case_content += " }\n"
test_case_content += f" setTimerCyclic(Timer_{msg_name}_msg,20);\n"
test_case_content += f" TestWaitFortimeout(500);\n"
test_case_content += f" //CRC判断\n"
test_case_content += f" if(@XCP::A2L::{a2lvaliable} == 0)\n"
test_case_content += " {\n"
test_case_content += f" testStepPass(\"CheckResult\", \"E2E check pass {a2lvaliable} == {{@XCP::A2L::{a2lvaliable}}}\");\n"
test_case_content += " }\n"
test_case_content += f" else\n"
test_case_content += f" {{\n"
test_case_content += f" testStepFail(\"CheckResult\", \"{a2lvaliable} != 0\");\n"
test_case_content += " }\n"
test_case_content += f" cancelTimer(Timer_{msg_name}_msg);\n"
test_case_content += f" testWaitForTimeout(500);\n"
test_case_content += f" stopLogging('Logging');\n"
test_case_content += "}\n\n"
# Generate test case name
test_case_name = f"TC1_RX_{msg_name}_msg"
# Append test case content and name to respective variables
test_cases_content += test_case_content
# test_cases_names += "<capltestcase name="test_case_name"/>" + "\n"
test_cases_names += f" <capltestcase name=\"{test_case_name}\"/>\n"
test_vxt = f"""<?xml version="1.0" encoding="iso-8859-1"?>
<!--Vector Test Automation Editor 2.1.34.0-->
<testmodule title="Someip_test" version="1.0" xmlns="http://www.vector-informatik.de/CANoe/TestModule/1.27">
<testgroup title="E2E_Test"> \
{test_cases_names}
</testgroup>
</testmodule>
"""
# Write test case content to .can file
with open(can_file, 'w', encoding='utf-8') as f:
f.write(test_cases_content)
# Write test case names to .vxt file
with open(vxt_file, 'w', encoding='utf-8') as f:
f.write(test_vxt)
wb.close()
if __name__ == "__main__":
excel_file = "messagewithE2E.xlsx"
can_file = "testcases.can"
vxt_file = "testcases.vxt"
generate_test_cases_vxt(excel_file, can_file, vxt_file)
第三步,我们可以把生成的.can和.vxt文件导入到canoe
作者:DYS_个人练习生