01不安全的CAN總線
1、如何保證ECU接收到的數據是合法的?
比如ECU1接收ECU2發出的一幀0x100報文,協議層是不會區分是ECU1發的,還是非法接入OBD的CAN盒發的?如果ECU1接收到非ECU2發出的0x100報文豈不是很危險?
2、ECU如何知道另一個節點掛死
比如ECU1還是接收ECU2發出的一幀0x100報文,但是由于某些神秘原因(程序跑飛了)導致ECU2掛死或者掉線,那ECU1如何知道此時的接收到0x100無效?
CAN通訊是一種廣播形式的通訊方式,自然協議層是無法做到數據合法性的校驗,這部分工作需要應用層來完成。由此就出現了RollingCounter與Checksum。這兩個東西好像也是功能安全的一部分,本期只是介紹這兩個東西的原理,不對功能安全做過多討論。
一個規范的CAN矩陣協議,每一幀報文都會要求有這個兩個信號。如上圖,從bit52到bit55是RollingCounter,取值范圍0~15,ECU沒發一次自動累加,滿15就歸零。從bit56到bit63(byte8)都是Checksum,取值范圍0x00~0xFF,用來表示該條報文的校驗值。
對于判斷發送報文ECU有沒有掛死很簡單,只要在接收端對RollingCounter進行判斷,幾個周期內協議棧上的buff沒有得到更新則就能判斷為節點異常。
對于報文合法性的判斷則就要負責得多,且會有各種花樣
車企制定的通訊協議時,除了制定矩陣信號外,會規定Checksum的計算方法,比如這個是采用多項式的CRC校驗算法。
并且規定出需要校驗的數據,有的是對矩陣的前7個byte進行校驗,有的則要增加報文ID作為校驗計算的輸入,各種花樣都有。
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CRC8校驗子程序0x1D(x8+x4+x3+x2+1) * * * * * * * * * * * * * * 參數1,uint8_t *data:需要計算的數據 * * * * * * * * * * * * * 參數1,uint16_t len:需要計算的數據字節長度 * * * * * * * * * * 返回值,uint8_t crc8:計算出的CRC值 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ uint8_t crc_8find(uint8_t *data, uint16_t len) { uint8_tcrc8=0x00; while( len-- ) { crc8 = crc_table[crc8 ^ *data]; data++; } return crc8; }
甚至貼心的給出校驗計算的偽代碼,這函數寫法C、C++應該都可以直接運行的。理解下上面的代碼!
當ECU2發出0x100之前,會對RollingCounter累加,并且通過計算包含RollingCounter的前七個字節的CRC值,填充到數據域的第8個字節;
ECU1接收到0x100的時候使用同樣的校驗算法,計算數據域的前7個字節,并且與第8個字節發送源計算的CRC值進行比較。如果兩者相同,則數據合法。
02CANOE仿真
接下來在CANOE的CAPL進行RollingCounter與Checksum的模擬
創建兩個ECU節點,ECU1為發送節點,ECU2為接收節點。ECU2會對ECU1的節點做Checksum,如果非法數據會在log窗口中打印出來。ECU1會而這個IG是用來模擬非法的數據發送。
int GetCrcChecksum (int crc_position ,message *data) { byte checksum; byte bitIndex; byte byteIndex; byte tdata; checksum = 0x00; for (byteIndex = DBLookup(data).dlc; byteIndex >= 1; byteIndex--) { if(byteIndex-1 != crc_position) { tdata = data.byte(byteIndex-1); } else { tdata = 0; } checksum ^= tdata; for (bitIndex = 0; bitIndex < 8; bitIndex++) { if ((checksum & 0x80) != 0) { checksum = (checksum << 1) ^ 0x1D; // cb_CRC_POLY: 0x1D } else { checksum = (checksum << 1); } } } checksum &= 0xFF; return (checksum); }
CAPL計算Checksum的函數,在ECU1與ECU2里都存在
on timer Timer1 { Req.rollingCounter_0x100=LiveCount; Req.checksum_0x100=GetCrcChecksum(7,Req); output(Req); setTimer(Timer1,20); LiveCount=LiveCount+1; if(LiveCount==16) { LiveCount=0; }
ECU1的定時器函數,發送前調用GetCrcChecksum函數生成Checksum
on message RCTest1 { if(this.checksum_0x100==GetCrcChecksum(7,this)) { Rep=this; }else { write("Invaild Message"); } }
ECU2接收事件中重新計算Checksum跟發送報文里的Checksum進行比較,不同則拋出錯誤
按F2,開始仿真,可以監控到ECU1發送出來的rollingCounter與Checksum
在Write窗口中打印ECU2接收到的數據
在IG節點設置一個非法的報文,rollingcounter與Checksum都設置0
對非法數據進行拋出。
來源:古德曼汽車工業
審核編輯:湯梓紅
-
CAN總線
+關注
關注
145文章
1954瀏覽量
130920 -
仿真
+關注
關注
50文章
4111瀏覽量
133793 -
ecu
+關注
關注
14文章
890瀏覽量
54604 -
通訊協議
+關注
關注
10文章
278瀏覽量
20386
原文標題:CAN總線報文數據一致性校驗
文章出處:【微信號:談思實驗室,微信公眾號:談思實驗室】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論