Arctic教程(二)—— AUTOSAR应用程序设计入门
1. 介绍(Introduction)
在介绍如何修改AUTOSAR软件之前,对所有各种元素进行概念性介绍至关重要。 在继续使用Arctic教程之前,了解AUTOSAR软件包含的许多实体(entities)是一个很好的开始。 因此,强烈建议在阅读其它Arctic教程之前阅读下面的内容。 为了介绍各种AUTOSAR实体,使用了名为InteriorLightCAN的项目。 InteriorLightCAN是一个AUTOSAR项目,旨在模拟汽车内部灯光的行为。 该项目本身可以在Arctic Core中找到,名称为InteriorLightCAN(和InteriorLightCAN-artext)。
2. 概览(Overview)
下图描绘了InteriorLightCAN的应用层。 请仔细查看图片,以下示例基于此。 在接下来的部分中,InteriorLightCAN的集群将被细分并详细描述。
3. 用户符号(User Symbols)
上图描绘了软件组件(SWC)通过端口(通过接口进行通信 - 稍后将详细介绍)。 常用的端口有四种:
- Sender Port
- Receiver Port
- Server Port
- Client Port
发件人端口只能连接到接收器端口(创建委派连接器时除外 - 稍后会详细介绍),并且服务器端口只能连接到客户端端口。 无论是在发件人和接收器端口之间,还是在服务器和客户端端口之间建立连接,连接的端口都必须通过同一接口进行通信。 接口依次实现各种数据类型,例如boolean,uint32等。遵循前面的逻辑,配置为发送布尔值的发送方端口不能连接到配置为接收uint32值的接收端口。
在上图中,深灰色容器显示了SWC,其端口,内部行为,Runnables及其实现的实例。 再次,稍后会有更多内容。
SWC可以看作是应该如何设计某个东西的蓝图,而实际的实例化对象则称为原型。 在InteriorLightCAN系统中,原型用深灰色矩形表示,其名称(下图中的SWC原型名称)在右下角用斜体键入。 SWC和原型之间的区别允许同一SWC的多个原型。 一个例子是SWC DoorSensor。 SWC DoorSensor实例化两次,一个是leftDoorSensor,另一个是rightDoorSensor; 可能会有比本例中给出的两个更多的实例。
4. 服务组件(Service Component)
表示原型的红色框称为服务组件。服务组件是从BSW编辑器生成的SWC,用于配置基本软件(BSW)。使用服务组件,以便可以从应用层连接驻留在BSW中的服务模块。因此,SWC EcuM,BswM和IoHwAb(如上图所示)都是基于BSW配置生成的。目前,请将服务组件视为一种联系各种BSW服务模块的方法。例如,应用层中的SWC可以调用EcuM服务组件(与BSW中相应的服务模块通信)来控制ECU的模式。类似地,BswM服务组件允许应用层访问要发送的各种PDU组(一组消息)。此示例中的最后一个服务组件是IoHwAb,它负责处理一个名为DIO的模块,负责数字输入/输出。如果没有服务组件,我们无法在此示例中实现任何功能。 (IoHwAb SWC实际上不是一个服务组件,而是一个名为Ecu Abstraction的东西 - 这两个具有非常相似的功能,所以现在我们将其视为服务组件。)
5. 内部照明灯(Interior Light)
Root CompositionLightCANCAN右侧的深灰色容器表示手动创建的SWC(即不是由BSW编辑器生成的)。 这些SWC构成了本例中执行的大部分逻辑。 如果您查看页面顶部的概述图,您可以看到下面的图片不包括ModeManager,EcuM和BswM。 这三个SWC仅负责启动ECU,并不是本示例的重点。 下面的所有深灰色SWC原型每隔100毫秒由OS调用,并具有各种端口以相互通信。 每个SWC都有非常明确的责任,下面将详细介绍。
6. 门传感器(DoorSensor)
DoorSensor SWC有两个端口,如下所示。一个客户端端口(名称:DoorSwitchSignal)用于触发对IoHwAb的服务器端口的函数调用(名称:Digital_FrontDoorLeft和Digital_FrontDoorRight)。在我们的示例中,对这些服务器端口的调用会触发输入DIO的读取。由于IoHwAb,DIO和端口模块的BSW配置,在整个堆栈中调用两个DIO(稍后将对此进行更详细的描述)。为了能够在IoHwAb中触发服务器端口,DoorSensor必须首先具有Runnable。在这种情况下,Runnable会定期触发(具有所谓的timingEvent触发器)。这允许在稍后配置RTE时将Runnable连接到RTE编辑器中的OsTask。
此外,DoorSensor Runnable必须有一个所谓的serverCallPoint,它通过客户端端口的接口触发一个功能。在这种情况下,我们必须定义我们的serverCallPoint来调用DoorSensor的客户端端口DoorSwitchSignal,以及在DoorSwitchSignal实现的ClientServerInterface DigitalServiceRead中定义的函数Read。配置这样的serverCallPoint将导致RTE生成可以从我们的DoorSensor Runnable的c代码实现(其中写入实际逻辑)调用的函数。 DoorSensor还有一个Sender Port DoorStatus。为了使RTE生成发送数据的函数,DoorSensor Runnable必须具有所谓的dataWriteAccess。作为serverCallPoint,dataWriteAccess需要一个它应该通过的端口(在这种情况下是DoorStatus端口)和一个与DoorStatus通信的接口上的参数(在这种情况下是参数状态)。此端口只是将信息传递给InteriorLightManager,无论其DIO是打开还是关闭。 InteriorLightManager依次处理是否应该打开InteriorLight的所有逻辑。 DoorSensor SWC的唯一责任是读取其DIO并将此信息传递给InteriorLightManager以进行进一步处理。
7. 灯执行器(LightActuator)
LightActuator SWC与DoorSensor SWC具有相似的职责,但不是通过其客户端端口读取(如DoorSensor所做的那样),LightActuator负责为每个LightActuator实例写入一个LED。 除了客户端端口的不同之外,LightActuator还有一个接收器端口(而不是作为DoorSensor的发送器端口),用于接收来自InteriorLightManager的信息,以确定LightActuator是应该打开还是关闭其连接的LED。 拥有Receiver Port需要Runnable具有dataReadAccess(类似于上面的DoorSensors dataWriteAccess)。 LightActuator的两个实例分别负责一个LED。 作为DoorSensor,LightActuator有一个timingEvent,因此它的唯一Runnable可以由OsTask定期触发。 目前,关于LightActuator还有很多话要说。
8. 内部灯管理者(InteriorLightManager)
InteriorLightManager SWC负责处理InteriorLightCAN示例的逻辑。它读取DoorStatus(通过InteriorLightManager连接到的两个DoorSensor SWC),并将InteriorLightStatus(连接到它的两个LightActuator)通信,从而打开或关闭LED。对于两个Sender Ports RightLightStatus和LeftLightStatus中的每一个,必须定义dataWriteAccess。同样,两个Receiver Ports必须都有一个相应的dataReadAccess。
左边是两个端口 - 一个发送器端口和一个接收器端口 - 尚未详细描述。这些端口并不是唯一的。它们与任何其他端口一样是发送器端口和接收器端口。然而,这两个端口的目的是通过CAN与模拟ECU进行通信,模拟ECU负责接收(通过CAN)状态,无论是否打开行李箱,以及发送状态是否有任何门或舱门是否打开。如果这三个中的任何一个被发出信号打开,则InteriorLightManager将向LightActuators和模拟后ECU发出信号,指示灯应该打开。然后由每个执行器打开灯。在LightActuator的情况下,通过打开各自的LED来转动灯。在主干的情况下,如果通过CAN接收到0x01(通过InteriorLightManager的端口RearLightStatus),则打开灯。
9. 外部端口(External Ports)
正如上一节中简要讨论的那样,InteriorLightManager有一个发送器端口和一个连接到根组合的外部端口的接收器端口。 这些外部端口又可以连接到BSW中的Com模块,因此可以通过CAN(或您喜欢的任何总线)进行通信 - 这完全取决于您的BSW配置; InteriorLightCAN应用层不知道消息将使用哪个总线 发送过来)。 根组合将在本章的最后部分详细描述。 目前,重要的是要知道我们有两个端口 - 一个发送器端口和一个接收器端口 - 可以与Com模块通信,因此可以与例如CAN总线通信。 标题为“CAN BUS”的灰色矩形模拟后部ECU。
10. 启动集群(Startup Cluster)
在根组合的左上角,找到了SWC EcuM,BswM和ModeManager。如前所述,EcuM和BswM是服务组件,并通过其BSW配置控制ECU。在我们的示例中,BSW配置已设置,以便EcuM为任何外部SWC(在我们的示例中为ModeManager)提供读取其(以及ECU的)currentMode的可能性。 EcuM的currentMode是跟踪ECU所处模式的参数。例如,EcuM可以处于RUN,STARTUP,SHUTDOWN等状态,具体取决于它的配置方式。在我们的例子中,ModeManager Runnable应该由一个所谓的modeSwitchEvent触发。更具体地说,当modeSwitchEvent退出STARTUP时(因此,当ECU启动时)。发生这种情况时,我们要求ECU应通过Client Port RunControl进入RUN状态。 ModeManager负责的最后一件事是告诉BswM它应该请求COMM_FULL_COMMUNICATION。 BswM收到此消息并相应地触发某些操作。在此示例中,BswM配置为执行打开两个PduGroup(ComIPduGroupRx和ComIPduGroupTx)的操作。 Com中的所有Pdus都属于这些组中的任何一个。所以我们所说的基本上就是:尽可能让我们在BSW堆栈中发送Pdus。没有这个调用,就无法与后面的(rear)ECU通信。
11. 根组成(Root Composition)
为简化起见,将Root Composition视为所有SWC原型(不是SWC!)的容器,这些原型与根组合的外部端口之间的连接。 从下图中可以看出,有三个服务组件原型,以及在ARText中定义的六个原型,总共九个原型。 第一步是实例化所有这九个原型。 然后,必须定义外部端口。 最后,必须进行所有内部连接。 在内部连接端口时,发送器端口连接到接收器端口(相反的情况不可用),服务器端口连接到客户端端口(这里也不可能相反)。
12. 连接器(Connectors)
外部发件人端口连接到InteriorLightManager中的发件人端口,外部接收器端口连接到InteriorLightManager中的接收器端口。这与上述SWC之间的连接指令相矛盾。但是,内部和外部连接之间存在差异。在同一组合中的两个SWC之间创建内部连接时,会创建一个所谓的Assembly Connector。对于装配连接器(Assembly Connector),上述规则适用:发件人端口必须连接到接收器端口,服务器端口必须连接到客户端端口。但是,在创建外部连接时(我们将InteriorLightManager连接到根组合的外部端口时就是这种情况),会创建所谓的委派连接器(Delegation Connectors)。顾名思义,委托连接器负责委托某些东西 - 它可以是函数调用(服务器端口到服务器端口,或客户端端口到客户端端口),也可以是数据(发送端口到发送端口,或者接收端口到接收端口)。在我们的示例中,InteriorLightManager的发件人端口RearLightStatus通过委派连接器连接到根组合的发件人端口LightStatus。因此,InteriorLightManager中的发件人端口将其数据委托给根组合的外部端口。同样,Root Composition的Receiver Port DoorStatus负责将此数据委托给InteriorLightManager的Receiver Port RearDoorStatus。通过这种方式,在CAN总线上进行通信的所有其他ECU都不知道(并且不关心)根组合内部发生的事情,但只知道(并关心)它可以将DoorStatus发送到我们的应用程序,它可以收回LightStatus。