【Python】读取elf文件,更新a2l文件中变量地址

前言

a2l文件是汽车行业常见的用于标定的数据库文件。在开发过程中,通常由MATLAB或者Excel生成a2l文件,但变量的地址是需要load elf文件去更新的,一般使用的是Vector的CANape工具。
下面记录和分享一下通过脚本去更新a2l文件。

1 使用CANoe中的ASAP2Updater

1.1 ASAP2Updater工具路径

一般在CANoe安装路径下,比如:

C:\Program Files\Vector CANoe 12.0\ASAP2Updater\Exec\ASAP2Updater.exe

同级目录下存在手册Manual.pdf。

1.2 使用方式

Manual.pdf
参考“Manual.pdf”手册中的3.2章节(如上图所示),则可在命令行中执行:

C:\Program Files\Vector CANoe 12.0\ASAP2Updater\Exec\ASAP2Updater.exe -I Test.a2l -A Test.elf -O Gen.a2l

需要注意的是,读取elf文件时,需要指定elf的格式,目前常用的是ELF 32 Bit。这个和在Vector工具ASAP2 Studio中选择elf格式一样的,如下图。
请添加图片描述
参考手册中的3.4章节,需要创建一个名称为“UPDATER.INI”的文件,在其中写入如下信息,并放到执行命令行的路径中。

[OPTIONS]
MAP_FORMAT = 31

如果有其他options需要设定,请参考手册。

2 使用Python

2.1 处理a2l文件

2.1.1 三方库

使用pya2l,参考: https://pypi.org/project/pya2l/

2.1.2 读取a2l文件

pya2l读取a2l文件后的格式是tree,这个格式不方便读取和编辑,可以转换成json,再到dict。参考以下步骤可读入a2l并转换成dict。
1) 导入json和pya2l中的A2lParser

import json
from pya2l.parser import A2lParser as Parser

2)读入a2l

self.parser = Parser()
# 读取a2l文件,二进制。
with open(self.a2l_file, "rb") as f:
    byte = f.read()
    f.close()
# a2l转换成内部的tree。
r_ast = self.parser.tree_from_a2l(byte)
# tree转换成json,方便修改
r_json_bytes = self.parser.json_from_tree(r_ast)
# load json,转换成字典,方便修改。
self.r_json_py = json.loads(r_json_bytes.decode())
  • tree_from_a2l()读取的是byte格式数据,不是字符串。
  • json_from_tree()可将tree转换成json格式。
  • json.loads()将json格式转为字典,便于编辑。

2.1.3 保存a2l文件

保存成a2l文件的方式和读取a2l的步骤刚好相反,可参考如下:

# json转换成tree。
w_json = json.dumps(self.r_json_py, indent=4)
w_ast = self.parser.tree_from_json(w_json.encode())
# tree转换成a2l。
w_a2l = self.parser.a2l_from_tree(w_ast, indent=4).decode()  # SYMBOL_LINK没了
w_a2l = self.add_SYMBOL_LINK(w_a2l)
print(w_a2l, file=open(a2l_file, "w"))
  • json.dumps()将字典转换为json。
  • tree_from_json()将json转成tree,用于保存成a2l。
  • a2l_from_tree()将tree转换成byte格式,后面加个decode()即可转为str。

注意 a2l_from_tree()返回的文本中丢失了SYMBOL_LINK,Vector工具更新地址会用到。可以用正则表达式添加,参考如下:

regex = re.compile(r"(/begin (MEASUREMENT|CHARACTERISTIC) ([^ ]+) .*)")
str_out = regex.sub(r"\1" + " SYMBOL_LINK " + r'"\3" 0', str_in)

2.1.4 读取a2l文件中的RECORD_LAYOUT

RECORD_LAYOUT是a2l中的数据类型。读取数据类型,便于对比a2l和elf变量类型是否相同。
a2l中的基础类型一般是UBYTE、UWORD这种,在此基础上可以定义成其他的类型,比如Scalar_UBYTE。其本质还是基础类型,所以可以用一个字典表示这些类型,方便后面查找和对比。{basetype: set(data types)}
打印的示例如下:

record_dict: {'FLOAT32_IEEE': {'Lookup1D_FLOAT32_IEEE', 'FLOAT32_IEEE', 'Scalar_FLOAT32_IEEE', 'Axis_FLOAT32_IEEE'}, 'UBYTE': {'UBYTE', 'Scalar_UBYTE'}, 'ULONG': {'Scalar_ULONG', 'ULONG'}, 'UWORD': {'Scalar_UWORD', 'UWORD'}}

读取RECORD_LAYOUT,保存成上述数据格式的示例代码如下:

def read_record(self):
    """
    a2l中的RECORD_LAYOUT,数据类型。
    """
    project = self.r_json_py.get("PROJECT")
    modules = project.get("MODULE")
    for module in modules:  # MODULE长度是1
        records = module.get("RECORD_LAYOUT")
        for record in records:
            name = record["Name"]["Value"]
            fnc = record.get("FNC_VALUES") or record.get("AXIS_PTS_X")
            data_type = fnc["DataType"]["Value"]
            if not self.record_dict.get(data_type):
                self.record_dict[data_type] = {
   data_type}
            self.record_dict[data_type].add(name)

2.1.5 读取a2l文件中的变量信息

a2l中的变量信息有两种,分别是标定量(CHARACTERISTIC)和观测量(MEASUREMENT)。这两种变量在a2l中的节点有所差别,但对于地址和数据类型的处理还是一样的。
1)CHARACTERISTIC的信息读取和写入

project = self.r_json_py.get("PROJECT")
modules = project.get("MODULE")
for module in modules:  # MODULE长度是1
    characteristics = module.get("CHARACTERISTIC")
    for variable in characteristics:
        # a2l中变量的属性读取
        name = variable["Name"]["Value"]
        d
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kook 1995

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值