
前言
一直以來,我們都是以Autosar工具鏈使用者的角度去理解Autosar各個模塊以及配置項,很多模塊、配置項總感覺理解不夠深入。
通過看Autosar標準規范去理解吧,規范又過于抽象。

(Autosar標準規范舉例)
看工具鏈的代碼吧,代碼量實在是太大,不知從何看起,實在是沒辦法從頭到尾研究完某個模塊的代碼。

(HaloOS代碼舉例)
但仔細想了想,不理解或許是正常的。
因為Autosar工具鏈廠家設計的代碼,是把Autosar標準的所有功能都實現了。
他們的目的,是把這套工具鏈賣給整個行業內的各個企業、匹配各種需求場景。
......
然而,如果我們以設計者的角度去理解Autosar模塊,情況就完全不一樣了。
這篇文章,我們就以設計者的角度,去從0去實現CanIf模塊,從根源上理解Autosar CanIf模塊功能、各個配置項的意義。
參考資料介紹:
在我們進入正題之前,先把我們會用到的資料列一下:
1、Autosar標準規范-MCAL-Can模塊規范
AUTOSAR_SWS_CANDriver.pdf
2、Autosar標準規范-Bsw-CanIf模塊規范
AUTOSAR_SWS_CANInterface.pdf
3、HaloOs開源代碼(Can模塊代碼、CanIf模塊代碼)
https://gitee.com/haloos/
(本文涉及的源代碼來源都是開源的HaloOs,大家可自行下載)
1
Autosar架構Can通訊鏈路介紹
在深入了解CanIf模塊之前,我們先從宏觀視角了解一下CanIf模塊在Autosar架構Can協議棧中的位置:

(圖片來源:AUTOSAR_SWS_CANInterface.pdf)
可以看到,CanIf的上層模塊非常多,比如CanTp(診斷報文)、PduR(應用報文)、CanNm(網管)等等。
下層模塊我們主要是2個:Can模塊(Can控制器)、Can收發器模塊。
好了,CanIf模塊所處的位置及上下層模塊有個概念就行,我們暫時不去糾結各個模塊的作用。
接下來,我們就從微觀角度,理解CanIf模塊功能。
2
Canlf 模塊報文
接收鏈路的理解與實現
功能實現1:軟件過濾
在了解CanIf模塊軟件過濾的功能前,先來看看Can模塊收到報文后,是怎么傳給CanIf模塊的:
當接收到CAN總線的Can報文時,Can模塊會把CANID、報文類型、DLC這些內容一起傳給CanIf模塊,如下圖所示:

(圖片來源:AUTOSAR_SWS_CANInterface.pdf)

(圖片來源:AUTOSAR_SWS_CANInterface.pdf)
其中Can報文類型已經包含在CanIf_RxIndication的CanId參數里面了。
舉個栗子:
0x00000123則代表標準幀、CAN格式的0x123報文
0x01000123則代表標準幀、CANFD格式的0x123報文。
好了,了解了這些內容后,我們就可以來認識一下CanIf模塊的軟件過濾功能了。
我們從前面的Autosar架構圖可以看到:“所有的Can報文都必須經過CanIf模塊”:

(圖片來源:AUTOSAR_SWS_CANInterface.pdf)
這句話實際上隱藏了很多信息:
①為什么接收報文經過了CanIf模塊,就知道要往哪個上層送?
②如果是Can矩陣(或DBC)里面沒有定義的報文,CanIf能知道上層模塊是誰嗎?
因此,對于接收報文來說,很重要的一個功能就出來了:軟件過濾。
CanIf模塊會定義Can矩陣(或DBC)里所有需要接收的報文的CANID、報文類型、DLC。
具體怎么定義呢?
我們來看下CanIf模塊的代碼:

(HaloOs源代碼)
可以看到,上圖中結構體數組大小為2,即定義了2條接收報文。(這個結構體數組我們下面的講解會經常用到,hrh_rx_pdu_canif_hrh_cfg[ ])
數組中詳細定義了2條接收報文對應的報文屬性(CanID、DLC、報文類型)。
報文從Can模塊送至CanIf模塊后,CanIf模塊會輪詢上面這個數組,并把Can模塊傳過來的CanId跟數組中的每個報文的CanId進行對比。
情況1:如果在數組中找到了對應的CanId,那么就認為成功接收到了我們需要的報文,然后再根據用戶需求決定是否進行報文DLC判斷,如果需要判斷DLC,且最后DLC檢查通過了,則把報文送到對應的上層模塊進行處理。
情況2:如果找完了一整個數組都沒找到對應的CanId,或找到CanId后需要檢查DLC,但DLC檢查不通過,CanIf模塊就會把這條報文丟掉,不再繼續送到上層進行處理。(說明:實際上不是找完一整個數組,原因我們下面會講到,我們這里暫時認為找完了一整個數組)
至于每條報文的上層模塊是哪里,則取決于數組里面每條報文的這個參數:

(HaloOs源代碼)
可見,0x299這條報文的上層模塊為PduR。
朋友們,我們上面說的這么多內容,不就是對應Autosar工具鏈接收報文的這些配置項嘛:

(HaloOs配置工具鏈)

(HaloOs配置工具鏈)
功能實現2:接收報文查找算法(軟件濾波類型)
好了,我們現在知道接收報文要進行軟件過濾,從代碼層面來說,就是要輪詢CanIf模塊的接收報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ],如下圖所示(只有2條接收報文):

