linux CAN控制器使用--基于Nvidia-TX2

来源:互联网 发布:淘宝天猫类目成交排名 编辑:程序博客网 时间:2024/06/03 07:05

默认CAN总线驱动加载完毕, 通过ifconfig来查看can是否挂载成功


#1. 首先关闭can0$ sudo ifconfig can0 down#2. 打开回环用于调试$ sudo ip link set can0 type can bitrate 1000000 loopback on#3. 设置重启时间==> up 代表开启can0$ sudo ip link set can0 up type can restart-ms 100#4. 查看can0的状态$ ip -details link show can0 ##==> ERROR-ACTIVE 这个是正确的状态




虚拟CAN网卡vcan加载方式

$ modprobe can$ modprobe can_raw$ modprobe vcan$ sudo ip link add dev vcan0 type vcan$ sudo ip link set up vcan0$ ip link show vcan03: vcan0: <NOARP,UP,LOWER_UP> mtu 16 qdisc noqueue state UNKNOWN     link/can


下面的代码片段是使用SocketCAN API的一个实例,来自于https://en.wikipedia.org/wiki/SocketCAN, 使用raw interface发送数据包. 

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <net/if.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <linux/can.h>#include <linux/can/raw.h>intmain(void){int s;int nbytes;struct sockaddr_can addr;struct can_frame frame;struct ifreq ifr;const char *ifname = "vcan0";if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {perror("Error while opening socket");return -1;}strcpy(ifr.ifr_name, ifname);ioctl(s, SIOCGIFINDEX, &ifr);addr.can_family  = AF_CAN;addr.can_ifindex = ifr.ifr_ifindex;printf("%s at index %d\n", ifname, ifr.ifr_ifindex);if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {perror("Error in socket bind");return -2;}frame.can_id  = 0x123;frame.can_dlc = 2;frame.data[0] = 0x11;frame.data[1] = 0x22;nbytes = write(s, &frame, sizeof(struct can_frame));printf("Wrote %d bytes\n", nbytes);return 0;}

The packet can be analyzed on the vcan0 interface using the candump utility which is part of the SocketCAN can-utils [3] package.

user@server:~/can-utils $ ./candump vcan0  vcan0  123  [2] 11 22


/* * Controller Area Network Identifier structure * * bit 0-28: CAN identifier (11/29 bit) * bit 29: error message frame flag (0 = data frame, 1 = error message) * bit 30: remote transmission request flag (1 = rtr frame) * bit 31: frame format flag (0 = standard 11 bit, 1 = extended 29 bit) */typedef __u32 canid_t;/* CAN payload length and DLC definitions according to ISO 11898-1 */#define CAN_MAX_DLC 8#define CAN_MAX_DLEN 8/* CAN FD payload length and DLC definitions according to ISO 11898-7 */#define CANFD_MAX_DLC 15#define CANFD_MAX_DLEN 64struct can_frame {canid_t can_id;  /* 32 bit CAN_ID + EFF/RTR/ERR flags */__u8    can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */__u8    data[CAN_MAX_DLEN] __attribute__((aligned(8)));};



命令行CAN发送命令: 

命令行提示:Wrong CAN-frame format! Try:    <can_id>#{R|data}          for CAN 2.0 frames    <can_id>##<flags>{data}    for CAN FD frames<can_id> can have 3 (SFF) or 8 (EFF) hex chars{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')<flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flagse.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311     1F334455#1122334455667788 / 123#R for remote transmission request.示例:cansend can0 1F334455#1122334455667788candump can0 5A1#1122334455667788

在一个终端通过cansend命令来发送数据帧,  另一个终端通过candump来测试回环发送: 


翻译内核Document/networking/can.txt

