canutils-4.0.6-cansend源码解析

一、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

  1.  <msg>   //msg用空格隔开最多8个字节
     例:cansend can0 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88  //默认标准帧 ID为1
    
  2.  -i CANID <msg>//指定CANID
     例:cansend can0 -i 0x1f 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88
    
  3.  -r //发送远程帧
    
  4.  -e//发送扩展帧
    
  5.  -f   <FAMILY>//指定协议族 默认是PF_CAN对于CAN来说难道还有其他协议族?AF_CAN?
    
  6.  -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
    
  7.  -p  <PROTO>
     --protocol=PROTO
    
  8.  -v //输出更多的信息
    
  9.  -h //帮助说明
    
  10. –version//查看版本号
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值