简单写一下,学习autosar can协议栈的总结。写的也不好,可能也有很多错误,欢迎指出。
主要参考etas的代码,如果有侵权,请联系删除。
CAN发送
COM
应用层会调用Com_SendSignal 更新信号。
注:ASW调用Com_SendSignal
那么Com_SendSignal,内部干了什么?
uint8 Com_SendSignal(Com_SignalIdType idSignal_u16, const void * signalDataPtr_pcv);
idSignal_u16: signal 的ID,每一个signal都有一个ID
signalDataPtr_pcv:ASW层传入的数据地址
signal ID可以在Cfg文件中看到
/* Begin section for Signal symbolic names */
/* Signal IDs*/
/* Tx Signal ID*/
#define ComConf_ComSignal_IPDS_ADC1PowerFaultSt_IDU_1 0
#define ComConf_ComSignal_IPDS_ADC1PowerSt_IDU_1 1
#define ComConf_ComSignal_IPDS_ADC2PowerFaultSt_IDU_1 2
#define ComConf_ComSignal_IPDS_ADC2PowerSt_IDU_1 3
.........
/* Rx Signal ID*/
#define ComConf_ComSignal_IPDS_AMPPowerSup_CCU_PowerOn 0
#define ComConf_ComSignal_IPDS_ASCOMPPowerSup_CCU_PowerOn 1
#define ComConf_ComSignal_IPDS_EPS1PowerSup_CCU_PowerOn 2
...................
/* ------------------------------------------------------------------------ */
/* Begin section for Signal group symbolic names */
注:Siganl的宏定义
往下,Com_SendSignal。会调用内部Com_Prv_InternalSendSignal。会把signal data Copy到 pdu buffer。然后会对signal对应的pdu进行检测,检测是否被激活(BSWM模块激活)。如果被激活就会进入到Com_Prv_ProceedToSendIpdu进一步发送。
uint8 Com_Prv_InternalSendSignal(Com_SignalIdType idSignal_u16, const void * signalDataPtr_pcv)
{
/*获取对应的signal 结构体*/
txSigConstPtr_pcst = COM_GET_TXSIG_CONSTDATA(idSignal_u16);
/*获取signal 对应的 IpduID*/
idIpdu_uo = txSigConstPtr_pcst->idComIPdu_uo;
/* Copy signal data from application buffer into IPdu buffer.
signal data Copy到 pdu buffer*/
txSigNewVal_uo = Com_Prv_SigBufftoIpduBuff(idSignal_u16, signalDataPtr_pcv);
TxIpdustatus = Com_Prv_CheckTxIPduStatus(idIpdu_uo); //检测signal对应的pdu是否被激活
if (TxIpdustatus)
{
/* Proceed further to send ipdu
进一步发送*/
Com_Prv_ProceedToSendIpdu( (Com_IpduId_tuo)idIpdu_uo, sendIpduFlag_st );
} /* End of Com_Prv_CheckTxIPduStatus */
else
{
/* corresponding I-PDU group is stopped, so donot process txIPdu */
status_u8 = COM_SERVICE_NOT_AVAILABLE;
}
return status_u8;
}
代码跑到了Com_Prv_ProceedToSendIpdu函数。老规矩先看参数
这时候,就有疑问了。怎么回事?不是在发送singal 吗?,现在怎么传入了一个IpduId。pdu、Ipdu、signal之间的关系可以具体再看其他文档。简单来说就是signal是对应实际的值的,一个Ipdu包含很多个signal;而ipdu是autosar 的概念。
所以,每一个signal都有一个ipduID。具体的对应关系可以看signal structure。
在autosar CAN协议栈中有两个概念。一个概念是信号的发送属性,一个概念是pdu的传输模式。这里讨论pdu的传输模式是周期的情况,在这种情况下,函数Com_Prv_SendIpdu不会被执行。
我的天!不是说发送数据吗?怎么还没有发送出去。周期发送Can报文的情况下,Can报文其实是被Com_MainFunctionTx发送出去的。
Com_Prv_ProceedToSendIpdu(Com_IpduId_tuo idComTxPdu_uo, Com_SendIpduInfo_tst sendIpduFlag_st)
idComTxPdu_uo: TxPdu的ID
sendIpduFlag_st: 传输标志位,传输标志位决定下一步的操作
sendIpduFlag_st 列表
/*
* This structure contains flags that are intialized before calling Com_Prv_SendIpdu internal API \n
*
* typedef struct \n
* { \n
* unsigned int isEventTrig_u1 : 1; Set, If the call to Com_Prv_SendIpdu is not from MainFunctionTx. \n
* unsigned int isModeChangd_u1 : 1; Set, If Mode change has happened for the Ipdu \n
* unsigned int isSigTriggered_u1 : 1; Set, If signal transfer property is triggered(1)/pending(0) \n
* unsigned int isTimeoutReq_u1 : 1; Set, If Timeout monitoring is required \n
* unsigned int ignoreRepetitions_u1 : 1; Set, If configured repetitions are to be ignored \n
* unsigned int isSwtIpduTxMode_u1 : 1;Set , If the call is made from Com_SwitchIpduTxMode \n
* } Com_SendIpduInfo_tst; \n
*/
LOCAL_INLINE void Com_Prv_ProceedToSendIpdu(Com_IpduId_tuo idComTxPdu_uo, Com_SendIpduInfo_tst sendIpduFlag_st)
{
if (((sendIpduFlag_st.isSigTriggered_u1 != COM_RESET) &&
(COM_TX_MODE_IS_EVENT(Com_GetRamValue(TXIPDU,_LATESTMODE,txIpduRamPtr_pst->transMode_u8))))
#ifdef COM_TxFilters
|| (sendIpduFlag_st.isModeChangd_u1 != COM_RESET)
#endif
)
{
/* this flag will be set, as call happens apart from Com_MainFunctionTx */
sendIpduFlag_st.isEventTrig_u1 = COM_SET;
Com_Prv_SendIpdu((PduIdType)idComTxPdu_uo, sendIpduFlag_st);
}
}
}
注:Com_Prv_ProceedToSendIpdu 函数
好吧。接下来,来到了Com_MainFunctionTx。
Com_MainFuncationTx 函数被周期的调用。函数会loop所有的ipdu,查看发送状态。然后调用Com_Prv_MainFunctionTx_SendIPdu 进一步发送。
void Com_Prv_InternalMainFunctionTx(Com_MainFunc_tuo idTxMainFunc_uo)
{
/* Get the first TxIPdu-Id to be processed for given ComMainFunction */
idxIdTxIpdu_qu16 = COM_GET_MAINFUNCTION_CFG(COM_NUM_OF_RX_MAINFUNCTION + (uint16)idTxMainFunc_uo).idFirstIpdu_uo;
numOfIpdus_qu16 = (idxIdTxIpdu_qu16 + COM_GET_MAINFUNCTION_CFG(COM_NUM_OF_RX_MAINFUNCTION + (uint16)idTxMainFunc_uo).numOfIpdus_uo);
for ( ; idxIdTxIpdu_qu16 < numOfIpdus_qu16; idxIdTxIpdu_qu16++ )
{
.....
.....
.....
.....
.....
/* Send the IPdu */ /*发送*/
if (sendIPdu_b)
{
Com_Prv_MainFunctionTx_SendIPdu(idxIdTxIpdu_qu16);
}
}
}
Com_Prv_MainFunctionTx_SendIPdu,内会调用到PduR_ComTransmit。这是PduR和COM层的接口函数。
好吧,终于走到PDUR了。
PDUR
/**
**************************************************************************************************
* PduR_ComTransmit
* This function is called by the COM to request a transmission.
*
* \param PduIdType id: ID of COM I-PDU to be transmitted.
* const PduInfoType * ptr: Pointer to a structure with I-PDU related data that shall be transmitted:
* data length and pointer to I-SDU buffer
*
* \retval E_OK Transmit request has been accepted
* E_NOT_OK Transmit request has not been accepted
*
* \seealso PDUR202, PDUR206
* \usedresources
**************************************************************************************************
*/
Std_ReturnType PduR_ComTransmit( PduIdType id, const PduInfoType * ptr)
pdur最重要的就是路由了,路由的路径一般都会有一个API列表,也就是路由路径。
/* Routing table data structures */
Below functions can assignde to function pointer PduR_loTransmitFunc:
PduR_MF_Com_Transmit_Func
PduR_MF_Dcm_Transmit_Func
PduR_RF_CanIf_Transmit_Func
PduR_RF_FrNm_Transmit_Func
PduR_RF_FrIf_Transmit_Func
PduR_RF_LinIf_Transmit_Func
PduR_RF_CanTp_Transmit_Func
PduR_RF_FrTp_Transmit_Func
PduR_RF_LinTp_Transmit_Func
const PduR_loTransmitFuncType PduR_loTransmitTable[] =
{
{&PduR_RF_CanIf_Transmit_Func},
{&PduR_RF_CanTp_Transmit_Func},
......
};
我们这里讨论的是CAN 报文。所以PduR_RF_CanIf_Transmit_Func会被调用。代码就跑到了CanIf层。
CanIf
/* Function name : CanIf_Transmit */
/* Syntax : Std_ReturnType CanIf_Transmit(
PduIdType CanIfTxSduId,
const PduInfoType * CanIfTxInfoPtr
) */
/* Description : This service initiates a request for transmission of the CAN L-PDU specified by the
CanTxPduId and CAN related data in the L-PDU structure. */
/* Parameter : CanTxPduId, PduInfoPtr */
/* Return value : E_OK / E_NOT_OK */
/************************************************************************************************************/
Std_ReturnType CanIf_Transmit(PduIdType CanIfTxSduId,
const PduInfoType * CanIfTxInfoPtr)
注:CanIf 层的入口函数
CanIf_Transmit 内部会调用 mcal的Can_Write 完成can报文的发送。
流程图
Com_SendSignal 更新数据
MainFunction-->PduR
canif -->Candrv