4.1  RAW protocol sockets with can_filters (SOCK_RAW)使用CAN_RAW socket类似与使用CAN字符驱动设备,为了满足multi user SocketCAN approach提供的新可能性,在建立RAW socket被bind的时候设置了一些合理的默认值:1. 滤波器被设置成接收所有消息2. socket只接收有效的数据帧(不接收错误帧)3. 默认开启回环功能4. socket不接收自己发出的数据帧(在回环模式)默认的设置在bind socket前或者bind socket后可以被改变,如果对CAN_RAW socket的参考设置选项,需要包含头文件include <linux/can/raw.h>,这个头文件的主要内容是:  54 enum { 55     CAN_RAW_FILTER = 1, /* set 0 .. n can_filter(s)          */ 56     CAN_RAW_ERR_FILTER, /* set filter for error frames       */ 57     CAN_RAW_LOOPBACK,   /* local loopback (default:on)       */ 58     CAN_RAW_RECV_OWN_MSGS,  /* receive my own msgs (default:off) */ 59     CAN_RAW_FD_FRAMES,  /* allow CAN FD frames (default:off) */ 60     CAN_RAW_JOIN_FILTERS,   /* all filters must match to trigger */ 61 };4.1.1 RAW socket option CAN_RAW_FILTER  使用CAN_RAW socket的CAN帧接收可以通过定义0~n个带有CAN_RAW_FILTER socket选项的滤波器来进行控制    CAN滤波器结构图被定义在 <include/linux/can.h>中:  struct can_filter {          canid_t can_id;          canid_t can_mask;  };  滤波器匹配的定义:                  <received_can_id> & mask == can_id & mask   ######################################  ###  其实这里所说的滤波器是软件概念上的  ###  ######################################  这个形式是一个CAN总线控制器硬件滤波器的语义模拟.  在这个语义中当can_filter结构体的can_id元素的CAN_INV_FILTER位被置位的时候滤波器可以被反转.  与CAN控制器硬件滤波器相反,用户可以分别对每一个打开的socket设置0~n个接收滤波器:  这里反应的硬件滤波器和软件滤波器的区别<<<<<<<    struct can_filter rfilter[2];    rfilter[0].can_id   = 0x123;    rfilter[0].can_mask = CAN_SFF_MASK;    rfilter[1].can_id   = 0x200;    rfilter[1].can_mask = 0x700;    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));    在选择的CAN_RAW socket上禁止接收CAN帧:    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);        ##################################################################    ######### 如果不设置滤波器那么socket是不会接收CAN数据帧的  ##############    ##################################################################    将滤波器设置为零滤波器已经过时了,因为不读取数据会导致原始套接字丢弃接收到的CAN帧。    但是有了这个“只发送”的用例,我们可以删除内核中的接收列表来节省一点(真的很少!)CPU使用率。4.1.1.1 CAN filter usage optimisation    在CAN帧接收的时,CAN滤波器在每一个设备的滤波器列表都被处理。为了减少walking through    滤波器列表时必须执行的检查数量,当滤波器订阅关注一个单独的CAN ID时,    CAN core提供了一个优化的滤波器处理方法        对于可能2048种SFF(标准帧)identifiers标识符,这些标识符被用作不用进一步check而直接访问相应的订阅列表的索引    对于2^29种可能的EFF(扩展帧),一个10位的XOR folding被用作哈希函数来恢复EFF表索引    #######  这里非常重要  #######    为了从单个CAN标识符的优化过的滤波器中受益: 1.设置CAN_SFF_MASK或CAN_EFF_MASK 到 can_filter.mask,                                         2.设置CAN_EFF_FLAG 和 CAN_RTR_FLAG位。    can_filter.mask中的一个CAN_EFF_FLAG位设置清楚地说明了是否订阅了SFF或EFF CAN ID。    例如:    rfilter[0].can_id   = 0x123;    rfilter[0].can_mask = CAN_SFF_MASK;    SFF frames with CAN ID 0x123 和 EFF frames with 0xXXXXX123 都能接收(pass).    为了只过滤 0x123 (SFF) and 0x12345678 (EFF) 这两个CAN ID.     the filter has to be defined in this way to benefit from the optimized filters:    struct can_filter rfilter[2];    rfilter[0].can_id   = 0x123;    rfilter[0].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_SFF_MASK);    rfilter[1].can_id   = 0x12345678 | CAN_EFF_FLAG;    rfilter[1].can_mask = (CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_EFF_MASK);    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));    ###############################################################    #######################    宏定义    ###########################    /* special address description flags for the CAN_ID */    #define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */    #define CAN_RTR_FLAG 0x40000000U /* remote transmission request */    #define CAN_ERR_FLAG 0x20000000U /* error message frame */    /* valid bits in CAN ID for frame formats */      #define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */    #define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */    #define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */4.1.2 RAW socket option >>>CAN_RAW_ERR_FILTER    设置接收错误帧的方法:        can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF );    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,               &err_mask, sizeof(err_mask));4.1.3 RAW socket option >>>CAN_RAW_LOOPBACK    为了满足多用户需求,本地回环默认开启. 在某些应用实例中,回环功能可以被禁止(针对每个socket)    int loopback = 0; /* 0 = disabled, 1 = enabled (default) */    setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));4.1.4 RAW socket option >>>CAN_RAW_RECV_OWN_MSGS    当本地回环被使能的时候,所用的发出的CAN数据帧被回环到打开的CAN sockets,这些socket注册了这个CAN_ID在这个给定的接口上    用于满足多用户需求(什么意思???)    接收自己发出的CAN数据包默认是不需要的,因此这个选项默认关闭    int recv_own_msgs = 1; /* 0 = disabled (default), 1 = enabled */    setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,               &recv_own_msgs, sizeof(recv_own_msgs));4.1.5 RAW socket option >>>CAN_RAW_FD_FRAMES    CAN_RAW sockets的CAN FD功能可以通过这个选项来使能. CAN FD是CAN总线协议的一个拓展    CAN_RAW_FD_FRAMES默认关闭. 如果老内核的CAN_RAW socket不支持这个选项,切换CAN_RAW_FD_FRAMES选项将返回 -ENOPROTOOPT错误    CAN_RAW_FD_FRAMES一旦被使能,应用程序既可以发送CAN数据帧也可以发送CAN FD数据帧.    另一方面,应用程序必须处理CAN数据帧和CAN FD数据帧        CAN_RAW_FD_FRAMES enabled:  CAN_MTU and CANFD_MTU are allowed    CAN_RAW_FD_FRAMES disabled: only CAN_MTU is allowed (default)  Example:    [ remember: CANFD_MTU == sizeof(struct canfd_frame) ]    struct canfd_frame cfd;    nbytes = read(s, &cfd, CANFD_MTU); //注意这里的长度参数是: CANFD_MTU    if (nbytes == CANFD_MTU) {            printf("got CAN FD frame with length %d\n", cfd.len);    /* cfd.flags contains valid data */    } else if (nbytes == CAN_MTU) {            printf("got legacy CAN frame with length %d\n", cfd.len);    /* cfd.flags is undefined */    } else {            fprintf(stderr, "read: invalid CAN(FD) frame\n");            return 1;    }    /* the content can be handled independently from the received MTU size */    printf("can_id: %X data length: %d data: ", cfd.can_id, cfd.len);    for (i = 0; i < cfd.len; i++)            printf("%02X ", cfd.data[i]);    当以CANFD_MTU作为参数调用read时,仅仅当从这个socket读取到一个有效CAN帧(不是CAN FD帧)的时候返回CAN_MTU字节到CAN FD结构体,    canfd_frame.flags数据域在can_frame结构体中并没有指定,因此canfd_frame.flags仅在CANFD_MTU大小的CAN FD帧中有效    实现提示:    1. 要构建一个CAN FD的应用程序,使用struct canfd_frame作为基于CAN_RAW的应用程序的基本CAN数据结构    2. 当在较旧的Linux内核上执行应用程序时,切换CAN_RAW_FD_FRAMES套接字选项将返回一个错误,没问题。       您将获得传统的CAN帧或CAN FD帧,并且可以以相同的方式处理它们。4.1.6 RAW socket option >>>CAN_RAW_JOIN_FILTERS    >>>>JOIN 这里可以理解为联合    CAN_RAW socket可以设置多个指定CAN ID的滤波器,其用于af_can.c中的多个滤波器进行处理.    这些滤波器彼此独立,在应用时会导致"逻辑或"滤波器    >>>> CAN_RAW_JOIN_FILTERS 这个选项用于加入给定的CAN滤波器,这样只有匹配所有的CAN滤波器的CAN数据帧才能进入用户空间    这个语义将滤波器的逻辑由逻辑或(OR)改成逻辑与(AND)    当滤波器组是滤波器的组合,其中设置了CAN_INV_FILTER标志以从输入流量中截取单个CAN ID或CAN ID范围时,这是特别有用的。4.1.7 RAW socket returned message flags    当调用recvmsg()函数,msg->msg_flags可能包含下列flags:    MSG_DONTROUTE: set when the received frame was created on the local host.    MSG_CONFIRM: 当CAN驱动支持驱动层的数据帧echo时,这个flag可以解释成作为'传输确认'.                 为了接收这些的数据帧,CAN_RAW_RECV_OWN_MSGS必须被设置