(HaloOs源代碼)
如果某個項目有幾十條,上百條報文呢?
那么,如果還是一個簡單的For循環從上到下輪詢這個結構體數組,這樣的查找方法就會導致浪費很多時間。
因此, CanIf模塊中的“SoftwareFilterType” (軟件濾波類型)功能就出來了。

(HaloOs配置工具鏈)
于是,靜態代碼中把“線性查找”、“二分法查找 ”等其它查找方式都實現了,然后用戶開發時再根據項目報文數量,開啟對應的濾波算法。
這就是軟件濾波類型的由來了。

功能實現3:Can郵箱索引在接收報文中的使用
(額......,“郵箱索引的使用”,這不能算功能,但這個內容很重要)
首先,我們假設要實現1路CAN總線,且共有5條接收報文。
我們都知道,報文是通過CAN控制器的CAN郵箱收上來的,在開發的時候,每條報文都必須配置對應的CAN郵箱。
對應方式可以一條報文對應一個CAN郵箱,即FullCAN。也可以多條報文對應一個郵箱,即BasicCAN。(關于FullCan和BasisCAN,這是屬于CAN模塊的內容,我們這里就不展開講解了)
接下來,我們假設配置了3個接收郵箱。
CAN郵箱0(BasicCAN):接收2條報文(報文ID:0x001,0x002)
CAN郵箱1(BasicCAN):接收2條報文(報文ID:0x003,0x004)
CAN郵箱2(FullCAN):接收1條報文(報文ID:0x005)
我們前面說了,CanIf模塊接收到報文后會輪詢接收報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ],CanIf模塊接收的5條報文的結構體數組如下示(代碼省略部分內容)

于是,我們的問題就來了。
假設現在CAN模塊收到了CAN報文的ID為0x005,然后送到了CanIf模塊,如果我們不管CAN郵箱,直接輪詢整個CanIf模塊的接收報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ],如下圖所示:

當然了,你可能說,這里只有5條報文,報文少,輪詢一下也沒什么問題。
但是,如果情況變成這樣:我們有100條報文要接收,Can郵箱0、Can郵箱1的報文加起來是99條,報文0x005還是在Can郵箱2里面,且還是只有1條。
這種情況下,如果收到0x005報文后,還是這樣輪詢,就實在太傻了,過于浪費時間了。
所以,為了避免這種情況,Can郵箱索引的作用就來了。
這個Can郵箱索引,是指每個Can郵箱都有1個對應的號碼,即郵箱ID(郵箱ID從0開始遞增),舉例如下圖所示:

(HaloOs工具鏈配置)
然后,我們把CanIf模塊定義好的每條接收報文,都對應自己所屬于CAN郵箱。
HaloOs的實現方式如下:

使用“NofRxPdus“這個參數表示這個郵箱有多少條報文。
如上圖代碼所示,Can郵箱0、1、2分別有2、2、1條報文。
再通過“RxPduList”這個參數,指向接收報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ]中對應的首條報文,如下圖所示:

于是,Can模塊在接收到CanId為0x005的報文后,由于這條報文是從Can郵箱2收上來的,且Can郵箱2是FullCan,只有1條報文。
因此,無論Can郵箱0、Can郵箱1有多少條報文,對于報文0x005來說,完全不用輪詢數組,直接就能找到了CanIf模塊報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ]所在的位置,如下圖所示。

而如果Can模塊是接收到CanId為0x002的報文,由于Can郵箱0只有2條報文,因此則只需要輪詢CanIf模塊報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ]中該郵箱對應的2個元素就可以了,如下圖所示:

朋友們,這時候感受到Can郵箱Id的作用了吧。
我們再來看一下CanIf模塊接收報文的標準接口函數:

(圖片來源:AUTOSAR_SWS_CANInterface.pdf)

(圖片來源:AUTOSAR_SWS_CANDriver.pdf)
從上圖可以看到,CanIf_RxIndicaiton函數的參數里面就有報文對應的Can郵箱ID。
朋友們,這就是為什么我們在工具鏈配置CanIf模塊的接收報文時,接收報文要索引Can模塊的Can郵箱,如下圖所示:

(HaloOs工具鏈配置)
功能實現4:接收一段范圍的CanId報文
這個功能一般情況下主要是用于接收Can網管報文。
這個功能實際上很好理解。
比如Can網管報文ID范圍為0x500-0x57F,我們不可能在CanIf模塊定義0x500-0x57F中的每條報文吧?
因此,我們只需要在CanIf模塊的報文結構體數組hrh_rx_pdu_canif_hrh_cfg[ ]中定義一個含CanId范圍的報文就可以了,如下圖所示:

(HaloOs源代碼)
在接收到Can報文后,CanIf模塊只需要判斷一下Canid是否在指定的范圍內即可。
對應的CanIf模塊配置項如下圖所示:

(HaloOs工具鏈配置)
3
源碼展示
在把我們上面講的功能捋清楚后,我們再來看看源代碼,這樣就非常清晰了。
我們這里僅簡單舉例,具體大家可以去下載HaloOs的源碼研究。




4
結 語
關于CanIf模塊的接收報文鏈路涉及的功能基本就是這些了,大家有興趣也可以打開Autosar工具鏈(HaloOs工具鏈)、源代碼看看。
下篇文章,我們繼續講解CanIf模塊剩余的功能:CanIf模塊的發送鏈路、設置Can控制器、收發器、Pdu模式、BusOff等。
作者公眾號: