]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
- added error frame support in lib.c
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 1 Jan 2007 18:29:52 +0000 (18:29 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 1 Jan 2007 18:29:52 +0000 (18:29 +0000)
- added sprint_* functions for CAN-frame output in lib.c / lib.h
- added comments / cosmetics

candump.c:
- removed support for the output in ASC representation (moved to log2asc.c)
- added option '-l' for logfile creation e.g. 'candump-2007-01-01_164123.log'
- added funtionality to terminate candump by pressing [ENTER] (not only ^C)
- added error frame support
- added color support even when reading from 'any'
- three different color levels (e.g. -c -c -c)
- making use if lib.c

cangen.c:
-  CAN frames generator for testing purposes (e.g. on vcanx)
(nice when you're on vacancy at the baltic sea and have no real CAN source :)

log2long.c:
- convert compact CAN frame representation into user readable representation

log2asc.c:
- convert compact CAN frame logfile to ASC logfile for 3rd party CAN tools

Next step: Create a tool to replay candump logfiles.

git-svn-id: svn://svn.berlios.de//socketcan/trunk@123 030b6a49-0b11-0410-94ab-b0dab22257f2

can-utils/Makefile
can-utils/candump.c
can-utils/cangen.c [new file with mode: 0644]
can-utils/cansend.c
can-utils/lib.c
can-utils/lib.h
can-utils/log2asc.c [new file with mode: 0644]
can-utils/log2long.c [new file with mode: 0644]

index 11fa7a1b8b5eba7719e1d266665aabbc74a038b7..441dbcb9ebdeafa8c8670ad1429cb7067eda2e65 100644 (file)
@@ -43,7 +43,7 @@
 CFLAGS    = -O2 -Wall -Wno-parentheses -I../kernel/2.6/include \
            -fno-strict-aliasing
 
-PROGRAMS = candump can-sniffer cansend
+PROGRAMS = candump can-sniffer cansend cangen log2long log2asc
 
 all: $(PROGRAMS)
 
@@ -51,8 +51,16 @@ clean:
        rm -f $(PROGRAMS) *.o
 
 distclean:
-       rm -f $(PROGRAMS) *~
+       rm -f $(PROGRAMS) *.o *~
 
-cansend.o: lib.h
+cansend.o:  lib.h
+cangen.o:   lib.h
+candump.o:  lib.h
+log2long.o: lib.h
+log2asc.o:  lib.h
 
-cansend: cansend.o lib.o
+cansend:  cansend.o  lib.o
+cangen:   cangen.o   lib.o
+candump:  candump.o  lib.o
+log2long: log2long.o lib.o
+log2asc:  log2asc.o  lib.o
index a680d2a52e5f9ab22da3d4a926cd8bdb0c38debf..444cf7d02c13ddde55f2227b5272d5620a073d6e 100644 (file)
@@ -66,8 +66,7 @@
 #include <linux/can/raw.h>
 
 #include "terminal.h"
-
-#define USE_RECVFROM /* use read() or recvfrom() syscall */
+#include "lib.h"
 
 #define MAXDEV 6 /* change sscanf()'s manually if changed here */
 #define ANYDEV "any"
 #define MAGENTA ATTBOLD FGMAGENTA
 #define CYAN    ATTBOLD FGCYAN
 
-static const char col_on [MAXDEV][19] = {BOLD, MAGENTA, GREEN, BLUE, CYAN, RED};
-static const char col_off [] = ATTRESET;
+const char col_on [MAXDEV][19] = {BOLD, MAGENTA, GREEN, BLUE, CYAN, RED};
+const char col_off [] = ATTRESET;
+
+static char devname[MAXDEV][IFNAMSIZ+1];
+static int  dindex[MAXDEV];
+static int  max_devname_len;
 
 #define MAXANI 8
 const char anichar[MAXANI] = {'|', '/', '-', '\\', '|', '/', '-', '\\'};
@@ -97,16 +100,16 @@ void print_usage(char *prg)
     fprintf(stderr, "Options: -m <mask>   (default 0x00000000)\n");
     fprintf(stderr, "         -v <value>  (default 0x00000000)\n");
     fprintf(stderr, "         -i <0|1>    (inv_filter)\n");
+    fprintf(stderr, "         -e <emask>  (mask for error frames)\n");
     fprintf(stderr, "         -t <type>   (timestamp: Absolute/Delta/Zero)\n");
     fprintf(stderr, "         -c          (color mode)\n");
+    fprintf(stderr, "         -a          (enable additional ASCII output)\n");
     fprintf(stderr, "         -s <level>  (silent mode - 1: animation 2: nothing)\n");
     fprintf(stderr, "         -b <can>    (bridge mode - send received frames to <can>)\n");
-    fprintf(stderr, "         -a          (create ASC compatible output)\n");
-    fprintf(stderr, "         -1          (increment interface numbering in ASC mode)\n");
-    fprintf(stderr, "         -A          (enable ASCII output)\n");
+    fprintf(stderr, "         -l          (log CAN-frames into file)\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "When using more than one CAN interface the options\n");
-    fprintf(stderr, "m/v/i have comma seperated values e.g. '-m 0,7FF,0'\n");
+    fprintf(stderr, "m/v/i/e have comma seperated values e.g. '-m 0,7FF,0'\n");
     fprintf(stderr, "Use interface name '%s' to receive from all can-interfaces\n", ANYDEV);
 }
 
@@ -115,6 +118,45 @@ void sigterm(int signo)
     running = 0;
 }
 
+int idx2dindex(int ifidx, int socket) {
+
+    int i;
+    struct ifreq ifr;
+
+    for (i=0; i<MAXDEV; i++) {
+       if (dindex[i] == ifidx)
+           return i;
+    }
+
+    /* create new interface index cache entry */
+
+    for (i=0; i < MAXDEV; i++)
+       if (!dindex[i]) /* free entry */
+           break;
+
+    if (i == MAXDEV) {
+       printf("BUG in interface index cache! MAXDEV?\n");
+       exit(1);
+    }
+
+    dindex[i] = ifidx;
+
+    ifr.ifr_ifindex = ifidx;
+    if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
+       perror("SIOCGIFNAME");
+
+    if (max_devname_len < strlen(ifr.ifr_name))
+       max_devname_len = strlen(ifr.ifr_name);
+
+    strcpy(devname[i], ifr.ifr_name);
+
+#ifdef DEBUG
+    printf("new index %d (%s)\n", i, devname[i]);
+#endif
+
+    return i;
+}
+
 int main(int argc, char **argv)
 {
     fd_set rdfs;
@@ -123,15 +165,13 @@ int main(int argc, char **argv)
     canid_t mask[MAXDEV] = {0};
     canid_t value[MAXDEV] = {0};
     int inv_filter[MAXDEV] = {0};
-    char devname[MAXDEV][IFNAMSIZ];
+    can_err_mask_t err_mask[MAXDEV] = {0};
     unsigned char timestamp = 0;
     unsigned char silent = 0;
     unsigned char silentani = 0;
     unsigned char color = 0;
     unsigned char ascii = 0;
-    unsigned char asc = 0;
-    unsigned char asc_inc_channel = 0;
-    int max_devname_len = 0;
+    unsigned char log = 0;
     int opt, ret;
     int currmax = 1; /* we assume at least one can bus ;-) */
     struct sockaddr_can addr;
@@ -139,9 +179,8 @@ int main(int argc, char **argv)
     struct can_frame frame;
     int nbytes, i, j;
     struct ifreq ifr;
-
-    time_t currtime;
     struct timeval tv, last_tv;
+    FILE *logfile = NULL;
 
     signal(SIGTERM, sigterm);
     signal(SIGHUP, sigterm);
@@ -149,7 +188,7 @@ int main(int argc, char **argv)
 
     last_tv.tv_sec = 0; /* init */
 
-    while ((opt = getopt(argc, argv, "m:v:i:b:s:ca1At:")) != -1) {
+    while ((opt = getopt(argc, argv, "m:v:i:e:t:cas:b:l")) != -1) {
        switch (opt) {
        case 'm':
            i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
@@ -175,6 +214,36 @@ int main(int argc, char **argv)
                currmax = i;
            break;
 
+       case 'e':
+           i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
+                      &err_mask[0], &err_mask[1], &err_mask[2],
+                      &err_mask[3], &err_mask[4], &err_mask[5]);
+           if (i > currmax)
+               currmax = i;
+           break;
+
+       case 't':
+           timestamp = optarg[0];
+           if ((timestamp != 'a') && (timestamp != 'A') &&
+               (timestamp != 'd') && (timestamp != 'z')) {
+               printf("%s: unknown timestamp mode '%c' - ignored\n",
+                      basename(argv[0]), optarg[0]);
+               timestamp = 0;
+           }
+           break;
+
+       case 'c':
+           color++;
+           break;
+
+       case 'a':
+           ascii = 1;
+           break;
+
+       case 's':
+           silent = atoi(optarg);
+           break;
+
        case 'b':
            if (strlen(optarg) >= IFNAMSIZ) {
                printf("Name of CAN device '%s' is too long!\n\n", optarg);
@@ -203,40 +272,14 @@ int main(int argc, char **argv)
            }
            break;
            
-       case 's':
-           silent = atoi(optarg);
-           break;
-
-       case 'c':
-           color = 1;
-           break;
-
-       case 'a':
-           asc = 1;
-           break;
-
-       case '1':
-           asc_inc_channel = 1;
-           break;
-
-       case 'A':
-           ascii = 1;
-           break;
-
-       case 't':
-           timestamp = optarg[0];
-           if ((timestamp != 'a') && (timestamp != 'A') && (timestamp != 'd') && (timestamp != 'z')) {
-               printf("%s: unknown timestamp mode '%c' - ignored\n",
-                      basename(argv[0]), optarg[0]);
-               timestamp = 0;
-           }
-           break;
-
-       case '?':
+       case 'l':
+           log = 1;
            break;
 
        default:
            fprintf(stderr, "Unknown option %c\n", opt);
+           print_usage(basename(argv[0]));
+           exit(1);
            break;
        }
     }
@@ -262,8 +305,9 @@ int main(int argc, char **argv)
     for (i=0; i<currmax; i++) {
 
 #ifdef DEBUG
-       printf("open %d '%s' m%08X v%08X i%d.\n",
-              i, argv[optind+i], mask[i], value[i], inv_filter[i]);
+       printf("open %d '%s' m%08X v%08X i%d e%d.\n",
+              i, argv[optind+i], mask[i], value[i],
+              inv_filter[i], err_mask[i]);
 #endif
 
        if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
@@ -273,19 +317,24 @@ int main(int argc, char **argv)
 
        if (mask[i] || value[i]) {
 
-           if (!(asc)) /* this output is not asc compatible! */
-               printf("CAN ID filter[%d] for %s set to mask = %08X, value = %08X %s\n",
-                      i, argv[optind+i], mask[i], value[i],
-                      (inv_filter[i]) ? "(inv_filter)" : "");
+           printf("CAN ID filter[%d] for %s set to "
+                  "mask = %08X, value = %08X %s\n",
+                  i, argv[optind+i], mask[i], value[i],
+                  (inv_filter[i]) ? "(inv_filter)" : "");
 
            rfilter.can_id   = value[i];
            rfilter.can_mask = mask[i];
            if (inv_filter[i])
                rfilter.can_id |= CAN_INV_FILTER;
 
-           setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
+           setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
+                      &rfilter, sizeof(rfilter));
        }
 
+       if (err_mask[i])
+           setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
+                      &err_mask[i], sizeof(err_mask[i]));
+
        j = strlen(argv[optind+i]);
 
        if (!(j < IFNAMSIZ)) {
@@ -293,8 +342,6 @@ int main(int argc, char **argv)
            return 1;
        }
 
-       strcpy(devname[i], argv[optind+i]);
-
        if (j > max_devname_len)
            max_devname_len = j; /* for nice printing */
 
@@ -302,8 +349,10 @@ int main(int argc, char **argv)
 
        if (strcmp(ANYDEV, argv[optind+i])) {
            strcpy(ifr.ifr_name, argv[optind+i]);
-           if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0)
+           if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
                perror("SIOCGIFINDEX");
+               exit(1);
+           }
            addr.can_ifindex = ifr.ifr_ifindex;
        }
        else
