从代码看autosar CAN协议栈之CAN发送

简单写一下,学习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

  • 17
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值