一、cansend源码解析
1 #include <can_config.h>
2
3 #include <getopt.h>
4 #include <libgen.h>
5 #include <signal.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <limits.h>
11
12 #include <net/if.h>
13
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <sys/types.h>
17 #include <sys/uio.h>
18
19 #include <linux/can.h>
20 #include <linux/can/raw.h>
21
22 extern int optind, opterr, optopt;
23
24 static void print_usage(char *prg)
25 {
26 fprintf(stderr,
27 "Usage: %s [<can-interface>] [Options] <can-msg>\n"
28 "<can-msg> can consist of up to 8 bytes given as a space separated list\n" //can-msg可以包含最多8个用空格隔开的字符
29 "Options:\n"
30 " -i, --identifier=ID CAN Identifier (default = 1)\n" //指定ID,默认CAN ID 1
31 " -r --rtr send remote request\n" //发送rtr
32 " -e --extended send extended frame\n" //发送扩展帧
33 " -f, --family=FAMILY Protocol family (default PF_CAN = %d)\n"//指定协议族
34 " -t, --type=TYPE Socket type, see man 2 socket (default SOCK_RAW = %d)\n"//指定socket type默认SOCK_RAW
35 " -p, --protocol=PROTO CAN protocol (default CAN_RAW = %d)\n"//指定协议
36 " -l send message infinite times\n"//发送信息 不限制次数 一直循环发送
37 " --loop=COUNT send message COUNT times\n"//指定发送次数 不指定的话默认循环1次
38 " -v, --verbose be verbose\n"//控制打印级别
39 " -h, --help this help\n"
40 " --version print version information and exit\n",
41 prg, PF_CAN, SOCK_RAW, CAN_RAW);
42 }
43
44 enum {
45 VERSION_OPTION = CHAR_MAX + 1,
46 };
47
48 int main(int argc, char **argv)
49 {
50 struct can_frame frame = {
51 .can_id = 1,
52 };
53 struct ifreq ifr;
54 struct sockaddr_can addr;
55 char *interface;
56 int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
57 int loopcount = 1, infinite = 0;
58 int s, opt, ret, i, dlc = 0, rtr = 0, extended = 0;
59 int verbose = 0;
60
61 struct option long_options[] = {
62 { "help", no_argument, 0, 'h' },//不加参数
63 { "identifier", required_argument, 0, 'i' },//必须要参数
64 { "rtr", no_argument, 0, 'r' },//不加参数
65 { "extended", no_argument, 0, 'e' },//不加参数
66 { "family", required_argument, 0, 'f' },//
67 { "protocol", required_argument, 0, 'p' },
68 { "type", required_argument, 0, 't' },
69 { "version", no_argument, 0, VERSION_OPTION},
70 { "verbose", no_argument, 0, 'v'},
71 { "loop", required_argument, 0, 'l'},//这里需要主要,长选项必须要加参数,与短选项相反
72 { 0, 0, 0, 0 },
73 };//所有长参数匹配后均会返回相应的第一个字符,等同与短参数的效果
74
75
76
77 while ((opt = getopt_long(argc, argv, "hf:t:p:vi:lre", long_options, NULL)) != -1) {
78 switch (opt) {//
79 case 'h':
80 print_usage(basename(argv[0]));//basename去掉路径 //打印使用说明
81 exit(0);
82
83 case 'f':
84 family = strtoul(optarg, NULL, 0);//指定协议族
85 break;
86
87 case 't':
88 type = strtoul(optarg, NULL, 0);//socket type
89 break;
90
91 case 'p':
92 proto = strtoul(optarg, NULL, 0);//协议
93 break;
94
95 case 'v':
96 verbose = 1;
97 break;
98
99 case 'l':
100 if (optarg)//非空代表长选项
101 loopcount = strtoul(optarg, NULL, 0);
102 else
103 infinite = 1;
104 break;
105 case 'i':
106 frame.can_id = strtoul(optarg, NULL, 0);
107 break;
108
109 case 'r':
110 rtr = 1;
111 break;
112
113 case 'e':
114 extended = 1;
115 break;
116
117 case VERSION_OPTION:
118 printf("cansend %s\n", VERSION);
119 exit(0);
120
121 default:
122 fprintf(stderr, "Unknown option %c\n", opt);
123 break;
124 }
125 }
126
127 if (optind == argc) {//意味着没有指定 can接口或者数据 不符合使用要求,就打印使用说明
128 print_usage(basename(argv[0]));
129 exit(0);
130 }
131
132 if (argv[optind] == NULL) {//代表没有按要求指定接口
133 fprintf(stderr, "No Interface supplied\n");
134 exit(-1);
135 }
136 interface = argv[optind];
137
138 printf("interface = %s, family = %d, type = %d, proto = %d\n",
139 interface, family, type, proto);
140
141 s = socket(family, type, proto);
142 if (s < 0) {
143 perror("socket");
144 return 1;
145 }
146 ///usr/include/linux/can.h 里有sockaddr_can的定义
147 #if 0
148 164 /**
149 165 * struct sockaddr_can - the sockaddr structure for CAN sockets
150 166 * @can_family: address family number AF_CAN.
151 167 * @can_ifindex: CAN network interface index.
152 168 * @can_addr: protocol specific address information
153 169 */
154 170 struct sockaddr_can {
155 171 __kernel_sa_family_t can_family;
156 172 int can_ifindex;
157 173 union {
158 174 /* transport protocol class address information (e.g. ISOTP) */
159 175 struct { canid_t rx_id, tx_id; } tp;
160 176
161 177 /* reserved for future CAN protocols address information */
162 178 } can_addr;
163 179 };
164 #endif
165 addr.can_family = family;
166 strcpy(ifr.ifr_name, interface);//要想获取接口索引首先需要接口名字,用来从网络名字空间查找对应的设备
167
168 /*
169 149 case SIOCGIFINDEX:
170 150 ifr->ifr_ifindex = dev->ifindex;
171 151 return 0;
172 */
173 if (ioctl(s, SIOCGIFINDEX, &ifr)) {//把 接口 的 索引 存入 ifr_ifindex.
174 perror("ioctl");
175 return 1;
176 }
177 addr.can_ifindex = ifr.ifr_ifindex;//
178
179 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {//绑定socket和通信地址
180 perror("bind");
181 return 1;
182 }
183
184 for (i = optind + 1; i < argc; i++) {//依次将数据填入frame.date
185 frame.data[dlc] = strtoul(argv[i], NULL, 0);
186 dlc++;
187 if (dlc == 8)
188 break;
189 }
190 frame.can_dlc = dlc;
191
192
193 if (extended) {
194 frame.can_id &= CAN_EFF_MASK;
195 frame.can_id |= CAN_EFF_FLAG;//设置帧格式
196 } else {
197 frame.can_id &= CAN_SFF_MASK;//标准帧
198 }
199
200 if (rtr)
201 frame.can_id |= CAN_RTR_FLAG;
202
203 if (verbose) {
204 printf("id: %d ", frame.can_id);//id
205 printf("dlc: %d\n", frame.can_dlc);//数据长度
206 for (i = 0; i < frame.can_dlc; i++)
207 printf("0x%02x ", frame.data[i]);
208 printf("\n");
209 }
210
211 while (infinite || loopcount--) {//循环发送
212 ret = write(s, &frame, sizeof(frame));
213 if (ret == -1) {
214 perror("write");
215 break;
216 }
217 }
218
219 close(s);
220 return 0;
221 }
二、cansend使用说明
cansend can0/1/2/3
-
<msg> //msg用空格隔开最多8个字节 例:cansend can0 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 //默认标准帧 ID为1
-
-i CANID <msg>//指定CANID 例:cansend can0 -i 0x1f 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
-
-r //发送远程帧
-
-e//发送扩展帧
-
-f <FAMILY>//指定协议族 默认是PF_CAN对于CAN来说难道还有其他协议族?AF_CAN?
-
-t <TYPE>//指定socket类型 153 /* particular protocols of the protocol family PF_CAN */ 154 #define CAN_RAW 1 /* RAW sockets */ 155 #define CAN_BCM 2 /* Broadcast Manager */ 156 #define CAN_TP16 3 /* VAG Transport Protocol v1.6 */ 157 #define CAN_TP20 4 /* VAG Transport Protocol v2.0 */ 158 #define CAN_MCNET 5 /* Bosch MCNet */ 159 #define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */ 160 #define CAN_NPROTO 7
-
-p <PROTO> --protocol=PROTO
-
-v //输出更多的信息
-
-h //帮助说明
- –version//查看版本号