@@ -315,31 +364,39 @@ int main(int argc, char **argv)
        }
     }
 
-    if (asc) {
-       char datestring[40];
-
-       /* print banner for ASC mode */
-
-       if (timestamp != 'd') /* delta time is allowed, else ... */
-           timestamp = 'z'; /* ASC-files always start with zero time */
+    if (log) {
+       time_t currtime;
+       struct tm now;
+       char fname[sizeof("candump-2006-11-20_202026.log")+1];
 
        if (time(&currtime) == (time_t)-1) {
            perror("time");
            return 1;
        }
-       strncpy(datestring, ctime(&currtime), 39); /* copy to private buffer */
-       datestring[strlen(datestring)-1] = 0; /* chop off trailing newline */
-       printf("date %s%s", datestring, ANL); /* print with own new line representation */
 
-       printf("base hex  timestamps %s%s", (timestamp == 'd')?"relative":"absolute", ANL);
-       printf("no internal events logged%s", ANL);
-       fflush(stdout);
+       localtime_r(&currtime, &now);
+
+       sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log",
+              now.tm_year + 1900,
+              now.tm_mon + 1,
+              now.tm_mday,
+              now.tm_hour,
+              now.tm_min,
+              now.tm_sec);
+
+       printf("\nEnabling Logfile '%s'\n\n", fname);
+
+       logfile = fopen(fname, "w");
+       if (!logfile) {
+           perror("logfile");
+           return 1;
+       }
     }
 
     while (running) {
 
        FD_ZERO(&rdfs);
-
+       FD_SET(0, &rdfs);
        for (i=0; i<currmax; i++)
            FD_SET(s[i], &rdfs);
 
@@ -349,155 +406,118 @@ int main(int argc, char **argv)
            continue;
        }
 
