编辑推荐: |
本文主要介绍了Autosar
RTE的功能相关内容。希望对您的学习有所帮助。
本文来自于微信公众号谦益行,由火龙果软件Linda编辑、推荐。 |
|
一、什么是RTE
RTE的作用有点像一个快递中转站或者说是电话接线员(就是上个世界那种要先打电话到接线员那里,然后通过接线员转接电话线到目的地),其作用就是将一个SWC的信息通过RTE连接到其他SWC或者BSW上。且RTE具有管理这些信息的功能,比如接收的SWC正忙(您所拨打的用户正忙),那么RTE负责让发送信息的SWC等待,或者做其他处理;RTE还能触发SWC,就像是这时接收的SWC在睡觉,这时发送的SWC发信息来了,那么RTE就要把接收的SWC叫醒起床。
一句话概括就是RTE提供了SWC的运行环境。
二、RTE的作用
提供跨ECU/ECU内部的通信管理。
提供对runnable的管理功能(触发、唤醒等,简单说就是runnable需要映射到Task上运行嘛,而这个映射就是通过RTE具体实现的),之前我们不是提到了VFB(虚拟功能总线),RTE就是VFB的具体实现。
在Vector的工具链中,RTE是自动生成的下面这种图,我们将其再做细化,就能很清楚的看出其关联关系了。这里的RTE就是统一的管理,具体那些连接时怎么连的,我们是不需要在RTE中关心的(因为AppL中配好,RTE就自动生成嘛)。
三、RTE对Runnables的运行支撑
1)作为运行环境的主要功能点
通过RTE给runnable提供触发事件。之前说过了runnable是可以被触发的,就是需要通过RTE来实现这个触发和调用runnable,具体在下面讲解通过RTE给runnable提供所需资源。就是之前说的接口通信(Ports那节),将runnable需要的一些资源通过接口传输给它将BSW和SWC做隔绝。因此OS和runnables也被隔绝了,runnable的运行条件由RTE提供,不能由OS直接提供
2)Runnables的触发条件
RTE给runnables提供触发条件,也就是runnable在设计的时候,需要有触发条件,不然无法运行,也就没有意义了。触发条件就是一些特定的事件,AutoSAR中主要规定了以下一些触发条件(图中是DaVinci软件中的配置项,灰色是因为我没有配置,不用在意):
初始化事件:初始化自动触发
定时器事件:给一个周期定时器,时间到了就触发
接收数据事件(S/R):Receiver Port 一旦收到数据,就触发
接收数据错误事件(S/R)
数据发送完成事件(S/R):Send Port 发送完成,就触发
操作调用事件(C/S):当调用到了该函数的时候
异步服务返回事件(C/S):之前说过C/S可以在异步下运行,就是说当我调用一个Server函数,但是我是异步调用的。那么该被掉函数作为一个线程和当前的运行程序并行运行,当被调函数运行结束返回(Return)的时候,这时触发异步服务返回事件
模式切换事件
模式切换应答事件
三 RTE对Ports的支撑(上)
1)扮演SWCs和BSW的交流途径
还是老生常谈的那么几点:
作为VFB的具体实现
作为S/R接口的通信实现
作为C/S接口的通信实现
ECU内部通信/跨ECU(通过COM)
实现AR-COM的回调功能,具体实现是在SWC中完成的,RTE负责完成这个回调机制
2)其他特征
提供了实现数据一致性的机制(所谓的数据一致性,就是说简单一点:当多个SWC同时操作同一个数据时,可能会发生一些不想看到的问题,数据一致性要求不能发生这些问题)
支持简单和复杂的数据类型
对SWC类型(SWC type,和SWC不同,SWC type是指SWC的一个类型,用这个类型可以实例化一个SWC,就好像用int这个类型实例化一个count一样)的实例化
3)S/R接口的不同方式
以下调用,在配置好Davinci后,是会自动生成到runnable上方的,可以直接复制。比如我复制了一段DaVinci生成的SWC中的代码,可以看到,其中的
Rte_ 的函数都是列出来在runnable上方的
Runnable Entity Name: RAB_Core0_100us
Executed if at least one of the
following trigger conditions occurred:
* - triggered on TimingEvent every 100us
Input Interfaces:
* Explicit S/R API:
* Std_ReturnType Rte_Read_AppPI_
Can_ReceiverCore0_DEP_Can_Receiver(Idt
_Can_Receiver *data)
**
Output Interfaces:
* Explicit S/R API:
* Std_ReturnType Rte_Write_AppPI_Can_
SenderCore0_DEP_Can_Sender(Idt_Can_Sender data,
Rte_TransformerError *transformerError)
**
Service Calls:
* Service Invocation:
* Std_ReturnType Rte_Call_
ComM_UserRequest_GetCurrentComMode
(ComM_ModeType *ComMode)
* Synchronous Service Invocation. Timeout: None
* Returned Application Errors:
RTE_E_ComM_UserRequest_E_NOT_OK
* Std_ReturnType Rte_Call_ComM_UserRequest_
GetMaxComMode(ComM_ModeType *ComMode)
* Synchronous Service Invocation. Timeout: None
* Returned Application Errors:
RTE_E_ComM_UserRequest_E_NOT_OK
* Std_ReturnType Rte_Call_ComM_UserRequest
_GetRequestedComMode(ComM_ModeType *ComMode)
* Synchronous Service Invocation. Timeout: None
* Returned Application Errors:
RTE_E_ComM_UserRequest_E_NOT_OK
* Std_ReturnType Rte_Call_ComM_UserRequest
_RequestComMode(ComM_ModeType ComMode)
* Synchronous Service Invocation. Timeout: None
* Returned Application Errors: RTE_E_ComM_UserRequest
_E_MODE_LIMITATION, RTE_E_ComM_UserRequest_E_NOT_OK
**
* DO NOT CHANGE THIS COMMENT! << Start
of documentation area >> DO NOT CHANGE
THIS COMMENT!
* Symbol: RAB_Core0_100us_doc
* DO NOT CHANGE THIS COMMENT! << End of
documentation
area >> DO NOT CHANGE THIS COMMENT!
FUNC(void, SWCCore0Basic_Type_CODE) RAB_
Core0_100us(void) /* PRQA S 0850 */ /* MD_MSR_19.8
*/
{/
* DO NOT CHANGE THIS COMMENT! << Start
of
runnable implementation >> DO NOT CHANGE
THIS COMMENT!
* Symbol: RAB_Core0_100us
* DO NOT CHANGE THIS COMMENT! << End of
runnable
implementation >> DO NOT CHANGE THIS COMMENT!
}
|
直接调用(Direct)
相当于有一个全局变量,runnable可以直接读写这个变量
用的是下面的语法:(注意 <data> 和 data 的区别,带<>的是指全局data的名字,不带<>的data是局部变量的名字,这里使用指针,就是说操作的是同一个地址,没有复制使用;同时,这些函数都是在runnable中使用的,不要看是Rte,就以为是RTE中的代码,因为调用的是RTE的机制,所以这里是Rte)
Std_ReturnType Rte_Read_<port>_<data>
(<DataType> *data)
Std_ReturnType Rte_Write_<port>_<data>
(<DataType> data)
缓存调用(Buffered)
相当于将全局变量先复制到一个runnable的局部变量中,再操作这个局部变量,最后把这个局部变量再赋值到全局变量中。在runnable操作这个局部变量期间,全局变量是不会改变的。
使用方法如下:(都是由RTE管理的,用户只需要正确调用函数就ok)
<DataType> Rte_IRead_<r>_<port>_<data>
(void)
void Rte_IWrite_<r>_<port>_<data>
(<DataType> data)
队列调用(Queued)
因为数据不止一个,是一组队列的数据,就像我们常用的串口FIFO。因此,可以设置循环接收或者等待接收,等待的话是有超时管理的。
调用代码如下:
Std_ReturnType Rte_Receive_<port>_<data>
(<DataType> *data)
Std_ReturnType Rte_Send_<port>_<data>
(<DataType> data)
4)跨ECU的方式
假如是跨ECU的数据传输。那么,我在runnable中使用 Rte_Write_<port>_<Data>()
这样的函数后,会需要走runnable(ECU1) ->RTE (ECU1) ->BSW
(ECU1) ->外部总线->BSW (ECU2)->RTE (ECU2) ->runnable
(ECU2),这里也列出了用于COM传输的两个函数名:
Com_SendSignal()
Com_ReceiveSignal()
四、RTE对Ports的支撑(下)
1)C/S接口的实现
之前在第二章AppL中讲过了C/S接口,这里再更加深入的说明一下其实现的原理:首先,C/S接口就是客户/服务接口,这个接口就是客户来调用服务端的操作的一个接口。也就是我写着写着,发现我想要调用一个函数,这个函数在其他的C文件中,就让RTE帮忙调用。还是举个例子:
我,客户,我想要执行一个函数,这个函数写在服务端上的。由于我和服务端有隔阂(SWC之间不能直接通信),这时,我就悄悄告诉RTE,我想要执行那个函数,RTE就会帮我告诉服务端,让服务端执行该函数。
而这里又有两种方式:异步和同步:
同步就是说我这个人很懒,我要等服务端运行完了这个函数,RTE返回这个函数的结果后,我才开始继续我的工作;
异步就是我这个人很勤快,我通知RTE让它帮忙告诉服务端运行函数后,我就继续干我的事了,等过一段时间后,我估摸着函数运行结束了,我再请求函数结果
2)C/S接口的不同方式
同步和异步调用不是通过函数区别的,这必须是事先配置好由RTE生成的,所以在Davinci中配置runnable的port时是有这个选项的(当然要C/S接口才有)
同步调用
从上文的例子,可以看出,同步调用其实就是我们平时调用函数是一样的,就是等同于将被调函数代码嵌入当前调用的函数代码中运行即可。
我们也用代码实际说明一下
//假如我们的被调函数是:
Std_ReturnType RunnableServer(int *param)
//那我们的客户中应该写的调用函数就是:
Std_ReturnType Rte_Call_<Port>_RunnableServer(int
*param)
//这个param就是我们希望被调函数操作的变量
异步调用
异步调用相当于有两个线程,一个线程运行我们的原函数中的内容,另一个执行被调函数的内容。然后可以过一段时间去读取一下被调函数的返回结果
而这时,如何知道被调函数是否执行完了呢?有三种方法:
循环检测,就是在那一直等,等到返回值为止,这样的话和同步就差不多了,意义不大
超时检测,定一个时间,时间到了就去读取,没到的时候继续运行我的程序
事件触发,当服务函数运行结束,RTE可以触发原函数,告诉它被调函数运行完了,你可以读取返回值了
读取函数也用代码实际说明一下
//执行下面的函数后就能将参数返回回来了
Std_ReturnType Rte_Result_<Port>_RunnableServer(int
*param)
五、RTE对数据一致性的管理
1)什么是数据一致性
引用百度百科:数据一致性,就是当多个用户试图同时访问一个数据库,它们的事务同时使用相同的数据时,可能会发生以下四种情况:丢失更新、未确定的相关性、不一致的分析和幻想读。
说的通俗一点:就是当多个操作同时读写同一个数据的时候,很有可能出bug(实际是由于优先级的问题,可能出现我们的数据被篡改的情况,造成作者不想看到的数据结果)
2)数据一致性的实现机制
利用RTE管理
这部分类容之前说过了,就是利用RTE来管理这里的数据,防止bug出现。比如IRead,大家都操作的是数据的备份,不直接操作原数据2、SWC内部变量这个内部变量就比较神奇了,因为它可以直接在DaVinci中配置,runnable可以直接调用,就类似于一个c文件中定义的全局变量,没有被extern出去。在c文件中定义的函数时可以直接使用的。那么这时就会出问题了,同一个c文件中的函数是可能被放在不同Task上运行的,就可能出现这些函数在同一时刻运行的状况,那么在调用这个全局变量的时候,就可能出bug。那么要如何解决呢?AutoSAR做了以下两种方式:
EAs(Exclusive Areas,专用区域):就是下面两句代码,相当于一个关中断,调用变量的语句放在里面,运行时不能有更高级的Task打断被保护的语句
Rte_Enter_<name>();
//这里放置被保护的语句
Rte_Exit_<name>();
IRVs(Inter-runnable variables,跨函数变量):还是两句代码,上面的EAs是整段代码段都被保护了,而这里的两句就相当于在改变变量的时候被保护,也就是这两句话执行的时候被保护
Rte_IrvWrite_<re>_<name>()
Rte_IrvRead_<re>_<name>()
六、RTE与Interface接口
1)Interface接口总览
少说废话,先上图
上图将所有的接口以及其分布的位置都详细的标识了出来,还是用的原来的那张ECU的图添加的,方便大家做对比
七、AutoSAR接口
一句话概括:之前说的S/R和C/S接口就是AutoSAR接口
特征:接口函数名可变,例如之前说过的 Std_ReturnType Rte_Read_<port>_<data>
(<DataType> *data) 这中形式的S/R函数,其中的 <port>
<data> 就是,用户自己配置的名字,因此,这些接口的函数名都是可以改变的,但大体的形式是不变的。
位置:SWC<>RTE、RTE<>CDD、RTE<>ECU AB(这里提一句,ECUAB之前没有讲到,其实很多的传感器、执行器都放在这里,是ECU的抽象,也是可以看作是SWC的,IoHwAb就在这里面)。说明白一点,就是
只要能看成是SWC处理的,就是AutoSAR接口。
八、标准接口
一句话概括:就是AutoSAR规定的C语言API
特征:接口函数名是固定不变的,是AutoSAR规定好的。比如:Com_SendSignal() WaitEvent()
这类都是API函数名,可以有上层调用,但是一般是使用工具配置生成的,做上层应用的一般是不用关心其具体实现的位置:第一张图中棕色的就是标准接口,说白了就是对函数API的调用。
需要特殊说明一点的是:下图中两个红圈中的箭头,OS和COM是唯一的两个标准接口允许直接和RTE相连的。因为RTE的很多功能是需要基于这两个模块来实现的
九、标准AutoSAR接口
一句话概括:就是AutoSAR接口,不过名称是由AutoSAR官方规定不能修改
特征:就是标准接口和AutoSAR接口的特征它都有一部分。首先是和AutoSAR接口一样,提供的是C/S、S/R接口;然后又和标准接口一样,函数名是不可变的。说白了就是官方规定好的C/S、S/R接口,咱们就当成是AutoSAR接口就行了,函数名字什么不用管它位置:RTE<>Services,就这么一个地方。
|