]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
Updated new 'cangen' and 'candump' in the trunk.
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 5 May 2008 12:20:34 +0000 (12:20 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Mon, 5 May 2008 12:20:34 +0000 (12:20 +0000)
git-svn-id: svn://svn.berlios.de//socketcan/trunk@726 030b6a49-0b11-0410-94ab-b0dab22257f2

can-utils/candump.c
can-utils/cangen.c

index 1ed2b8df0253516a02e29816fcb68423ada4cefb..f0b50edb5dc17de36ee6f31c5a3419cfd2f3f70b 100644 (file)
 #include "terminal.h"
 #include "lib.h"
 
-#define MAXDEV 6 /* change sscanf()'s manually if changed here */
-#define ANYDEV "any"
-#define ANL "\r\n" /* newline in ASC mode */
+#define MAXSOCK 16    /* max. number of CAN interfaces given on the cmdline */
+#define MAXFILTER 30  /* max. number of possible filters for each socket */
+#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
+#define MAXCOL 6      /* number of different colors for colorized output */
+#define ANYDEV "any"  /* name of interface to receive from any CAN interface */
+#define ANL "\r\n"    /* newline in ASC mode */
 
 #define BOLD    ATTBOLD
 #define RED     ATTBOLD FGRED
 #define MAGENTA ATTBOLD FGMAGENTA
 #define CYAN    ATTBOLD FGCYAN
 
-const char col_on [MAXDEV][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
+const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
 const char col_off [] = ATTRESET;
 
-static char devname[MAXDEV][IFNAMSIZ+1];
-static int  dindex[MAXDEV];
-static int  max_devname_len;
+static char devname[MAXIFNAMES][IFNAMSIZ+1];
+static int  dindex[MAXIFNAMES];
+static int  max_devname_len; /* to prevent frazzled device name output */ 
 
-#define MAXANI 8
-const char anichar[MAXANI] = {'|', '/', '-', '\\', '|', '/', '-', '\\'};
+#define MAXANI 4
+const char anichar[MAXANI] = {'|', '/', '-', '\\'};
 
 extern int optind, opterr, optopt;
 
@@ -97,25 +100,28 @@ void print_usage(char *prg)
 {
     fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
     fprintf(stderr, "  (use CTRL-C to terminate %s)\n\n", prg);
-    fprintf(stderr, "Options: -m <mask>   (ID filter mask.  Default 0x00000000) *\n");
-    fprintf(stderr, "         -v <value>  (ID filter value. Default 0x00000000) *\n");
-    fprintf(stderr, "         -i <0|1>    (invert the specified ID 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, "Options: -t <type>   (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n");
+    fprintf(stderr, "         -c          (increment color mode level)\n");
     fprintf(stderr, "         -a          (enable additional ASCII output)\n");
-    fprintf(stderr, "         -s <level>  (silent mode - 1: animation 2: nothing)\n");
+    fprintf(stderr, "         -s <level>  (silent mode - 1: animation 2: completely silent)\n");
     fprintf(stderr, "         -b <can>    (bridge mode - send received frames to <can>)\n");
     fprintf(stderr, "         -B <can>    (bridge mode - like '-b' with disabled loopback)\n");
     fprintf(stderr, "         -l          (log CAN-frames into file)\n");
     fprintf(stderr, "         -L          (use log file format on stdout)\n");
     fprintf(stderr, "\n");
-    fprintf(stderr, "* The CAN ID filter matches, when ...\n");
-    fprintf(stderr, "       <received_can_id> & mask == value & mask\n");
+    fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK);
+    fprintf(stderr, "on the commandline in the form: <ifname>[,filter]*\n");
+    fprintf(stderr, "\nUp to %d comma separated filters can be specified for each given CAN interface:\n", MAXFILTER);
+    fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
+    fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
+    fprintf(stderr, " #<error_mask>       (set error frame filter, see include/linux/can/error.h)\n");
+    fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n", ANYDEV);
+    fprintf(stderr, "CAN IDs, masks and data content are given and expected in hexadecimal values.\n");
+    fprintf(stderr, "\nExamples:\n");
+    fprintf(stderr, "%s -c -c -ta can0,123:7FF,400:700,#000000FF can2,400~7F0 can3 can8\n", prg);
+    fprintf(stderr, "%s -l any,0~0,#FFFFFFFF    (log only error frames but no(!) data frames)\n", prg);
+    fprintf(stderr, "%s vcan2,92345678:9FFFFFFF (match only for extended CAN ID 12345678)\n", prg);
     fprintf(stderr, "\n");
-    fprintf(stderr, "When using more than one CAN interface the options\n");
-    fprintf(stderr, "m/v/i/e have comma seperated values e.g. '-m 0,7FF,0'\n");
-    fprintf(stderr, "\nUse interface name '%s' to receive from all CAN interfaces.\n\n", ANYDEV);
 }
 
 void sigterm(int signo)
@@ -128,7 +134,7 @@ int idx2dindex(int ifidx, int socket) {
     int i;
     struct ifreq ifr;
 
-    for (i=0; i<MAXDEV; i++) {
+    for (i=0; i < MAXIFNAMES; i++) {
        if (dindex[i] == ifidx)
            return i;
     }
@@ -136,7 +142,7 @@ int idx2dindex(int ifidx, int socket) {
     /* create new interface index cache entry */
 
     /* remove index cache zombies first */
-    for (i=0; i < MAXDEV; i++) {
+    for (i=0; i < MAXIFNAMES; i++) {
        if (dindex[i]) {
            ifr.ifr_ifindex = dindex[i];
            if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
@@ -144,12 +150,13 @@ int idx2dindex(int ifidx, int socket) {
        }
     }
 
-    for (i=0; i < MAXDEV; i++)
+    for (i=0; i < MAXIFNAMES; i++)
        if (!dindex[i]) /* free entry */
            break;
 
-    if (i == MAXDEV) {
-       printf("Interface index cache only supports %d interfaces.\n", MAXDEV);
+    if (i == MAXIFNAMES) {
+       printf("Interface index cache only supports %d interfaces.\n",
+              MAXIFNAMES);
        exit(1);
     }
 
@@ -174,12 +181,8 @@ int idx2dindex(int ifidx, int socket) {
 int main(int argc, char **argv)
 {
     fd_set rdfs;
-    int s[MAXDEV];
+    int s[MAXSOCK];
     int bridge = 0;
-    canid_t mask[MAXDEV] = {0};
-    canid_t value[MAXDEV] = {0};
-    int inv_filter[MAXDEV] = {0};
-    can_err_mask_t err_mask[MAXDEV] = {0};
     unsigned char timestamp = 0;
     unsigned char silent = 0;
     unsigned char silentani = 0;
@@ -188,11 +191,13 @@ int main(int argc, char **argv)
     unsigned char log = 0;
     unsigned char logfrmt = 0;
     int opt, ret;
-    int currmax = 1; /* we assume at least one can bus ;-) */
+    int currmax, numfilter;
+    char *ptr, *nptr;
     struct sockaddr_can addr;
-    struct can_filter rfilter;
+    struct can_filter rfilter[MAXFILTER];
+    can_err_mask_t err_mask;
     struct can_frame frame;
-    int nbytes, i, j;
+    int nbytes, i;
     struct ifreq ifr;
     struct timeval tv, last_tv;
     FILE *logfile = NULL;
@@ -204,40 +209,8 @@ int main(int argc, char **argv)
     last_tv.tv_sec  = 0;
     last_tv.tv_usec = 0;
 
-    while ((opt = getopt(argc, argv, "m:v:i:e:t:cas:b:B:lL?")) != -1) {
+    while ((opt = getopt(argc, argv, "t:cas:b:B:lLh?")) != -1) {
        switch (opt) {
-       case 'm':
-           i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
-                      &mask[0], &mask[1], &mask[2],
-                      &mask[3], &mask[4], &mask[5]);
-           if (i > currmax)
-               currmax = i;
-           break;
-
-       case 'v':
-           i = sscanf(optarg, "%x,%x,%x,%x,%x,%x",
-                      &value[0], &value[1], &value[2],
-                      &value[3], &value[4], &value[5]);
-           if (i > currmax)
-               currmax = i;
-           break;
-
-       case 'i':
-           i = sscanf(optarg, "%d,%d,%d,%d,%d,%d",
-                      &inv_filter[0], &inv_filter[1], &inv_filter[2],
-                      &inv_filter[3], &inv_filter[4], &inv_filter[5]);
-           if (i > currmax)
-               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') &&
@@ -265,9 +238,9 @@ int main(int argc, char **argv)
            if (strlen(optarg) >= IFNAMSIZ) {
                printf("Name of CAN device '%s' is too long!\n\n", optarg);
                return 1;
-           }
-           else {
-               if ((bridge = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+           } else {
+               bridge = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+               if (bridge < 0) {
                    perror("bridge socket");
                    return 1;
                }
@@ -285,7 +258,8 @@ int main(int argc, char **argv)
                if (opt == 'B') {
                    int loopback = 0;
 
-                   setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
+                   setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
+                              &loopback, sizeof(loopback));
                }
 
                if (bind(bridge, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@@ -315,75 +289,106 @@ int main(int argc, char **argv)
        exit(0);
     }
        
-    /* count in options higher than device count ? */
-    if (optind + currmax > argc) {
-       printf("low count of CAN devices!\n");
-       return 1;
-    }
-
     currmax = argc - optind; /* find real number of CAN devices */
 
-    if (currmax > MAXDEV) {
-       printf("More than %d CAN devices!\n", MAXDEV);
+    if (currmax > MAXSOCK) {
+       printf("More than %d CAN devices given on commandline!\n", MAXSOCK);
        return 1;
     }
 
-    for (i=0; i<currmax; i++) {
+    for (i=0; i < currmax; i++) {
+
+       ptr = argv[optind+i];
+       nptr = strchr(ptr, ',');
 
 #ifdef DEBUG
-       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]);
+       printf("open %d '%s'.\n", i, ptr);
 #endif
 
-       if ((s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
+       s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+       if (s[i] < 0) {
            perror("socket");
            return 1;
        }
 
-       if (mask[i] || value[i]) {
-
-           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));
-       }
-
-       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 (nptr)
+           nbytes = nptr - ptr;  /* interface name is up the first ',' */
+       else
+           nbytes = strlen(ptr); /* no ',' found => no filter definitions */
 
-       if (!(j < IFNAMSIZ)) {
-           printf("name of CAN device '%s' is too long!\n", argv[optind+i]);
+       if (nbytes >= IFNAMSIZ) {
+           printf("name of CAN device '%s' is too long!\n", ptr);
            return 1;
        }
 
-       if (j > max_devname_len)
-           max_devname_len = j; /* for nice printing */
+       if (nbytes > max_devname_len)
+           max_devname_len = nbytes; /* for nice printing */
 
        addr.can_family = AF_CAN;
 
-       if (strcmp(ANYDEV, argv[optind+i])) {
-           strcpy(ifr.ifr_name, argv[optind+i]);
+       memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
+       strncpy(ifr.ifr_name, ptr, nbytes);
+
+#ifdef DEBUG
+       printf("using interface name '%s'.\n", ifr.ifr_name);
+#endif
+
+       if (strcmp(ANYDEV, ifr.ifr_name)) {
            if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
                perror("SIOCGIFINDEX");
                exit(1);
            }
            addr.can_ifindex = ifr.ifr_ifindex;
-       }
-       else
+       } else
            addr.can_ifindex = 0; /* any can interface */
 
+       if (nptr) {
+
+           /* found a ',' after the interface name => check for filters */
+
+           numfilter = 0;
+           err_mask = 0;
+
+           while (nptr) {
+
+               ptr = nptr+1; /* hop behind the ',' */
+               nptr = strchr(ptr, ','); /* update exit condition */
+
+               if (sscanf(ptr, "%lx:%lx",
+                          (long unsigned int *)
+                          &rfilter[numfilter].can_id, 
+                          (long unsigned int *)
+                          &rfilter[numfilter].can_mask) == 2) {
+                   numfilter++;
+               } else if (sscanf(ptr, "%lx~%lx",
+                                 (long unsigned int *)
+                                 &rfilter[numfilter].can_id, 
+                                 (long unsigned int *)
+                                 &rfilter[numfilter].can_mask) == 2) {
+                   rfilter[numfilter].can_id |= CAN_INV_FILTER;
+                   numfilter++;
+               } else if (sscanf(ptr, "#%lx",
+                                 (long unsigned int *)&err_mask) != 1) { 
+                   printf("Error in filter option parsing: '%s'\n", ptr);
+                   exit(1);
+               }
+
+               if (numfilter > MAXFILTER) {
+                   printf("Too many filters specified for '%s'.\n",
+                          ifr.ifr_name);
+                   exit(1);
+               }
+           }
+
+           if (err_mask)
+               setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
+                          &err_mask, sizeof(err_mask));
+
+           if (numfilter)
+               setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
+                          &rfilter, numfilter * sizeof(struct can_filter));
+       } /* if (nptr) */
+
        if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
            perror("bind");
            return 1;
@@ -403,12 +408,12 @@ int main(int argc, char **argv)
        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);
+               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);
 
@@ -438,9 +443,9 @@ int main(int argc, char **argv)
                socklen_t len = sizeof(addr);
                int idx;
 
-               if ((nbytes = recvfrom(s[i], &frame,
-                                      sizeof(struct can_frame), 0,
-                                      (struct sockaddr*)&addr, &len)) < 0) {
+               nbytes = recvfrom(s[i], &frame, sizeof(struct can_frame), 0,
+                                 (struct sockaddr*)&addr, &len);
+               if (nbytes < 0) {
                    perror("read");
                    return 1;
                }
@@ -451,8 +456,8 @@ int main(int argc, char **argv)
                }
 
                if (bridge) {
-                   if ((nbytes = write(bridge, &frame,
-                                       sizeof(struct can_frame))) < 0) {
+                   nbytes = write(bridge, &frame, sizeof(struct can_frame));
+                   if (nbytes < 0) {
                        perror("bridge write");
                        return 1;
                    } else if (nbytes < sizeof(struct can_frame)) {
@@ -492,7 +497,7 @@ int main(int argc, char **argv)
                    goto out_fflush; /* no other output to stdout */
                }
                      
-               printf(" %s", (color>2)?col_on[idx]:"");
+               printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
 
                switch (timestamp) {
 
@@ -535,7 +540,7 @@ int main(int argc, char **argv)
                    break;
                }
 
-               printf(" %s", (color && (color<3))?col_on[idx]:"");
+               printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
                printf("%*s", max_devname_len, devname[idx]);
                printf("%s  ", (color==1)?col_off:"");
 
@@ -554,7 +559,7 @@ out_fflush:
        close(s[i]);
 
     if (bridge)
-      close(bridge);
+       close(bridge);
 
     if (log)
        fclose(logfile);
index 101c47a135266566ace2e9c6f913d8d34b71c123..15890479c8c6f4dd8cd023c282b6f614aba4fffc 100644 (file)
@@ -47,6 +47,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
 
 #define DEFAULT_GAP 200 /* ms */
 
+#define MODE_RANDOM    0
+#define MODE_INCREMENT 1
+#define MODE_FIX       2
+
 extern int optind, opterr, optopt;
 
 static volatile int running = 1;
+static unsigned long long enobufs_count;
 
 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, "         -x            (disable loopback)      "
-           "default: standard loopback\n");
-    fprintf(stderr, "         -v            (verbose)               "
-           "default: don't print sent frames\n");
+    fprintf(stderr, "\n%s: generate CAN frames\n\n", prg);
+    fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
+    fprintf(stderr, "Options: -g <ms>       (gap in milli seconds "
+           "- default: %d ms)\n", DEFAULT_GAP);
+    fprintf(stderr, "         -e            (generate extended frame mode "
+           "(EFF) CAN frames)\n");
+    fprintf(stderr, "         -I <mode>     (CAN ID"
+           " generation mode - see below)\n");
+    fprintf(stderr, "         -L <mode>     (CAN data length code (dlc)"
+           " generation mode - see below)\n");
+    fprintf(stderr, "         -D <mode>     (CAN data (payload)"
+           " generation mode - see below)\n");
+    fprintf(stderr, "         -i            (ignore -ENOBUFS return values on"
+           " write() syscalls)\n");
+    fprintf(stderr, "         -x            (disable local loopback of "
+           "generated CAN frames)\n");
+    fprintf(stderr, "         -v            (increment verbose level for "
+           "printing sent CAN frames)\n\n");
+    fprintf(stderr, "Generation modes:\n");
+    fprintf(stderr, "'r'        => random values (default)\n");
+    fprintf(stderr, "'i'        => increment values\n");
+    fprintf(stderr, "<hexvalue> => fix value using <hexvalue>\n\n");
+    fprintf(stderr, "When incrementing the CAN data the data length code "
+           "minimum is set to 1.\n\n");
+    fprintf(stderr, "Examples:\n");
+    fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v   ", prg);
+    fprintf(stderr, "(fixed CAN ID and length, inc. data)\n");
+    fprintf(stderr, "%s vcan0 -e -L i -v -v -v              ", prg);
+    fprintf(stderr, "(generate EFF frames, incr. length)\n");
+    fprintf(stderr, "%s vcan0 -D 11223344DEADBEEF -L 8      ", prg);
+    fprintf(stderr, "(fixed CAN data payload and length)\n");
+    fprintf(stderr, "%s vcan0 -g 0 -i -x                    ", prg);
+    fprintf(stderr, "(full load test ignoring -ENOBUFS)\n");
+    fprintf(stderr, "%s vcan0                               ", prg);
+    fprintf(stderr, "(my favourite default :)\n\n");
 }
 
 void sigterm(int signo)
@@ -102,13 +125,14 @@ void sigterm(int signo)
 int main(int argc, char **argv)
 {
     unsigned long gap = DEFAULT_GAP; 
+    unsigned char ignore_enobufs = 0;
     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 id_mode = MODE_RANDOM;
+    unsigned char data_mode = MODE_RANDOM;
+    unsigned char dlc_mode = MODE_RANDOM;
     unsigned char loopback_disable = 0;
     unsigned char verbose = 0;
+    uint64_t incdata = 0;
 
     int opt;
     int s; /* socket */
@@ -116,6 +140,7 @@ int main(int argc, char **argv)
     struct sockaddr_can addr;
     static struct can_frame frame;
     int nbytes;
+    int i;
     struct ifreq ifr;
 
     struct timespec ts;
@@ -124,8 +149,13 @@ int main(int argc, char **argv)
     signal(SIGHUP, sigterm);
     signal(SIGINT, sigterm);
 
-    while ((opt = getopt(argc, argv, "g:eIDLf:xv")) != -1) {
+    while ((opt = getopt(argc, argv, "ig:eI:L:D:xvh?")) != -1) {
        switch (opt) {
+
+       case 'i':
+           ignore_enobufs = 1;
+           break;
+
        case 'g':
            gap = strtoul(optarg, NULL, 10);
            break;
@@ -135,65 +165,90 @@ int main(int argc, char **argv)
            break;
 
        case 'I':
-           fix_id = 1;
-           break;
-
-       case 'D':
-           fix_data = 1;
+           if (optarg[0] == 'r') {
+               id_mode = MODE_RANDOM;
+           } else if (optarg[0] == 'i') {
+               id_mode = MODE_INCREMENT;
+           } else {
+               id_mode = MODE_FIX;
+               frame.can_id = strtoul(optarg, NULL, 16);
+           }
            break;
 
        case 'L':
-           fix_dlc = 1;
+           if (optarg[0] == 'r') {
+               dlc_mode = MODE_RANDOM;
+           } else if (optarg[0] == 'i') {
+               dlc_mode = MODE_INCREMENT;
+           } else {
+               dlc_mode = MODE_FIX;
+               frame.can_dlc = atoi(optarg)%9;
+           }
            break;
 
-       case 'f':
-           default_frame = 0;
-           if (parse_canframe(optarg, &frame)) {
-               fprintf(stderr, "'%s' is a wrong CAN frame format.\n", optarg);
-               exit(1);
+       case 'D':
+           if (optarg[0] == 'r') {
+               data_mode = MODE_RANDOM;
+           } else if (optarg[0] == 'i') {
+               data_mode = MODE_INCREMENT;
+           } else {
+               data_mode = MODE_FIX;
+               incdata = strtoull(optarg, NULL, 16);
+               for (i=0; i<8 ;i++)
+                   frame.data[i] = (incdata >> (7-i)*8) & 0xFFULL;
            }
            break;
 
        case 'v':
-           verbose = 1;
+           verbose++;
            break;
 
        case 'x':
            loopback_disable = 1;
            break;
 
+       case '?':
+       case 'h':
        default:
            print_usage(basename(argv[0]));
-           exit(1);
+           return 1;
            break;
        }
     }
 
     if (optind == argc) {
        print_usage(basename(argv[0]));
-       exit(0);
+       return 1;
     }
 
     ts.tv_sec = gap / 1000;
     ts.tv_nsec = (gap % 1000) * 1000000;
 
 
-    if (default_frame) {
+    if (id_mode == MODE_FIX) {
+
+       /* recognize obviously missing commandline option */
+       if ((frame.can_id > 0x7FF) && !extended) {
+           printf("The given CAN-ID is greater than 0x7FF and "
+                  "the '-e' option is not set.\n");
+           return 1;
+       }
+
        if (extended)
-           frame.can_id = 0x12345678 | CAN_EFF_FLAG;
+           frame.can_id &= CAN_EFF_MASK;
        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;
+           frame.can_id &= CAN_SFF_MASK;
+    }
+
+    if (extended)
+           frame.can_id |=  CAN_EFF_FLAG;
+
+    if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
+       frame.can_dlc = 1; /* min dlc value for incr. data */
+
+    if (strlen(argv[optind]) >= IFNAMSIZ) {
+       printf("Name of CAN device '%s' is too long!\n\n", argv[optind]);
+       return 1;
     }
 
     if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
@@ -230,8 +285,10 @@ int main(int argc, char **argv)
 
     while (running) {
 
-       if (!fix_id) {
+       if (id_mode == MODE_RANDOM) {
+
            frame.can_id = random();
+
            if (extended) {
                frame.can_id &= CAN_EFF_MASK;
                frame.can_id |= CAN_EFF_FLAG;
@@ -239,21 +296,46 @@ int main(int argc, char **argv)
                frame.can_id &= CAN_SFF_MASK;
        }
 
-       if (!fix_dlc) {
+       if (dlc_mode == MODE_RANDOM) {
+
            frame.can_dlc = random() & 0xF;
+
            if (frame.can_dlc & 8)
                frame.can_dlc = 8; /* for about 50% of the frames */
+
+           if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
+               frame.can_dlc = 1; /* min dlc value for incr. data */
        }
 
-       if (!fix_data) {
+       if (data_mode == MODE_RANDOM) {
+
            /* 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;
+       if (verbose) {
+
+           printf("  %s  ", argv[optind]);
+
+           if (verbose > 1)
+               fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0);
+           else
+               fprint_canframe(stdout, &frame, "\n", 1);
+       }
+
+       nbytes = write(s, &frame, sizeof(struct can_frame));
+       if (nbytes < 0) {
+           if (errno != ENOBUFS) {
+               perror("write");
+               return 1;
+           }
+           if (!ignore_enobufs) {
+               perror("write");
+               return 1;
+           }
+           enobufs_count++;
+
        } else if (nbytes < sizeof(struct can_frame)) {
            fprintf(stderr, "write: incomplete CAN frame\n");
            return 1;
@@ -263,14 +345,39 @@ int main(int argc, char **argv)
            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
+       if (id_mode == MODE_INCREMENT) {
+
+           frame.can_id++;
+
+           if (extended) {
+               frame.can_id &= CAN_EFF_MASK;
+               frame.can_id |= CAN_EFF_FLAG;
+           } else
+               frame.can_id &= CAN_SFF_MASK;
+       }
+
+       if (dlc_mode == MODE_INCREMENT) {
+
+           frame.can_dlc++;
+           frame.can_dlc %= 9;
+
+           if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
+               frame.can_dlc = 1; /* min dlc value for incr. data */
+       }
+
+       if (data_mode == MODE_INCREMENT) {
+
+           incdata++;
+
+           for (i=0; i<8 ;i++)
+               frame.data[i] = (incdata >> i*8) & 0xFFULL;
+       }
     }
 
+    if (enobufs_count)
+       printf("\nCounted %llu ENOBUFS return values on write().\n\n",
+              enobufs_count);
+
     close(s);
 
     return 0;