提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
在基于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"
- 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])
- 用于创建self.refs指定的package路径的,使用时调用common_pkg_create()即可。
- 需注意,每一个package需要被setRole,否则用到的地方可能会报错,也可以在用到的地方调用。(Role参考https://autosar.readthedocs.io/en/latest/autosar4_guide/roles.html)
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}")
- 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}")
- 这个创建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)
- 用于生成如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}")
- 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}")
- 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__
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)
- 需要指定一个参考数据类型,这个可以按照判断最大值的方式选取。
- 需要指定“枚举”的名称和值。
- 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}")
- 这个在服务接口中可能会用到,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')
- 这个函数创建了常用的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
- 这个是创建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
"""
...
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)
- 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
- 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
- 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
一般情况下,初值的设置是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
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
- 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
- createDataReceivedEvent:需要传入接收数据的名称,格式是 “{portName}/{eleName}”。此函数做了封装,只传入名称即可。
- util_runnablePortAccess:将接口加到runnable的access中。
三、总结
autosar这个包功能很强大,就是不咋更新了。我目前仅使用了一部分功能,如果有其他需求,建议查看一下源码,理解更新。
第一次发文章,格式和内容会有所欠缺,欢迎批评指正和探讨交流。