0. 前言
在实际工程运用中,存在很多时序上的需求,也有类似于linux的信号机制。
所以这里说一下autosar下的下面两种机制使用方式
-
sender/receiver 来触发任务
-
event 触发任务
任务部署有以下三种情况
-
任务内通信发生在同一任务执行的组件之间(因此是序列化的)
-
任务间通信发生在同一个ECU中理论上并发的任务之间(实际上是需要看被激活的任务的调度方式)
-
ecu之间的通信发生在位于物理上不同的ecu上的并发执行组件之间
1. 需求
-
两个swc
-
作为server端,执行client的调用
-
实现任务
-
作为client,调用server
-
写数据,触发任务
-
OperEvent_Input_SWC
-
OperEvent_SWC
2. 设计
2.1 OperEvent_Input_SWC
Component | Port | PortType | Interface | Client Server Operation | DataElement/Trigger | Datatype |
---|---|---|---|---|---|---|
OperEvent_Input_SWC | PP_Interface_Event1 | P Port | SR_Interface_Event1 | Event1 | uint8 | |
OperEvent_Input_SWC | PP_Interface_Event2 | P Port | SR_Interface_Event2 | Event2 | uint8 | |
OperEvent_Input_SWC | PP_Interface_Event3 | R Port | SR_Interface_Event3 | |||
OperEvent_Input_SWC | PP_Interface_Event4 | R Port | SR_Interface_Event4 | |||
OperEvent_Input_SWC | RPortPrototype_0 | R Port | CS_Interface_Oper | RequestOpt0 | Opt0_Req | EventOptType |
OperEvent_Input_SWC | RPortPrototype_0 | R Port | CS_Interface_Oper | RequestOpt1 | Opt1_Req | EventOptType |
2.1.1 开发过程
2.2 OperEvent_SWC
Component | Port | PortType | Interface | Client Server Operation | DataElement/Trigger | Datatype |
---|---|---|---|---|---|---|
OperEvent_SWC | RP_Interface_Event1 | R Port | SR_Interface_Event1 | Event1 | uint8 | |
OperEvent_SWC | RP_Interface_Event2 | R Port | SR_Interface_Event2 | Event2 | uint8 | |
OperEvent_SWC | PP_Interface_Event3 | P Port | SR_Interface_Event3 | |||
OperEvent_SWC | PP_Interface_Event4 | P Port | SR_Interface_Event4 | |||
OperEvent_SWC | PP_CS_Interface_Oper | P Port | CS_Interface_Oper | RequestOpt0 | Opt0_Req | EventOptType |
OperEvent_SWC | PP_CS_Interface_Oper | P Port | CS_Interface_Oper | RequestOpt1 | Opt1_Req | EventOptType |
2.2.1 开发过程
2.3 composition 图
2.4 设计总结
2.4.1 任务间 client – server – 设计
2.4.1.1 OperEvent_Input_SWC 调用server。 Opt0 , Opt1
2.4.1.2 OperEvent_SWC 作为server端,来执行Req0 Req1
2.4.2 任务间 sender – receiver – 设计
2.4.2.1 OperEvent_Input_SWC 发送两个数据。 Event1, Event2
2.4.2.2 OperEvent_SWC 作为执行端,设置两个sender receiver event 来获取(得知) 数据的到来
3. 实现
3.1 OperEvent_Input_SWC
3.1.1 runnable
3.1.1.1 OperEvent_Input_SWC_func
根据需求设计,component中只有一个runnable. 从下面的 Server Call Point 和 Data Write 能发现,我们来调用两个server 的服务,和写两个数据。
FUNC (void, OperEvent_Input_SWC_CODE) OperEvent_Input_SWC_func/* return value & FctID */
(
void
)
{
EventOptType Opt0_Req1;
Std_ReturnType asyncCall1;
EventOptType Opt1_Req2;
Std_ReturnType asyncCall2;
uint8 write3;
Std_ReturnType retWrite3;
uint8 write4;
Std_ReturnType retWrite4;
/* Local Data Declaration */
/*PROTECTED REGION ID(UserVariables :OperEvent_Input_SWC_func) ENABLED START */
/* Start of user variable defintions - Do not remove this comment */
/* End of user variable defintions - Do not remove this comment */
/*PROTECTED REGION END */
Std_ReturnType retValue = RTE_E_OK;
/* -------------------------------------- Data Read ----------------------------------------- */
/* -------------------------------------- Server Call Point -------------------------------- */
asyncCall1 = Rte_Call_RPortPrototype_0_RequestOpt0(Opt0_Req1);
asyncCall2 = Rte_Call_RPortPrototype_0_RequestOpt1(Opt1_Req2);
/* -------------------------------------- CDATA --------------------------------------------- */
/* -------------------------------------- Data Write ---------------------------------------- */
retWrite3 = Rte_Write_PP_Interface_Event1_Event1(write3);
retWrite4 = Rte_Write_PP_Interface_Event2_Event2(write4);
/* -------------------------------------- Trigger Interface --------------------------------- */
/* -------------------------------------- Mode Management ----------------------------------- */
/* -------------------------------------- Port Handling ------------------------------------- */
/* -------------------------------------- Exclusive Area ------------------------------------ */
/* -------------------------------------- Multiple Instantiation ---------------------------- */
/*PROTECTED REGION ID(User Logic :OperEvent_Input_SWC_func) ENABLED START */
/* Start of user code - Do not remove this comment */
/* End of user code - Do not remove this comment */
/*PROTECTED REGION END */
}
3.1.2 client server interface
3.1.2.1 Rte_Call_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0
client 调用一个server 具体的流程如下(autosar 文档截图)
从下面代码也可以看出来,client端对Queue 进行了写入操作。也就是上图的 第一句Rte_Call()。
FUNC(Std_ReturnType, RTE_CODE)
Rte_Call_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0(VAR(EventOptType, AUTOMATIC) Opt0_Req) /* 2 */
{
VAR(Std_ReturnType, AUTOMATIC) rtn = RTE_E_OK;
Rte_CPT_OperEvent_SWC_PP_CS_Interface_Oper_RequestOpt0_QEType srvQEl;
/* Box: Copy Opt0_Req to Rte_Ms_000004 begin */
Rte_Ms_000004 = Opt0_Req;
/* Box: Copy Opt0_Req to Rte_Ms_000004 end */
if ( FALSE == Rte_Var_CPT_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0_outstanding )
{
srvQEl.Opt0_Req = Opt0_Req;
srvQEl.clientQueue = &Rte_Queue_CPT_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0.cmn;
Rte_Var_CPT_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0_outstanding = TRUE;
rtn = Rte_WriteQueue(&Rte_Queue_CPT_OperEvent_SWC_PP_CS_Interface_Oper_RequestOpt0.cmn, &srvQEl);
if ( ((VAR(StatusType, AUTOMATIC))E_OK) != rtn )
{
Rte_Var_CPT_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0_outstanding = FALSE;
}
}
else
{
rtn = RTE_E_LIMIT;
}
return rtn;
}
3.1.3 sender receiver interface
3.1.3.1 Rte_Write_OperEvent_Input_SWC_PP_Interface_Event1_Event1
数据发送端调用写接口,对数据进行写入。
从下面代码也可以看出来,数据写入的同时调用了 activateTask 来激活一个task. 随后这个task 就会交付给os 来调度使用。也做到了 同步的效果。
FUNC(Std_ReturnType, RTE_CODE)
Rte_Write_OperEvent_Input_SWC_PP_Interface_Event1_Event1(VAR(uint8, AUTOMATIC) data) /* 2 */
{
VAR(Std_ReturnType, AUTOMATIC) rtn = RTE_E_OK;
Std_ReturnType tmp;
rtn = ((VAR(Std_ReturnType, AUTOMATIC))RTE_E_OK);
/* Box: Send Event1 to /ETAS_FlatView/SwComponentTypes/ETAS_FlatView/CPT_OperEvent_SWC.RP_Interface_Event1 begin */
/* Optimizer: Removed resource lock for assignment of parameter to global in highest pri task */
Rte_Rx_000084 = data;
Rte_ActCount_CPT_OperEvent_SWC_DataReceivedEvent_1 = TRUE;
tmp = ActivateTask(OsTask_SysCore_EventTask);
if ( ( ((VAR(StatusType, AUTOMATIC))E_OK) != tmp ) && ( ((VAR(Std_ReturnType, AUTOMATIC))E_OS_LIMIT) != tmp ) )
{
rtn = ((VAR(Std_ReturnType, AUTOMATIC))RTE_E_COM_STOPPED);
}
/* Box: Send Event1 to /ETAS_FlatView/SwComponentTypes/ETAS_FlatView/CPT_OperEvent_SWC.RP_Interface_Event1 end */
/* Send complete */
return rtn;
}
3.2 OperEvent_SWC
3.2.1 runnable
3.2.1.1 RE_OperaEvent1_func
暂时没有实现任何逻辑,但是从代码里可以看出来,这里调用了read 接口。
FUNC (void, OperEvent_SWC_CODE) RE_OperaEvent1_func/* return value & FctID */
(
void
)
{
uint8 iRead1;
/* Local Data Declaration */
/*PROTECTED REGION ID(UserVariables :RE_OperaEvent1_func) ENABLED START */
/* Start of user variable defintions - Do not remove this comment */
/* End of user variable defintions - Do not remove this comment */
/*PROTECTED REGION END */
Std_ReturnType retValue = RTE_E_OK;
/* -------------------------------------- Data Read ----------------------------------------- */
iRead1 = Rte_IRead_RE_OperaEvent1_RP_Interface_Event1_Event1();
/* -------------------------------------- Server Call Point -------------------------------- */
/* -------------------------------------- CDATA --------------------------------------------- */
/* -------------------------------------- Data Write ---------------------------------------- */
/* -------------------------------------- Trigger Interface --------------------------------- */
/* -------------------------------------- Mode Management ----------------------------------- */
/* -------------------------------------- Port Handling ------------------------------------- */
/* -------------------------------------- Exclusive Area ------------------------------------ */
/* -------------------------------------- Multiple Instantiation ---------------------------- */
/*PROTECTED REGION ID(User Logic :RE_OperaEvent1_func) ENABLED START */
/* Start of user code - Do not remove this comment */
/* End of user code - Do not remove this comment */
/*PROTECTED REGION END */
}
我们在设计的时候,这个runnable 什么时候运行的呢? 需求是收到一个data的 时候运行该runnable.
我们在前一个swc 里面进行了写data. 配置完成后,在rte里的代码判断了数据:
/* Box: CPT_OperEvent_SWC end */
/* Box: CPT_OperEvent_SWC begin */
if ( Rte_ActCount_CPT_OperEvent_SWC_DataReceivedEvent_1 != FALSE )
{
Rte_ActCount_CPT_OperEvent_SWC_DataReceivedEvent_1 = FALSE;
RE_OperaEvent1_func();
}
Rte_ActCount_CPT_OperEvent_SWC_DataReceivedEvent_1这个event (数) 前面有进行赋值。
3.2.1.2 RE_OperaEvent2_func
同上
3.2.1.3 RE_OperaReq0_func
FUNC (void , OperEvent_SWC_CODE) RE_OperaReq0_func/* return value & FctID */
(
VAR(EventOptType, AUTOMATIC) Opt0_Req
)
{
/* Local Data Declaration */
/*PROTECTED REGION ID(UserVariables :RE_OperaReq0_func) ENABLED START */
/* Start of user variable defintions - Do not remove this comment */
/* End of user variable defintions - Do not remove this comment */
/*PROTECTED REGION END */
Std_ReturnType retValue = RTE_E_OK;
/* -------------------------------------- Data Read ----------------------------------------- */
/* -------------------------------------- Server Call Point -------------------------------- */
/* -------------------------------------- CDATA --------------------------------------------- */
/* -------------------------------------- Data Write ---------------------------------------- */
/* -------------------------------------- Trigger Interface --------------------------------- */
/* -------------------------------------- Mode Management ----------------------------------- */
/* -------------------------------------- Port Handling ------------------------------------- */
/* -------------------------------------- Exclusive Area ------------------------------------ */
/* -------------------------------------- Multiple Instantiation ---------------------------- */
/*PROTECTED REGION ID(User Logic :RE_OperaReq0_func) ENABLED START */
/* Start of user code - Do not remove this comment */
/* End of user code - Do not remove this comment */
/*PROTECTED REGION END */
}
在需求里我们需要这个runnable 来作为client server 的服务端。即前面client的代码,进行了event的写入。RTE 生成代码
for (;;) {
rtn = Rte_ReadQueue(&Rte_Queue_CPT_OperEvent_SWC_PP_CS_Interface_Oper_RequestOpt0.cmn, &srvQEl);
if ( ( ((VAR(Std_ReturnType, AUTOMATIC))RTE_E_OK) == rtn ) || ( ((VAR(Std_ReturnType, AUTOMATIC))RTE_E_LOST_DATA) == rtn ) )
{
RE_OperaReq0_func(srvQEl.Opt0_Req);
Rte_Var_CPT_OperEvent_Input_SWC_RPortPrototype_0_RequestOpt0_outstanding = FALSE;
Rte_WriteQueue(srvQEl.clientQueue, &cliQEl);
}
else
{
break;
}
}
可以看出这里有个for(::) 内部一直在判断 client 端是否有调用(写入)
3.2.1.4 RE_OperaReq1_func
同上
4. 集成编译
暂无
5. 测试
暂无
原文始发于微信公众号(汽车与基础软件):Autosar ClientServer/ SenderReceiver实践