前面对Communication Stack的通信管理理部分介绍清楚了,接下来就来看看Communication Stack中负责通信数据的部分了,第一就不得不说一个最核心的模块,那就是负责消息分发的PduR模块。
首先介绍一个在Communication Stack中出现频率很高的词I-PDU, 全称为Interaction Layer Protocol Data Unit, 意思就是交互PDU,可以理解成是软件协议层面上的一个完整性消息。
PduR即为PDU Router,看一看它在Communication Stack架构中的位置:
PduR 模块位于 AUTOSAR 的通信服务的核心位置, 作为上层模块与下层接口模块或传输层模块传输 I-PDU 的桥梁。说的简单一点就是个内部消息路由器,当PduR 收到底层传输层或者interface抽象层传输的 I-PDU后,将其传输到对应的服务模块,而上层服务模块需要发送 I-PDU时,PduR模块则会将消息传输到相应的传输层或者interface抽象层。
通信模块根据其在 AUTOSAR 架构中的位置和传输 I-PDU时的角色,可以分为三类:上层模块、下层接口模块和下层传输层模块。
上层模块位于 PduR 上层,一般包括 Com、 Dcm 和 Cdd。
下层接口模块位于 PduR 下层,一般包括 CanIf、 LinIf、 SoAdIf、 FrIf、 CddIf 等。
下层传输层模块同样位于 PduR 下层,一般包括 CanTp、 LinTp、 SoAdTp、 DoIPTp、FrTp 和 CddTp 等。
而PduR模块则是连接这些模块的枢纽,位于上层模块和下层模块之间,充当一个终极消息中转站。
如下图所示:
PduR模块主要包含两部分,分别是路由表和路由引擎,其中路由表非常好理解,就是它会给上层服务的所有 I-PDU编号,静态确定消息路径,里面会包含各种总线特征,比如CAN ID,这样PduR模块就可以根据路由表来进行消息路由,路由引擎则就是用来传输消息的搬运工,负责把 I-PDU从源方路由到目标方。
PduR 模块主要功能如下:
1. 初始化
2. 接收下层模块(接口模块、传输层模块) I-PDU并传递给上层模块
3. 发送上层模块 I-PDU到低层模块
4. 接收接口层 I-PDU并传递给其他接口层模块
5. 接收传输层 I-PDU并传递给其他传输层模块
下面举一个最简单的例子,如果PduR的下层模块为接口模块,以CAN为例子,那下层接口模块即为CanIf模块。如果Com模块需要通过CAN总线发送一条消息,那么这条消息的流向应该如下:
Com调用PduR_ComTransmit发起消息发送, PduR模块接收到消息查表后确认消息目的方为CAN,然后调用CanIf_Transmit触发CAN消息的发送,消息发送成功后,最终由CanIf模块传来发送确认。
当PduR的下层模块为传输层模块的时候,则当传输层接收到 FF 或 SF 时,传输层将调用 PduR_StartOfReception 通知 PduR模块接收开始, PduR 模块通过调用_StartOfReception 传递给相应的上层模块,例如StartOfIReception。传输层通过调用函数 PduR_CopyRxData 将数据传递给 PduR, PduR 模块通过调用CopyRxData 将数据传递给上层模块。当接收完成时传输层模块将调用 PduRRxIndication 通知 PduR 模块, PduR 将此指示传递给上层模块通过_TpRxIndication 函数。
PduR 通过路由路径实现路由。一个路由路径由一个源 Id 和一个(或多个)目的 Id组成。当路由路径只包含一个目的 Id 时,称为单播,当路由路径包含多个目的 Id 时,称为多播。路由路径全部静态配置,不支持动态路由。
某个路由路径的目的可能同时包含多个接口,如 CanIf 接口和 LinIf 接口,为了能够支持整体关闭某种接口, PduR 具有路由路径组的概念。一个路由路径组包含多个目的 Id,它们可以属于同一个路由路径,也可以属于不同路由路径。反过来一个路由路径的不同目的 Id 可以属于不同的路由路径组。
路由路径组也是静态配置的。路由路径组可以单独使能或关闭。每个路由路径组的初始状态由配置决定。 PduR 提供了两个接口函数来动态使能或关闭某个路由路径组,分别为 PduR_EnableRouting()和PduR_DisableRouting(),它们主要由 BswM 模块调用。
Zero Cost Operation是指当 PduR 只充当简单的路由功能时,为了优化性能而将各主要函数实现为宏的形式。该功能通过配置项 ZeroCostOperation 使能。要使用该功能,必须同时满足如下条件:
1)用户配置的 PduRRoutingTable 路径中仅包含 Com-CanIf, CanIf-Com, Dcm-CanTp,CanTp-Dcm , CanNm-Com , Com-CanNm时;
2) PduRGeneral 里 PduRVersionInfoApi 为 FALSE 时;
3)不包含 Routing Group 时。
仔细看上面的结构图,可以看到在PduR的旁边有一个IpduM(Interaction PDU multiplexer)模块,该模块看上去比较独立,它在AUTOSAR架构中,只和PduR模块和Com模块有交互。PDU多路复用即PDU的PCI相同而SDU布局不同,简单的来说就是使用相同的 IpduM I-PDU 发送或接收不同的 Com I-PDU,再简单一点说就是使用同一个PDU ID来发送不同的报文内容。对于多路复用的I-PDU来说,它的数据流向则变成了Com->PduR->IpduM->PduR->CanIf。
那么IpduM模块是怎么实现PDU复用的呢?IpduM 提供了两种模式来实现多路复用,分别是I-PDU Multiplexing和Multiple PDU to Container Mapping这两种形式。
其实现方式则为将一个多路复用的I-PDU分为一个静态部分和一个动态部分,其中静态部分由零个或多个信号或信号组组成,静态部分信号或者信号组的位置大小都是固定的,不会随着PDU多路复用而变化; 动态部分由Selector Field和一个或多个信号或信号组组成,这一部分除了Selector Field的位置不会变动外,信号和信号组的位置是可以随意发生变化的。如下图所示:
静态部分和动态部分的位置可根据I-PDU进行配置,静态部分和动态部分可以被细分为不同的段。对于每个多路复用的I-PDU,只能定义一个Selector Field,所以IpduM模块就是通过Selector Field的值来进行PD路由,根据其不同的值来解包I-PDU的动态部分的内容。Selector Field大小可以配置为1到16个连续位,其位置也可以通过配置来定义。
这种方式就更好理解了,即创建一个容器,然后将多路复用的每一种PDU layout都分配一个Header,当Com层出发信号发送时,则会根据该信号的I-PDU layout的所对应的Header在容器中来进行查找,然后进行数据组装最好进行发送,接收同理。