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_familycan_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:在流控制幀中提供的最大等待幀數。

傳輸 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