一.前言:
通信模塊可以大致分為三大功能:數(shù)據(jù)發(fā)送功能,數(shù)據(jù)接收功能,狀態(tài)切換和管理功能。
我們的系列按照這樣的功能排序和自底向上的模塊排序,每次只介紹其中的一個模塊的其中一個功能的實現(xiàn),所以在每篇文章中對于模塊不會事無巨細(xì)的介紹所有它所具備的功能,而是選擇性的介紹三大功能中的其中一個。BSW往上的所有模塊示例,為最大程度了解其設(shè)計思路以及避免侵權(quán)風(fēng)險,將會采用遵循AUTOSAR架構(gòu)的非商業(yè)代碼作為示例,其部分細(xì)節(jié)不保證完全遵循AUTOSAR最新的標(biāo)準(zhǔn),不保證所有功能的具備,敬請理解。
二.Canif模塊及其發(fā)送函數(shù)CanIf_Transmit
在上節(jié)的文章中介紹了CAN模塊的發(fā)送底層邏輯,Can_Write函數(shù)的介紹。Can_Write函數(shù)已經(jīng)對CAN驅(qū)動進(jìn)行了抽象。抽象為了HOH供上層使用。而它的上層就是CanIf層.在CanIf模塊中,主要實現(xiàn)的功能如下:
1.傳輸請求(Transmit request)
傳輸請求功能的實現(xiàn)主體函數(shù)是CanIf_Transmit,這個函數(shù)內(nèi)部調(diào)用Can_Write進(jìn)行報文的發(fā)送
2.傳輸確認(rèn)(Transmit confirmation)
傳輸確認(rèn)功能的實現(xiàn)主體函數(shù)是CanIf_TxConfirmation,這個函數(shù)在CAN發(fā)送完成后被調(diào)用,作用是調(diào)用更上層的發(fā)送確認(rèn)回調(diào)函數(shù)通知更上層的各個模塊對應(yīng)的PDU已發(fā)送成功。
3.接收提示(Reception indication)
傳輸確認(rèn)功能的實現(xiàn)主體函數(shù)是CanIf_RxIndication,這個函數(shù)在CAN發(fā)送完成后被調(diào)用,作用是調(diào)用更上層的發(fā)送確認(rèn)回調(diào)函數(shù)通知更上層的各個模塊對應(yīng)的PDU已發(fā)送成功。
4.CAN控制器模式切換(Controller mode control)
controller模式切換的功能實現(xiàn)主體函數(shù)是CanIf_SetControllerMode,涉及到模式切換的功能后面專題詳解
5.PDU模式切換(PDU mode control)
PDU模式切換的功能實現(xiàn)主體函數(shù)是CanIf_SetPduMode,涉及到模式切換的功能后面專題詳解
整個CanIf模塊實現(xiàn)的基本函數(shù)如下:
本文側(cè)重介紹CanIf模塊的發(fā)送功能。CanIf的報文發(fā)送功能由CanIf_Transmit函數(shù)實現(xiàn),此函數(shù)原型如下:
Std_ReturnType CanIf_Transmit(PduIdType CanTxPduId,
const PduInfoType *PduInfoPtr)
此函數(shù)會調(diào)用MCAL的Can模塊中的Can_Write函數(shù)進(jìn)行報文的發(fā)送。在上節(jié)介紹Can_Write函數(shù)的時候,說過其傳入的參數(shù)是以下:
- HOH
- CAN id:報文ID
- length:報文長度
- sdu:報文數(shù)據(jù)
- swPduHandle :tx_confirm的ID
而CanIf層的傳入?yún)?shù)變?yōu)榱耍?/p>
- CanTxPduId,
- PduInfoPtr這個參數(shù)包括了SduDataPtr和SduLength
所以CanTxPduId對Can_Write函數(shù)所需的HOH,CAN ID,swPduHandle做了抽象。我們基本也可以推斷出CanIf的TxPDU所需要配置的主要內(nèi)容了。
三.Canif模塊的發(fā)送配置解析
以下例子用于說明CanIf層的tx配置。
Canif涉及到發(fā)送報文的主要配置結(jié)構(gòu)體如下:
const CanIf_InitConfigType CanIfInitConfig =
{
.CanIfConfigSet = 0,
.CanIfNumberOfCanRxPduIds = sizeof(CanIfRxPduConfigData)/sizeof(CanIf_RxPduConfigType),
.CanIfNumberOfCanTXPduIds = sizeof(CanIfTxPduConfigData)/sizeof(CanIf_TxPduConfigType),
.CanIfNumberOfDynamicCanTXPduIds = 0,
// Containers
.CanIfHohConfigPtr = CanIfHohConfigData,
.CanIfRxPduConfigPtr = CanIfRxPduConfigData,
.CanIfTxPduConfigPtr = CanIfTxPduConfigData,
};
我們以下主要關(guān)注:
1.HOH的配置結(jié)構(gòu)體CanIfHohConfigData,
2.發(fā)送PDU配置結(jié)構(gòu)體CanIfTxPduConfigData
1.HOH的配置結(jié)構(gòu)體CanIfHohConfigData,
對于HOH的配置結(jié)構(gòu)體CanIfHohConfigData的結(jié)構(gòu)如下:
const CanIf_InitHohConfigType CanIfHohConfigData[] = {
{
#if(CANIF_CONTROL_CAN_DRIVER ==STD_ON)
.CanConfigSet = &CanConfigSetData,
#endif
.CanIfHrhConfig = CanIfHrhConfigData_Hoh_1,
.CanIfHthConfig = CanIfHthConfigData_Hoh_1,
},
};
其中配置了發(fā)送的HTH和接收的HRH。對于發(fā)送的HTH配置如下:
const CanIf_HthConfigType CanIfHthConfigData_Hoh_1[] =
{
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_UDSTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_NMTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_XCPTX_Node,
},
{
.CanIfHthType = CAN_BASIC,
.CanIfCanControllerIdRef = CANIF_Channel_1,
.CanIfHthIdSymRef = HOH_3_EcuTestNode_CanCluster,
},
};
主要就是引用了上節(jié)文章例子中介紹的CAN模塊配置的四個HOH。
2.發(fā)送PDU配置結(jié)構(gòu)體數(shù)組CanIfTxPduConfigData
這個結(jié)構(gòu)體數(shù)組有所有的發(fā)送PDU配置,每個PDU都是一個結(jié)構(gòu)體成員,其中的一個成員配置示例如下:
const CanIf_TxPduConfigType CanIfTxPduConfigData[] = {
{
.CanIfTxConfrimPduId = CANTP_PDU_ID_UDS_PHYS_TX,
.CanIfCanTxPduIdCanId = 0x7ea,
.CanIfCanTxPduIdDlc = 8,
.CanIfCanTxPduType = CANIF_PDU_TYPE_STATIC,
#if ( CANIF_READTXPDU_NOTIFY_STATUS_API == STD_ON )
.CanIfReadTxPduNotifyStatus = false,
#endif
.CanIfTxPduIdCanIdType = CANIF_CAN_ID_TYPE_11,
.CanIfUserTxConfirmation = CanTp_TxConfirmation,
.CanIfCanTxPduHthRef = &CanIfHthConfigData_Hoh_1[0],
.PduIdRef = NULL,
},
.....
}
關(guān)鍵的參數(shù)解釋如下:
- CanIfTxConfrimPduId :用于為swPduHandle 復(fù)值,向?qū)?yīng)的TxConfirm函數(shù)傳入?yún)?shù)。
- CanIfCanTxPduIdCanId:對應(yīng)PDU的報文ID
- CanIfCanTxPduIdDlc:對應(yīng)PDU的報文長度
- CanIfUserTxConfirmation:發(fā)送確認(rèn)回調(diào)函數(shù)
- CanIfCanTxPduHthRef:發(fā)送此PDU要使用的HOH
類似上節(jié)的結(jié)尾說到的抽象。這些配置元素打包成一個結(jié)構(gòu)體數(shù)組元素,
CanIf_Transmit需要傳入的CanTxPduId,即代表這個配置結(jié)構(gòu)體數(shù)組的數(shù)組下標(biāo)。用來索引到其抽象的對象屬性。說起來比較枯燥,以下是CanIf_Transmit的實現(xiàn)函數(shù):
Std_ReturnType CanIf_Transmit(PduIdType CanTxPduId,
const PduInfoType *PduInfoPtr)
{
Can_PduType canPdu;
const CanIf_TxPduConfigType *txEntry;
CanIf_ControllerModeType csMode;
CanIf_ChannelGetModeType pduMode;
VALIDATE(CanIf_Global.initRun, CANIF_TRANSMIT_ID, CANIF_E_UNINIT );
VALIDATE((PduInfoPtr != 0), CANIF_TRANSMIT_ID, CANIF_E_PARAM_POINTER );
// Get the controller from L-PDU handle
txEntry = CanIf_FindTxPduEntry(CanTxPduId);
if (txEntry == 0)
{
VALIDATE(FALSE, CANIF_TRANSMIT_ID, CANIF_E_INVALID_TXPDUID);
return E_NOT_OK;
}
CanIf_Arc_ChannelIdType channel = txEntry- >CanIfCanTxPduHthRef- >CanIfCanControllerIdRef;
// Get and verify the controller mode
if (CanIf_GetControllerMode(channel, &csMode) == E_NOT_OK){
return E_NOT_OK;
}
if (csMode != CANIF_CS_STARTED){ // CANIF_161
return E_NOT_OK;
}
// Get and verify the PDU channel mode control
if (CanIf_GetPduMode(channel, &pduMode) == E_NOT_OK){
return E_NOT_OK;
}
if ((pduMode != CANIF_GET_TX_ONLINE) && (pduMode != CANIF_GET_ONLINE)){
return E_NOT_OK;
}
canPdu.id = txEntry- >CanIfCanTxPduIdCanId;
canPdu.length = PduInfoPtr- >SduLength;
canPdu.sdu = PduInfoPtr- >SduDataPtr;
canPdu.swPduHandle = CanTxPduId;
Can_ReturnType rVal = Can_Write(txEntry- >CanIfCanTxPduHthRef- >CanIfHthIdSymRef, &canPdu);
if (rVal == CAN_NOT_OK){
return E_NOT_OK;
}
if (rVal == CAN_BUSY) // CANIF 082, CANIF 161
{
// Tx buffering not supported so just return.
return E_NOT_OK;
}
return E_OK;
}
注意到其中CanIf_Transmit的傳入?yún)?shù)CanTxPduId的使用方式:
txEntry = CanIf_FindTxPduEntry(CanTxPduId);
CanIf_FindTxPduEntry的函數(shù)原型如下
static const CanIf_TxPduConfigType * CanIf_FindTxPduEntry(PduIdType id)
{
if (id >= CanIf_ConfigPtr- >InitConfig- >CanIfNumberOfCanTXPduIds) {
return NULL;
} else {
return &CanIf_ConfigPtr- >InitConfig- >CanIfTxPduConfigPtr[id];
}
}
就是以CanIf_Transmit的傳入?yún)?shù)CanTxPduId為下標(biāo),找到對應(yīng)的CanIfTxPduConfigData的數(shù)組成員。并獲取其屬性,對Can_Write函數(shù)的傳入?yún)?shù)進(jìn)行配置。調(diào)用Can_Write函數(shù)進(jìn)行發(fā)送。
四.發(fā)送確認(rèn)函數(shù):CanIf_TxConfirmation
CanIf_TxConfirmation是由Can模塊底層驅(qū)動在PDU傳輸完成后調(diào)用的。之前講到Can_Write函數(shù)的其中一個傳入?yún)?shù):swPduHandle是用來在底層標(biāo)記傳輸?shù)腜DU ID,在更新MessageBuffer前記住PDU對應(yīng)的swPduHandle參數(shù),在對應(yīng)的PDU發(fā)出去后,底層驅(qū)動函數(shù)調(diào)用CanIf_TxConfirmation傳入swPduHandle。
而我們的CanIf_TxConfirmation實現(xiàn)如下:
void CanIf_TxConfirmation(PduIdType canTxPduId)
{
VALIDATE_NO_RV(CanIf_Global.initRun, CANIF_TXCONFIRMATION_ID, CANIF_E_UNINIT)
VALIDATE_NO_RV(canTxPduId < CanIf_ConfigPtr- >InitConfig- >CanIfNumberOfCanTXPduIds, CANIF_TXCONFIRMATION_ID, CANIF_E_PARAM_LPDU);
const CanIf_TxPduConfigType* entry =
&CanIf_ConfigPtr- >InitConfig- >CanIfTxPduConfigPtr[canTxPduId];
if (entry- >CanIfUserTxConfirmation != NULL)
{
CanIf_ChannelGetModeType mode;
CanIf_GetPduMode(entry- >CanIfCanTxPduHthRef- >CanIfCanControllerIdRef, &mode);
if ((mode == CANIF_GET_TX_ONLINE) || (mode == CANIF_GET_ONLINE)
|| (mode == CANIF_GET_OFFLINE_ACTIVE) || (mode == CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE) )
{
entry- >CanIfUserTxConfirmation(entry- >CanIfTxPduId); /* CANIF053 */
}
}
return;
}
在這個函數(shù)中,會直接向上文CanIfTxPduConfigData配置的CanIfUserTxConfirmation中傳入swPduHandle。
而在CanIf_Transmit中,swPduHandle又是由CanIfTxPduConfigData配置的CanIfTxConfrimPduId決定的。所以CanIfTxConfrimPduId會作為參數(shù)傳入對應(yīng)的CanIfUserTxConfirmation。
這期的介紹就到這,本期介紹了CanIf主要實現(xiàn)的功能,主要函數(shù),主要的發(fā)送配置以及CanIf_Transmit,CanIf_TxConfirmation的機制,可以了解CanIf做了更進(jìn)一步的抽象,將HOH進(jìn)一步抽象為了PDU。各個AUTOSAR架構(gòu)的代碼實現(xiàn)并不一致,文中所有的函數(shù)實現(xiàn)和配置思路僅作參考。
-
CAN通信
+關(guān)注
關(guān)注
5文章
94瀏覽量
17932 -
接收機
+關(guān)注
關(guān)注
8文章
1184瀏覽量
53586 -
AUTOSAR
+關(guān)注
關(guān)注
10文章
363瀏覽量
21733 -
PDU
+關(guān)注
關(guān)注
0文章
94瀏覽量
17013 -
CAN控制器
+關(guān)注
關(guān)注
3文章
74瀏覽量
15081
發(fā)布評論請先 登錄
相關(guān)推薦
評論