ISO 15765-2 (ISO-TP)¶
概述¶
ISO 15765-2,也稱為ISO-TP,是一種專門為CAN上的診斷通訊定義的傳輸協議。它廣泛應用於汽車工業,例如作為UDSonCAN(ISO 14229-3)或排放相關診斷服務(ISO 15031-5)的傳輸協議。
ISO-TP可用於基於CAN CC(又名經典CAN)和CAN FD(具有靈活資料速率的CAN)的網路。它也被設計為與使用SAE J1939作為資料鏈路層的CAN網路相容(但這並非強制要求)。
使用的規範¶
ISO 15765-2:2024 : 道路車輛 - 基於控制器區域網 (DoCAN) 的診斷通訊。第 2 部分:傳輸協議和網路層服務。
定址¶
在其最簡單的形式中,ISO-TP基於連線到同一網路的節點的兩種定址模式
物理定址由兩個節點特定的地址實現,用於1對1通訊。
功能定址由一個節點特定的地址實現,用於1對N通訊。
可以採用三種不同的定址格式
“normal”:每個地址都簡單地由一個CAN ID表示。
“extended”:每個地址由一個CAN ID加上CAN有效負載的第一個位元組表示;兩個地址之間的CAN ID和有效負載內的位元組都應該不同。
“mixed”:每個地址由一個CAN ID加上CAN有效負載的第一個位元組表示;兩個地址之間的CAN ID不同,但附加位元組相同。
傳輸協議和相關幀型別¶
當使用ISO-TP協議傳輸資料時,有效負載可以容納在一個CAN訊息中,也可以不容納,還要考慮到協議產生的開銷和可選的擴充套件定址。在第一種情況下,資料使用所謂的單幀(SF)一次性傳輸。在第二種情況下,ISO-TP定義了一個多幀協議,其中傳送方提供(透過第一幀 - FF)要傳輸的PDU長度,並請求流控制(FC)幀,該幀提供宏資料塊的最大支援大小(blocksize)以及組成該塊的單個CAN訊息之間的最短時間(stmin)。一旦收到此資訊,傳送方開始傳送包含資料有效負載片段的幀(稱為連續幀 - CF),並在每個blocksize大小的塊後停止,以等待來自接收方的確認,接收方應傳送另一個流控制幀,以通知傳送方其接收更多資料的可用性。
如何使用ISO-TP¶
與其他CAN協議一樣,ISO-TP堆疊支援內置於用於CAN匯流排的Linux網路子系統,又名。Linux-CAN或SocketCAN,因此遵循相同的套接字API。
建立和基本使用ISO-TP套接字¶
要使用ISO-TP堆疊,應使用#include <linux/can/isotp.h>。然後可以使用PF_CAN協議族、SOCK_DGRAM型別(因為底層協議在設計上是基於資料報的)和CAN_ISOTP協議來建立套接字
s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
成功建立套接字後,應呼叫bind(2)將套接字繫結到所需的CAN介面;為此
應在提供給呼叫的sockaddr中指定TX CAN ID。
還應指定RX CAN ID,除非已透過套接字選項設定了廣播標誌(如下所述)。
繫結到介面後,可以使用常用的read(2)和write(2)系統呼叫以及send(2)、sendmsg(2)、recv(2)和recvmsg(2)來讀取和寫入套接字。與CAN_RAW套接字API不同,只有ISO-TP資料欄位(實際有效負載)由使用者空間應用程式使用這些呼叫傳送和接收。地址資訊和協議資訊由ISO-TP堆疊使用套接字建立期間提供的配置自動填充。同樣,堆疊將在需要時使用傳輸機制(即,當資料有效負載的大小超過底層CAN匯流排的MTU時)。
用於SocketCAN的sockaddr結構具有用於ISO-TP的擴充套件,如下所示
struct sockaddr_can {
sa_family_t can_family;
int can_ifindex;
union {
struct { canid_t rx_id, tx_id; } tp;
...
} can_addr;
}
can_family和can_ifindex與用於其他SocketCAN套接字的目的相同。can_addr.tp.rx_id指定接收(RX)CAN ID,並將用作RX過濾器。can_addr.tp.tx_id指定傳送(TX)CAN ID
ISO-TP套接字選項¶
建立ISO-TP套接字時,會設定合理的預設值。可以使用setsockopt(2)修改某些選項,和/或使用getsockopt(2)讀取這些選項。
常規選項¶
可以使用CAN_ISOTP_OPTS optname傳遞常規套接字選項
struct can_isotp_options opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts))
其中can_isotp_options結構具有以下內容
struct can_isotp_options {
u32 flags;
u32 frame_txtime;
u8 ext_address;
u8 txpad_content;
u8 rxpad_content;
u8 rx_ext_address;
};
flags:應用於ISO-TP堆疊預設行為的修飾符。以下標誌可用CAN_ISOTP_LISTEN_MODE:僅偵聽(不傳送FC幀);通常用作測試功能。CAN_ISOTP_EXTEND_ADDR:使用ext_address中指定的位元組作為附加地址元件。如果單獨使用,這將啟用“混合”定址格式;如果與CAN_ISOTP_RX_EXT_ADDR結合使用,則啟用“擴充套件”定址格式。CAN_ISOTP_TX_PADDING:啟用傳送幀的填充,使用txpad_content作為填充位元組的值。CAN_ISOTP_RX_PADDING:啟用接收幀的填充,使用rxpad_content作為填充位元組的值。CAN_ISOTP_CHK_PAD_LEN:檢查接收幀上正確的填充長度。CAN_ISOTP_CHK_PAD_DATA:根據rxpad_content檢查接收幀上的填充位元組;如果未指定CAN_ISOTP_RX_PADDING,則忽略此標誌。CAN_ISOTP_HALF_DUPLEX:強制ISO-TP套接字進入半雙工模式(即,傳輸機制只能是同時傳入或傳出,而不能兩者兼有)。CAN_ISOTP_FORCE_TXSTMIN:忽略來自接收到的FC的stmin;通常用作測試功能。CAN_ISOTP_FORCE_RXSTMIN:忽略取決於rx stmin的CF;通常用作測試功能。CAN_ISOTP_RX_EXT_ADDR:在接收路徑上使用rx_ext_address而不是ext_address作為擴充套件定址位元組。如果與CAN_ISOTP_EXTEND_ADDR結合使用,此標誌有效地啟用“擴充套件”定址格式。CAN_ISOTP_WAIT_TX_DONE:在從write(2)和send(2)呼叫返回之前,等待直到傳送完幀(即,阻塞寫入操作)。CAN_ISOTP_SF_BROADCAST:使用1對N功能定址(不能與CAN_ISOTP_CF_BROADCAST一起指定)。CAN_ISOTP_CF_BROADCAST:使用1對N傳輸,無需流量控制(不能與CAN_ISOTP_SF_BROADCAST一起指定)。注意:這不在ISO 15765-2標準範圍內。CAN_ISOTP_DYN_FC_PARMS:啟用流控制引數的動態更新。
frame_txtime:幀傳輸時間(在ISO標準中定義為N_As/N_Ar);如果0,則使用預設值(或最後設定的值)。要將傳輸時間設定為0,應使用CAN_ISOTP_FRAME_TXTIME_ZERO宏(等於0xFFFFFFFF)。ext_address:擴充套件定址位元組,如果指定了CAN_ISOTP_EXTEND_ADDR標誌,則使用該位元組。txpad_content:用作傳送幀的填充值的位元組。rxpad_content:用作接收幀的填充值的位元組。rx_ext_address:接收路徑的擴充套件定址位元組,如果指定了CAN_ISOTP_RX_EXT_ADDR標誌,則使用該位元組。
流控制選項¶
可以使用CAN_ISOTP_RECV_FC optname傳遞流控制(FC)選項,以提供用於接收ISO-TP PDU的通訊引數。
struct can_isotp_fc_options fc_opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fc_opts, sizeof(fc_opts));
其中can_isotp_fc_options結構具有以下內容
struct can_isotp_options {
u8 bs;
u8 stmin;
u8 wftmax;
};
bs:在流控制幀中提供的塊大小。stmin:在流控制幀中提供的最小間隔時間;可以具有以下值(其他值已保留)0x00 - 0x7F : 0 - 127 毫秒
0xF1 - 0xF9 : 100 微秒 - 900 微秒
wftmax:在流控制幀中提供的最大等待幀數。
鏈路層選項¶
可以使用CAN_ISOTP_LL_OPTS optname傳遞鏈路層(LL)選項
struct can_isotp_ll_options ll_opts;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &ll_opts, sizeof(ll_opts));
其中can_isotp_ll_options結構具有以下內容
struct can_isotp_ll_options {
u8 mtu;
u8 tx_dl;
u8 tx_flags;
};
mtu:生成和接受的CAN幀型別,可以等於CAN_MTU用於經典CAN幀,或等於CANFD_MTU用於CAN FD幀。tx_dl:傳送幀的最大有效負載長度,可以具有以下值之一:8、12、16、20、24、32、48、64。大於8的值僅適用於CAN FD流量(即:mtu = CANFD_MTU)。tx_flags:在幀建立時設定到struct canfd_frame.flags中的標誌。僅適用於CAN FD流量(即:mtu = CANFD_MTU)。
傳輸 stmin¶
可以使用CAN_ISOTP_TX_STMIN optname強制傳輸最小間隔時間(stmin),並以32位無符號整數的形式提供以微秒為單位的stmin值;這將覆蓋接收方在流控制幀中傳送的值
uint32_t stmin;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &stmin, sizeof(stmin));
接收 stmin¶
可以使用CAN_ISOTP_RX_STMIN optname強制接收最小間隔時間(stmin),並以32位無符號整數的形式提供以微秒為單位的stmin值;接收到的連續幀(CF)的時間戳差異小於該值將被忽略
uint32_t stmin;
ret = setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &stmin, sizeof(stmin));
多幀傳輸支援¶
Linux核心中包含的ISO-TP堆疊支援標準定義的多幀傳輸機制,但具有以下約束
PDU的最大大小由模組引數定義,在構建時施加了硬性限制。
當傳輸正在進行時,後續對
write(2)的呼叫將阻塞,而對send(2)的呼叫將阻塞或失敗,具體取決於是否存在MSG_DONTWAIT標誌。不支援傳送“等待幀”:PDU是否可以完全接收是在收到第一幀時決定的。
錯誤¶
以下錯誤會報告給使用者空間
RX路徑錯誤¶
-ETIMEDOUT |
資料接收超時 |
-EILSEQ |
多幀接收期間的序列號不匹配 |
-EBADMSG |
資料接收填充錯誤 |
TX路徑錯誤¶
-ECOMM |
流控制接收超時 |
-EMSGSIZE |
流控制接收溢位 |
-EBADMSG |
流控制接收佈局/填充錯誤 |
示例¶
基本節點示例¶
以下示例使用“normal”物理定址實現一個節點,RX ID等於0x18DAF142,TX ID等於0x18DA42F1。所有選項都保留為其預設值。
int s;
struct sockaddr_can addr;
int ret;
s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP);
if (s < 0)
exit(1);
addr.can_family = AF_CAN;
addr.can_ifindex = if_nametoindex("can0");
addr.can_addr.tp.tx_id = 0x18DA42F1 | CAN_EFF_FLAG;
addr.can_addr.tp.rx_id = 0x18DAF142 | CAN_EFF_FLAG;
ret = bind(s, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0)
exit(1);
/* Data can now be received using read(s, ...) and sent using write(s, ...) */
更多示例¶
更完整(和複雜)的示例可以在isotp*使用者空間工具中找到,這些工具作為can-utils實用程式的一部分分發,網址為:https://github.com/linux-can/can-utils