diff --git a/Makefile b/Makefile index 11fa7a1..441dbcb 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/candump.c b/candump.c index a680d2a..444cf7d 100644 --- a/candump.c +++ b/candump.c @@ -66,8 +66,7 @@ #include #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" @@ -81,8 +80,12 @@ #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 (default 0x00000000)\n"); fprintf(stderr, " -v (default 0x00000000)\n"); fprintf(stderr, " -i <0|1> (inv_filter)\n"); + fprintf(stderr, " -e (mask for error frames)\n"); fprintf(stderr, " -t (timestamp: Absolute/Delta/Zero)\n"); fprintf(stderr, " -c (color mode)\n"); + fprintf(stderr, " -a (enable additional ASCII output)\n"); fprintf(stderr, " -s (silent mode - 1: animation 2: nothing)\n"); fprintf(stderr, " -b (bridge mode - send received frames to )\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 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 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 0x1F) && (frame.data[j] < 0x7F)) - putchar(frame.data[j]); - else - putchar('.'); - printf("' "); - } - if (frame.can_id & CAN_RTR_FLAG) - printf("remote request"); - printf("\n"); - } - } - fflush(stdout); } + + 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 (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++; + } + continue; + } + + 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; + } + + 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/cangen.c b/cangen.c new file mode 100644 index 0000000..660dacb --- /dev/null +++ b/cangen.c @@ -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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#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 (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 (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; +} diff --git a/cansend.c b/cansend.c index 7b94ff8..dd9d73e 100644 --- a/cansend.c +++ b/cansend.c @@ -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); diff --git a/lib.c b/lib.c index 475ecd3..acbbb4b 100644 --- a/lib.c +++ b/lib.c @@ -52,10 +52,15 @@ #include /* for sa_family_t */ #include +#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); - - fprintf(stream, "[%d] ", cf->can_dlc); - - for (i = 0; i < cf->can_dlc; i++) { - fprintf(stream, "%02X ", cf->data[i]); - } - if (cf->can_id & CAN_RTR_FLAG) - fprintf(stream, "remote request"); + 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 */ + + int i,offset; + + 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) /* 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, "'"); + } + } +} + diff --git a/lib.h b/lib.h index 4b010da..70d440d 100644 --- a/lib.h +++ b/lib.h @@ -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/log2asc.c b/log2asc.c new file mode 100644 index 0000000..914a396 --- /dev/null +++ b/log2asc.c @@ -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 + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#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 (default stdin)\n"); + fprintf(stderr, " -O (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 + * + */ + +#include + +#include +#include + +#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; +}