当前位置:   article > 正文

【Python】生成SWC arxml_arxml文件如何生成

arxml文件如何生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在基于AUTOSAR平台开发的软件系统中,SWC的描述文件的格式是arxml。这个文件常由Vector的Developer导出或者MATLAB编译生成,但在开发过程中模块的接口文档一般是写在Excel表格中的,手动在工具中创建比较麻烦,所以如果能够由表格生成arxml再导入到开发工具或者集成工具中就比较方便了。
以下没有Excel表格读取的内容,仅分享arxml的生成,并且是SWC中常见的内容:SWC、runnable、SR接口和数据类型的创建。

一、第三方库autosar

以下功能是基于Python第三方库autosar (0.4.2)的基础上进行的封装,仅用了里面一部分功能,详细内容可查阅 https://autosar.readthedocs.io/en/latest/

二、代码分享

由于库中的函数和一些方法不好理解,所以按照自己的方式进行了一层封装,只封装了常使用的一些功能。

1. Swc类初始化

Swc是自定义的一个类,一些功能都写在这个类的方法中。
代码如下(示例):

class Swc(object):
    def __init__(self, swc, file):
        self.swc = swc
        pkg_swc = swc
        pkg = pkg_swc + '_pkg'
        self.refs = {
            # Package Paths
            'componentPackage': f'/{pkg}/{pkg_swc}_swc',
            'datatypePackage': f'/{pkg}/{pkg_swc}_dt',  # /ImplementationDataTypes
            'interfacePackage': f'/{pkg}/{pkg_swc}_if',  # "PortInterfaces", #
            # Qualified Names
            # 'internalBehaviorName': f'/{pkg}/{pkg_swc}_swc/ib/{pkg_swc}',
            # 'implementationName': f'/{pkg}/{pkg_swc}_swc/{pkg_swc}_imp',
            # Additional Packages
            'applicationDataTypePackage': f'/{pkg}/{pkg_swc}_dt/ApplDataTypes',
            'swBaseTypePackage': f'/{pkg}/{pkg_swc}_dt/SwBaseTypes',
            'dataTypeMappingSetPackage': f'/{pkg}/{pkg_swc}_dt/DataTypeMappings',
            'constantSpecificationPackages': f'/{pkg}/{pkg_swc}_dt/Ground',
            'physicalDataConstraintsPackage': f'/{pkg}/{pkg_swc}_dt/ApplDataTypes/DataConstrs',
            'systemConstantPackage': '',
            'swAddressMethodPackage': f'/{pkg}/{pkg_swc}_dt/SwAddrMethods',
            'modeDeclarationGroupPackage': '',
            'compuMethodPackage': f'/{pkg}/{pkg_swc}_dt/CompuMethod',
            'unitPackage': f'/{pkg}/{pkg_swc}_dt',
            'swRecordLayoutPackage': f'/{pkg}/{pkg_swc}_dt/ApplDataTypes/RecordLayouts',
            'internalDataConstraintsPackage': 'AUTOSAR_Platform/DataConstrs'
        }
        self.ws = autosar.workspace("4.2.2")
        if file:
            self.ws.loadXML(file)
        self.ws.version = "4.2.2"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • swc:swc的名称。(如果容易混淆,可以改成其他名字。)
  • file:arxml文件路径。autosar也是可以读取arxml文件的,可以在此基础上修改。如果从零创建,可以传入None。

功能说明:

  • self.refs:这个是package的路径,后续创建的内容会放到这里面。MATLAB生成的arxml也是可以设置这个路径的,如下:
    在这里插入图片描述
  • self.ws = autosar.workspace(“4.2.2”):后续的处理都是在workspace的基础上进行的,传入的数字是arxml版本,4.0以后的都可以。(这个workspace是可以创建一个Developer工程的,没用到就没咋研究。)
  • self.ws.loadXML:是用于读取arxml。
  • self.ws.version = “4.2.2”:读取后需要设置一下arxml版本,否则后续处理会出现exception。(好像4.0以后SWC的arxml没事区别,设置一个即可。)

2. 创建package

代码如下(示例):

    def common_pkg_create(self):
        """
        Create common package according to self.refs.
        If package already exist, it will not be created controlling by autosar.workspace. See createPackage.
        """
        for ref in self.refs.values():
            if ref:
                refList = autosar.base.splitRef(ref)
                pkg = self.ws.createPackage(refList[0])  # 创建一级目录
                if len(refList) > 1:
                    self.create_sub_pkg_by_ref(pkg, '/'.join(refList[1::]))  # 创建子目录

    def create_sub_pkg_by_ref(self, pkg, ref):
        """
        Create subPackage for pkg according to ref.
        """
        refList = autosar.base.splitRef(ref)
        f = pkg.find(refList[0])  # 查找是否已经存在package (refList[0])
        if len(refList) > 1:  # 存在深层次路径,则需要迭代创建
            if f:
                self.create_sub_pkg_by_ref(f, '/'.join(refList[1::]))
            else:  # 如果不存在pkg,则创建
                temp = pkg.createSubPackage(refList[0])
                self.create_sub_pkg_by_ref(temp, '/'.join(refList[1::]))
        else:
            if not f:
                pkg.createSubPackage(refList[0])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

