转自:http://velep.com/archives/1177.html
最近写了个自认为不错的基于linux socket can程序,主要功能:
- 程序具备全部CAN功能,包括CAN标准帧/扩展帧接收与发送、CAN总线错误判断、环回等功能
- 适用基于LINUX SOCKET机制实现的CAN接口,可用于嵌入式LINUX的CAN测试
- 程序采用标准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 |
} |
使用示例
程序源码
下载地址:linux socket can程序cantool