4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)    广播管理协议提供一个基于命令的配置接口用于在内核空间的滤波和发送CAN消息    可以使用接收过滤器来减少对频繁消息的采样、 用于检测消息内容改变事件、包长度改变事件以及监控接收消息超时.    可以在运行时创建或改变==>CAN数据帧周期性发送任务或者一个发送序列,消息内容和两个可能的发送间隔都可以被改变    A BCM socket并不是为使用已知的can_frame结构体发送单独的数据帧而准备的. 取而代之,定义了一种特殊的BCM配置消息    基本的配置消息(configuration message)用于:1.与broadcast manager通信 2.在linux/can/bcm.h中定义的可使用的操作    BCM消息的结构体定义:   struct bcm_msg_head {            __u32 opcode;                   /* command */            __u32 flags;                    /* special flags */            __u32 count;                    /* run 'count' times with ival1 */            struct timeval ival1, ival2;    /* count and subsequent interval */            canid_t can_id;                 /* unique can_id for task */            __u32 nframes;                  /* number of can_frames following */            struct can_frame frames[0];    };    所有在从户空间发送给broadcast manager的消息都使用bcm_msg_head 结构体.    CAN_BCM socket创建后必须被connected 而不是bind.    下面的例子没做错误检查>>>/////////////////////////////////////////////////////////////    int s;    struct sockaddr_can addr;    struct ifreq ifr;    s = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);    strcpy(ifr.ifr_name, "can0");    ioctl(s, SIOCGIFINDEX, &ifr);    addr.can_family = AF_CAN;    addr.can_ifindex = ifr.ifr_ifindex;    connect(s, (struct sockaddr *)&addr, sizeof(addr));    (..)//////////////////////////////////////////////////////////////   broadcast manager socket有能力并行处理==>1.任意数量的传输或者 2.接收滤波器   不同的发送/接收任务在BCM消息中使用唯一的can_id来进行区分   然而额外的CAN_BCM sockets被推荐用于==>在多个CAN接口上通信   当broadcast manager socket被bind to 'any' CAN interface (==> 接口索引被设置为0)   这个接口上所有已经配置的滤波器都会被apply,除非使用sendto()函数overrule the 'any' CAN interface index   使用recvfrom() 而不是read()用于retrieve BCM socket messages the originating CAN interface is provided in can_ifindex.4.2.1 Broadcast Manager operations   opcode定义了: 1. the operation for the broadcast manager to carry out  ==>BM执行的操作                2. details the broadcast managers response to several events, including user requests.  ==>BM的响应  Transmit Operations (user space to broadcast manager):    TX_SETUP:   Create (cyclic) transmission task.    TX_DELETE:  Remove (cyclic) transmission task, requires only can_id.    TX_READ:    Read properties of (cyclic) transmission task for can_id.    TX_SEND:    Send one CAN frame.  Transmit Responses (broadcast manager to user space):    TX_STATUS:  Reply to TX_READ request (transmission task configuration).    TX_EXPIRED: Notification when counter finishes sending at initial interval      'ival1'. Requires the TX_COUNTEVT flag to be set at TX_SETUP.  Receive Operations (user space to broadcast manager):    RX_SETUP:   Create RX content filter subscription.    RX_DELETE:  Remove RX content filter subscription, requires only can_id.    RX_READ:    Read properties of RX content filter subscription for can_id.  Receive Responses (broadcast manager to user space):    RX_STATUS:  Reply to RX_READ request (filter task configuration).    RX_TIMEOUT: Cyclic message is detected to be absent (timer ival1 expired).    RX_CHANGED: BCM message with updated CAN frame (detected content change).      Sent on first message received or on receipt of revised CAN messages.4.2.2 Broadcast Manager message flags    SETTIMER:           Set the values of ival1, ival2 and count    STARTTIMER:         Start the timer with the actual values of ival1, ival2      and count. Starting the timer leads simultaneously to emit a CAN frame.    TX_COUNTEVT:        Create the message TX_EXPIRED when count expires    TX_ANNOUNCE:        A change of data by the process is emitted immediately.    TX_CP_CAN_ID:       Copies the can_id from the message header to each      subsequent frame in frames. This is intended as usage simplification. For      TX tasks the unique can_id from the message header may differ from the      can_id(s) stored for transmission in the subsequent struct can_frame(s).    RX_FILTER_ID:       Filter by can_id alone, no frames required (nframes=0).    RX_CHECK_DLC:       A change of the DLC leads to an RX_CHANGED.    RX_NO_AUTOTIMER:    Prevent automatically starting the timeout monitor.    RX_ANNOUNCE_RESUME: If passed at RX_SETUP and a receive timeout occurred, a      RX_CHANGED message will be generated when the (cyclic) receive restarts.    TX_RESET_MULTI_IDX: Reset the index for the multiple frame transmission.    RX_RTR_FRAME:       Send reply for RTR-request (placed in op->frames[0]).4.2.3 Broadcast Manager transmission timers4.2.4 Broadcast Manager message sequence transmission4.2.5 Broadcast Manager receive filter timers  定时器值ival1或ival2可以在RX_SETUP处设置为非零值。当SET_TIMER标志被设置时,定时器被使能:  ival1: Send RX_TIMEOUT when a received message is not received again within    the given time. When START_TIMER is set at RX_SETUP the timeout detection    is activated directly - even without a former CAN frame reception.    当在给定的时间内没有收到消息时发送RX_TIMEOUT。    当START_TIMER设置为RX_SETUP时,即使没有以前的CAN帧接收,超时检测也会直接激活。  ival2: Throttle the received message rate down to the value of ival2. This    is useful to reduce messages for the application when the signal inside the    CAN frame is stateless as state changes within the ival2 periode may get    lost.    将收到的消息速率调低至ival2的值。当CAN帧内的信号是无状态的时,    这对于减少应用程序的消息很有用,因为ival2周期内的状态改变可能会丢失。4.2.6 Broadcast Manager multiplex message receive filter要filter多个消息序列中的内容改变,可以在一个RX_SETUP配置消息中传递an array of more than one CAN framesThe data bytes of the first CAN frame contain the mask of relevant bits that have to match in the subsequent CAN frames with the received CAN frame.If one of the subsequent CAN frames is matching the bits in that frame data  mark the relevant content to be compared with the previous received content.Up to 257 CAN frames (multiplex filter bit mask CAN frame plus 256 CAN  filters) can be added as array to the TX_SETUP BCM configuration message.    /* usually used to clear CAN frame data[] - beware of endian problems! */    #define U64_DATA(p) (*(unsigned long long*)(p)->data)    struct {            struct bcm_msg_head msg_head;            struct can_frame frame[5];    } msg;    msg.msg_head.opcode  = RX_SETUP;    msg.msg_head.can_id  = 0x42;    msg.msg_head.flags   = 0;    msg.msg_head.nframes = 5;    U64_DATA(&msg.frame[0]) = 0xFF00000000000000ULL; /* MUX mask */    U64_DATA(&msg.frame[1]) = 0x01000000000000FFULL; /* data mask (MUX 0x01) */    U64_DATA(&msg.frame[2]) = 0x0200FFFF000000FFULL; /* data mask (MUX 0x02) */    U64_DATA(&msg.frame[3]) = 0x330000FFFFFF0003ULL; /* data mask (MUX 0x33) */    U64_DATA(&msg.frame[4]) = 0x4F07FC0FF0000000ULL; /* data mask (MUX 0x4F) */    write(s, &msg, sizeof(msg));  4.3 connected transport protocols (SOCK_SEQPACKET)  4.4 unconnected transport protocols (SOCK_DGRAM)5. SocketCAN core module-----------------------------------SocketCAN core 模块实现PF_CAN协议族. 在运行时CAN协议模块被core模块加载. core模块为CAN模块提供一个接口用于订阅所需的CAN IDs  5.1 can.ko module params  - stats_timer:  To calculate the SocketCAN core statistics ##计算统计  - debug: (removed since SocketCAN SVN r546)  5.2 procfs content  5.3 writing own CAN protocol modules    为了在PF_CAN协议族中实现一个新的协议,必须在include/linux/can.h中定义一个新的协议。    使用SocketCAN内核的原型和定义可以通过<include/linux/can/core.h>来访问    除了注册CAN协议和CAN设备通知程序链的功能之外,还有一些功能用于订阅CAN接口接收到的CAN帧并发送CAN帧:    can_rx_register   - subscribe CAN frames from a specific interface    can_rx_unregister - unsubscribe CAN frames from a specific interface    can_send          - transmit a CAN frame (optional with local loopback)