电子说
一.前言
前两期,我们讲了CAN模块的发送逻辑,Canif模块的发送逻辑和发送确认逻辑,可以看到MCAL的CAN模块是对MessgeBuffer这个CAN邮箱机制 做了抽象,将其抽象成一个个的HOH。而Canif则是从报文层面做了抽象,抽象成了一个个的PDUID。再往上会有CANtp以及PDUR模块调用Canif,本期我们讲解PDUR的发送路由功能,请思考PduR这个模块对什么进行了抽象呢?
通信架构中PduR的位置如图所示:
PDUR作用是对IPDU进行路由,分发到正确的模块,它是双向的,即上层的COM DCM的报文数据发送,会经由PDUR分发到canif 或cantp或其他底层通信模块.而下层的报文接收,也会经由PDUR进行分发 告知对应的COM或者DCM,除此之外还有一些buffer功能等不在我们此系列介绍范围内。
二.PduR模块及其发送函数,发送确认函数
在PDUR中实现发送报文的函数是PduR_Transmit
这个函数被PduR_ComTransmit和PduR_DcmTransmit调用,上层模块COM以及DCM模块通过这两个函数和PduR模块交互,实现发送报文的。在这个PduR_Transmit中,同样是按照IPDUID去索引对应的配置结构体数组成员,找到对应PDU的对应RoutingPaths,对RoutingPaths中配置的目标PDU进行分发,根据配置的目标模块调用对应的下层CAN发送函数如Canif_transmit或者CanTp_Transmit…. 说起来比较抽象,我们看看一个具体的配置实例。
下面是RoutingPaths的配置:
const PduRRoutingPath_type * const PduRRoutingPaths[] = {
&PduRRoutingPath_PDU_ID_UDS_PHYS_TX,
&PduRRoutingPath_PDU_ID_UDS_FUNC_TX,
&PduRRoutingPath_PDU_ID_UDS_PHYS_RX,
&PduRRoutingPath_PDU_ID_UDS_FUNC_RX,
&PduRRoutingPath_Pdu_Tx_272T,
&PduRRoutingPath_Pdu_Tx_273T,
&PduRRoutingPath_Pdu_Rx_256R,
NULL_PTR
};
在配置中,对每个IPDU都配置了对应的RoutingPaths,
其中的一个RoutingPath配置实例如下:
const PduRRoutingPath_type PduRRoutingPath_PDU_ID_UDS_PHYS_TX = {
.SrcModule = PDUR_DCM,
.SrcPduId = 0,
.SduLength = 0,
.PduRDestPdus = PduRDestinations_PDU_ID_UDS_PHYS_TX
};
RoutingPath中定义了SrcModule,用以说明这个PDU来源于什么模块,同时也定义了他要传输到的目标pdu组。
const PduRDestPdu_type * const PduRDestinations_PDU_ID_UDS_PHYS_TX[] = {
&PduRDestination_PDU_ID_UDS_PHYS_TX_PduRDestination,
NULL_PTR
};
在目标PDU组中你可以定义多个PduRDestPdu,在PduRDestPdu中定义了目标模块。即这个pdu数据需要去的模块。
const PduRDestPdu_type PduRDestination_PDU_ID_UDS_PHYS_TX_PduRDestination = {
.DestModule = PDUR_CANTP,
.DestPduId = CANTP_PDU_ID_UDS_PHYS_TX,
.DataProvision = PDUR_NO_PROVISION,
.TxBufferRef = NULL_PTR
};
按照示例配置分析分配过程,假如现在上层传过来一个pduid为0的PDU,按照0索引找到
PduRRoutingPath_PDU_ID_UDS_PHYS_TX作为RoutingPath。遍历这个RoutingPath配置的所有目标PDU组
获取对应PDU的destination.根据destination的DestModule(PDUR_DCM),调用对应的Transmit函数(CanTp_Transmit)。向对应模块的Transmit函数传入DestPduId。完成报文发送。这是整个PduR_Transmit的报文发送的路由过程
Std_ReturnType PduR_Transmit(PduIdType PduId, const PduInfoType* PduInfo, uint8 serviceId) {
PDUR_VALIDATE_INITIALIZED(serviceId,E_NOT_OK);
PDUR_VALIDATE_PDUPTR(serviceId, PduInfo, E_NOT_OK);
PDUR_VALIDATE_PDUID(serviceId, PduId, E_NOT_OK);
Std_ReturnType retVal = E_OK;
const PduRRoutingPath_type *route = PduRConfig- >RoutingPaths[PduId];
uint8 i = 0;
for (i = 0; route- >PduRDestPdus[i] != NULL; i++) {
const PduRDestPdu_type * destination = route- >PduRDestPdus[i];
retVal |= PduR_RouteTransmit(destination, PduInfo);
}
return retVal;
}
Std_ReturnType PduR_RouteTransmit(const PduRDestPdu_type * destination, const PduInfoType * pduInfo) {
Std_ReturnType retVal = E_NOT_OK;
switch (destination- >DestModule) {
case PDUR_CANIF:
#if PDUR_CANIF_SUPPORT == STD_ON
retVal = CanIf_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_COM:
#if PDUR_COM_SUPPORT == STD_ON
Com_RxIndication(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_LINIF:
#if PDUR_LINIF_SUPPORT == STD_ON
retVal = LinIf_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_CANTP:
#if PDUR_CANTP_SUPPORT == STD_ON
retVal = CanTp_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_SOADIF:
#if PDUR_SOAD_SUPPORT == STD_ON
retVal = SoAdIf_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_SOADTP:
#if PDUR_SOAD_SUPPORT == STD_ON
retVal = SoAdTp_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
case PDUR_J1939TP:
#if PDUR_J1939TP_SUPPORT == STD_ON
retVal = J1939Tp_Transmit(destination- >DestPduId, pduInfo);
#endif
break;
default:
retVal = E_NOT_OK;
break;
}
return retVal;
}
在PDUR中实现报文发送确认的函数是PduR_TxConfirmation,其被PduR_CanIfTxConfirmation调用,也被PduR_CanTpTxConfirmation调用。其和报文发送的逻辑类似。只不过最后调用的是对应模块的Confirmation函数。
总结:PDUR这个模块把各个报文收发的分配路径做了抽象。上层调用PDUR的发送接口传输数据,传入IPDU ID即可根据PDUR的Routing Path配置知道这些IPDU应该下发给哪些下层模块.同理对于接收也是这样。
全部0条评论
快来发表一下你的评论吧 !