]> rtime.felk.cvut.cz Git - sojka/can-utils.git/blob - candump.c
changed user space programs to use new include files.
[sojka/can-utils.git] / candump.c
1 /*
2  *  $Id$
3  */
4
5 /*
6  * candump.c
7  *
8  * Copyright (c) 2002-2005 Volkswagen Group Electronic Research
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, the following disclaimer and
16  *    the referenced file 'COPYING'.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of Volkswagen nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * Alternatively, provided that this notice is retained in full, this
25  * software may be distributed under the terms of the GNU General
26  * Public License ("GPL") version 2 as distributed in the 'COPYING'
27  * file from the main directory of the linux kernel source.
28  *
29  * The provided data structures and external interfaces from this code
30  * are not restricted to be used by modules with a GPL compatible license.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
39  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
40  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
42  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
43  * DAMAGE.
44  *
45  * Send feedback to <socketcan-users@lists.berlios.de>
46  *
47  */
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <signal.h>
54 #include <ctype.h>
55 #include <libgen.h>
56 #include <time.h>
57
58 #include <sys/time.h>
59 #include <sys/types.h>
60 #include <sys/socket.h>
61 #include <sys/ioctl.h>
62 #include <sys/uio.h>
63 #include <net/if.h>
64
65 #include <linux/can.h>
66 #include <linux/can/raw.h>
67
68 #include "terminal.h"
69
70 #define USE_RECVFROM /* use read() or recvfrom() syscall */
71
72 #define MAXDEV 6 /* change sscanf()'s manually if changed here */
73 #define ANYDEV "any"
74 #define ANL "\r\n" /* newline in ASC mode */
75
76 #define BOLD    ATTBOLD
77 #define RED     ATTBOLD FGRED
78 #define GREEN   ATTBOLD FGGREEN
79 #define YELLOW  ATTBOLD FGYELLOW
80 #define BLUE    ATTBOLD FGBLUE
81 #define MAGENTA ATTBOLD FGMAGENTA
82 #define CYAN    ATTBOLD FGCYAN
83
84 static const char col_on [MAXDEV][19] = {BOLD, MAGENTA, GREEN, BLUE, CYAN, RED};
85 static const char col_off [] = ATTRESET;
86
87 #define MAXANI 8
88 const char anichar[MAXANI] = {'|', '/', '-', '\\', '|', '/', '-', '\\'};
89
90 extern int optind, opterr, optopt;
91
92 static volatile int running = 1;
93
94 void print_usage(char *prg)
95 {
96     fprintf(stderr, "Usage: %s [can-interfaces]\n", prg);
97     fprintf(stderr, "Options: -m <mask>   (default 0x00000000)\n");
98     fprintf(stderr, "         -v <value>  (default 0x00000000)\n");
99     fprintf(stderr, "         -i <0|1>    (inv_filter)\n");
100     fprintf(stderr, "         -t <type>   (timestamp: Absolute/Delta/Zero)\n");
101     fprintf(stderr, "         -c          (color mode)\n");
102     fprintf(stderr, "         -s <level>  (silent mode - 1: animation 2: nothing)\n");
103     fprintf(stderr, "         -b <can>    (bridge mode - send received frames to <can>)\n");
104     fprintf(stderr, "         -a          (create ASC compatible output)\n");
105     fprintf(stderr, "         -1          (increment interface numbering in ASC mode)\n");
106     fprintf(stderr, "         -A          (enable ASCII output)\n");
107     fprintf(stderr, "\n");
108     fprintf(stderr, "When using more than one CAN interface the options\n");
109     fprintf(stderr, "m/v/i have comma seperated values e.g. '-m 0,7FF,0'\n");
110     fprintf(stderr, "Use interface name '%s' to receive from all can-interfaces\n", ANYDEV);
111 }
112
113 void sigterm(int signo)
114 {
115     running = 0;
116 }
117
118 int main(int argc, char **argv)
119 {
120     fd_set rdfs;
121     int s[MAXDEV];
122     int bridge = 0;
123     canid_t mask[MAXDEV] = {0};
124     canid_t value[MAXDEV] = {0};
125     int inv_filter[MAXDEV] = {0};
126     char devname[MAXDEV][IFNAMSIZ];
127     unsigned char timestamp = 0;
128     unsigned char silent = 0;
129     unsigned char silentani = 0;
130     unsigned char color = 0;
131     unsigned char ascii = 0;
132     unsigned char asc = 0;
133     unsigned char asc_inc_channel = 0;
134     int max_devname_len = 0;
135     int opt, ret;
136     int currmax = 1; /* we assume at least one can bus ;-) */
137     struct sockaddr_can addr;
138     struct can_filter rfilter;
139     struct can_frame frame;
140     int nbytes, i, j;
141     struct ifreq ifr;
142
143     time_t currtime;
144     struct timeval tv, last_tv;
145
146     signal(SIGTERM, sigterm);
147     signal(SIGHUP, sigterm);
148     signal(SIGINT, sigterm);
149
150     last_tv.tv_sec = 0; /* init */
151
152     while ((opt = getopt(argc, argv, "m:v:i:b:s:ca1At:")) != -1) {
153         switch (opt) {
154         case 'm':
155             i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
156                        &mask[0], &mask[1], &mask[2],
157                        &mask[3], &mask[4], &mask[5]);
158             if (i > currmax)
159                 currmax = i;
160             break;
161
162         case 'v':
163             i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
164                        &value[0], &value[1], &value[2],
165                        &value[3], &value[4], &value[5]);
166             if (i > currmax)
167                 currmax = i;
168             break;
169
170         case 'i':
171             i = sscanf(optarg, "%d,%d,%d,%d,%d,%d",
172                        &inv_filter[0], &inv_filter[1], &inv_filter[2],
173                        &inv_filter[3], &inv_filter[4], &inv_filter[5]);
174             if (i > currmax)
175                 currmax = i;
176             break;
177
178         case 'b':
179             if (strlen(optarg) >= IFNAMSIZ) {
180                 printf("Name of CAN device '%s' is too long!\n\n", optarg);
181                 return 1;
182             }
183             else {
184                 if ((bridge = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
185                     perror("bridge socket");
186                     return 1;
187                 }
188                 addr.can_family = AF_CAN;
189                 strcpy(ifr.ifr_name, optarg);
190                 if (ioctl(bridge, SIOCGIFINDEX, &ifr) < 0)
191                     perror("SIOCGIFINDEX");
192                 addr.can_ifindex = ifr.ifr_ifindex;
193                 
194                 if (!addr.can_ifindex) {
195                     perror("invalid bridge interface");
196                     return 1;
197                 }
198
199                 if (bind(bridge, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
200                     perror("bridge bind");
201                     return 1;
202                 }
203             }
204             break;
205             
206         case 's':
207             silent = atoi(optarg);
208             break;
209
210         case 'c':
211             color = 1;
212             break;
213
214         case 'a':
215             asc = 1;
216             break;
217
218         case '1':
219             asc_inc_channel = 1;
220             break;
221
222         case 'A':
223             ascii = 1;
224             break;
225
226         case 't':
227             timestamp = optarg[0];
228             if ((timestamp != 'a') && (timestamp != 'A') && (timestamp != 'd') && (timestamp != 'z')) {
229                 printf("%s: unknown timestamp mode '%c' - ignored\n",
230                        basename(argv[0]), optarg[0]);
231                 timestamp = 0;
232             }
233             break;
234
235         case '?':
236             break;
237
238         default:
239             fprintf(stderr, "Unknown option %c\n", opt);
240             break;
241         }
242     }
243
244     if (optind == argc) {
245         print_usage(basename(argv[0]));
246         exit(0);
247     }
248         
249     /* count in options higher than device count ? */
250     if (optind + currmax > argc) {
251         printf("low count of CAN devices!\n");
252         return 1;
253     }
254
255     currmax = argc - optind; /* find real number of CAN devices */
256
257     if (currmax > MAXDEV) {
258         printf("More than %d CAN devices!\n", MAXDEV);
259         return 1;
260     }
261
262     for (i=0; i<currmax; i++) {
263
264 #ifdef DEBUG
265         printf("open %d '%s' m%08X v%08X i%d.\n",
266                i, argv[optind+i], mask[i], value[i], inv_filter[i]);
267 #endif
268
269         if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
270             perror("socket");
271             return 1;
272         }
273
274         if (mask[i] || value[i]) {
275
276             if (!(asc)) /* this output is not asc compatible! */
277                 printf("CAN ID filter[%d] for %s set to mask = %08X, value = %08X %s\n",
278                        i, argv[optind+i], mask[i], value[i],
279                        (inv_filter[i]) ? "(inv_filter)" : "");
280
281             rfilter.can_id   = value[i];
282             rfilter.can_mask = mask[i];
283             if (inv_filter[i])
284                 rfilter.can_id |= CAN_INV_FILTER;
285
286             setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
287         }
288
289         j = strlen(argv[optind+i]);
290
291         if (!(j < IFNAMSIZ)) {
292             printf("name of CAN device '%s' is too long!\n", argv[optind+i]);
293             return 1;
294         }
295
296         strcpy(devname[i], argv[optind+i]);
297
298         if (j > max_devname_len)
299             max_devname_len = j; /* for nice printing */
300
301         addr.can_family = AF_CAN;
302
303         if (strcmp(ANYDEV, argv[optind+i])) {
304             strcpy(ifr.ifr_name, argv[optind+i]);
305             if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0)
306                 perror("SIOCGIFINDEX");
307             addr.can_ifindex = ifr.ifr_ifindex;
308         }
309         else
310             addr.can_ifindex = 0; /* any can interface */
311
312         if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
313             perror("bind");
314             return 1;
315         }
316     }
317
318     if (asc) {
319         char datestring[40];
320
321         /* print banner for ASC mode */
322
323         if (timestamp != 'd') /* delta time is allowed, else ... */
324             timestamp = 'z'; /* ASC-files always start with zero time */
325
326         if (time(&currtime) == (time_t)-1) {
327             perror("time");
328             return 1;
329         }
330         strncpy(datestring, ctime(&currtime), 39); /* copy to private buffer */
331         datestring[strlen(datestring)-1] = 0; /* chop off trailing newline */
332         printf("date %s%s", datestring, ANL); /* print with own new line representation */
333
334         printf("base hex  timestamps %s%s", (timestamp == 'd')?"relative":"absolute", ANL);
335         printf("no internal events logged%s", ANL);
336         fflush(stdout);
337     }
338
339     while (running) {
340
341         FD_ZERO(&rdfs);
342
343         for (i=0; i<currmax; i++)
344             FD_SET(s[i], &rdfs);
345
346         if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, NULL)) < 0) {
347             //perror("select");
348             running = 0;
349             continue;
350         }
351
352         for (i=0; i<currmax; i++) {
353
354             if (FD_ISSET(s[i], &rdfs)) {
355
356 #ifdef USE_RECVFROM
357                 socklen_t len = sizeof(addr);
358                 if ((nbytes = recvfrom(s[i], &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, &len)) < 0) {
359 #else
360                 if ((nbytes = read(s[i], &frame, sizeof(struct can_frame))) < 0) {
361 #endif
362                     perror("read");
363                     return 1;
364                 } else if (nbytes < sizeof(struct can_frame)) {
365                     fprintf(stderr, "read: incomplete CAN frame\n");
366                     return 1;
367                 } else {
368                     if (bridge) {
369                         if ((nbytes = write(bridge, &frame, sizeof(struct can_frame))) < 0) {
370                             perror("bridge write");
371                             return 1;
372                         } else if (nbytes < sizeof(struct can_frame)) {
373                             fprintf(stderr, "bridge write: incomplete CAN frame\n");
374                             return 1;
375                         }
376                     }
377                     
378                     if (silent){
379                       if (silent == 1)
380                         printf("%c\b", anichar[silentani%=MAXANI]), silentani++;
381                     }
382                     else {
383                       
384                         switch (timestamp) {
385
386                         case 'a': /* absolute with timestamp */
387                             if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
388                                 perror("SIOCGSTAMP");
389                             if (asc)
390                                 printf("%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
391                             else
392                                 printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
393                             break;
394
395                         case 'A': /* absolute with date */
396                             {
397                                 struct tm tm;
398                                 char timestring[25];
399                                 if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
400                                     perror("SIOCGSTAMP");
401                                 tm = *localtime(&tv.tv_sec);
402                                 strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
403                                 if (asc)
404                                     printf("%s.%04ld ", timestring, tv.tv_usec/100);
405                                 else
406                                     printf("(%s.%06ld) ", timestring, tv.tv_usec);
407                             }
408                             break;
409
410                         case 'd': /* delta */
411                         case 'z': /* starting with zero */
412                             {
413                                 struct timeval diff;
414
415                                 if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
416                                     perror("SIOCGSTAMP");
417                                 if (last_tv.tv_sec == 0)   /* first init */
418                                     last_tv = tv;
419                                 diff.tv_sec  = tv.tv_sec  - last_tv.tv_sec;
420                                 diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
421                                 if (diff.tv_usec < 0)
422                                     diff.tv_sec--, diff.tv_usec += 1000000;
423                                 if (diff.tv_sec < 0)
424                                     diff.tv_sec = diff.tv_usec = 0;
425                                 if (asc)
426                                     printf("%4ld.%04ld ", diff.tv_sec, diff.tv_usec/100);
427                                 else
428                                     printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
429                                 
430                                 if (timestamp == 'd')
431                                     last_tv = tv; /* update for delta calculation */
432                             }
433                             break;
434
435                         default: /* no timestamp output */
436                             break;
437                         }
438
439                         if (asc) {
440                             char id[10];
441
442                             printf("%-2d ", i + asc_inc_channel); /* channel number - left aligned */
443
444                             sprintf(id, "%X%c", frame.can_id & CAN_EFF_MASK,
445                                     (frame.can_id & CAN_EFF_FLAG)?'x':' ');
446                             printf("%-15s Rx   ", id);
447
448                             if (frame.can_id & CAN_RTR_FLAG)
449                                 printf("r"); /* RTR frame: nothing else to print */
450                             else {
451                                 printf("d %d ", frame.can_dlc); /* data frame */
452
453                                 for (j = 0; j < frame.can_dlc; j++) {
454                                     printf("%02X ", frame.data[j]);
455                                 }
456                             }
457                             printf("%s", ANL);
458                         }
459                         else {
460                             printf(" %s",(color)?col_on[i]:"");
461 #ifdef USE_RECVFROM
462                             ifr.ifr_ifindex = addr.can_ifindex;
463                             if (ioctl(s[i], SIOCGIFNAME, &ifr) < 0)
464                                 perror("SIOCGIFNAME");
465
466                             if (max_devname_len < strlen(ifr.ifr_name))
467                                 max_devname_len = strlen(ifr.ifr_name);
468
469                             printf("%*s", max_devname_len, ifr.ifr_name);
470 #else
471                             printf("%*s", max_devname_len, devname[i]); /* device name */
472 #endif
473                             printf("%s  ",(color)?col_off:"");
474                             if (frame.can_id & CAN_EFF_FLAG)
475                                 printf("%8X  ", frame.can_id & CAN_EFF_MASK);
476                             else
477                                 printf("%3X  ", frame.can_id & CAN_SFF_MASK);
478
479                             printf("[%d] ", frame.can_dlc);
480
481                             for (j = 0; j < frame.can_dlc; j++) {
482                                 printf("%02X ", frame.data[j]);
483                             }
484                             if (ascii) {
485                                 printf("%*s", 3*(8-frame.can_dlc)+3, "'");
486                                 for (j = 0; j < frame.can_dlc; j++)
487                                     if ((frame.data[j] > 0x1F) && (frame.data[j] < 0x7F))
488                                         putchar(frame.data[j]);
489                                     else
490                                         putchar('.');
491                                 printf("' ");
492                             }
493                             if (frame.can_id & CAN_RTR_FLAG)
494                                 printf("remote request");
495                             printf("\n");
496                         }
497                     }
498                     fflush(stdout);
499                 }
500             }
501         }
502     }
503
504     for (i=0; i<currmax; i++)
505         close(s[i]);
506
507     if (bridge)
508       close(bridge);
509
510     return 0;
511 }