文档原名称:can.txt,位于 linux-3.2.0-m3352/Documentation/networking/can.txt。
CAN 控制器局域网络协议族之 Readme 文件(aka Socket CAN)。另外在该文档的后边附加一个CAN收发测试程序,用于与下位机通信。
目录
1 概述 / 什么是 Socket CAN?
2 目的 / 为什么要使用 socket API?
3 socket can 概念
3.1 接收列表
3.2 数据发送的本地回环模式(loopback)
3.3 网络安全问题(capabilities)
3.4 网络问题注意事项
4 怎样使用 Socket Can?
4.1 使用 can 过滤器的原始套接字
4.1.1 原始套接字选项- CAN_RAW_FILTER
4.1.2 原始套接字选项- CAN_RAW_ERR_FILTER
4.1.3 原始套接字选项- CAN_RAW_LOOPBACK
4.1.4 原始套接字选项- CAN_RAW_RECV_OWN_MSGS
4.1.5 原始套接字返回的消息标志
4.2 广播管理协议套接字(SOCK_DGRAM)
4.3 面向连接的传输协议(SOCK_SEQPACKET)
4.4 非连接传输协议(SOCK_DGRAM)
5 Socket CAN 核心模块
5.1 can.ko 模块参数
5.2 procfs 内容
5.3 编写自定义 CAN 协议模块
6 CAN 驱动程序
6.1 通用设置
6.2 数据发送的本地回环模式
6.3 CAN 控制器硬件过滤器
6.4 虚拟 CAN 驱动(vcan)
6.5 CAN 驱动程序接口
6.5.1 Netlink 接口-设置/获取器件属性
6.5.2 设置 CAN 位时序
6.5.3 启动和停止 CAN 器件
6.6 支持的 CAN 器件
7 学习 Socket CAN 相关资源
8 致谢
1 概述 / 什么是 Socket CAN?
Socketcan 套接字是 Linux 下 CAN 协议的实现方法。 CAN 协议通信技术在自动化领域,
存在的 CAN 实现方法,基于字符设备,提供相对较少的功能。通常,具体针对某一种设备
的驱动程序提供一种字符设备接口用来发送和接收 CAN 原始数据帧,直接同硬件打交道。
数据帧队列和更高层的传输协议像 ISO-TP 在用户空间程序中实现。另外,大多数基于字符
设备的实现方法仅仅提供一种每次只能打开一个设备的访问方法,就像串口通信接口。往往,
伴随着 CAN 控制器的变化,就需要实现新的驱动程序和应用程序因为新驱动程序接口改变
而需要发生变化的适应性。
CAN 驱动程序向网络层注册自己为网络器件,所以,CAN 控制器的 CAN 数据帧能够被传
送到网络层和 CAN 通信协议模块,反之亦然。 CAN 协议通信模块为传输协议模块提供注册
API,所以,其它的 CAN 通信传输协议可以被动态的加载和卸载。事实上,CAN 核心模块
并不能提供任何协议,在没有载入任何协议时,也不能使用。与此同时,可以同时打开多个
套接字,不论它们是不是基于同一种 CAN 通信协议,它们都能实现监听和发送 CAN 数据
帧,不论它们是否具有相同的 CAN ID。几个使用相同接口监听具有相同的 CAN ID 的通信
帧的套接字,能够得到相同的 CAN 数据帧。如果,用户程序想要使用某一种通信协议,例
如 ISO-IP 协议,只需要在打开套接字的时候选择相应的协议即可,然后就能够读写用户数
据,而不闭关心 CAN ID,帧结构等信息了。
(1)复杂的使用方法。与传递给 socket(2)协议参数不同,使用 bind(2)选择 CAN 通信
接口和 CAN ID,应用程序必须使用 ioctl(2)实现许多的控制。
(2)代码复用性。字符设备不能使用 Linux 网络层的队列相关代码,所以必须为字符
设备重新实现这部分代码。
(3)抽象性。许多已存的基于字符设备的实现方法,针对 CAN 控制器而提供的特定
硬件驱动程序直接提供给用户程序字符设备接口使用。这与 Unix 系统下的字符和块设备是
不相同的。例如,你没有为某一种 UART 设备,某一种声卡,某一种 SCSI 或 IDE 控制器提
供访问你硬盘或者磁盘的字符设备接口。取而代之的是,建立一个抽象层,一方面为应用程
序提供统一的字符或者块设备接口,另一方面为特定的硬件驱动程序提供一个接口。这些抽
象层由子系统提供,像 tty 层,音频系统和 SCSI 或 IDE 系统。
最简单的实现 CAN 驱动的方法是使用没有抽象层或者只有部分抽象的字符设备,这也
是已经存在的驱动程序常用的方法。但是,最正确的方式是添加一个这样具有所有功能的抽
象层,像使用 CAN ID 注册功能,支持同时打开几个文件描述符和 CAN 通信帧的复用, CAN
通信帧的复杂队列的实现,以及提供注册器件驱动的 API。但是,通过使用 Linux 内核提供
的网络层,使得这一切变得不再困难,不再复杂。这就是 Socket CAN 所做的。
使用 Linux 内核的网络层协议框架实现 Linux CAN 通信是最自然,也是最恰当的方法
其主要设计目的。与众所周知的 TCP/IP 协议和以太网通信协议不同的是,CAN 总线没有
MAC 层地址,你能用于广播。CAN ID 仅仅用来 CAN 总线的仲裁。因此 CAN-ID 在总线上
必须是唯一的。当设计一个 CAN-ECU(Electronic Control Unit 电子控制单元)网络的时候,
CAN-ID 可以映射到具体的 ECU。因此 CAN-ID 可以当作发送源的地址来使用。
同一个 CAN 网络接口上对具有相同 CAN-ID 的帧感兴趣。Socket CAN 的核心部分实现了
Socket CAN 的协议族,通过高效的接收队列解决了这个问题。比如一个用户空间的程序打
开了一个原始 CAN 套接字,原始协议模块将向 CAN 套接字的核心模块申请用户空间需要
的一系列 CAN-ID。Socket CAN 的核心向 CAN 协议模块提供预约和解约 CAN-ID 的接口
-can_rx_(un)register(),无论这个 CAN-ID 是针对一个具体的 CAN 接口还是所有已知的 CAN
接口(参考第 5 章)
为了优化 CPU 的运行效率,每个设备都对应一个接收队列,这样比较容易实现各种报
文过滤规则。
和 B 在同一个 CAN 设备上),必须实现 CAN 数据发送的本地回环模式。
Linux 下的网络设备仅仅处理物理媒介上帧的发送和接受。总线仲裁机制下,高优先级
的帧会将低优先级的帧延后。为了正确反映实际的通信活动,回环必须在正确传输成功之后
进行。如果 CAN 网络接口的硬件不支持回环功能,一种低效的方案是使用 Socket CAN 核
心部分来实现软件回环。具体的情况请参考 6.2 小节。
CAN 网络的回环功能是默认开启的。由于 RT-SocketCAN(实时 CAN 通信协议) 的特
殊需求,每个套接字的回环功能可以被独立关闭。CAN 原始套接字的控制选项请参考 4.1
小节。
当你在同一个节点上运行 CAN 分析命令“candump”或者“cansniffer”的时候就会发
现回环功能真的很有用。
CAN 控制器局域网络协议族之 Readme 文件(aka Socket CAN)。另外在该文档的后边附加一个CAN收发测试程序,用于与下位机通信。
目录
1 概述 / 什么是 Socket CAN?
2 目的 / 为什么要使用 socket API?
3 socket can 概念
3.1 接收列表
3.2 数据发送的本地回环模式(loopback)
3.3 网络安全问题(capabilities)
3.4 网络问题注意事项
4 怎样使用 Socket Can?
4.1 使用 can 过滤器的原始套接字
4.1.1 原始套接字选项- CAN_RAW_FILTER
4.1.2 原始套接字选项- CAN_RAW_ERR_FILTER
4.1.3 原始套接字选项- CAN_RAW_LOOPBACK
4.1.4 原始套接字选项- CAN_RAW_RECV_OWN_MSGS
4.1.5 原始套接字返回的消息标志
4.2 广播管理协议套接字(SOCK_DGRAM)
4.3 面向连接的传输协议(SOCK_SEQPACKET)
4.4 非连接传输协议(SOCK_DGRAM)
5 Socket CAN 核心模块
5.1 can.ko 模块参数
5.2 procfs 内容
5.3 编写自定义 CAN 协议模块
6 CAN 驱动程序
6.1 通用设置
6.2 数据发送的本地回环模式
6.3 CAN 控制器硬件过滤器
6.4 虚拟 CAN 驱动(vcan)
6.5 CAN 驱动程序接口
6.5.1 Netlink 接口-设置/获取器件属性
6.5.2 设置 CAN 位时序
6.5.3 启动和停止 CAN 器件
6.6 支持的 CAN 器件
7 学习 Socket CAN 相关资源
8 致谢
1 概述 / 什么是 Socket CAN?
Socketcan 套接字是 Linux 下 CAN 协议的实现方法。 CAN 协议通信技术在自动化领域,
嵌入式器件编程,和汽车领域等具有广泛的应用。尽管,在 Linux 下有多种基于字符设备的
CAN 协议的实现,但是 Socket CAN 运用 Berkeley socket API,linux 网络协议栈,将 CAN
器件驱动程序实现为网络接口。CAN socket API 设计实现尽可能的与 TCP/IP 协议相同,
允许程序员像使用网络编程一样,非常简单地学习怎样使用 CAN sockets。
在 Socket CAN 出现之前,Linux 下 CAN 通信的实现方法存在着许多的问题,这就是我
们为什么停止那些 CAN 实现方法的研究转而实现 Socket CAN 的原因。当时,大多数已经存在的 CAN 实现方法,基于字符设备,提供相对较少的功能。通常,具体针对某一种设备
的驱动程序提供一种字符设备接口用来发送和接收 CAN 原始数据帧,直接同硬件打交道。
数据帧队列和更高层的传输协议像 ISO-TP 在用户空间程序中实现。另外,大多数基于字符
设备的实现方法仅仅提供一种每次只能打开一个设备的访问方法,就像串口通信接口。往往,
伴随着 CAN 控制器的变化,就需要实现新的驱动程序和应用程序因为新驱动程序接口改变
而需要发生变化的适应性。
Socket CAN 被设计用来解决这些局限性。新实现的协议族提供用户程序一个套接字接
口,它是基于 Linux 网络层构建的,所以,能够使用网络层提供的与队列相关的所有功能。CAN 驱动程序向网络层注册自己为网络器件,所以,CAN 控制器的 CAN 数据帧能够被传
送到网络层和 CAN 通信协议模块,反之亦然。 CAN 协议通信模块为传输协议模块提供注册
API,所以,其它的 CAN 通信传输协议可以被动态的加载和卸载。事实上,CAN 核心模块
并不能提供任何协议,在没有载入任何协议时,也不能使用。与此同时,可以同时打开多个
套接字,不论它们是不是基于同一种 CAN 通信协议,它们都能实现监听和发送 CAN 数据
帧,不论它们是否具有相同的 CAN ID。几个使用相同接口监听具有相同的 CAN ID 的通信
帧的套接字,能够得到相同的 CAN 数据帧。如果,用户程序想要使用某一种通信协议,例
如 ISO-IP 协议,只需要在打开套接字的时候选择相应的协议即可,然后就能够读写用户数
据,而不闭关心 CAN ID,帧结构等信息了。
在用户程序空间基于字符设备提供的方法也能狗实现相似的功能,但是这种设计方法不
够完美,原因有两方面:(1)复杂的使用方法。与传递给 socket(2)协议参数不同,使用 bind(2)选择 CAN 通信
接口和 CAN ID,应用程序必须使用 ioctl(2)实现许多的控制。
(2)代码复用性。字符设备不能使用 Linux 网络层的队列相关代码,所以必须为字符
设备重新实现这部分代码。
(3)抽象性。许多已存的基于字符设备的实现方法,针对 CAN 控制器而提供的特定
硬件驱动程序直接提供给用户程序字符设备接口使用。这与 Unix 系统下的字符和块设备是
不相同的。例如,你没有为某一种 UART 设备,某一种声卡,某一种 SCSI 或 IDE 控制器提
供访问你硬盘或者磁盘的字符设备接口。取而代之的是,建立一个抽象层,一方面为应用程
序提供统一的字符或者块设备接口,另一方面为特定的硬件驱动程序提供一个接口。这些抽
象层由子系统提供,像 tty 层,音频系统和 SCSI 或 IDE 系统。
最简单的实现 CAN 驱动的方法是使用没有抽象层或者只有部分抽象的字符设备,这也
是已经存在的驱动程序常用的方法。但是,最正确的方式是添加一个这样具有所有功能的抽
象层,像使用 CAN ID 注册功能,支持同时打开几个文件描述符和 CAN 通信帧的复用, CAN
通信帧的复杂队列的实现,以及提供注册器件驱动的 API。但是,通过使用 Linux 内核提供
的网络层,使得这一切变得不再困难,不再复杂。这就是 Socket CAN 所做的。
使用 Linux 内核的网络层协议框架实现 Linux CAN 通信是最自然,也是最恰当的方法
了。
3 socket can 概念
正如第二章所述,Socket CAN 提供给用户程序基于 Linux 网络层构建的套接字接口是其主要设计目的。与众所周知的 TCP/IP 协议和以太网通信协议不同的是,CAN 总线没有
MAC 层地址,你能用于广播。CAN ID 仅仅用来 CAN 总线的仲裁。因此 CAN-ID 在总线上
必须是唯一的。当设计一个 CAN-ECU(Electronic Control Unit 电子控制单元)网络的时候,
CAN-ID 可以映射到具体的 ECU。因此 CAN-ID 可以当作发送源的地址来使用。
3.1 接收队列
允许多个应用程序同时访问网络导致了新的问题出现,那就是不同的应用程序可能会在同一个 CAN 网络接口上对具有相同 CAN-ID 的帧感兴趣。Socket CAN 的核心部分实现了
Socket CAN 的协议族,通过高效的接收队列解决了这个问题。比如一个用户空间的程序打
开了一个原始 CAN 套接字,原始协议模块将向 CAN 套接字的核心模块申请用户空间需要
的一系列 CAN-ID。Socket CAN 的核心向 CAN 协议模块提供预约和解约 CAN-ID 的接口
-can_rx_(un)register(),无论这个 CAN-ID 是针对一个具体的 CAN 接口还是所有已知的 CAN
接口(参考第 5 章)
为了优化 CPU 的运行效率,每个设备都对应一个接收队列,这样比较容易实现各种报
文过滤规则。
3.2 数据发送的本地回环模式(loopback)
在其它种类的网络中,在相同或者不同网络节点上的应用程序都可以相互交换数据。
和 B 在同一个 CAN 设备上),必须实现 CAN 数据发送的本地回环模式。
Linux 下的网络设备仅仅处理物理媒介上帧的发送和接受。总线仲裁机制下,高优先级
的帧会将低优先级的帧延后。为了正确反映实际的通信活动,回环必须在正确传输成功之后
进行。如果 CAN 网络接口的硬件不支持回环功能,一种低效的方案是使用 Socket CAN 核
心部分来实现软件回环。具体的情况请参考 6.2 小节。
CAN 网络的回环功能是默认开启的。由于 RT-SocketCAN(实时 CAN 通信协议) 的特
殊需求,每个套接字的回环功能可以被独立关闭。CAN 原始套接字的控制选项请参考 4.1
小节。
当你在同一个节点上运行 CAN 分析命令“candump”或者“cansniffer”的时候就会发
现回环功能真的很有用。