From e7631bd7f94804962e48cde2e7de37370c31a8b8 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 14 Nov 2012 19:47:21 +0100 Subject: [PATCH] canfd: upgrade tools to support CAN FD for Linux 3.6 This is a major upgrade of the basic tools to handle CAN FD frames. The library to parse and print CAN frames and logfiles has been extended. In detail: asc2log.c | 5 + candump.c | 24 ++++--- cangen.c | 172 +++++++++++++++++++++++++++++++++------------------ canlogserver.c | 28 +++++--- canplayer.c | 25 ++++--- cansend.c | 55 ++++++++++++---- lib.c | 189 ++++++++++++++++++++++++++++++++++++++------------------- lib.h | 109 ++++++++++++++++++++++++-------- log2asc.c | 8 +- log2long.c | 26 ++++++- 10 files changed, 440 insertions(+), 201 deletions(-) asc2log.c / log2asc.c - updates for new lib functions - still can only handle CAN2.0 frames (no new info about ASC file layout) log2long.c / canlogserver.c / canplayer.c - updates for new lib functions to handle CAN FD lib.h / lib.c - reworked lib functions to handle CAN FD - parse_canframe() now returns CAN_MTU and CANFD_MTU on success, 0 at failure - added can_dlc2len() and can_len2dlc() helpers - moved hexstring2candata to hexstring2data to support simple byte buffers - in the long CAN frame representation use %03X/%08X instead of %3X/%8X - introduced unified buffer size definitions for ASCII CAN frames - updated documentation cangen.c - support CAN FD frames (added -f option to create CAN FD frames) - added -m option ('mix') to create random extended / RTR / CAN FD frames - fixed the 'fixed data' option which was zero'ing the payload by the time - updated help text candump.c - support CAN FD frames (print, bridge, log) - distinguish frame types by length info: [0] = CAN2.0 [00] = CAN FD frame Signed-off-by: Oliver Hartkopp --- asc2log.c | 5 +- candump.c | 24 ++++--- cangen.c | 172 ++++++++++++++++++++++++++++---------------- canlogserver.c | 28 +++++--- canplayer.c | 25 ++++--- cansend.c | 55 ++++++++++---- lib.c | 189 +++++++++++++++++++++++++++++++++---------------- lib.h | 109 ++++++++++++++++++++-------- log2asc.c | 8 +-- log2long.c | 26 +++++-- 10 files changed, 440 insertions(+), 201 deletions(-) diff --git a/asc2log.c b/asc2log.c index 8c0e0a5..cc0a7c3 100644 --- a/asc2log.c +++ b/asc2log.c @@ -73,11 +73,14 @@ void print_usage(char *prg) void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) { fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec); + if (dev > 0) fprintf(file, "can%d ", dev-1); else fprintf(file, "canX "); - fprint_canframe(file, cf, "\n", 0); + + /* no CAN FD support so far */ + fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN); } void get_can_id(struct can_frame *cf, char *idstring, int base) { diff --git a/candump.c b/candump.c index ac51192..11be0ae 100644 --- a/candump.c +++ b/candump.c @@ -95,6 +95,7 @@ static __u32 last_dropcnt[MAXSOCK]; static char devname[MAXIFNAMES][IFNAMSIZ+1]; static int dindex[MAXIFNAMES]; static int max_devname_len; /* to prevent frazzled device name output */ +const int canfd_on = 1; #define MAXANI 4 const char anichar[MAXANI] = {'|', '/', '-', '\\'}; @@ -223,8 +224,8 @@ int main(int argc, char **argv) struct cmsghdr *cmsg; struct can_filter *rfilter; can_err_mask_t err_mask; - struct can_frame frame; - int nbytes, i; + struct canfd_frame frame; + int nbytes, i, maxdlen; struct ifreq ifr; struct timeval tv, last_tv; FILE *logfile = NULL; @@ -483,6 +484,9 @@ int main(int argc, char **argv) } /* if (nptr) */ + /* try to switch the socket into CAN FD mode */ + setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + if (rcvbuf_size) { int curr_rcvbuf_size; @@ -611,7 +615,11 @@ int main(int argc, char **argv) return 1; } - if ((size_t)nbytes < sizeof(struct can_frame)) { + if ((size_t)nbytes == CAN_MTU) + maxdlen = CAN_MAX_DLEN; + else if ((size_t)nbytes == CANFD_MTU) + maxdlen = CANFD_MAX_DLEN; + else { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; } @@ -623,11 +631,11 @@ int main(int argc, char **argv) if (bridge_delay) usleep(bridge_delay); - nbytes = write(bridge, &frame, sizeof(struct can_frame)); + nbytes = write(bridge, &frame, nbytes); if (nbytes < 0) { perror("bridge write"); return 1; - } else if ((size_t)nbytes < sizeof(struct can_frame)) { + } else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) { fprintf(stderr,"bridge write: incomplete CAN frame\n"); return 1; } @@ -670,14 +678,14 @@ int main(int argc, char **argv) fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); fprintf(logfile, "%*s ", max_devname_len, devname[idx]); /* without seperator as logfile use-case is parsing */ - fprint_canframe(logfile, &frame, "\n", 0); + fprint_canframe(logfile, &frame, "\n", 0, maxdlen); } if (logfrmt) { /* print CAN frame in log file style to stdout */ printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); printf("%*s ", max_devname_len, devname[idx]); - fprint_canframe(stdout, &frame, "\n", 0); + fprint_canframe(stdout, &frame, "\n", 0, maxdlen); goto out_fflush; /* no other output to stdout */ } @@ -736,7 +744,7 @@ int main(int argc, char **argv) printf("%*s", max_devname_len, devname[idx]); printf("%s ", (color==1)?col_off:""); - fprint_long_canframe(stdout, &frame, NULL, view); + fprint_long_canframe(stdout, &frame, NULL, view, maxdlen); printf("%s", (color>1)?col_off:""); printf("\n"); diff --git a/cangen.c b/cangen.c index efb8251..6cf6c07 100644 --- a/cangen.c +++ b/cangen.c @@ -87,6 +87,9 @@ void print_usage(char *prg) "- default: %d ms)\n", DEFAULT_GAP); fprintf(stderr, " -e (generate extended frame mode " "(EFF) CAN frames)\n"); + fprintf(stderr, " -f (generate CAN FD CAN frames)\n"); + fprintf(stderr, " -R (send RTR frame)\n"); + fprintf(stderr, " -m (mix -e -f -R frames)\n"); fprintf(stderr, " -I (CAN ID" " generation mode - see below)\n"); fprintf(stderr, " -L (CAN data length code (dlc)" @@ -101,7 +104,6 @@ void print_usage(char *prg) " write() syscalls)\n"); fprintf(stderr, " -x (disable local loopback of " "generated CAN frames)\n"); - fprintf(stderr, " -R (send RTR frame)\n"); fprintf(stderr, " -v (increment verbose level for " "printing sent CAN frames)\n\n"); fprintf(stderr, "Generation modes:\n"); @@ -137,6 +139,8 @@ int main(int argc, char **argv) unsigned long polltimeout = 0; unsigned char ignore_enobufs = 0; unsigned char extended = 0; + unsigned char canfd = 0; + unsigned char mix = 0; unsigned char id_mode = MODE_RANDOM; unsigned char data_mode = MODE_RANDOM; unsigned char dlc_mode = MODE_RANDOM; @@ -144,14 +148,17 @@ int main(int argc, char **argv) unsigned char verbose = 0; unsigned char rtr_frame = 0; int count = 0; + int mtu, maxdlen; uint64_t incdata = 0; + int incdlc = 0; + unsigned char fixdata[CANFD_MAX_DLEN]; int opt; int s; /* socket */ struct pollfd fds; struct sockaddr_can addr; - static struct can_frame frame; + static struct canfd_frame frame; int nbytes; int i; struct ifreq ifr; @@ -167,7 +174,7 @@ int main(int argc, char **argv) signal(SIGHUP, sigterm); signal(SIGINT, sigterm); - while ((opt = getopt(argc, argv, "ig:eI:L:D:xp:n:vRh?")) != -1) { + while ((opt = getopt(argc, argv, "ig:efmI:L:D:xp:n:vRh?")) != -1) { switch (opt) { case 'i': @@ -182,6 +189,15 @@ int main(int argc, char **argv) extended = 1; break; + case 'f': + canfd = 1; + break; + + case 'm': + mix = 1; + canfd = 1; /* to switch the socket into CAN FD mode */ + break; + case 'I': if (optarg[0] == 'r') { id_mode = MODE_RANDOM; @@ -200,7 +216,7 @@ int main(int argc, char **argv) dlc_mode = MODE_INCREMENT; } else { dlc_mode = MODE_FIX; - frame.can_dlc = atoi(optarg)%9; + frame.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */ } break; @@ -211,7 +227,7 @@ int main(int argc, char **argv) data_mode = MODE_INCREMENT; } else { data_mode = MODE_FIX; - if (hexstring2candata(optarg, &frame)) { + if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) { printf ("wrong fix data definition\n"); return 1; } @@ -259,30 +275,13 @@ int main(int argc, char **argv) ts.tv_sec = gap / 1000; ts.tv_nsec = ((int)(gap * 1000000)) % 1000000000; - 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 &= CAN_EFF_MASK; - else - frame.can_id &= CAN_SFF_MASK; + /* recognize obviously missing commandline option */ + if (id_mode == MODE_FIX && 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 (rtr_frame) - frame.can_id |= CAN_RTR_FLAG; - - 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; @@ -315,6 +314,34 @@ int main(int argc, char **argv) &loopback, sizeof(loopback)); } + if (canfd) { + int enable_canfd = 1; + + /* check if the frame fits into the CAN netdevice */ + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + perror("SIOCGIFMTU"); + return 1; + } + + if (ifr.ifr_mtu != CANFD_MTU) { + printf("CAN interface ist not CAN FD capable - sorry.\n"); + return 1; + } + + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))){ + printf("error when enabling CAN FD support\n"); + return 1; + } + + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + frame.len = can_dlc2len(can_len2dlc(frame.len)); + } else { + /* sanitize CAN 2.0 frame length */ + if (frame.len > 8) + frame.len = 8; + } + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; @@ -330,51 +357,73 @@ int main(int argc, char **argv) if (count && (--count == 0)) running = 0; - if (id_mode == MODE_RANDOM) { + if (canfd){ + mtu = CANFD_MTU; + maxdlen = CANFD_MAX_DLEN; + } else { + mtu = CAN_MTU; + maxdlen = CAN_MAX_DLEN; + } + if (id_mode == MODE_RANDOM) 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 (dlc_mode == MODE_RANDOM) { + if (extended) { + frame.can_id &= CAN_EFF_MASK; + frame.can_id |= CAN_EFF_FLAG; + } else + frame.can_id &= CAN_SFF_MASK; - frame.can_dlc = random() & 0xF; + if (rtr_frame && !canfd) + frame.can_id |= CAN_RTR_FLAG; - if (frame.can_dlc & 8) - frame.can_dlc = 8; /* for about 50% of the frames */ + if (dlc_mode == MODE_RANDOM) { - if ((data_mode == MODE_INCREMENT) && !frame.can_dlc) - frame.can_dlc = 1; /* min dlc value for incr. data */ + if (canfd) + frame.len = can_dlc2len(random() & 0xF); + else { + frame.len = random() & 0xF; + if (frame.len & 8) + frame.len = 8; /* for about 50% of the frames */ + } } + if (data_mode == MODE_INCREMENT && !frame.len) + frame.len = 1; /* min dlc value for incr. 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(); + + /* omit extra random number generation for CAN FD */ + if (canfd && frame.len > 8) { + memcpy(&frame.data[8], &frame.data[0], 8); + memcpy(&frame.data[16], &frame.data[0], 16); + memcpy(&frame.data[32], &frame.data[0], 32); + } } + if (data_mode == MODE_FIX) + memcpy(frame.data, fixdata, CANFD_MAX_DLEN); + /* set unused payload data to zero like the CAN driver does it on rx */ - if (frame.can_dlc < 8) - memset(&frame.data[frame.can_dlc], 0, 8 - frame.can_dlc); + if (frame.len < maxdlen) + memset(&frame.data[frame.len], 0, maxdlen - frame.len); if (verbose) { printf(" %s ", argv[optind]); if (verbose > 1) - fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0); + fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0, maxdlen); else - fprint_canframe(stdout, &frame, "\n", 1); + fprint_canframe(stdout, &frame, "\n", 1, maxdlen); } resend: - nbytes = write(s, &frame, sizeof(struct can_frame)); + nbytes = write(s, &frame, mtu); if (nbytes < 0) { if (errno != ENOBUFS) { perror("write"); @@ -394,7 +443,7 @@ resend: } else enobufs_count++; - } else if (nbytes < sizeof(struct can_frame)) { + } else if (nbytes < mtu) { fprintf(stderr, "write: incomplete CAN frame\n"); return 1; } @@ -403,24 +452,20 @@ resend: if (nanosleep(&ts, NULL)) return 1; - if (id_mode == MODE_INCREMENT) { - + 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; + incdlc++; - if ((data_mode == MODE_INCREMENT) && !frame.can_dlc) - frame.can_dlc = 1; /* min dlc value for incr. data */ + if (canfd && !mix) { + incdlc &= 0xF; + frame.len = can_dlc2len(incdlc); + } else { + incdlc %= 9; + frame.len = incdlc; + } } if (data_mode == MODE_INCREMENT) { @@ -430,6 +475,13 @@ resend: for (i=0; i<8 ;i++) frame.data[i] = (incdata >> i*8) & 0xFFULL; } + + if (mix) { + i = random(); + extended = i&1; + canfd = i&2; + rtr_frame = ((i&12) == 12); /* reduce RTR frames to 1/4 */ + } } if (enobufs_count) diff --git a/canlogserver.c b/canlogserver.c index b6fa403..6aeb150 100644 --- a/canlogserver.c +++ b/canlogserver.c @@ -74,6 +74,9 @@ #define ANYDEV "any" #define ANL "\r\n" /* newline in ASC mode */ +#define COMMENTSZ 200 +#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */ + #define DEFPORT 28700 static char devname[MAXDEV][IFNAMSIZ+1]; @@ -183,15 +186,16 @@ int main(int argc, char **argv) int currmax = 1; /* we assume at least one can bus ;-) */ struct sockaddr_can addr; struct can_filter rfilter; - struct can_frame frame; - int nbytes, i, j; + struct canfd_frame frame; + const int canfd_on = 1; + int nbytes, i, j, maxdlen; struct ifreq ifr; struct timeval tv, last_tv; int port = DEFPORT; struct sockaddr_in inaddr; struct sockaddr_in clientaddr; socklen_t sin_size = sizeof(clientaddr); - char temp[128]; + char temp[BUFSZ]; sigemptyset(&sigset); signalaction.sa_handler = &childdied; @@ -339,6 +343,9 @@ int main(int argc, char **argv) setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask[i], sizeof(err_mask[i])); + /* try to switch the socket into CAN FD mode */ + setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + j = strlen(argv[optind+i]); if (!(j < IFNAMSIZ)) { @@ -387,14 +394,17 @@ int main(int argc, char **argv) socklen_t len = sizeof(addr); int idx; - if ((nbytes = recvfrom(s[i], &frame, - sizeof(struct can_frame), 0, + if ((nbytes = recvfrom(s[i], &frame, CANFD_MTU, 0, (struct sockaddr*)&addr, &len)) < 0) { perror("read"); return 1; } - if (nbytes < sizeof(struct can_frame)) { + if ((size_t)nbytes == CAN_MTU) + maxdlen = CAN_MAX_DLEN; + else if ((size_t)nbytes == CANFD_MTU) + maxdlen = CANFD_MAX_DLEN; + else { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; } @@ -407,7 +417,7 @@ int main(int argc, char **argv) sprintf(temp, "(%ld.%06ld) %*s ", tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]); - sprint_canframe(temp+strlen(temp), &frame, 0); + sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen); strcat(temp, "\n"); if (write(accsocket, temp, strlen(temp)) < 0) { @@ -415,13 +425,11 @@ int main(int argc, char **argv) return 1; } - /* printf("%s\n",temp2); */ - #if 0 /* print CAN frame in log file style to stdout */ printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); printf("%*s ", max_devname_len, devname[idx]); - fprint_canframe(stdout, &frame, "\n", 0); + fprint_canframe(stdout, &frame, "\n", 0, maxdlen); #endif } diff --git a/canplayer.c b/canplayer.c index b0b6333..7952177 100644 --- a/canplayer.c +++ b/canplayer.c @@ -64,7 +64,8 @@ #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 400 /* for one line in the logfile */ +#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 { @@ -73,6 +74,7 @@ struct assignment { char rxif[IFNAMSIZ]; }; static struct assignment asgn[CHANNELS]; +const int canfd_on = 1; extern int optind, opterr, optopt; @@ -236,7 +238,7 @@ 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 canfd_frame frame; static struct timeval today_tv, log_tv, last_log_tv, diff_tv; struct timespec sleep_ts; int s; /* CAN_RAW socket */ @@ -249,7 +251,7 @@ int main(int argc, char **argv) static int loops = DEFAULT_LOOPS; int assignments; /* assignments defined on the commandline */ int txidx; /* sendto() interface index */ - int eof, nbytes, i, j; + int eof, txmtu, i, j; char *fret; while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) { @@ -333,6 +335,9 @@ int main(int argc, char **argv) /* disable unneeded default receive filter on this RAW socket */ setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); + /* 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; @@ -432,7 +437,8 @@ int main(int argc, char **argv) } else if (txidx > 0) { /* only send to valid CAN devices */ - if (parse_canframe(ascframe, &frame)) { + txmtu = parse_canframe(ascframe, &frame); + if (!txmtu) { fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe); return 1; } @@ -440,17 +446,18 @@ int main(int argc, char **argv) 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 (nbytes != sizeof(struct can_frame)) { + if (sendto(s, &frame, txmtu, 0, (struct sockaddr*)&addr, sizeof(addr)) != txmtu) { perror("sendto"); return 1; } 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", 0, CAN_MAX_DLEN); + else + fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN); } } diff --git a/cansend.c b/cansend.c index 9be2163..d4620e5 100644 --- a/cansend.c +++ b/cansend.c @@ -62,9 +62,11 @@ int main(int argc, char **argv) { int s; /* can raw socket */ - int nbytes; + int required_mtu; + int mtu; + int enable_canfd = 1; struct sockaddr_can addr; - struct can_frame frame; + struct canfd_frame frame; struct ifreq ifr; /* check command line options */ @@ -74,14 +76,18 @@ int main(int argc, char **argv) } /* parse CAN frame */ - if (parse_canframe(argv[2], &frame)){ - fprintf(stderr, "\nWrong CAN-frame format!\n\n"); - fprintf(stderr, "Try: #{R|data}\n"); - fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n"); - fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)"); - fprintf(stderr, " be seperated by '.'\n\n"); - fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / "); - fprintf(stderr, "5AA# /\n 1F334455#1122334455667788 / 123#R "); + required_mtu = parse_canframe(argv[2], &frame); + if (!required_mtu){ + fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n"); + fprintf(stderr, " #{R|data} for CAN 2.0 frames\n"); + fprintf(stderr, " ##{data} for CAN FD frames\n\n"); + fprintf(stderr, " can have 3 (SFF) or 8 (EFF) hex chars\n"); + fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally"); + fprintf(stderr, " seperated by '.')\n"); + fprintf(stderr, " a single ASCII Hex value (0 .. F) which defines"); + fprintf(stderr, " canfd_frame.flags\n\n"); + fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / "); + fprintf(stderr, "123##1 / 213##311\n 1F334455#1122334455667788 / 123#R "); fprintf(stderr, "for remote transmission request.\n\n"); return 1; } @@ -101,6 +107,31 @@ int main(int argc, char **argv) } addr.can_ifindex = ifr.ifr_ifindex; + if (required_mtu > CAN_MTU) { + + /* check if the frame fits into the CAN netdevice */ + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + perror("SIOCGIFMTU"); + return 1; + } + mtu = ifr.ifr_mtu; + + if (mtu != CANFD_MTU) { + printf("CAN interface ist not CAN FD capable - sorry.\n"); + return 1; + } + + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfd, sizeof(enable_canfd))){ + printf("error when enabling CAN FD support\n"); + return 1; + } + + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + frame.len = can_dlc2len(can_len2dlc(frame.len)); + } + /* 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 */ @@ -113,13 +144,11 @@ int main(int argc, char **argv) } /* send frame */ - if ((nbytes = write(s, &frame, sizeof(frame))) != sizeof(frame)) { + if (write(s, &frame, required_mtu) != required_mtu) { perror("write"); return 1; } - //fprint_long_canframe(stdout, &frame, "\n", 0); - close(s); return 0; diff --git a/lib.c b/lib.c index 5738f2b..927f064 100644 --- a/lib.c +++ b/lib.c @@ -58,8 +58,36 @@ #define CANID_DELIM '#' #define DATA_SEPERATOR '.' -#define MAX_CANFRAME "12345678#01.23.45.67.89.AB.CD.EF" -#define MAX_LONG_CANFRAME_SIZE 256 +/* CAN DLC to real data length conversion helpers */ + +static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7, + 8, 12, 16, 20, 24, 32, 48, 64}; + +/* get data length from can_dlc with sanitized can_dlc */ +unsigned char can_dlc2len(unsigned char can_dlc) +{ + return dlc2len[can_dlc & 0x0F]; +} + +static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ + 9, 9, 9, 9, /* 9 - 12 */ + 10, 10, 10, 10, /* 13 - 16 */ + 11, 11, 11, 11, /* 17 - 20 */ + 12, 12, 12, 12, /* 21 - 24 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ + 15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */ + +/* map the sanitized data length to an appropriate data length code */ +unsigned char can_len2dlc(unsigned char len) +{ + if (len > 64) + return 0xF; + + return len2dlc[len]; +} unsigned char asc2nibble(char c) { @@ -75,53 +103,57 @@ unsigned char asc2nibble(char c) { return 16; /* error */ } -int hexstring2candata(char *arg, struct can_frame *cf) { +int hexstring2data(char *arg, unsigned char *data, int maxdlen) { int len = strlen(arg); int i; unsigned char tmp; - if (!len || len%2 || len > 16) + if (!len || len%2 || len > maxdlen*2) return 1; + memset(data, 0, maxdlen); + for (i=0; i < len/2; i++) { tmp = asc2nibble(*(arg+(2*i))); if (tmp > 0x0F) return 1; - cf->data[i] = (tmp << 4); + data[i] = (tmp << 4); tmp = asc2nibble(*(arg+(2*i)+1)); if (tmp > 0x0F) return 1; - cf->data[i] |= tmp; + data[i] |= tmp; } return 0; } -int parse_canframe(char *cs, struct can_frame *cf) { +int parse_canframe(char *cs, struct canfd_frame *cf) { /* documentation see lib.h */ - int i, idx, dlc, len; + int i, idx, dlen, len; + int maxdlen = CAN_MAX_DLEN; + int ret = CAN_MTU; unsigned char tmp; len = strlen(cs); //printf("'%s' len %d\n", cs, len); - memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */ + memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */ if (len < 4) - return 1; + return 0; if (cs[3] == CANID_DELIM) { /* 3 digits */ idx = 4; for (i=0; i<3; i++){ if ((tmp = asc2nibble(cs[i])) > 0x0F) - return 1; + return 0; cf->can_id |= (tmp << (2-i)*4); } @@ -130,21 +162,34 @@ int parse_canframe(char *cs, struct can_frame *cf) { idx = 9; for (i=0; i<8; i++){ if ((tmp = asc2nibble(cs[i])) > 0x0F) - return 1; + return 0; 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 - return 1; + return 0; if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */ cf->can_id |= CAN_RTR_FLAG; - return 0; + return ret; + } + + if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */ + + maxdlen = CANFD_MAX_DLEN; + ret = CANFD_MTU; + + /* CAN FD frame ##* */ + if ((tmp = asc2nibble(cs[idx+1])) > 0x0F) + return 0; + + cf->flags = tmp; + idx += 2; } - for (i=0, dlc=0; i<8; i++){ + for (i=0, dlen=0; i < maxdlen; i++){ if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */ idx++; @@ -153,35 +198,34 @@ int parse_canframe(char *cs, struct can_frame *cf) { break; if ((tmp = asc2nibble(cs[idx++])) > 0x0F) - return 1; + return 0; cf->data[i] = (tmp << 4); if ((tmp = asc2nibble(cs[idx++])) > 0x0F) - return 1; + return 0; cf->data[i] |= tmp; - dlc++; + dlen++; } + cf->len = dlen; - cf->can_dlc = dlc; - - return 0; + return ret; } -void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep) { +void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen) { /* documentation see lib.h */ - char buf[sizeof(MAX_CANFRAME)+1]; /* max length */ + char buf[CL_CFSZ]; /* max length */ - sprint_canframe(buf, cf, sep); + sprint_canframe(buf, cf, sep, maxdlen); fprintf(stream, "%s", buf); if (eol) fprintf(stream, "%s", eol); } -void sprint_canframe(char *buf , struct can_frame *cf, int sep) { +void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) { /* documentation see lib.h */ int i,offset; - int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc; + int len = (cf->len > maxdlen) ? maxdlen : cf->len; if (cf->can_id & CAN_ERR_FLAG) { sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG)); @@ -194,25 +238,34 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep) { offset = 4; } - if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */ + /* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */ + if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) { sprintf(buf+offset, "R"); - else - for (i = 0; i < dlc; i++) { - sprintf(buf+offset, "%02X", cf->data[i]); - offset += 2; - if (sep && (i+1 < dlc)) - sprintf(buf+offset++, "."); - } + return; + } + if (maxdlen == CANFD_MAX_DLEN) { + /* add CAN FD specific escape char and flags */ + sprintf(buf+offset, "#%X", cf->flags & 0xF); + offset += 2; + if (sep && len) + sprintf(buf+offset++, "."); + } + for (i = 0; i < len; i++) { + sprintf(buf+offset, "%02X", cf->data[i]); + offset += 2; + if (sep && (i+1 < len)) + sprintf(buf+offset++, "."); + } } -void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view) { +void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen) { /* documentation see lib.h */ - char buf[MAX_LONG_CANFRAME_SIZE]; + char buf[CL_LONGCFSZ]; - sprint_long_canframe(buf, cf, view); + sprint_long_canframe(buf, cf, view, maxdlen); fprintf(stream, "%s", buf); if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) { snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t"); @@ -222,41 +275,45 @@ void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int vi fprintf(stream, "%s", eol); } -void sprint_long_canframe(char *buf , struct can_frame *cf, int view) { +void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen) { /* documentation see lib.h */ int i, j, dlen, offset; - int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc; + int len = (cf->len > maxdlen)? maxdlen : cf->len; if (cf->can_id & CAN_ERR_FLAG) { - sprintf(buf, "%8X ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG)); + sprintf(buf, "%08X ", 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); + sprintf(buf, "%08X ", cf->can_id & CAN_EFF_MASK); offset = 10; } else { - sprintf(buf, "%3X ", cf->can_id & CAN_SFF_MASK); + sprintf(buf, "%03X ", cf->can_id & CAN_SFF_MASK); offset = 5; } - sprintf(buf+offset, "[%d]", dlc); - offset += 3; - - if (cf->can_id & CAN_RTR_FLAG) { /* there are no ERR frames with RTR */ - sprintf(buf+offset, " remote request"); - return; + if (maxdlen == CAN_MAX_DLEN) { + sprintf(buf+offset, " [%d] ", len); + /* standard CAN frames may have RTR enabled */ + if (cf->can_id & CAN_RTR_FLAG) { + sprintf(buf+offset+5, " remote request"); + return; + } + } else { + sprintf(buf+offset, "[%02d] ", len); } + offset += 5; if (view & CANLIB_VIEW_BINARY) { dlen = 9; /* _10101010 */ if (view & CANLIB_VIEW_SWAP) { - for (i = dlc - 1; i >= 0; i--) { - buf[offset++] = (i == dlc-1)?' ':SWAP_DELIMITER; + for (i = len - 1; i >= 0; i--) { + buf[offset++] = (i == len-1)?' ':SWAP_DELIMITER; for (j = 7; j >= 0; j--) buf[offset++] = (1<data[i])?'1':'0'; } } else { - for (i = 0; i < dlc; i++) { + for (i = 0; i < len; i++) { buf[offset++] = ' '; for (j = 7; j >= 0; j--) buf[offset++] = (1<data[i])?'1':'0'; @@ -266,28 +323,36 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) { } else { dlen = 3; /* _AA */ if (view & CANLIB_VIEW_SWAP) { - for (i = dlc - 1; i >= 0; i--) { + for (i = len - 1; i >= 0; i--) { sprintf(buf+offset, "%c%02X", - (i == dlc-1)?' ':SWAP_DELIMITER, + (i == len-1)?' ':SWAP_DELIMITER, cf->data[i]); offset += dlen; } } else { - for (i = 0; i < dlc; i++) { + for (i = 0; i < len; i++) { sprintf(buf+offset, " %02X", cf->data[i]); offset += dlen; } } } + /* + * The ASCII & ERRORFRAME output is put at a fixed len behind the data. + * For now we support ASCII output only for payload length up to 8 bytes. + * Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console? + */ + if (len > CAN_MAX_DLEN) + return; + if (cf->can_id & CAN_ERR_FLAG) - sprintf(buf+offset, "%*s", dlen*(8-dlc)+13, "ERRORFRAME"); + sprintf(buf+offset, "%*s", dlen*(8-len)+13, "ERRORFRAME"); else if (view & CANLIB_VIEW_ASCII) { - j = dlen*(8-dlc)+4; + j = dlen*(8-len)+4; if (view & CANLIB_VIEW_SWAP) { sprintf(buf+offset, "%*s", j, "`"); offset += j; - for (i = dlc - 1; i >= 0; i--) + for (i = len - 1; i >= 0; i--) if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) buf[offset++] = cf->data[i]; else @@ -297,7 +362,7 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) { } else { sprintf(buf+offset, "%*s", j, "'"); offset += j; - for (i = 0; i < dlc; i++) + for (i = 0; i < len; i++) if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) buf[offset++] = cf->data[i]; else @@ -399,14 +464,14 @@ static int snprintf_error_data(char *buf, size_t len, uint8_t err, return n; } -static int snprintf_error_lostarb(char *buf, size_t len, struct can_frame *cf) +static int snprintf_error_lostarb(char *buf, size_t len, struct canfd_frame *cf) { if (len <= 0) return 0; return snprintf(buf, len, "{at bit %d}", cf->data[0]); } -static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf) +static int snprintf_error_ctrl(char *buf, size_t len, struct canfd_frame *cf) { int n = 0; @@ -422,7 +487,7 @@ static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf) return n; } -static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf) +static int snprintf_error_prot(char *buf, size_t len, struct canfd_frame *cf) { int n = 0; @@ -443,7 +508,7 @@ static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf) return n; } -void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf, +void snprintf_can_error_frame(char *buf, size_t len, struct canfd_frame *cf, char* sep) { canid_t class, mask; diff --git a/lib.h b/lib.h index 8ef34bb..695498b 100644 --- a/lib.h +++ b/lib.h @@ -45,6 +45,26 @@ * */ +/* buffer sizes for CAN frame string representations */ + +#define CL_ID (sizeof("12345678##1")) +#define CL_DATA sizeof(".AA") +#define CL_BINDATA sizeof(".10101010") + + /* CAN FD ASCII hex short representation with DATA_SEPERATORs */ +#define CL_CFSZ (2*CL_ID + 64*CL_DATA) + +/* CAN FD ASCII hex long representation with binary output */ +#define CL_LONGCFSZ (2*CL_ID + sizeof(" [255] ") + (64*CL_BINDATA)) + +/* CAN DLC to real data length conversion helpers especially for CAN FD */ + +/* get data length from can_dlc with sanitized can_dlc */ +unsigned char can_dlc2len(unsigned char can_dlc); + +/* map the sanitized data length to an appropriate data length code */ +unsigned char can_len2dlc(unsigned char len); + unsigned char asc2nibble(char c); /* * Returns the decimal value of a given ASCII hex character. @@ -53,9 +73,9 @@ unsigned char asc2nibble(char c); * On invalid characters the value 16 is returned for error handling. */ -int hexstring2candata(char *arg, struct can_frame *cf); +int hexstring2data(char *arg, unsigned char *data, int maxdlen); /* - * Converts a given ASCII hex string to values in the can_frame data[]. + * Converts a given ASCII hex string to a (binary) byte string. * * A valid ASCII hex string consists of an even number of up to 16 chars. * Leading zeros '00' in the ASCII hex string are interpreted. @@ -69,53 +89,76 @@ int hexstring2candata(char *arg, struct can_frame *cf); * 0 = success * 1 = error (in length or the given characters are no ASCII hex characters) * - * Remark: The not written data[] elements remain unchanged. + * Remark: The not written data[] elements are initialized with zero. * */ -int parse_canframe(char *cs, struct can_frame *cf); +int parse_canframe(char *cs, struct canfd_frame *cf); /* - * Transfers a valid ASCII string decribing a CAN frame into struct can_frame. + * Transfers a valid ASCII string decribing a CAN frame into struct canfd_frame. * - * #{R|data} + * CAN 2.0 frames + * - string layout #{R|data} + * - {data} has 0 to 8 hex-values that can (optionally) be seperated by '.' + * - return value on successful parsing: CAN_MTU * - * can_id can have 3 (standard frame format) or 8 (extended frame format) - * hexadecimal chars + * CAN FD frames + * - string layout ##{data} + * - a single ASCII Hex value (0 .. F) which defines canfd_frame.flags + * - {data} has 0 to 64 hex-values that can (optionally) be seperated by '.' + * - return value on successful parsing: CANFD_MTU + * + * Return value on detected problems: 0 + * + * can have 3 (standard frame format) or 8 (extended frame format) + * hexadecimal chars * - * data has 0 to 8 hex-values that can (optionally) be seperated by '.' * * Examples: * - * 123# -> standard CAN-Id = 0x123, dlc = 0 - * 12345678# -> extended CAN-Id = 0x12345678, dlc = 0 - * 123#R -> standard CAN-Id = 0x123, dlc = 0, RTR-frame - * 7A1#r -> standard CAN-Id = 0x7A1, dlc = 0, RTR-frame + * 123# -> standard CAN-Id = 0x123, len = 0 + * 12345678# -> extended CAN-Id = 0x12345678, len = 0 + * 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame + * 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame * - * 123#00 -> standard CAN-Id = 0x123, dlc = 1, data[0] = 0x00 - * 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 + * 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00 + * 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8 + * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8 + * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8 * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set * + * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3 + * 123##1112233 -> CAN FD frame, flags = CANFD_BRS, len = 3 + * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3 + * 123##3 -> CAN FD frame, flags = (CANFD_ESI | CANFD_BRS), len = 0 + * ^^ + * CAN FD extension to handle the canfd_frame.flags content + * * 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 - * + * - CAN FD frames do not have a RTR bit */ -void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep); -void sprint_canframe(char *buf , struct can_frame *cf, int sep); +void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen); +void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen); /* * Creates a CAN frame hexadecimal output in compact format. * The CAN data[] is seperated by '.' when sep != 0. * + * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen: + * maxdlen = 8 -> CAN2.0 frame + * maxdlen = 64 -> CAN FD frame + * * 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 + * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3 + * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3 * * Examples: * @@ -131,24 +174,32 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep); #define SWAP_DELIMITER '`' -void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view); -void sprint_long_canframe(char *buf , struct can_frame *cf, int view); +void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen); +void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen); /* * 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) + * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen: + * maxdlen = 8 -> CAN2.0 frame + * maxdlen = 64 -> CAN FD frame + * + * 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) + * 12345678 [03] 11 22 33 -> CAN FD with exended CAN-Id = 0x12345678, dlc = 3 * * Examples: * - * fprint_long_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT - * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR + * // CAN FD frame with eol to STDOUT + * fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN); + * + * // CAN 2.0 frame without eol to STDERR + * fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN); * */ -void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf, +void snprintf_can_error_frame(char *buf, size_t len, struct canfd_frame *cf, char *sep); /* * Creates a CAN error frame output in user readable format. diff --git a/log2asc.c b/log2asc.c index 899f0d2..029cd49 100644 --- a/log2asc.c +++ b/log2asc.c @@ -73,7 +73,7 @@ int main(int argc, char **argv) { static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10]; - struct can_frame cf; + struct canfd_frame cf; static struct timeval tv, start_tv; FILE *infile = stdin; FILE *outfile = stdout; @@ -162,7 +162,7 @@ int main(int argc, char **argv) } if (devno) { /* only convert for selected CAN devices */ - if (parse_canframe(ascframe, &cf)) + if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */ return 1; tv.tv_sec = tv.tv_sec - start_tv.tv_sec; @@ -189,9 +189,9 @@ int main(int argc, char **argv) if (cf.can_id & CAN_RTR_FLAG) fprintf(outfile, "r"); /* RTR frame */ else { - fprintf(outfile, "d %d", cf.can_dlc); /* data frame */ + fprintf(outfile, "d %d", cf.len); /* data frame */ - for (i = 0; i < cf.can_dlc; i++) { + for (i = 0; i < cf.len; i++) { fprintf(outfile, " %02X", cf.data[i]); } } diff --git a/log2long.c b/log2long.c index 795aaa5..297d43f 100644 --- a/log2long.c +++ b/log2long.c @@ -52,17 +52,33 @@ #include "lib.h" +#define COMMENTSZ 200 +#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */ + int main(int argc, char **argv) { - char buf[100], timestamp[100], device[100], ascframe[100]; - struct can_frame cf; + char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; + struct canfd_frame cf; + int mtu, maxdlen; - while (fgets(buf, 99, stdin)) { + while (fgets(buf, BUFSZ-1, stdin)) { if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3) return 1; - if (parse_canframe(ascframe, &cf)) + + mtu = parse_canframe(ascframe, &cf); + if (mtu == CAN_MTU) + maxdlen = CAN_MAX_DLEN; + else if (mtu == CANFD_MTU) + maxdlen = CANFD_MAX_DLEN; + else { + fprintf(stderr, "read: incomplete CAN frame\n"); return 1; - sprint_long_canframe(ascframe, &cf, 1); /* with ASCII output */ + } + + sprint_long_canframe(ascframe, &cf, + CANLIB_VIEW_ASCII, + maxdlen); /* with ASCII output */ + printf("%s %s %s\n", timestamp, device, ascframe); } -- 2.39.2