linux socket can程序cantool

转自:http://velep.com/archives/1177.html

最近写了个自认为不错的基于linux socket can程序,主要功能:

  1. 程序具备全部CAN功能,包括CAN标准帧/扩展帧接收与发送、CAN总线错误判断、环回等功能
  2. 适用基于LINUX SOCKET机制实现的CAN接口,可用于嵌入式LINUX的CAN测试
  3. 程序采用标准LINUX命令行参数选项形式,接受用户参数

现把源码进行分享

功能介绍

SOCKET CAN工具程序 – Ver1.0 Build Nov 20 2015, COPYRIGHT (C) 2015 reille @ http://velep.com/

介绍:
本SOCKET CAN程序具备全部CAN功能,包括CAN标准帧/扩展帧接收与发送、CAN总线错误判断、环回等功能
适用基于LINUX SOCKET机制实现的CAN接口,可用于嵌入式LINUX中的CAN测试程序
程序采用标准LINUX命令行参数选项形式,接受用户参数

用法: ./cantool [选项]…

选项:
-p, –port=CAN接口号 指定CAN接口号,从1开始, 默认为 1(即CAN1接口)
-b, –baud=波特率 指定CAN通讯波特率,单位Kbps,默认为 250 Kbps
可用波特率:5,10,20,40,50,80,100,125,200,250,400,500,666,800,1000

-i, –frame-id=帧ID 指定CAN发送帧ID(Hex格式), 默认为1801F456
-d, –data=数据 指定CAN发送帧数据, 默认为:00 01 FF FF FF FF FF FF,字节数据间以空格隔开
-f, –freq=间隔 指定CAN帧发送间隔,单位ms, 默认为250ms, 最小值为1ms
-t, –times=次数 指定CAN帧发送次数, 默认为0次
-s, 指定CAN发送帧为标准帧, 默认为发送扩展帧
-I, 帧ID每发送一帧递增, 默认不递增
-g, 发送数据每发送一帧递增, 默认不递增
-l, 发送数据时本地环回, 默认不环回

–help 显示此帮助信息并退出

注意,以下CAN帧ID作为系统使用:
0x00000001 – TX timeout (by netdevice driver)
0x00000002 – lost arbitration / data[0]
0x00000004 – controller problems / data[1]
0x00000008 – protocol violations / data[2..3]
0x00000010 – transceiver status / data[4]
0x00000020 – received no ACK on transmission
0x00000040 – bus off
0x00000080 – bus error (may flood!)
0x00000100 – controller restarted

使用 Ctrl^C 组合键结束程序运行

 

部分源码

