X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=canplayer.c;h=f74668e0fa6e597f4ef9b353da0701069cbd049a;hb=2fa9b0005b59b6f91779c194499998374c5ffa05;hp=7260b3a17a803e72d819e7bb057e2fbd3a23ecd0;hpb=d0b24ffc1098f03b7cd1ded73e55fe3b9390d38e;p=profile%2Fivi%2Fcan-utils.git diff --git a/canplayer.c b/canplayer.c index 7260b3a..f74668e 100644 --- a/canplayer.c +++ b/canplayer.c @@ -1,8 +1,4 @@ /* - * $Id$ - */ - -/* * canplayer.c - replay a compact CAN frame logfile to CAN devices * * Copyright (c) 2002-2007 Volkswagen Group Electronic Research @@ -41,7 +37,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * - * Send feedback to + * Send feedback to * */ @@ -53,6 +49,7 @@ #include #include +#include #include #include #include @@ -60,44 +57,51 @@ #include "lib.h" -#define DEFAULT_GAP 1 /* ms */ -#define DEFAULT_LOOPS 1 /* only one replay */ -#define CHANNELS 20 /* anyone using more than 20 CAN interfaces at a time? */ -#define BUFSZ 100 /* for one line in the logfile */ +#define DEFAULT_GAP 1 /* ms */ +#define DEFAULT_LOOPS 1 /* only one replay */ +#define CHANNELS 20 /* anyone using more than 20 CAN interfaces at a time? */ +#define COMMENTSZ 200 +#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */ +#define STDOUTIDX 65536 /* interface index for printing on stdout - bigger than max uint16 */ struct assignment { - char txif[IFNAMSIZ]; - int txifidx; - char rxif[IFNAMSIZ]; + char txif[IFNAMSIZ]; + int txifidx; + char rxif[IFNAMSIZ]; }; static struct assignment asgn[CHANNELS]; +const int canfd_on = 1; extern int optind, opterr, optopt; void print_usage(char *prg) { - fprintf(stderr, "\nUsage: %s [interface assignment]*\n\n", prg); - fprintf(stderr, "Options: -I (default stdin)\n"); - fprintf(stderr, " -l " - "(process input file times)\n" - " " - "(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS); - fprintf(stderr, " -t (ignore timestamps: " - "send frames immediately)\n"); - fprintf(stderr, " -g (gap in milli " - "seconds - default: %d ms)\n", DEFAULT_GAP); - fprintf(stderr, " -s (skip gaps in " - "timestamps > 's' seconds)\n"); - fprintf(stderr, " -x (disable local " - "loopback of sent CAN frames)\n"); - fprintf(stderr, " -v (verbose: print " - "sent CAN frames)\n\n"); - fprintf(stderr, "Interface assignment: 0..n assignments like " - "=\n"); - fprintf(stderr, "e.g. vcan2=can0 ( send frames received from can0 on " - "vcan2 )\n"); - fprintf(stderr, "No assignments => send frames to the interface(s) they " - "had been received from.\n\n"); + fprintf(stderr, "\nUsage: %s [interface assignment]*\n\n", prg); + fprintf(stderr, "Options: -I (default stdin)\n"); + fprintf(stderr, " -l " + "(process input file times)\n" + " " + "(Use 'i' for infinite loop - default: %d)\n", DEFAULT_LOOPS); + fprintf(stderr, " -t (ignore timestamps: " + "send frames immediately)\n"); + fprintf(stderr, " -g (gap in milli " + "seconds - default: %d ms)\n", DEFAULT_GAP); + fprintf(stderr, " -s (skip gaps in " + "timestamps > 's' seconds)\n"); + fprintf(stderr, " -x (disable local " + "loopback of sent CAN frames)\n"); + fprintf(stderr, " -v (verbose: print " + "sent CAN frames)\n\n"); + fprintf(stderr, "Interface assignment: 0..n assignments like " + "=\n"); + fprintf(stderr, "e.g. vcan2=can0 ( send frames received from can0 on " + "vcan2 )\n"); + fprintf(stderr, "extra hook: stdout=can0 ( print logfile line marked with can0 on " + "stdout )\n"); + fprintf(stderr, "No assignments => send frames to the interface(s) they " + "had been received from.\n\n"); + fprintf(stderr, "Lines in the logfile not beginning with '(' (start of " + "timestamp) are ignored.\n\n"); } /* copied from /usr/src/linux/include/linux/time.h ... @@ -107,367 +111,402 @@ void print_usage(char *prg) */ static inline int timeval_compare(struct timeval *lhs, struct timeval *rhs) { - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_usec - rhs->tv_usec; + if (lhs->tv_sec < rhs->tv_sec) + return -1; + if (lhs->tv_sec > rhs->tv_sec) + return 1; + return lhs->tv_usec - rhs->tv_usec; } static inline void create_diff_tv(struct timeval *today, struct timeval *diff, struct timeval *log) { - /* create diff_tv so that log_tv + diff_tv = today_tv */ - diff->tv_sec = today->tv_sec - log->tv_sec; - diff->tv_usec = today->tv_usec - log->tv_usec; + /* create diff_tv so that log_tv + diff_tv = today_tv */ + diff->tv_sec = today->tv_sec - log->tv_sec; + diff->tv_usec = today->tv_usec - log->tv_usec; } static inline int frames_to_send(struct timeval *today, struct timeval *diff, struct timeval *log) { - /* return value <0 when log + diff < today */ + /* return value <0 when log + diff < today */ - struct timeval cmp; + struct timeval cmp; - cmp.tv_sec = log->tv_sec + diff->tv_sec; - cmp.tv_usec = log->tv_usec + diff->tv_usec; + cmp.tv_sec = log->tv_sec + diff->tv_sec; + cmp.tv_usec = log->tv_usec + diff->tv_usec; - if (cmp.tv_usec > 1000000) { - cmp.tv_usec -= 1000000; - cmp.tv_sec++; - } + if (cmp.tv_usec > 1000000) { + cmp.tv_usec -= 1000000; + cmp.tv_sec++; + } - if (cmp.tv_usec < 0) { - cmp.tv_usec += 1000000; - cmp.tv_sec--; - } + if (cmp.tv_usec < 0) { + cmp.tv_usec += 1000000; + cmp.tv_sec--; + } - return timeval_compare(&cmp, today); + return timeval_compare(&cmp, today); } int get_txidx(char *logif_name) { - int i; + int i; - for (i=0; i= IFNAMSIZ) { - fprintf(stderr, "write-if interface name '%s' too long!", txname); - return 1; - } - strcpy(asgn[i].txif, txname); - - if (strlen(rxname) >= IFNAMSIZ) { - fprintf(stderr, "log-if interface name '%s' too long!", rxname); - return 1; - } - strcpy(asgn[i].rxif, rxname); - - strcpy(ifr.ifr_name, txname); - if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) { - perror("SIOCGIFINDEX"); - fprintf(stderr, "write-if interface name '%s' is wrong!\n", txname); - return 1; - } - asgn[i].txifidx = ifr.ifr_ifindex; - - if (verbose > 1) /* use -v -v to see this */ - printf("added %s assignment: log-if=%s write-if=%s write-if-idx=%d\n", - mode, asgn[i].rxif, asgn[i].txif, asgn[i].txifidx); - - return 0; + struct ifreq ifr; + int i; + + /* find free entry */ + for (i=0; i= IFNAMSIZ) { + fprintf(stderr, "write-if interface name '%s' too long!", txname); + return 1; + } + strcpy(asgn[i].txif, txname); + + if (strlen(rxname) >= IFNAMSIZ) { + fprintf(stderr, "log-if interface name '%s' too long!", rxname); + return 1; + } + strcpy(asgn[i].rxif, rxname); + + if (strcmp(txname, "stdout")) { + strcpy(ifr.ifr_name, txname); + if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) { + perror("SIOCGIFINDEX"); + fprintf(stderr, "write-if interface name '%s' is wrong!\n", txname); + return 1; + } + asgn[i].txifidx = ifr.ifr_ifindex; + } else + asgn[i].txifidx = STDOUTIDX; + + if (verbose > 1) /* use -v -v to see this */ + printf("added %s assignment: log-if=%s write-if=%s write-if-idx=%d\n", + mode, asgn[i].rxif, asgn[i].txif, asgn[i].txifidx); + + return 0; } int main(int argc, char **argv) { - static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; - struct sockaddr_can addr; - static struct can_frame frame; - static struct timeval today_tv, log_tv, last_log_tv, diff_tv; - struct timespec sleep_ts; - int s; /* CAN_RAW socket */ - FILE *infile = stdin; - unsigned long gap = DEFAULT_GAP; - int use_timestamps = 1; - static int verbose, opt, delay_loops, skipgap; - static int loopback_disable = 0; - static int infinite_loops = 0; - static int loops = DEFAULT_LOOPS; - int assignments; /* assignments defined on the commandline */ - int txidx; /* sendto() interface index */ - int eof, nbytes, i, j; - - while ((opt = getopt(argc, argv, "I:l:tg:s:xv")) != -1) { - switch (opt) { - case 'I': - infile = fopen(optarg, "r"); - if (!infile) { - perror("infile"); - return 1; - } - break; - - case 'l': - if (optarg[0] == 'i') - infinite_loops = 1; - else - if (!(loops = atoi(optarg))) { - fprintf(stderr, "Invalid argument for option -l !\n"); - return 1; + static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; + struct sockaddr_can addr; + static struct canfd_frame frame; + static struct timeval today_tv, log_tv, last_log_tv, diff_tv; + struct timespec sleep_ts; + int s; /* CAN_RAW socket */ + FILE *infile = stdin; + unsigned long gap = DEFAULT_GAP; + int use_timestamps = 1; + static int verbose, opt, delay_loops, skipgap; + static int loopback_disable = 0; + static int infinite_loops = 0; + static int loops = DEFAULT_LOOPS; + int assignments; /* assignments defined on the commandline */ + int txidx; /* sendto() interface index */ + int eof, txmtu, i, j; + char *fret; + + while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) { + switch (opt) { + case 'I': + infile = fopen(optarg, "r"); + if (!infile) { + perror("infile"); + return 1; + } + break; + + case 'l': + if (optarg[0] == 'i') + infinite_loops = 1; + else + if (!(loops = atoi(optarg))) { + fprintf(stderr, "Invalid argument for option -l !\n"); + return 1; + } + break; + + case 't': + use_timestamps = 0; + break; + + case 'g': + gap = strtoul(optarg, NULL, 10); + break; + + case 's': + skipgap = strtoul(optarg, NULL, 10); + if (skipgap < 1) { + fprintf(stderr, "Invalid argument for option -s !\n"); + return 1; + } + break; + + case 'x': + loopback_disable = 1; + break; + + case 'v': + verbose++; + break; + + case '?': + default: + print_usage(basename(argv[0])); + return 1; + break; } - break; + } + + assignments = argc - optind; /* find real number of user assignments */ - case 't': - use_timestamps = 0; - break; + if (infile == stdin) { /* no jokes with stdin */ + infinite_loops = 0; + loops = 1; + } + + if (verbose > 1) { /* use -v -v to see this */ + if (infinite_loops) + printf("infinite_loops\n"); + else + printf("%d loops\n", loops); + } - case 'g': - gap = strtoul(optarg, NULL, 10); - break; + sleep_ts.tv_sec = gap / 1000; + sleep_ts.tv_nsec = (gap % 1000) * 1000000; - case 's': - skipgap = strtoul(optarg, NULL, 10); - if (skipgap < 1) { - fprintf(stderr, "Invalid argument for option -s !\n"); + /* open socket */ + if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + perror("socket"); return 1; - } - break; + } - case 'x': - loopback_disable = 1; - break; + addr.can_family = AF_CAN; + addr.can_ifindex = 0; - case 'v': - verbose++; - break; + /* disable unneeded default receive filter on this RAW socket */ + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - default: - print_usage(basename(argv[0])); - return 1; - break; + /* try to switch the socket into CAN FD mode */ + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + + if (loopback_disable) { + int loopback = 0; + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, + &loopback, sizeof(loopback)); } - } - - assignments = argc - optind; /* find real number of user assignments */ - - if (infile == stdin) { /* no jokes with stdin */ - infinite_loops = 0; - loops = 1; - } - - if (verbose > 1) /* use -v -v to see this */ - if (infinite_loops) - printf("infinite_loops\n"); - else - printf("%d loops\n", loops); - - sleep_ts.tv_sec = gap / 1000; - sleep_ts.tv_nsec = (gap % 1000) * 1000000; - - /* open socket */ - if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { - perror("socket"); - return 1; - } - - addr.can_family = AF_CAN; - addr.can_ifindex = 0; - - /* disable unneeded default receive filter on this RAW socket */ - setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - - if (loopback_disable) { - int loopback = 0; - - setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, - &loopback, sizeof(loopback)); - } - - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - perror("bind"); - return 1; - } - - if (assignments) { - /* add & check user assginments from commandline */ - for (i=0; i= BUFSZ) { - fprintf(stderr, "Assignment too long!\n"); - print_usage(basename(argv[0])); - return 1; - } - strcpy(buf, argv[optind+i]); - for (j=0; j= BUFSZ-2) { + fprintf(stderr, "comment line too long for input buffer\n"); + return 1; + } + } - if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec, - device, ascframe) != 4) - return 1; + if (!fret) + goto out; /* nothing to read */ - if (use_timestamps) { /* throttle sending due to logfile timestamps */ + eof = 0; - gettimeofday(&today_tv, NULL); - create_diff_tv(&today_tv, &diff_tv, &log_tv); - last_log_tv = log_tv; - } + if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec, + device, ascframe) != 4) { + fprintf(stderr, "incorrect line format in logfile\n"); + return 1; + } - while (!eof) { + if (use_timestamps) { /* throttle sending due to logfile timestamps */ - while ((!use_timestamps) || - (frames_to_send(&today_tv, &diff_tv, &log_tv) < 0)) { + gettimeofday(&today_tv, NULL); + create_diff_tv(&today_tv, &diff_tv, &log_tv); + last_log_tv = log_tv; + } - /* log_tv/device/ascframe are valid here */ + while (!eof) { - if (strlen(device) >= IFNAMSIZ) { - fprintf(stderr, "log interface name '%s' too long!", device); - return 1; - } + while ((!use_timestamps) || + (frames_to_send(&today_tv, &diff_tv, &log_tv) < 0)) { - txidx = get_txidx(device); /* get ifindex for sending the frame */ + /* log_tv/device/ascframe are valid here */ + + if (strlen(device) >= IFNAMSIZ) { + fprintf(stderr, "log interface name '%s' too long!", device); + return 1; + } + + txidx = get_txidx(device); /* get ifindex for sending the frame */ - if ((!txidx) && (!assignments)) { - /* ifindex not found and no user assignments */ - /* => assign this device automatically */ - if (add_assignment("auto", s, device, device, verbose)) - return 1; - txidx = get_txidx(device); - } + if ((!txidx) && (!assignments)) { + /* ifindex not found and no user assignments */ + /* => assign this device automatically */ + if (add_assignment("auto", s, device, device, verbose)) + return 1; + txidx = get_txidx(device); + } - if (txidx) { /* only send to valid CAN devices */ + if (txidx == STDOUTIDX) { /* hook to print logfile lines on stdout */ - if (parse_canframe(ascframe, &frame)) { - fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe); - return 1; - } + printf("%s", buf); /* print the line AS-IS without extra \n */ + fflush(stdout); + + } else if (txidx > 0) { /* only send to valid CAN devices */ - addr.can_family = AF_CAN; - addr.can_ifindex = txidx; /* send via this interface */ + txmtu = parse_canframe(ascframe, &frame); + if (!txmtu) { + fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe); + return 1; + } + + addr.can_family = AF_CAN; + addr.can_ifindex = txidx; /* send via this interface */ - nbytes = sendto(s, &frame, sizeof(struct can_frame), 0, - (struct sockaddr*)&addr, sizeof(addr)); + if (sendto(s, &frame, txmtu, 0, (struct sockaddr*)&addr, sizeof(addr)) != txmtu) { + perror("sendto"); + return 1; + } - if (nbytes != sizeof(struct can_frame)) { - perror("sendto"); - return 1; - } + if (verbose) { + printf("%s (%s) ", get_txname(device), device); - if (verbose) { - printf("%s (%s) ", get_txname(device), device); - fprint_long_canframe(stdout, &frame, "\n", 1); - } - } + if (txmtu == CAN_MTU) + fprint_long_canframe(stdout, &frame, "\n", CANLIB_VIEW_INDENT_SFF, CAN_MAX_DLEN); + else + fprint_long_canframe(stdout, &frame, "\n", CANLIB_VIEW_INDENT_SFF, CANFD_MAX_DLEN); + } + } - /* read next frame from logfile */ - if (!fgets(buf, BUFSZ-1, infile)) { - eof = 1; /* this file is completely processed */ - break; - } + /* read next non-comment frame from logfile */ + while ((fret = fgets(buf, BUFSZ-1, infile)) != NULL && buf[0] != '(') { + if (strlen(buf) >= BUFSZ-2) { + fprintf(stderr, "comment line too long for input buffer\n"); + return 1; + } + } - if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec, - device, ascframe) != 4) - return 1; + if (!fret) { + eof = 1; /* this file is completely processed */ + break; + } - if (use_timestamps) { - gettimeofday(&today_tv, NULL); + if (sscanf(buf, "(%ld.%ld) %s %s", &log_tv.tv_sec, &log_tv.tv_usec, + device, ascframe) != 4) { + fprintf(stderr, "incorrect line format in logfile\n"); + return 1; + } - /* test for logfile timestamps jumping backwards OR */ - /* if the user likes to skip long gaps in the timestamps */ - if ((last_log_tv.tv_sec > log_tv.tv_sec) || - (skipgap && abs(last_log_tv.tv_sec - log_tv.tv_sec) > skipgap)) - create_diff_tv(&today_tv, &diff_tv, &log_tv); + if (use_timestamps) { + gettimeofday(&today_tv, NULL); - last_log_tv = log_tv; - } + /* test for logfile timestamps jumping backwards OR */ + /* if the user likes to skip long gaps in the timestamps */ + if ((last_log_tv.tv_sec > log_tv.tv_sec) || + (skipgap && abs(last_log_tv.tv_sec - log_tv.tv_sec) > skipgap)) + create_diff_tv(&today_tv, &diff_tv, &log_tv); - } /* while frames_to_send ... */ + last_log_tv = log_tv; + } - if (nanosleep(&sleep_ts, NULL)) - return 1; + } /* while frames_to_send ... */ - delay_loops++; /* private statistics */ - gettimeofday(&today_tv, NULL); + if (nanosleep(&sleep_ts, NULL)) + return 1; - } /* while (!eof) */ + delay_loops++; /* private statistics */ + gettimeofday(&today_tv, NULL); - } /* while (infinite_loops || loops--) */ + } /* while (!eof) */ - out: + } /* while (infinite_loops || loops--) */ - close(s); - fclose(infile); +out: - if (verbose > 1) /* use -v -v to see this */ - printf("%d delay_loops\n", delay_loops); + close(s); + fclose(infile); + + if (verbose > 1) /* use -v -v to see this */ + printf("%d delay_loops\n", delay_loops); - return 0; + return 0; }