Linux内核Socket CAN中文文档 联系客服

发布时间 : 星期日 文章Linux内核Socket CAN中文文档更新完毕开始阅读c7eae43b5a8102d276a22f91

论这个CAN-ID是针对一个具体的CAN接口还是所有已知的CAN接口(参考第5章)。

为了优化CPU的运行效率,每个设备都对应一个接收队列,这样比较容易实现各种报文过滤规则。

3.2 发送帧的本地回环 -----------------

在其它种类的网络中,在相同或者不同网络节点上的应用程序都可以相互交换数据。

___ ___ ___ _______ ___ | _ | | _ | | _ | | _ _ | | _ | ||A|| ||B|| ||C|| ||A| |B|| ||C|| |___| |___| |___| |_______| |___| | | | | | -----------------(1)- CAN bus -(2)---------------

请看上图的两个例子。为了保证应用程序A在两个例子中能够接收到同样的例子(例2中A和B在同一个CAN设备上),发送出去的CAN帧需要能够在本地回环。

Linux下的网络设备仅仅处理物理媒介上帧的发送和接受。总线仲裁机制下,高优先级的帧会将低优先级的帧延后。为了正确反映实际的通信活动,回环必须在正确传输成功之后进行。如果CAN网络的硬件不支持回环功能,一种低效的方案是使用Socket CAN核心部分来实现软件回环。具体的情况请参考6.2小节。

CAN网络的回环功能是默认开启的。由于RT-SocketCAN 的特殊需求,每个套接字的回环功能可以被独立关闭。CAN原始套接字的控制选项请参考4.1小节。

*当你在同一个节点上运行CAN分析命令“candump”或者“cansniffer”的时候就会发现回环功能真的很有用。

3.3 网络安全相关 --------------------

CAN网络是一种现场总线,仅仅支持没有路由和安全控制的广播传输。大部分应用程序都需要要直接处理原始CAN帧,所以和其它类型的网络一样,CAN网络对所有的用户(而不仅仅是root用户)访问没有任何限制。由于当前CAN_RAW和CAN_BCM的实现仅仅支持对CAN接口的读写,所以允许所有的用户访问CAN并不影响其它类型网络的安全性。为了使能非root用户对CAN_RAW和CAN_BCM协议套接字的访问,必须在编译内核的时候选上Kconfig的CAN_RAW_USER/CAN_BCM_USER选项。

3.4 网络故障监测 --------------------

使用CAN总线的时候,可能会遇到物理和mac(media access control)层的问题。为了方便用户分析物理收发器的硬件错误、总线仲裁错误和不同的ECU( Electrical Conversion Unit,电气转换装置)引起的错误,对于底层(物理和mac层)的监测和记录是至关重要的。拥有精确时间戳的错误监测对于诊断错误是非常重要的。基于以上原因,CAN接口的驱动可以可以选择性的产生所谓的错误帧,这些帧以和其它的CAN帧一样的方式传递给用户程序。当一个物理层或者MAC层的错误被(CAN控制器)检测到之后,驱动创建一个相应的错误帧。错误帧可以被应用程序通过CAN的过滤机制请求得到。过滤机制允许选择需要的错误帧的类型。默认情况下,接收错误帧的功能是禁止的。

CAN错误帧的详细格式定义在linux头文件中:include/linux/can/error.h。

4. 如何使用Socket CAN ===============

就像TCP/IP协议一样,在使用CAN网络之前你首先需要打开一个套接字。CAN的套接字使用到了一个新的协议族,所以在调用socket(2)这个系统函数的时候需要将PF_CAN作为第一个参数。当前有两个CAN的协议可以选择,一个是原始套接字协议( raw socket protocol),另一个是广播管理协议BCM(broadcast manager)。你可以这样来打开一个套接字:

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

或者

s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);

在成功创建一个套接字之后,你通常需要使用bind(2)函数将套接字绑定在某个CAN接口上(这和TCP/IP使用不同的IP地址不同,参见第3章)。在绑定 (CAN_RAW)或连接(CAN_BCM)套接字之后,你可以在套接字上使用read(2)/write(2),也可以使用send(2)/sendto(2)/sendmsg(2)和对应的recv*操作。当然也会有CAN特有的套接字选项,下面将会说明。

基本的CAN帧结构体和套接字地址结构体定义在include/linux/can.h:

/*

* 扩展格式识别符由 29 位组成。其格式包含两个部分:11 位基本 ID、18 位扩展 ID。

* Controller Area Network Identifier structure *

* bit 0-28 : CAN识别符 (11/29 bit)

* bit 29 : 错误帧标志 (0 = data frame, 1 = error frame) * bit 30 : 远程发送请求标志 (1 = rtr frame)

* bit 31 :帧格式标志 (0 = standard 11 bit, 1 = extended 29 bit) */

typedef __u32 canid_t;

struct can_frame {

canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* 数据长度: 0 .. 8 */ __u8 data[8] __attribute__((aligned(8))); };

结构体的有效数据在data[]数组中,它的字节对齐是64bit的,所以用户可以比较方便的在data[]中传输自己定义的结构体和共用体。CAN总线中没有默认的字节序。在CAN_RAW套接字上调用read(2),返回给用户空间的数据是一个struct can_frame结构体。

就像PF_PACKET套接字一样,sockaddr_can结构体也有接口的索引,这个索引绑定了特定接口:

struct sockaddr_can { sa_family_t can_family; int can_ifindex; union {

/* transport protocol class address info (e.g. ISOTP) */ struct { canid_t rx_id, tx_id; } tp;

/* reserved for future CAN protocols address information */ } can_addr; };

指定接口索引需要调用ioctl()(比如对于没有错误检查CAN_RAW套接字):

int s;

struct sockaddr_can addr; struct ifreq ifr;

s = socket(PF_CAN, SOCK_RAW, CAN_RAW);

strcpy(ifr.ifr_name, \

ioctl(s, SIOCGIFINDEX, &ifr);

addr.can_family = AF_CAN;

addr.can_ifindex = ifr.ifr_ifindex;

bind(s, (struct sockaddr *)&addr, sizeof(addr));

(..)

为了将套接字和所有的CAN接口绑定,接口索引必须是0。这样套接字便可以从所有使能的CAN接口接收CAN帧。recvfrom(2)可以指定从哪个接口接收。在一个已经和所有CAN接口绑定的套接字上,sendto(2)可以指定从哪个接口发送。