001 int main(int argc, char **argv)
002 {
003     S_CanFrame sendframe, recvframe;
004     byte *psendframe = (byte *)&sendframe;
005     byte *precvframe = (byte *)&recvframe;
006     u_canframe_data_t *psend_data = (u_canframe_data_t *)sendframe.data;
007     const int can_frame_len = sizeof(S_CanFrame);
008  
009     pid_t pid = -1;
010     int   status;
011  
012     int  ret = 0;
013     char buf[128] = {0};
014     bool carry_bit = false;// 进位标志
015  
016     int segment_id;//id for shared memo
017  
018  
019     if (parse_options(argc, argv))
020     {
021         usage();    return  0;
022     }
023  
024     if (!find_can(port))
025     {
026         sprintf(buf, "\n\t错误:CAN%d设备不存在\n\n", port + 1);
027         panic(buf);
028         return  -1;
029     }
030  
031     close_can(port);// 必须先关闭CAN,才能成功设置CAN波特率
032     set_bitrate(port, bitrate);// 操作CAN之前,先要设置波特率
033     open_can(port, bitrate);
034  
035     send_socket_fd = socket_connect(port);
036     recv_socket_fd = socket_connect(port);
037     //printf("send_socket_fd = %d, recv_socket_fd = %d\n", send_socket_fd, recv_socket_fd);
038     if (send_socket_fd < 0 || send_socket_fd < 0)
039     {
040         disconnect(&send_socket_fd);
041         disconnect(&recv_socket_fd);
042         panic("\n\t打开socket can错误\n\n");
043         return  -1;
044     }
045     set_can_filter();
046     set_can_loopback(send_socket_fd, lp);
047  
048     printf_head();
049  
050     memset(&sendframe, 0x00, sizeof(sendframe));
051     memset(&recvframe, 0x00, sizeof(recvframe));
052  
053     if (extended_frame) // 指定发送帧类型:扩展帧或标准帧
054     {
055         sendframe.can_id = (send_frame_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
056     }
057     else
058     {
059         sendframe.can_id = (send_frame_id & CAN_SFF_MASK);
060     }
061     sendframe.can_dlc = dlc;
062     memcpy(sendframe.data, send_frame_data, dlc);
063  
064      
065     segment_id = shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR);// allocate memo
066     pframeno = (int *)shmat(segment_id, NULL, 0);// attach the memo
067     if (pframeno == NULL)
068     {
069         panic("\n\t创建共享内存失败\n\n");
070         return  -1;
071     }
072     *pframeno = 1;
073  
074     run = true;
075  
076     pid = fork();
077     if(pid == -1)
078     {
079         panic("\n\t创建进程失败\n\n");
080         return  -1;
081     }
082     else if(pid == 0) // 子进程,用于发送CAN帧
083     {
084         while (run && (send_frame_times > 0))
085         {
086             ret = send_frame(send_socket_fd, (char *)&sendframe, sizeof(sendframe));
087             printf_frame(sendframe.can_id & CAN_EFF_MASK, sendframe.data, sendframe.can_dlc,
088                 ((sendframe.can_id & CAN_EFF_FLAG) ? true false),
089                 ret > 0 ? true false,
090                 true);
091             delay_ms(send_frame_freq_ms);
092  
093             if (send_frame_id_inc_en)
094             {
095                 sendframe.can_id++;
096                 if (extended_frame)
097                 {
098                     sendframe.can_id = (sendframe.can_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
099                 }
100                 else
101                 {
102                     sendframe.can_id = (sendframe.can_id & CAN_SFF_MASK);
103                 }
104             }
105  
106             if (send_frame_data_inc_en && dlc > 0)
107             {
108                 if (dlc > 4 && psend_data->s.dl == ((__u32)0xFFFFFFFF))
109                 {
110                     carry_bit = true;// 发生进位
111                 }
112                 psend_data->s.dl++;
113  
114                 if (dlc <= 4)
115                 {
116                     if (psend_data->s.dl >= (1 << (dlc * 8)))
117                     {
118                         psend_data->s.dl = 0;
119                     }
120                 }
121                 else if (dlc <= 8)
122                 {
123                     if (carry_bit)
124                     {
125                         psend_data->s.dh++;
126                         if (psend_data->s.dh >= (1 << ((dlc - 4) * 8)))
127                         {
128                             psend_data->s.dh = 0;
129                         }
130  
131                         carry_bit = false;
132                     }
133                 }
134             }
135  
136             send_frame_times--;
137         }
138  
139         exit(0);
140     }
141     else // 父进程,接收CAN帧
142     {
143         install_sig();
144  
145         while (run)
146         {
147             memset(precvframe, 0x00, can_frame_len);
148             ret = recv_frame(recv_socket_fd, precvframe, can_frame_len, 5 * 1000);
149             if (ret > 0)
150             {
151                 printf_frame(recvframe.can_id & CAN_EFF_MASK, recvframe.data, recvframe.can_dlc,
152                     ((recvframe.can_id & CAN_EFF_FLAG) ? true false),
153                     true,
154                     false);
155             }
156         }
157  
158         while(((pid = wait(&status)) == -1) && (errno == EINTR))
159         {
160             delay_ms(10);
161         }
162     }
163  
164     disconnect(&send_socket_fd);
165     disconnect(&recv_socket_fd);
166  
167     shmdt(pframeno);// detach memo
168     shmctl(segment_id, IPC_RMID, NULL);// remove
169  
170     return  0;
171 }

使用示例

cantool使用示例

cantool使用示例

程序源码

下载地址:linux socket can程序cantool


猜你喜欢

转载自blog.csdn.net/ppdyhappy/article/details/79461205