3. 创建数据类型

3.1 BaseType

代码如下(示例):

    def util_createSwBaseType(self, name, size=None, encoding=None, nativeDeclaration=None, category='FIXED_LENGTH',
                              adminData=None):
        baseTypes = self.ws.find(self.refs.get('swBaseTypePackage'))
        self.ws.setRole(self.refs.get('swBaseTypePackage'), 'DataType')
        try:
            baseTypes.createSwBaseType(name, size, encoding, nativeDeclaration, category, adminData)
        except ValueError:
            LOG.debug(f"Already exist SwBaseType: {name}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • self.ws.find:可以findpackage,但需要注意传入ref的绝对路径(因为会常用这个路径,所以定义了一个refs字典)。
  • self.ws.setRole:需要将swBaseTypePackage设置为DataType角色,一些内部的处理用的这个“Role”。也可在创建package时设置,设置一次即可。
  • baseTypes.createSwBaseType:创建BaseType的函数。(后面会有例子)

3.2 ImplementationDataType

代码如下(示例):

    def util_createImplementationDataType(self, name, baseTypeRef, lowerLimit=None, upperLimit=None, valueTable=None,
                                          bitmask=None, offset=None, scaling=None, unit=None, forceFloat=False,
                                          dataConstraint='', swCalibrationAccess='', typeEmitter=None,
                                          lowerLimitType=None, upperLimitType=None, category='VALUE', adminData=None):
        implTypes = self.ws.find(self.refs.get('datatypePackage'))
        self.ws.setRole(implTypes.ref, 'DataType')
        try:
            implTypes.createImplementationDataType(name, baseTypeRef, lowerLimit, upperLimit, valueTable, bitmask,
                                                   offset, scaling, unit, forceFloat, dataConstraint,
                                                   swCalibrationAccess, typeEmitter, lowerLimitType, upperLimitType,
                                                   category, adminData)
        except ValueError:
            LOG.debug(f"Already exist ImplementationDataType: {name}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 这个创建Implementation类型,不同的类型(结构体,数组,枚举等)需要传入的参数不同。在此基础上又进行了一次封装。
3.2.1 一般类型

代码如下(示例):

    def util_createDataType(self, name, baseType):
        implTypes = self.ws.find(self.refs.get('datatypePackage'))
        self.ws.setRole(implTypes.ref, 'DataType')
        if not implTypes.find(name):
            baseTypeRef = f'{self.refs.get("swBaseTypePackage")}/{baseType}'
            return self.util_createImplementationDataType(name=name, baseTypeRef=baseTypeRef)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 用于生成如uint8、sint8、float32的一般类型。
  • 需要传入baseTypeRef,这个用的是创建的BaseType,其ref在swBaseTypePackage路径下。(在某package下创建的某物,其路径都是在package后面加“/”再加某物的名称。)
3.2.2 数组类型

代码如下(示例):

    def util_createImplementationArrayDataType(self, name, dataTypeRef, arraySize):
        implTypes = self.ws.find(self.refs.get('datatypePackage'))
        self.ws.setRole(implTypes.ref, 'DataType')
        implementationTypeRef = implTypes.find(dataTypeRef)
        if not implTypes.find(name):
            try:
                return implTypes.createImplementationArrayDataType(name, implementationTypeRef.ref, arraySize)
            except ValueError as e:
                LOG.exception(f"Exception: {e}, {name}, {dataTypeRef}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • name:类型的名称。
  • dataTypeRef:使用的ImplementationDataType类型。(所以在创建数组类型前,先创建其使用的类型。)
  • arraySize:数组的长度。
3.2.3 结构体类型

代码如下(示例):

    def util_createImplementationRecordDataType(self, name, itemList: [ElementInformation]):
        implTypes = self.ws.find(self.refs.get('datatypePackage'))
        self.ws.setRole(implTypes.ref, 'DataType')
        if not implTypes.find(name):
            try:
                return implTypes.createImplementationRecordDataType(
                    name,
                    ((item.name, item.dataType) for item in itemList)
                )
            except Exception as e:
                LOG.exception(f"Exception: {e}, {name}, {itemList}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • name:类型的名称。
  • itemList:结构体中字段的一些信息。需要字段名称和其数据类型名称(不用ref全部路径),createImplementationRecordDataType()第二个参数是元组((name1, dataType1), (name2, dataType2)…)。

ElementInformation类如下:

@dataclass
class ElementInformation:
    name: str = ""
    dataType: str = ""
    initValue: int = None  # None则初值为0。枚举的值,也存在这。

    def __str__(self):
        return str(self.__dict__)

    __repr__ = __str__
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
3.2.4 “枚举”类型

arxml中没发现 enum 类型的定义方式,但可采用宏定义进行替代。
代码如下(示例):

    def util_createEnumDataType(self, name, itemList: [ElementInformation]):
        """ 不支持Enum类型,但可采用 #define 的方式。即在基础类型加上comp method """
        valueTable = []
        maxValue = float("-inf")
        for item in itemList:  # type: ElementInformation
            maxValue = max(maxValue, item.initValue)
            valueTable.append((item.initValue, item.initValue, item.name))
        if maxValue < (2 ** 8):
            baseTypeRef = f'{self.refs.get("swBaseTypePackage")}/uint8'
        elif maxValue < (2 ** 16):
            baseTypeRef = f'{self.refs.get("swBaseTypePackage")}/uint16'
        elif maxValue < (2 ** 32):
            baseTypeRef = f'{self.refs.get("swBaseTypePackage")}/uint32'
        elif maxValue < (2 ** 64):
            baseTypeRef = f'{self.refs.get("swBaseTypePackage")}/uint64'
        else:
            raise ValueError(f"ERROR: too big maxValue: <{maxValue}>")
        return self.util_createImplementationDataType(name=name, baseTypeRef=baseTypeRef, valueTable=valueTable)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 需要指定一个参考数据类型,这个可以按照判断最大值的方式选取。
  • 需要指定“枚举”的名称和值。
  • util_createImplementationDataType()传入的第三个参数也是元组((lowerLimit1, upperLimit1, textValue1), (lowerLimit2, upperLimit2, textValue2)…),这个是可以定义范围的,但宏定义只有单个值,所以最小和最大值一样即可。
3.2.5 创建指针类型

代码如下(示例):

    def util_createImplementationDataTypePtr(self, name, baseTypeRef, swImplPolicy=None, category='DATA_REFERENCE',
                                             targetCategory='VALUE', adminData=None):
        implTypes = self.ws.find(self.refs.get('datatypePackage'))
        self.ws.setRole(implTypes.ref, 'DataType')
        if not implTypes.find(name):
            try:
                return implTypes.createImplementationDataTypePtr(name, baseTypeRef, swImplPolicy, category,
                                                                 targetCategory, adminData)
            except Exception as e:
                LOG.exception(f"Exception: {e}, {name}, {baseTypeRef}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 这个在服务接口中可能会用到,SR接口不会用到的。(后面有(void *)的例子,其他没用过,没细看过代码。)

3.3 常用类型创建

代码如下(示例):

    def common_type_create(self):
        """
        Create common data type (BaseType, ImplementationType, ...), containing: dtRef_const_VOID, dtRef_VOID,
        boolean, float32, float64, sint8, sint16, sint32, uint8, uint16, uint32.
        """
        # CompuMethod and DataConstraint are required.
        self.ws.setRole(self.refs.get('compuMethodPackage'), 'CompuMethod')
        self.ws.setRole(self.refs.get('physicalDataConstraintsPackage'), 'DataConstraint')
        # create SwBaseType
        self.util_createSwBaseType('dtRef_const_VOID', 1, encoding='VOID', nativeDeclaration='void')
        self.util_createSwBaseType('dtRef_VOID', 1, encoding='VOID', nativeDeclaration='void')
        self.util_createSwBaseType('boolean', 8, encoding='BOOLEAN', nativeDeclaration='boolean')
        self.util_createSwBaseType('float32', 32, encoding='IEEE754', nativeDeclaration='float32')
        self.util_createSwBaseType('float64', 64, encoding='IEEE754', nativeDeclaration='float64')
        self.util_createSwBaseType('sint8', 8, encoding='2C', nativeDeclaration='sint8')
        self.util_createSwBaseType('sint16', 16, encoding='2C', nativeDeclaration='sint16')
        self.util_createSwBaseType('sint32', 32, encoding='2C', nativeDeclaration='sint32')
        self.util_createSwBaseType('sint64', 64, encoding='2C', nativeDeclaration='sint64')
        self.util_createSwBaseType('uint8', 8, nativeDeclaration='uint8')
        self.util_createSwBaseType('uint16', 16, nativeDeclaration='uint16')
        self.util_createSwBaseType('uint32', 32, nativeDeclaration='uint32')
        self.util_createSwBaseType('uint64', 64, nativeDeclaration='uint64')
        # create ImplementationDataType
        self.util_createImplementationDataTypePtr('dtRef_const_VOID',
                                                  f'{self.refs.get("swBaseTypePackage")}/dtRef_const_VOID',
                                                  swImplPolicy='CONST')
        self.util_createImplementationDataTypePtr('dtRef_VOID', f'{self.refs.get("swBaseTypePackage")}/dtRef_VOID')
        self.util_createImplementationDataType('boolean', f'{self.refs.get("swBaseTypePackage")}/boolean',
                                               valueTable=['FALSE', 'TRUE'], typeEmitter='RTE')
        self.util_createImplementationDataType('float32', f'{self.refs.get("swBaseTypePackage")}/float32',
                                               typeEmitter='RTE')
        self.util_createImplementationDataType('float64', f'{self.refs.get("swBaseTypePackage")}/float64',
                                               typeEmitter='RTE')
        self.util_createImplementationDataType('sint8', f'{self.refs.get("swBaseTypePackage")}/sint8',
                                               lowerLimit=-128, upperLimit=127, typeEmitter='RTE')
        self.util_createImplementationDataType('sint16', f'{self.refs.get("swBaseTypePackage")}/sint16',
                                               lowerLimit=-32768, upperLimit=32767, typeEmitter='RTE')
        self.util_createImplementationDataType('sint32', f'{self.refs.get("swBaseTypePackage")}/sint32',
                                               lowerLimit=-2147483648, upperLimit=2147483647, typeEmitter='RTE')
        self.util_createImplementationDataType('sint64', f'{self.refs.get("swBaseTypePackage")}/sint64',
                                               lowerLimit=-9223372036854775808, upperLimit=9223372036854775807,
                                               typeEmitter='RTE')
        self.util_createImplementationDataType('uint8', f'{self.refs.get("swBaseTypePackage")}/uint8',
                                               lowerLimit=0, upperLimit=255, typeEmitter='RTE')
        self.util_createImplementationDataType('uint16', f'{self.refs.get("swBaseTypePackage")}/uint16',
                                               lowerLimit=0, upperLimit=65535, typeEmitter='RTE')
        self.util_createImplementationDataType('uint32', f'{self.refs.get("swBaseTypePackage")}/uint32',
                                               lowerLimit=0, upperLimit=4294967295, typeEmitter='RTE')
        self.util_createImplementationDataType('uint64', f'{self.refs.get("swBaseTypePackage")}/uint64',
                                               lowerLimit=0, upperLimit=18446744073709551615, typeEmitter='RTE')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 这个函数创建了常用的BaseType和ImplementationDataType类型。(我习惯使用 boolean、uint8、sint8这种小写的类型,有其他习惯可以自行修改或添加。)

4. 创建SWC

代码如下(示例):

    def util_createApplicationSoftwareComponent(self, swcName, behaviorName=None, implementationName=None,
                                                multipleInstance=False, autoCreatePortAPIOptions=True):
        pkg_swc = self.ws.find(self.refs.get('componentPackage'))
        swc = pkg_swc.find(self.swc)  # same as pkg_swc.map['elements'][self.swc]
        if not swc:  # None
            swc = pkg_swc.createApplicationSoftwareComponent(swcName, behaviorName, implementationName,
                                                             multipleInstance, autoCreatePortAPIOptions)
        return swc
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 这个是创建ApplicationSoftwareComponent,也可以按照此方式创建其他类型的(一般用这个就够了)。
  • swcName:名称。仅传入此参数创建空SWC即可,在空SWC基础上再进行其他内容的添加。(创建SWC的接口可重复调用,不会重复创建。)

5. 创建swAddressMethod

swAddressMethod用于将代码放入指定的内存段中(MemMap定义的),目前autosar包中不支持。在MATLAB-2018版本前,可以为代码选择指定段。
代码如下(示例):

    def common_swAddressMethod_create(self):
        """
        Create common swAddressMethod according to self.refs.
        NotImplementedError: SW-ADDR-METHOD-REF
        """
        ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

6. 创建SR接口

6.1 SR接口创建到package中

代码如下(示例):

    def util_createSenderReceiverInterface(self, portName, eleList: [ElementInformation]):
        """
        Create a S/R port, if dt not find, raise an exception.
        If existed, will not create.
        :param portName: (str) name of port
        :param eleList: name and dataType of port's element.
        """
        pkg_dt = self.ws.find(self.refs.get('datatypePackage'))
        dataElements = []
        for eleName, dt in ((item.name, item.dataType) for item in eleList):
            if pkg_dt.find(dt):
                dataElements.append(autosar.DataElement(eleName, f'{self.refs.get("datatypePackage")}/{dt}'))
            else:
                raise autosar.base.InvalidDataTypeRef(portName, str(dt), len(str(dt)))
        pkg_if = self.ws.find(self.refs.get('interfacePackage'))
        pkg_if.createSenderReceiverInterface(portName, dataElements)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • portName:接口的名称。对应Developer如下图的“Name”:
    在这里插入图片描述
  • eleList:element的信息,至少包含element的名称和数据类型。对应Developer如下图的“Data Element”:
    在这里插入图片描述

6.2 SR接口放到SWC中

对应Developer如下图:
在这里插入图片描述
代码如下(示例):

    def util_createPort(self, isSend, portName, eleList: [ElementInformation]):
        """ 在swc创建接口 """
        swc = self.util_createApplicationSoftwareComponent(self.swc)
        ref = f'{self.refs.get("interfacePackage")}/{portName}'  # it can different with refName
        port = swc.find(portName)
        if not port:
            if isSend:
                port = swc.createProvidePort(portName, ref)
            else:
                port = swc.createRequirePort(portName, ref)
            self.util_createPortInitValue(port, eleList)
        else:
            LOG.debug(f"Already exist Port: {portName}")
        return port
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • isSend:接口在SWC中需要定义传输方向。对于发出的叫“ProvidePort”,接收的叫“RequirePort”。
  • 在这之前,需要先在package中创建好接口。
  • 接口的初值需要定义。根据数据类型不同,初值不一样,后面单独说明。

6.3 SR接口放到SWC的runnable中

对应Developer如下图:
在这里插入图片描述
代码如下(示例):

    def util_runnablePortAccess(self, runnableName, portName, accessType):
        runnable = self.util_createRunnable(runnableName)
        swc = self.util_createApplicationSoftwareComponent(self.swc)
        port = swc.find(portName)
        portInterface = self.ws.find(port.portInterfaceRef, role='PortInterface')
        for dataElement in portInterface.dataElements:
            swc.behavior._createSendReceivePoint(port, dataElement, runnable)  # accessType
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • runnableName:runnable的名称。
  • portName:接口的名称。
  • accessType:这里指的是接口的显示或隐式,即代码中的Rte_Read还是Rte_IRead。(autosar仅支持显式接口,后面介绍如何添加隐式接口)
  • _createSendReceivePoint()是私有方法不建议外部调用。autosar是在创建runnable的时候,一起把access port加进去的,我习惯分开创建,但autosar没有合适的函数支持调用。

6.4 SR接口设置初值

util_createPortInitValue() 并没有创建Constant,然后接口去“Reference”,而是直接把值写到这里。
在这里插入图片描述
代码如下(示例):

    def util_createPortInitValue(self, port: autosar.port, eleList: [ElementInformation]):
        """ 给swc中的接口创建初值 """
        _dict = {}  # {ele: (dataType, initValue)}
        for ele in eleList:
            _dict.update({ele.name: (ele.dataType, ele.initValue)})

        # port 中的每个element建立初值
        for comspec in port.comspec:
            # 查找接口的element是否存在于入参中。找不到则定为u8
            dataType, initValue = _dict.get(comspec.name, ("uint8", 0))
            if initValue is not None:  # 如果指定初值。这里没有初值的check!!
                valueBuilder = autosar.builder.ValueBuilder()
                implTypes = self.ws.find(self.refs.get('datatypePackage'))
                comspec.initValue = valueBuilder.buildFromDataType(implTypes.find(dataType), initValue)
            else:  # 否则初值为0
                comspec.initValue = self.__util_buildZeroInit(dataType)

    def __util_buildZeroInit(self, dataTypeName):
        """ 建立初值的实体,swc中的接口的element创建初值使用。 """

        def get_initValue(dataType):
            """ 获取初值为0的数值、列表、字典。 """
            implTypes = self.ws.find(self.refs.get('datatypePackage'))
            # 如果传入参数是str,如 uint8,则查找其dataType实体
            if isinstance(dataType, str):
                dataType = implTypes.find(dataTypeName)
                if not dataType:
                    raise ValueError(f"Undefined data type: {dataType}")
            # 如果传入参数是dataType实体,则直接使用传参
            elif isinstance(dataType, autosar.datatype.ImplementationDataType):
                dataType = dataType
            elif isinstance(dataType, autosar.datatype.ImplementationDataTypeElement):
                dataType = dataType
            # 如果传入参数未知类型,报错
            else:
                raise ValueError(f"Undefined data type: {dataType}")
            # 根据dataType的类型,计算出对应初值的格式
            if dataType.category == 'VALUE':
                return 0
            elif dataType.category == 'ARRAY':
                return [get_initValue(dataType.subElements[0])] * int(dataType.arraySize)
            elif dataType.category == 'STRUCTURE':
                _dict = {}
                for sub in dataType.subElements:
                    _dict.update({sub.name: get_initValue(sub)})
                return _dict
            elif dataType.category == 'TYPE_REFERENCE':
                # 找到其参考的数据类型,计算出初值类型。
                dataType = implTypes.find(dataType.variantProps[0].implementationTypeRef)
                return get_initValue(dataType)
            else:
                raise NotImplementedError(dataType.category)

        # 建立value
        valueBuilder = autosar.builder.ValueBuilder()
        # value = valueBuilder.buildFromDataType(dataType, get_initValue(dataType))  # 不好用
        value = valueBuilder.build(dataTypeName, get_initValue(dataTypeName))
        return value
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

一般情况下,初值的设置是0。如果有其他情况,可以参考__util_buildZeroInit()方法中的定义。对于不同的类型,初值的格式是不同的,即valueBuilder.build()的第二个参数是不同的:

  • VALUE类型,即uint8, boolean等类型:直接用数字即可。
  • ARRAY类型:需要用列表,列表的长度和数组长度一样,列表中的初值格式要和数组的参考类型一样。
  • STRUCTURE类型:需要用字典,{字段名称:初值}。
  • TYPE_REFERENCE类型:需要找到参考类型,再在参考类型的基础上创建初值。

对于数组类型和结构体类型,其参考类型或字段的类型如果不是一般类型,则需要层层嵌套。比如:

  • uint8_2_3的数组类型,初值格式是:[ [1, 2], [3, 4], [5, 6]].
  • struct{uint8_2 a;};的结构体类型,其中字段a是数组类型,初值格式是:{‘a’: [1, 2]}。

boolean类型属于"TEXTTABLE",其初值默认会是Textual,这会导致达芬奇工具报错,需要改为一般用的Numeric。
在这里插入图片描述
在autosar包中,将builder.py中创建为TextValue的分支屏蔽或删除,如下图位置:
在这里插入图片描述

6.5 添加隐式接口

runnable中的PortAccess是有两种的,autosar仅支持显式的,这里说明下如何添加隐式的。用不到隐式接口可忽略此节

修改behavior.py的内容

  • DataReceivePoint和DataSendPoint两个类中,加一个accessType量。可用0表示显示,1表示隐式。
    在这里插入图片描述
  • 在用到以上两个类的地方,添加accessType参数。仅方法_createSendReceivePoint()需要。
    在这里插入图片描述

修改behavior_writer.py的内容,这个文件是最终写入arxml的文件。修改方法_writeRunnableXML(),代码示例如下:(代码太长,不对比了)

    def _writeRunnableXML(self,runnable):
        ws=runnable.rootWS()
        assert(ws is not None)
        lines=['<RUNNABLE-ENTITY>',
               self.indent('<SHORT-NAME>%s</SHORT-NAME>'%runnable.name,1),
              ]
        if runnable.adminData is not None:
            lines.extend(self.indent(self.writeAdminDataXML(runnable.adminData),1))
        if len(runnable.exclusiveAreaRefs)>0:
            lines.append(self.indent('<CAN-ENTER-EXCLUSIVE-AREA-REFS>',1))
            for exclusiveAreaRef in runnable.exclusiveAreaRefs:
                exclusiveArea = ws.find(exclusiveAreaRef)
                if exclusiveArea is None:
                    raise ValueError('invalid reference:' + exclusiveAreaRef)
                lines.append(self.indent('<CAN-ENTER-EXCLUSIVE-AREA-REF DEST="%s">%s</CAN-ENTER-EXCLUSIVE-AREA-REF>'%(exclusiveArea.tag(self.version),exclusiveArea.ref),2))
            lines.append(self.indent('</CAN-ENTER-EXCLUSIVE-AREA-REFS>',1))
        if self.version >= 4.0:
            if runnable.minStartInterval is not None:
                minStartInterval = self.format_float(float(runnable.minStartInterval)/1000.0)
                lines.append(self.indent('<MINIMUM-START-INTERVAL>{}</MINIMUM-START-INTERVAL>'.format(minStartInterval),1))
        lines.append(self.indent('<CAN-BE-INVOKED-CONCURRENTLY>%s</CAN-BE-INVOKED-CONCURRENTLY>'%('true' if runnable.invokeConcurrently else 'false'),1))
        if len(runnable.dataReceivePoints)>0:
            if self.version >= 4.0:
                dataReceivePoint_Read_List = []
                dataReceivePoint_IRead_List = []
                dataReceivePoint_DRead_List = []
                for dataReceivePoint in runnable.dataReceivePoints:
                    if dataReceivePoint.accessType == 0:  # Read
                        dataReceivePoint_Read_List.append(dataReceivePoint)
                    elif dataReceivePoint.accessType == 1:  # IRead
                        dataReceivePoint_IRead_List.append(dataReceivePoint)
                    elif dataReceivePoint.accessType == 2:  # DRead
                        dataReceivePoint_DRead_List.append(dataReceivePoint)
                    else:
                        raise Exception('Unexpected value(%s) of accessType(0-ExplicitByArgument, 1-Implicit, 2-ExplicitByValue): ' % dataReceivePoint.accessType)
                # Do not change sequence of if condition!
                if dataReceivePoint_IRead_List:
                    lines.append(self.indent('<DATA-READ-ACCESSS>', 1))
                    for dataReceivePoint in dataReceivePoint_IRead_List:
                        lines.extend(self.indent(self._writeDataReceivePointXML(ws, dataReceivePoint), 2))
                    lines.append(self.indent('</DATA-READ-ACCESSS>', 1))
                if dataReceivePoint_Read_List:
                    lines.append(self.indent('<DATA-RECEIVE-POINT-BY-ARGUMENTS>', 1))
                    for dataReceivePoint in dataReceivePoint_Read_List:
                        lines.extend(self.indent(self._writeDataReceivePointXML(ws, dataReceivePoint), 2))
                    lines.append(self.indent('</DATA-RECEIVE-POINT-BY-ARGUMENTS>', 1))
                if dataReceivePoint_DRead_List:
                    lines.append(self.indent('<DATA-RECEIVE-POINT-BY-VALUES>', 1))
                    for dataReceivePoint in dataReceivePoint_DRead_List:
                        lines.extend(self.indent(self._writeDataReceivePointXML(ws, dataReceivePoint), 2))
                    lines.append(self.indent('</DATA-RECEIVE-POINT-BY-VALUES>', 1))
                # This is previous code.
                # lines.append(self.indent('<DATA-RECEIVE-POINT-BY-ARGUMENTS>',1))
                # for dataReceivePoint in runnable.dataReceivePoints:
                #     lines.extend(self.indent(self._writeDataReceivePointXML(ws, dataReceivePoint),2))
                # lines.append(self.indent('</DATA-RECEIVE-POINT-BY-ARGUMENTS>',1))
            else:
                lines.append(self.indent('<DATA-RECEIVE-POINTS>',1))
                for dataReceivePoint in runnable.dataReceivePoints:
                    lines.extend(self.indent(self._writeDataReceivePointXML(ws, dataReceivePoint),2))
                lines.append(self.indent('</DATA-RECEIVE-POINTS>',1))
        if len(runnable.dataSendPoints)>0:
            dataSendPoint_Write_List = []
            dataSendPoint_IWrite_List = []
            for dataSendPoint in runnable.dataSendPoints:
                if dataSendPoint.accessType == 0:  # Write
                    dataSendPoint_Write_List.append(dataSendPoint)
                elif dataSendPoint.accessType == 1:  # IWrite
                    dataSendPoint_IWrite_List.append(dataSendPoint)
                else:
                    raise Exception('Unexpected value(%s) of accessType(0-Explicit, 1-Implicit): ' % dataSendPoint.accessType)

            if dataSendPoint_Write_List:
                lines.append(self.indent('<DATA-SEND-POINTS>', 1))
                for dataSendPoint in dataSendPoint_Write_List:
                    lines.append(self.indent('<%s>'%dataSendPoint.tag(self.version),2))
                    lines.append(self.indent('<SHORT-NAME>%s</SHORT-NAME>'%dataSendPoint.name,3))
                    lines.extend(self.indent(self._writeDataElementInstanceRefXML(ws, dataSendPoint.portRef, dataSendPoint.dataElemRef),3))
                    lines.append(self.indent('</%s>'%dataSendPoint.tag(self.version),2))
                lines.append(self.indent('</DATA-SEND-POINTS>', 1))
            if dataSendPoint_IWrite_List:
                lines.append(self.indent('<DATA-WRITE-ACCESSS>', 1))
                for dataSendPoint in dataSendPoint_IWrite_List:
                    lines.append(self.indent('<%s>' % dataSendPoint.tag(self.version), 2))
                    lines.append(self.indent('<SHORT-NAME>%s</SHORT-NAME>' % dataSendPoint.name, 3))
                    lines.extend(self.indent(
                        self._writeDataElementInstanceRefXML(ws, dataSendPoint.portRef, dataSendPoint.dataElemRef), 3))
                    lines.append(self.indent('</%s>' % dataSendPoint.tag(self.version), 2))
                lines.append(self.indent('</DATA-WRITE-ACCESSS>', 1))
            # This is previous code.
            # lines.append(self.indent('<DATA-SEND-POINTS>',1))
            # for dataSendPoint in runnable.dataSendPoints:
            #     lines.append(self.indent('<%s>'%dataSendPoint.tag(self.version),2))
            #     lines.append(self.indent('<SHORT-NAME>%s</SHORT-NAME>'%dataSendPoint.name,3))
            #     lines.extend(self.indent(self._writeDataElementInstanceRefXML(ws, dataSendPoint.portRef, dataSendPoint.dataElemRef),3))
            #     lines.append(self.indent('</%s>'%dataSendPoint.tag(self.version),2))
            # lines.append(self.indent('</DATA-SEND-POINTS>',1))
        if (self.version >= 4.0) and (len(runnable.modeAccessPoints)>0):
            lines.append(self.indent('<MODE-ACCESS-POINTS>',1))
            for modeAccessPoint in runnable.modeAccessPoints:
                lines.extend(self.indent(self._writeModeAccessPointXML(ws, modeAccessPoint),2))
            lines.append(self.indent('</MODE-ACCESS-POINTS>',1))
        if (self.version >= 4.0) and (len(runnable.modeSwitchPoints)>0):
            lines.append(self.indent('<MODE-SWITCH-POINTS>',1))
            for modeSwitchPoint in runnable.modeSwitchPoints:
                lines.extend(self.indent(self._writeModePointXML(ws, modeSwitchPoint),2))
            lines.append(self.indent('</MODE-SWITCH-POINTS>',1))
        if (self.version >= 4.0) and (len(runnable.parameterAccessPoints)>0):
            lines.append(self.indent('<PARAMETER-ACCESSS>',1))
            for parameterAccessPoint in runnable.parameterAccessPoints:
                lines.extend(self.indent(self._writeParameterAccessPointXML(ws, parameterAccessPoint),2))
            lines.append(self.indent('</PARAMETER-ACCESSS>',1))
        if len(runnable.serverCallPoints)>0:
            lines.append(self.indent('<SERVER-CALL-POINTS>',1))
            for callPoint in runnable.serverCallPoints:
                lines.extend(self.indent(self._writeServerCallPointXML(ws, runnable, callPoint),2))
            lines.append(self.indent('</SERVER-CALL-POINTS>',1))
        lines.append(self.indent('<SYMBOL>%s</SYMBOL>'%runnable.symbol,1))
        lines.append('</RUNNABLE-ENTITY>')
        return lines
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120

7. 创建SWC中的runnable

7.1 创建周期性和初始化runnable

    def util_createRunnable(self, runnableName, TimerMs: int = 0):
        # todo, 增加swAddrMethod - CODE. 指定代码段,matlab 2018之后版本需要。
        swc = self.util_createApplicationSoftwareComponent(self.swc)
        runnable = swc.behavior.find(runnableName)
        if not runnable:
            runnable = swc.behavior.createRunnable(runnableName)
            if TimerMs == 0:  # Init
                swc.behavior.createInitEvent(runnableName)
            else:  # cyclic
                swc.behavior.createTimerEvent(runnableName, TimerMs)
        return runnable
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • createRunnable:创建runnable。此处是创建的空runnable,这个方法支持将access port一起添加进去。
  • createInitEvent:创建初始化Trigger,仅需传入runnableName参数,内部会把runnable和这个trigger关联。
  • createTimerEvent:创建周期性Trigger,传入runnableName和周期ms。
    在这里插入图片描述

7.2 创建OnDataReception runnable

有些时候,需要在接收到数据的时,立即执行这个runnable,Trigger就需要为“OnDataReception”。
代码如下(示例):

    def util_createRunnable_DataReceived(self, runnableName, portName, eleName):
        # todo, 增加swAddrMethod - CODE. 指定代码段,matlab 2018之后版本需要。
        swc = self.util_createApplicationSoftwareComponent(self.swc)
        runnable = swc.behavior.find(runnableName)
        if not runnable:
            runnable = swc.behavior.createRunnable(runnableName)
            swc.behavior.createDataReceivedEvent(runnableName, f"{portName}/{eleName}")
            self.util_runnablePortAccess(runnableName, portName, 0)
        else:
            LOG.debug(f"Already exist Runnable: {runnableName}")
        return runnable
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • createDataReceivedEvent:需要传入接收数据的名称,格式是 “{portName}/{eleName}”。此函数做了封装,只传入名称即可。
  • util_runnablePortAccess:将接口加到runnable的access中。

三、总结

autosar这个包功能很强大,就是不咋更新了。我目前仅使用了一部分功能,如果有其他需求,建议查看一下源码,理解更新。
第一次发文章,格式和内容会有所欠缺,欢迎批评指正和探讨交流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/1010997
推荐阅读
相关标签
  

闽ICP备14008679号