-       for (i=0; i<currmax; i++) {
+       if (FD_ISSET(0, &rdfs)) {
+           running = 0; /* stop with input from stdin */
+           getchar();
+       }
+
+       for (i=0; i<currmax; i++) {  /* check all CAN RAW sockets */
 
            if (FD_ISSET(s[i], &rdfs)) {
 
-#ifdef USE_RECVFROM
                socklen_t len = sizeof(addr);
-               if ((nbytes = recvfrom(s[i], &frame, sizeof(struct can_frame), 0, (struct sockaddr*)&addr, &len)) < 0) {
-#else
-               if ((nbytes = read(s[i], &frame, sizeof(struct can_frame))) < 0) {
-#endif
+               int idx;
+
+               if ((nbytes = recvfrom(s[i], &frame,
+                                      sizeof(struct can_frame), 0,
+                                      (struct sockaddr*)&addr, &len)) < 0) {
                    perror("read");
                    return 1;
-               } else if (nbytes < sizeof(struct can_frame)) {
+               }
+
+               if (nbytes < sizeof(struct can_frame)) {
                    fprintf(stderr, "read: incomplete CAN frame\n");
                    return 1;
-               } else {
-                   if (bridge) {
-                       if ((nbytes = write(bridge, &frame, sizeof(struct can_frame))) < 0) {
-                           perror("bridge write");
-                           return 1;
-                       } else if (nbytes < sizeof(struct can_frame)) {
-                           fprintf(stderr, "bridge write: incomplete CAN frame\n");
-                           return 1;
-                       }
+               }
+
+               if (bridge) {
+                   if ((nbytes = write(bridge, &frame,
+                                       sizeof(struct can_frame))) < 0) {
+                       perror("bridge write");
+                       return 1;
+                   } else if (nbytes < sizeof(struct can_frame)) {
+                       fprintf(stderr,"bridge write: incomplete CAN frame\n");
+                       return 1;
                    }
+               }
                    
-                   if (silent){
-                     if (silent == 1)
-                       printf("%c\b", anichar[silentani%=MAXANI]), silentani++;
+               if (timestamp || log)
+                   if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
+                       perror("SIOCGSTAMP");
+
+
+               idx = idx2dindex(addr.can_ifindex, s[i]);
+
+               if (log) {
+                   /* log CAN frame with absolute timestamp & device */
+                   fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
+                   fprintf(logfile, "%*s", max_devname_len, devname[idx]);
+                   fprintf(logfile, " ");
+                   /* without seperator as logfile use-case is parsing */
+                   fprint_canframe(logfile, &frame, "\n", 0);
+               }
+
+               if (silent){
+                   if (silent == 1) {
+                       printf("%c\b", anichar[silentani%=MAXANI]);
+                       silentani++;
                    }
-                   else {
+                   continue;
+               }
                      
-                       switch (timestamp) {
-
-                       case 'a': /* absolute with timestamp */
-                           if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
-                               perror("SIOCGSTAMP");
-                           if (asc)
-                               printf("%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
-                           else
-                               printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
-                           break;
-
-                       case 'A': /* absolute with date */
-                           {
-                               struct tm tm;
-                               char timestring[25];
-                               if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
-                                   perror("SIOCGSTAMP");
-                               tm = *localtime(&tv.tv_sec);
-                               strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
-                               if (asc)
-                                   printf("%s.%04ld ", timestring, tv.tv_usec/100);
-                               else
-                                   printf("(%s.%06ld) ", timestring, tv.tv_usec);
-                           }
-                           break;
-
-                       case 'd': /* delta */
-                       case 'z': /* starting with zero */
-                           {
-                               struct timeval diff;
-
-                               if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
-                                   perror("SIOCGSTAMP");
-                               if (last_tv.tv_sec == 0)   /* first init */
-                                   last_tv = tv;
-                               diff.tv_sec  = tv.tv_sec  - last_tv.tv_sec;
-                               diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
-                               if (diff.tv_usec < 0)
-                                   diff.tv_sec--, diff.tv_usec += 1000000;
-                               if (diff.tv_sec < 0)
-                                   diff.tv_sec = diff.tv_usec = 0;
-                               if (asc)
-                                   printf("%4ld.%04ld ", diff.tv_sec, diff.tv_usec/100);
-                               else
-                                   printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
+               printf(" %s",(color>2)?col_on[idx]:"");
+
+               switch (timestamp) {
+
+               case 'a': /* absolute with timestamp */
+                   printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
+                   break;
+
+               case 'A': /* absolute with date */
+                   {
+                       struct tm tm;
+                       char timestring[25];
+
+                       tm = *localtime(&tv.tv_sec);
+                       strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
+                       printf("(%s.%06ld) ", timestring, tv.tv_usec);
+                   }
+                   break;
+
+               case 'd': /* delta */
+               case 'z': /* starting with zero */
+                   {
+                       struct timeval diff;
+
+                       if (last_tv.tv_sec == 0)   /* first init */
+                           last_tv = tv;
+                       diff.tv_sec  = tv.tv_sec  - last_tv.tv_sec;
+                       diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
+                       if (diff.tv_usec < 0)
+                           diff.tv_sec--, diff.tv_usec += 1000000;
+                       if (diff.tv_sec < 0)
+                           diff.tv_sec = diff.tv_usec = 0;
+                       printf("(%ld.%06ld) ", diff.tv_sec, diff.tv_usec);
                                
-                               if (timestamp == 'd')
-                                   last_tv = tv; /* update for delta calculation */
-                           }
-                           break;
-
-                       default: /* no timestamp output */
-                           break;
-                       }
-
-                       if (asc) {
-                           char id[10];
-
-                           printf("%-2d ", i + asc_inc_channel); /* channel number - left aligned */
-
-                           sprintf(id, "%X%c", frame.can_id & CAN_EFF_MASK,
-                                   (frame.can_id & CAN_EFF_FLAG)?'x':' ');
-                           printf("%-15s Rx   ", id);
-
-                           if (frame.can_id & CAN_RTR_FLAG)
-                               printf("r"); /* RTR frame: nothing else to print */
-                           else {
-                               printf("d %d ", frame.can_dlc); /* data frame */
-
-                               for (j = 0; j < frame.can_dlc; j++) {
-                                   printf("%02X ", frame.data[j]);
-                               }
-                           }
-                           printf("%s", ANL);
-                       }
-                       else {
-                           printf(" %s",(color)?col_on[i]:"");
-#ifdef USE_RECVFROM
-                           ifr.ifr_ifindex = addr.can_ifindex;
-                           if (ioctl(s[i], SIOCGIFNAME, &ifr) < 0)
-                               perror("SIOCGIFNAME");
-
-                           if (max_devname_len < strlen(ifr.ifr_name))
-                               max_devname_len = strlen(ifr.ifr_name);
-
-                           printf("%*s", max_devname_len, ifr.ifr_name);
-#else
-                           printf("%*s", max_devname_len, devname[i]); /* device name */
-#endif
-                           printf("%s  ",(color)?col_off:"");
-                           if (frame.can_id & CAN_EFF_FLAG)
-                               printf("%8X  ", frame.can_id & CAN_EFF_MASK);
-                           else
-                               printf("%3X  ", frame.can_id & CAN_SFF_MASK);
-
-                           printf("[%d] ", frame.can_dlc);
-
-                           for (j = 0; j < frame.can_dlc; j++) {
-                               printf("%02X ", frame.data[j]);
-                           }
-                           if (ascii) {
-                               printf("%*s", 3*(8-frame.can_dlc)+3, "'");
-                               for (j = 0; j < frame.can_dlc; j++)
-                                   if ((frame.data[j] > 0x1F) && (frame.data[j] < 0x7F))
-                                       putchar(frame.data[j]);
-                                   else
-                                       putchar('.');
-                               printf("' ");
-                           }
-                           if (frame.can_id & CAN_RTR_FLAG)
-                               printf("remote request");
-                           printf("\n");
-                       }
+                       if (timestamp == 'd')
+                           last_tv = tv; /* update for delta calculation */
                    }
-                   fflush(stdout);
+                   break;
+
+               default: /* no timestamp output */
+                   break;
                }
+
+               printf(" %s",(color && (color<3))?col_on[idx]:"");
+               printf("%*s", max_devname_len, devname[idx]);
+               printf("%s  ",(color<2)?col_off:"");
+
+               fprint_long_canframe(stdout, &frame, NULL, ascii);
+
+               printf("%s",(color>1)?col_off:"");
+               printf("\n");
            }
+           fflush(stdout);
        }
     }
 
@@ -507,5 +527,8 @@ int main(int argc, char **argv)
     if (bridge)
       close(bridge);
 
+    if (log)
+       fclose(logfile);
+
     return 0;
 }
diff --git a/can-utils/cangen.c b/can-utils/cangen.c
new file mode 100644 (file)
index 0000000..660dacb
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ *  $Id$
+ */
+
+/*
+ * cangen.c - CAN frames generator for testing purposes
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, the following disclaimer and
+ *    the referenced file 'COPYING'.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2 as distributed in the 'COPYING'
+ * file from the main directory of the linux kernel source.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <net/if.h>
+
+#include <linux/can.h>
+#include <linux/can/raw.h>
+#include "lib.h"
+
+#define DEFAULT_GAP 200 /* ms */
+
+extern int optind, opterr, optopt;
+
+static volatile int running = 1;
+
+void print_usage(char *prg)
+{
+    fprintf(stderr, "\n%s: generate random CAN frames\n\n", prg);
+    fprintf(stderr, "Usage: %s [can-interface]\n", prg);
+    fprintf(stderr, "Options: -g <ms>       (gap in milli seconds)  "
+           "default: %d\n", DEFAULT_GAP);
+    fprintf(stderr, "         -e            (extended frame mode)   "
+           "default: standard frame format \n");
+    fprintf(stderr, "         -I            (fixed CAN ID)          "
+           "default: 0x123\n");
+    fprintf(stderr, "         -D            (fixed CAN Data)        "
+           "default: 01 23 45 67 89 AB CD EF\n");
+    fprintf(stderr, "         -L            (fixed CAN DLC)         "
+           "default: 8\n");
+    fprintf(stderr, "         -f <canframe> (other fixed CAN frame) "
+           "default: 123#0123456789ABCDEF\n");
+    fprintf(stderr, "         -v            (verbose)               "
+           "default: don't print sent frames\n");
+}
+
+void sigterm(int signo)
+{
+    running = 0;
+}
+
+int main(int argc, char **argv)
+{
+    unsigned long gap = DEFAULT_GAP; 
+    unsigned char extended = 0;
+    unsigned char fix_id = 0;
+    unsigned char fix_data = 0;
+    unsigned char fix_dlc = 0;
+    unsigned char default_frame = 1;
+    unsigned char verbose = 0;
+
+    int opt;
+    int s; /* socket */
+
+    struct sockaddr_can addr;
+    static struct can_frame frame;
+    int nbytes;
+    struct ifreq ifr;
+
+    struct timespec ts;
+
+    signal(SIGTERM, sigterm);
+    signal(SIGHUP, sigterm);
+    signal(SIGINT, sigterm);
+
+    while ((opt = getopt(argc, argv, "g:eIDLf:v")) != -1) {
+       switch (opt) {
+       case 'g':
+           gap = strtoul(optarg, NULL, 10);
+           break;
+
+       case 'e':
+           extended = 1;
+           break;
+
+       case 'I':
+           fix_id = 1;
+           break;
+
+       case 'D':
+           fix_data = 1;
+           break;
+
+       case 'L':
+           fix_dlc = 1;
+           break;
+
+       case 'f':
+           default_frame = 0;
+           if (parse_canframe(optarg, &frame)) {
+               fprintf(stderr, "'%s' is a wrong CAN frame format.\n", optarg);
+               exit(1);
+           }
+           break;
+
+       case 'v':
+           verbose = 1;
+           break;
+
+       default:
+           print_usage(basename(argv[0]));
+           exit(1);
+           break;
+       }
+    }
+
+    if (optind == argc) {
+       print_usage(basename(argv[0]));
+       exit(0);
+    }
+
+    ts.tv_sec = gap / 1000;
+    ts.tv_nsec = (gap % 1000) * 1000000;
+
+
+    if (default_frame) {
+       if (extended)
+           frame.can_id = 0x12345678 | CAN_EFF_FLAG;
+       else
+           frame.can_id = 0x123;
+
+       frame.can_dlc = 8;
+
+       frame.data[0] = 0x01;
+       frame.data[1] = 0x23;
+       frame.data[2] = 0x45;
+       frame.data[3] = 0x67;
+       frame.data[4] = 0x89;
+       frame.data[5] = 0xAB;
+       frame.data[6] = 0xCD;
+       frame.data[7] = 0xEF;
+    }
+
+    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+       perror("socket");
+       return 1;
+    }
+
+    addr.can_family = AF_CAN;
+
+    strcpy(ifr.ifr_name, argv[optind]);
+    if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
+       perror("SIOCGIFINDEX");
+    addr.can_ifindex = ifr.ifr_ifindex;
+
+    /* disable default receive filter on this RAW socket */
+    /* This is obsolete as we do not read from the socket at all, but for */
+    /* this reason we can remove the receive list in the Kernel to save a */
+    /* little (really a very little!) CPU usage.                          */
+    setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
+
+    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+       perror("bind");
+       return 1;
+    }
+
+    while (running) {
+
+       if (!fix_id) {
+           frame.can_id = random();
+           if (extended) {
+               frame.can_id &= CAN_EFF_MASK;
+               frame.can_id |= CAN_EFF_FLAG;
+           } else
+               frame.can_id &= CAN_SFF_MASK;
+       }
+
+       if (!fix_dlc) {
+           frame.can_dlc = random() & 0xF;
+           if (frame.can_dlc & 8)
+               frame.can_dlc = 8; /* for about 50% of the frames */
+       }
+
+       if (!fix_data) {
+           /* that's what the 64 bit alignment of data[] is for ... :) */
+           *(unsigned long*)(&frame.data[0]) = random();
+           *(unsigned long*)(&frame.data[4]) = random();
+       }
+
+       if ((nbytes = write(s, &frame, sizeof(struct can_frame))) < 0) {
+           perror("write");
+           return 1;
+       } else if (nbytes < sizeof(struct can_frame)) {
+           fprintf(stderr, "write: incomplete CAN frame\n");
+           return 1;
+       }
+
+       if (gap) /* gap == 0 => performance test :-] */
+           if (nanosleep(&ts, NULL))
+               return 1;
+                   
+       if (verbose)
+#if 0
+           fprint_long_canframe(stdout, &frame, "\n", 1);
+#else
+           fprint_canframe(stdout, &frame, "\n", 1);
+#endif
+    }
+
+    close(s);
+
+    return 0;
+}
index 7b94ff8db71f6d15b0373ada203cbd287ea86d9a..dd9d73edbb0a7befc0a1ba6837e3ad618eac8ec9 100644 (file)
@@ -109,7 +109,7 @@ int main(int argc, char **argv)
       return 1;
     }
 
-    //fprint_canframe(stdout, &frame, "\n");
+    //fprint_long_canframe(stdout, &frame, "\n", 0);
 
     close(s);
 
index 475ecd394c72c5e28abfb3e35bba48f50f94435b..acbbb4b0ddb6f01cbe951d920688ad31c3ee97c7 100644 (file)
 #include <sys/socket.h> /* for sa_family_t */
 #include <linux/can.h>
 
+#include "lib.h"
+
 #define CANID_DELIM '#'
 #define DATA_SEPERATOR '.'
 
-static int asc2nibble(char c){
+#define MAX_CANFRAME      "12345678#01.23.45.67.89.AB.CD.EF"
+#define MAX_LONG_CANFRAME "12345678  [8] 01 23 45 67 89 AB CD EF   '........'"
+
+static int asc2nibble(char c) {
 
     if ((c >= '0') && (c <= '9'))
        return c - '0';
@@ -69,7 +74,7 @@ static int asc2nibble(char c){
     return 16; /* error */
 }
 
-int parse_canframe(char *cs, struct can_frame *cf){
+int parse_canframe(char *cs, struct can_frame *cf) {
     /* documentation see lib.h */
 
     int i, idx, dlc, len, tmp;
@@ -85,17 +90,18 @@ int parse_canframe(char *cs, struct can_frame *cf){
     if (!((cs[3] == CANID_DELIM) || (cs[8] == CANID_DELIM)))
        return 1;
 
-    if (cs[8] == CANID_DELIM) {
+    if (cs[8] == CANID_DELIM) { /* 8 digits */
 
        idx = 9;
-       cf->can_id = CAN_EFF_FLAG;
        for (i=0; i<8; i++){
            if ((tmp = asc2nibble(cs[i])) > 0x0F)
                return 1;
            cf->can_id |= (tmp << (7-i)*4);
        }
+       if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
+           cf->can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
 
-    } else {
+    } else { /* 3 digits */
 
        idx = 4;
        for (i=0; i<3; i++){
@@ -132,24 +138,96 @@ int parse_canframe(char *cs, struct can_frame *cf){
     return 0;
 }
 
-void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol){
+void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep) {
     /* documentation see lib.h */
 
-    int i;
+    char buf[sizeof(MAX_CANFRAME)+1]; /* max length */
 
-    if (cf->can_id & CAN_EFF_FLAG)
-       fprintf(stream, "%8X  ", cf->can_id & CAN_EFF_MASK);
-    else
-       fprintf(stream, "%3X  ", cf->can_id & CAN_SFF_MASK);
+    sprint_canframe(buf, cf, sep);
+    fprintf(stream, "%s", buf);
+    if (eol)
+       fprintf(stream, "%s", eol);
+}
+
+void sprint_canframe(char *buf , struct can_frame *cf, int sep) {
+    /* documentation see lib.h */
 
-    fprintf(stream, "[%d] ", cf->can_dlc);
+    int i,offset;
 
-    for (i = 0; i < cf->can_dlc; i++) {
-       fprintf(stream, "%02X ", cf->data[i]);
+    if (cf->can_id & CAN_ERR_FLAG) {
+       sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
+       offset = 9;
+    } else if (cf->can_id & CAN_EFF_FLAG) {
+       sprintf(buf, "%08X#", cf->can_id & CAN_EFF_MASK);
+       offset = 9;
+    } else {
+       sprintf(buf, "%03X#", cf->can_id & CAN_SFF_MASK);
+       offset = 4;
     }
-    if (cf->can_id & CAN_RTR_FLAG)
-       fprintf(stream, "remote request");
+
+    if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */
+       sprintf(buf+offset, "R");
+    else
+       for (i = 0; i < cf->can_dlc; i++) {
+           sprintf(buf+offset, "%02X", cf->data[i]);
+           offset += 2;
+           if (sep && (i+1 < cf->can_dlc))
+               sprintf(buf+offset++, ".");
+       }
+
+
+}
+
+void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int ascii) {
+    /* documentation see lib.h */
+
+    char buf[sizeof(MAX_LONG_CANFRAME)+1]; /* max length */
+
+    sprint_long_canframe(buf, cf, ascii);
+    fprintf(stream, "%s", buf);
     if (eol)
        fprintf(stream, "%s", eol);
 }
 
+void sprint_long_canframe(char *buf , struct can_frame *cf, int ascii) {
+    /* documentation see lib.h */
+
+    int i, offset;
+
+    if (cf->can_id & CAN_ERR_FLAG) {
+       sprintf(buf, "%8X  ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
+       offset = 10;
+    } else if (cf->can_id & CAN_EFF_FLAG) {
+       sprintf(buf, "%8X  ", cf->can_id & CAN_EFF_MASK);
+       offset = 10;
+    } else {
+       sprintf(buf, "%3X  ", cf->can_id & CAN_SFF_MASK);
+       offset = 5;
+    }
+
+    sprintf(buf+offset, "[%d]", cf->can_dlc);
+    offset += 3;
+
+    if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */
+       sprintf(buf+offset, " remote request");
+    else {
+       for (i = 0; i < cf->can_dlc; i++) {
+           sprintf(buf+offset, " %02X", cf->data[i]);
+           offset += 3;
+       }
+       if (cf->can_id & CAN_ERR_FLAG)
+           sprintf(buf+offset, "%*s", 3*(8-cf->can_dlc)+13, "ERRORFRAME");
+       else if (ascii) {
+           sprintf(buf+offset, "%*s", 3*(8-cf->can_dlc)+4, "'");
+           offset += 3*(8-cf->can_dlc)+4;
+
+           for (i = 0; i < cf->can_dlc; i++)
+               if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
+                   buf[offset++] = cf->data[i];
+               else
+                   buf[offset++] = '.';
+           sprintf(buf+offset, "'");
+       } 
+    }
+}
+
index 4b010dab21b5190d2239633d318b8e3252ef5d90..70d440d445c193dc44c61fbe7305ca79727131a9 100644 (file)
@@ -68,19 +68,48 @@ int parse_canframe(char *cs, struct can_frame *cf);
  * 123#1122334455667788 -> standard CAN-Id = 0x123, dlc = 8
  * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8
  * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, dlc = 8
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ *
+ * Simple facts on this compact ASCII CAN frame representation:
+ *
+ * - 3 digits: standard frame format
+ * - 8 digits: extendend frame format OR error frame
+ * - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
+ * - an error frame is never a RTR frame
+ * 
+ */
+
+void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep);
+void sprint_canframe(char *buf , struct can_frame *cf, int sep);
+/*
+ * Creates a CAN frame hexadecimal output in compact format.
+ * The CAN data[] is seperated by '.' when sep != 0.
+ *
+ * 12345678#112233 -> exended CAN-Id = 0x12345678, dlc = 3, data, sep = 0
+ * 12345678#R -> exended CAN-Id = 0x12345678, RTR
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
+ * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ *
+ * Examples:
+ *
+ * fprint_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
+ * fprint_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
  *
  */
 
-void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol);
+void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int ascii);
+void sprint_long_canframe(char *buf , struct can_frame *cf, int ascii);
 /*
  * Creates a CAN frame hexadecimal output in user readable format.
  *
  * 12345678  [3] 11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data
  * 12345678  [0] remote request -> exended CAN-Id = 0x12345678, RTR
+ * 14B0DC51  [8] 4A 94 E8 2A EC 58 55 62   'J..*.XUb' -> (with ASCII output)
+ * 20001111  [7] C6 23 7B 32 69 98 3C      ERRORFRAME -> (CAN_ERR_FLAG set)
  *
  * Examples:
  *
- * fprint_canframe(stdout, &frame, "\n"); // with eol to STDOUT
- * fprint_canframe(stderr, &frame, NULL); // no eol to STDERR
+ * fprint_long_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
+ * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
  *
  */
diff --git a/can-utils/log2asc.c b/can-utils/log2asc.c
new file mode 100644 (file)
index 0000000..914a396
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  $Id$
+ */
+
+/*
+ * log2asc.c - convert compact CAN frame logfile to ASC logfile
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, the following disclaimer and
+ *    the referenced file 'COPYING'.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2 as distributed in the 'COPYING'
+ * file from the main directory of the linux kernel source.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <libgen.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <linux/can.h>
+
+#include "lib.h"
+
+extern int optind, opterr, optopt;
+
+void print_usage(char *prg)
+{
+    fprintf(stderr, "Usage: %s [can-interfaces]\n", prg);
+    fprintf(stderr, "Options: -I <infile>  (default stdin)\n");
+    fprintf(stderr, "         -O <outfile> (default stdout)\n");
+    fprintf(stderr, "         -n (set newline to cr/lf - default lf)\n");
+}
+
+int main(int argc, char **argv)
+{
+    char buf[100], device[100], ascframe[100], id[10];
+
+    struct can_frame cf;
+    static struct timeval tv, start_tv;
+    FILE *infile = stdin;
+    FILE *outfile = stdout;
+    static int maxdev, devno, i, crlf, opt;
+
+    while ((opt = getopt(argc, argv, "I:O:n")) != -1) {
+       switch (opt) {
+       case 'I':
+           infile = fopen(optarg, "r");
+           if (!infile) {
+               perror("infile");
+               return 1;
+           }
+           break;
+
+       case 'O':
+           outfile = fopen(optarg, "w");
+           if (!outfile) {
+               perror("outfile");
+               return 1;
+           }
+           break;
+
+       case 'n':
+           crlf = 1;
+           break;
+
+       default:
+           fprintf(stderr, "Unknown option %c\n", opt);
+           print_usage(basename(argv[0]));
+           return 1;
+           break;
+       }
+    }
+
+    maxdev = argc - optind; /* find real number of CAN devices */
+
+    if (!maxdev) {
+       fprintf(stderr, "no CAN interfaces defined!\n");
+       print_usage(basename(argv[0]));
+       return 1;
+    }
+       
+    //printf("Found %d CAN devices!\n", maxdev);
+
+    while (fgets(buf, 99, infile)) {
+       if (sscanf(buf, "(%ld.%ld) %s %s", &tv.tv_sec, &tv.tv_usec,
+                  device, ascframe) != 4)
+           return 1;
+
+       if (!start_tv.tv_sec) { /* print banner */
+           start_tv = tv;
+           fprintf(outfile, "date %s", ctime(&start_tv.tv_sec));
+           fprintf(outfile, "base hex  timestamps absolute%s",
+                   (crlf)?"\r\n":"\n");
+           fprintf(outfile, "no internal events logged%s",
+                   (crlf)?"\r\n":"\n");
+       }
+
+       for (i=0, devno=0; i<maxdev; i++) {
+           if (!strcmp(device, argv[optind+i])) {
+               devno = i+1; /* start with channel '1' */
+               break;
+           }
+       }
+
+       if (devno) { /* only convert for selected CAN devices */
+           if (parse_canframe(ascframe, &cf))
+               return 1;
+
+           tv.tv_sec  = tv.tv_sec - start_tv.tv_sec;
+           tv.tv_usec = tv.tv_usec - start_tv.tv_usec;
+           if (tv.tv_usec < 0)
+               tv.tv_sec--, tv.tv_usec += 1000000;
+           if (tv.tv_sec < 0)
+               tv.tv_sec = tv.tv_usec = 0;
+           fprintf(outfile, "%4ld.%04ld ", tv.tv_sec, tv.tv_usec/100);
+
+           fprintf(outfile, "%-2d ", devno); /* channel number left aligned */
+
+           if (cf.can_id & CAN_ERR_FLAG)
+               fprintf(outfile, "(errorframe)");
+           else {
+               sprintf(id, "%X%c", cf.can_id & CAN_EFF_MASK,
+                       (cf.can_id & CAN_EFF_FLAG)?'x':' ');
+               fprintf(outfile, "%-15s Rx   ", id);
+               
+               if (cf.can_id & CAN_RTR_FLAG)
+                   fprintf(outfile, "r"); /* RTR frame */
+               else {
+                   fprintf(outfile, "d %d", cf.can_dlc); /* data frame */
+                   
+                   for (i = 0; i < cf.can_dlc; i++) {
+                       fprintf(outfile, " %02X", cf.data[i]);
+                   }
+               }
+           }
+           if (crlf)
+               fprintf(outfile, "\r");
+           fprintf(outfile, "\n");
+       }
+    }
+    fflush(outfile);
+
+    return 0;
+}
diff --git a/can-utils/log2long.c b/can-utils/log2long.c
new file mode 100644 (file)
index 0000000..05ef800
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  $Id$
+ */
+
+/*
+ * log2long.c - convert compact CAN frame representation into user readable
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, the following disclaimer and
+ *    the referenced file 'COPYING'.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2 as distributed in the 'COPYING'
+ * file from the main directory of the linux kernel source.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <stdio.h>
+
+#include <net/if.h>
+#include <linux/can.h>
+
+#include "lib.h"
+
+int main(int argc, char **argv)
+{
+    char buf[100], timestamp[100], device[100], ascframe[100];
+    struct can_frame cf;
+
+    while (fgets(buf, 99, stdin)) {
+       if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3)
+           return 1;
+       if (parse_canframe(ascframe, &cf))
+           return 1;
+       sprint_long_canframe(ascframe, &cf, 1); /* with ASCII output */
+       printf("%s  %s  %s\n", timestamp, device, ascframe);
+    }
+
+    return 0;
+}