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