From 43a3cca54deaaea4df888ebbf3b51c952b2ccc18 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 9 May 2020 13:10:27 +0200 Subject: [PATCH 01/11] asc2log: reorder code to prepare CAN FD support Signed-off-by: Oliver Hartkopp --- asc2log.c | 165 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/asc2log.c b/asc2log.c index cecaa9f..9d61184 100644 --- a/asc2log.c +++ b/asc2log.c @@ -57,6 +57,8 @@ #include "lib.h" +#define BUFLEN 400 /* CAN FD mode lines can be pretty long */ + extern int optind, opterr, optopt; void print_usage(char *prg) @@ -124,6 +126,85 @@ void calc_tv(struct timeval *tv, struct timeval *read_tv, } } +void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, int dplace, FILE *outfile) { + + int interface; + static struct timeval tv; /* current frame timestamp */ + static struct timeval read_tv; /* frame timestamp from ASC file */ + struct can_frame cf; + char rtr; + int dlc = 0; + int data[8]; + char tmp1[BUFLEN]; + int i, found; + + /* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */ + + found = 0; /* found valid CAN frame ? */ + + if (base == 'h') { /* check for CAN frames with hexadecimal values */ + + if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &rtr, &dlc, + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7] + ) == dlc + 6 ) { + + found = 1; + get_can_id(&cf, tmp1, 16); + } + + } else { /* check for CAN frames with decimal values */ + + if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &rtr, &dlc, + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7] + ) == dlc + 6 ) { + + found = 1; + get_can_id(&cf, tmp1, 10); + } + } + + if (found) { + if (rtr == 'r') + cf.can_id |= CAN_RTR_FLAG; + + cf.can_dlc = dlc & 0x0FU; + for (i=0; i Date: Sat, 9 May 2020 18:19:24 +0200 Subject: [PATCH 02/11] asc2log: make date time sting milliseconds aware strptime() does not support milliseconds but the latest ASC logfile also provides a fraction of seconds, e.g. date Fri May 8 08:49:04.052 pm 2020 Read the value into the year variable before parsing the real year. We will therefore omit the milliseconds resolution for now. Signed-off-by: Oliver Hartkopp --- asc2log.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/asc2log.c b/asc2log.c index 9d61184..4ed8134 100644 --- a/asc2log.c +++ b/asc2log.c @@ -207,12 +207,12 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, char base, int get_date(struct timeval *tv, char *date) { - char ctmp[10]; + char ctmp[14]; int itmp; struct tm tms; - if (sscanf(date, "%9s %d %9s %9s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) { + if (sscanf(date, "%9s %d %13s %3s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) { /* assume EN/US date due to existing am/pm field */ if (!setlocale(LC_TIME, "en_US")) { @@ -220,13 +220,18 @@ int get_date(struct timeval *tv, char *date) { return 1; } - if (!strptime(date, "%B %d %r %Y", &tms)) - return 1; + if (!strptime(date, "%B %d %I:%M:%S %p %Y", &tms)) { + /* The string might contain a milliseconds value which strptime() + does not support. So we read the ms value into the year variable + before parsing the real year value (hack) */ + if (!strptime(date, "%B %d %I:%M:%S.%Y %p %Y", &tms)) + return 1; + } } else { /* assume DE date due to non existing am/pm field */ - if (sscanf(date, "%9s %d %9s %d", ctmp, &itmp, ctmp, &itmp) != 4) + if (sscanf(date, "%9s %d %13s %d", ctmp, &itmp, ctmp, &itmp) != 4) return 1; if (!setlocale(LC_TIME, "de_DE")) { @@ -234,8 +239,13 @@ int get_date(struct timeval *tv, char *date) { return 1; } - if (!strptime(date, "%B %d %T %Y", &tms)) - return 1; + if (!strptime(date, "%B %d %H:%M:%S %Y", &tms)) { + /* The string might contain a milliseconds value which strptime() + does not support. So we read the ms value into the year variable + before parsing the real year value (hack) */ + if (!strptime(date, "%B %d %H:%M:%S.%Y %Y", &tms)) + return 1; + } } //printf("h %d m %d s %d d %d m %d y %d\n", From df0b25c17e28f1be8b882634daee98eb4eb32ae6 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 9 May 2020 18:42:55 +0200 Subject: [PATCH 03/11] asc2log: support CANFD tagged asc file content Handles CANFD asc files with classic CAN and CAN FD frames. Signed-off-by: Oliver Hartkopp --- asc2log.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 15 deletions(-) diff --git a/asc2log.c b/asc2log.c index 4ed8134..303803a 100644 --- a/asc2log.c +++ b/asc2log.c @@ -70,7 +70,7 @@ void print_usage(char *prg) fprintf(stderr, "\t-O \t(default stdout)\n"); } -void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) { +void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, unsigned int max_dlen) { fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec); @@ -79,11 +79,10 @@ void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) { else fprintf(file, "canX "); - /* no CAN FD support so far */ - fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN); + fprint_canframe(file, cf, "\n", 0, max_dlen); } -void get_can_id(struct can_frame *cf, char *idstring, int base) { +void get_can_id(struct canfd_frame *cf, char *idstring, int base) { if (idstring[strlen(idstring)-1] == 'x') { cf->can_id = CAN_EFF_FLAG; @@ -131,7 +130,7 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i int interface; static struct timeval tv; /* current frame timestamp */ static struct timeval read_tv; /* frame timestamp from ASC file */ - struct can_frame cf; + struct canfd_frame cf; char rtr; int dlc = 0; int data[8]; @@ -170,15 +169,19 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i } if (found) { + + if (dlc > CAN_MAX_DLC) + return; + + cf.len = dlc; if (rtr == 'r') cf.can_id |= CAN_RTR_FLAG; - - cf.can_dlc = dlc & 0x0FU; - for (i=0; i + and probably some content we skip anyway. Don't trust the docs! */ + + /* 21.671796 CANFD 1 Tx 11 msgCanFdFr1 1 0 a 16 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 c0 \ + 100000 214 223040 80000000 46500250 460a0250 20011736 20010205 */ + + memset(&cf, 0, sizeof(cf)); + + if (sscanf(buf, "%ld.%ld %*s %d %*s %s %hhx %hhx %x %d ", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &brs, &esi, &dlc, &dlen) == 8) { + /* no symbolic name */ + } else if (sscanf(buf, "%ld.%ld %*s %d %*s %s %*s %hhx %hhx %x %d ", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &brs, &esi, &dlc, &dlen) == 8) { + /* with symbolic name */ + } else + return; /* no valid CANFD format pattern */ + + get_can_id(&cf, tmp1, 16); + + /* now search for the beginning of the data[] content */ + sprintf(tmp1, " %x %x %x %2d ", brs, esi, dlc, dlen); + + /* search for the pattern generated by real data */ + ptr = strcasestr(buf, tmp1); + if (ptr == NULL) + return; + + ptr += strlen(tmp1); /* hop to the start of hex data */ + + if (dlen > CANFD_MAX_DLEN) + return; + + /* don't trust ASCII content - sanitize data length */ + if (dlen != can_dlc2len(can_len2dlc(dlen))) + return; + + cf.len = dlen; + + for (i = 0; i < dlen; i++) { + ctmp = asc2nibble(ptr[0]); + if (ctmp > 0x0F) + return; + + cf.data[i] = (ctmp << 4); + + ctmp = asc2nibble(ptr[1]); + if (ctmp > 0x0F) + return; + + cf.data[i] |= ctmp; + + ptr += 3; /* start of next ASCII hex byte */ + } + + /* skip MessageDuration and MessageLength to get Flags value */ + if (sscanf(ptr, " %*x %*x %x ", &flags) != 1) + return; + + /* relevant flags in Flags field */ +#define ASC_F_RTR 0x00000010 +#define ASC_F_FDF 0x00001000 +#define ASC_F_BRS 0x00002000 +#define ASC_F_ESI 0x00004000 + + if (flags & ASC_F_FDF) { + dlen = CANFD_MAX_DLEN; + if (flags & ASC_F_BRS) + cf.flags |= CANFD_BRS; + if (flags & ASC_F_ESI) + cf.flags |= CANFD_ESI; + } else { + /* yes. The 'CANFD' format supports classic CAN content! */ + dlen = CAN_MAX_DLEN; + if (flags & ASC_F_RTR) { + cf.can_id |= CAN_RTR_FLAG; + /* dlen is always 0 for classic CAN RTR frames + but the DLC value is valid in RTR cases */ + cf.len = dlc; + } + } + + calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); + prframe(outfile, &tv, interface, &cf, dlen); + fflush(outfile); + return; + + /* No support for really strange CANFD ErrorFrames format m( */ } int get_date(struct timeval *tv, char *date) { @@ -368,7 +473,7 @@ int main(int argc, char **argv) /* check classic CAN format or the CANFD tag which can take both types */ if (sscanf(buf, "%ld.%ld %s ", &tmp_tv.tv_sec, &tmp_tv.tv_usec, tmp1) == 3){ if (!strncmp(tmp1, "CANFD", 5)) - eval_canfd(buf, &date_tv, timestamps, base, dplace, outfile); + eval_canfd(buf, &date_tv, timestamps, dplace, outfile); else eval_can(buf, &date_tv, timestamps, base, dplace, outfile); } From ed9c64660873a91c8d4f83cc2cda40a9531feaa2 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 9 May 2020 19:04:53 +0200 Subject: [PATCH 04/11] log2asc: reorder code to prepare CAN FD support Signed-off-by: Oliver Hartkopp --- log2asc.c | 59 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/log2asc.c b/log2asc.c index de32659..f40ee84 100644 --- a/log2asc.c +++ b/log2asc.c @@ -69,15 +69,45 @@ void print_usage(char *prg) fprintf(stderr, " -n (set newline to cr/lf - default lf)\n"); } +void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) +{ + int i; + char id[10]; + + fprintf(outfile, "%-2d ", devno); /* channel number left aligned */ + + if (cf->can_id & CAN_ERR_FLAG) + fprintf(outfile, "ErrorFrame"); + else { + sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK, + (cf->can_id & CAN_EFF_FLAG)?'x':' '); + fprintf(outfile, "%-15s Rx ", id); + + if (cf->can_id & CAN_RTR_FLAG) + fprintf(outfile, "r"); /* RTR frame */ + else { + fprintf(outfile, "d %d", cf->len); /* data frame */ + + for (i = 0; i < cf->len; i++) { + fprintf(outfile, " %02X", cf->data[i]); + } + } + } +} + +void canfd_asc(struct canfd_frame *cf, int devno, FILE *outfile) +{ +} + int main(int argc, char **argv) { - static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10]; + static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; struct canfd_frame cf; static struct timeval tv, start_tv; FILE *infile = stdin; FILE *outfile = stdout; - static int maxdev, devno, i, crlf, d4, opt; + static int maxdev, devno, i, crlf, d4, opt, mtu; while ((opt = getopt(argc, argv, "I:O:4n?")) != -1) { switch (opt) { @@ -162,7 +192,8 @@ int main(int argc, char **argv) } if (devno) { /* only convert for selected CAN devices */ - if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */ + mtu = parse_canframe(ascframe, &cf); + if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) return 1; tv.tv_sec = tv.tv_sec - start_tv.tv_sec; @@ -177,25 +208,11 @@ int main(int argc, char **argv) else fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec); - fprintf(outfile, "%-2d ", devno); /* channel number left aligned */ + if (mtu == CAN_MTU) + can_asc(&cf, devno, outfile); + else + canfd_asc(&cf, devno, outfile); - if (cf.can_id & CAN_ERR_FLAG) - fprintf(outfile, "ErrorFrame"); - else { - sprintf(id, "%X%c", cf.can_id & CAN_EFF_MASK, - (cf.can_id & CAN_EFF_FLAG)?'x':' '); - fprintf(outfile, "%-15s Rx ", id); - - if (cf.can_id & CAN_RTR_FLAG) - fprintf(outfile, "r"); /* RTR frame */ - else { - fprintf(outfile, "d %d", cf.len); /* data frame */ - - for (i = 0; i < cf.len; i++) { - fprintf(outfile, " %02X", cf.data[i]); - } - } - } if (crlf) fprintf(outfile, "\r"); fprintf(outfile, "\n"); From 9a079942cd54a8620a5b00056a6627f8b6a437c5 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 9 May 2020 22:08:19 +0200 Subject: [PATCH 05/11] log2asc: support CANFD asc file generation The CANFD asc format adds information about the CAN controllers bitrate settings, CRCs and message length (in bits) and its duration. The plan is to provide static values for these attributes that we can not get from the log file anyway and stay on the 'old style' format for classic CAN frames - which has been successfully tested on the latest tools. The remaining drawback is that the 'old style' format is not able to provide a DLC information for RTR frames. Signed-off-by: Oliver Hartkopp --- log2asc.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/log2asc.c b/log2asc.c index f40ee84..ad9fe8e 100644 --- a/log2asc.c +++ b/log2asc.c @@ -97,6 +97,36 @@ void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) void canfd_asc(struct canfd_frame *cf, int devno, FILE *outfile) { + int i; + char id[10]; + unsigned int flags; + + fprintf(outfile, "CANFD %3d Rx ", devno); /* 3 column channel number right aligned */ + + sprintf(id, "%X%c", cf->can_id & CAN_EFF_MASK, + (cf->can_id & CAN_EFF_FLAG)?'x':' '); + fprintf(outfile, "%11s ", id); + fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0'); + fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0'); + fprintf(outfile, "%x ", can_len2dlc(cf->len)); + fprintf(outfile, "%2d", cf->len); + + for (i = 0; i < cf->len; i++) { + fprintf(outfile, " %02X", cf->data[i]); + } + + /* relevant flags in Flags field */ +#define ASC_F_FDF 0x00001000 +#define ASC_F_BRS 0x00002000 +#define ASC_F_ESI 0x00004000 + + flags = ASC_F_FDF; + if (cf->flags & CANFD_BRS) + flags |= ASC_F_BRS; + if (cf->flags & CANFD_ESI) + flags |= ASC_F_ESI; + + fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags); } int main(int argc, char **argv) @@ -196,6 +226,10 @@ int main(int argc, char **argv) if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) return 1; + /* we don't support error message frames in CAN FD */ + if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG)) + continue; + tv.tv_sec = tv.tv_sec - start_tv.tv_sec; tv.tv_usec = tv.tv_usec - start_tv.tv_usec; if (tv.tv_usec < 0) From ad9fc28f9e5fe1410bad9bc3e4db5ffc2dfa015c Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 10:44:11 +0200 Subject: [PATCH 06/11] asc2log: add sanity checks for search pattern Add some more sanity checks and increase readability for the sscanf() procedure to read a CANFD tagged line. Signed-off-by: Oliver Hartkopp --- asc2log.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/asc2log.c b/asc2log.c index 303803a..404d663 100644 --- a/asc2log.c +++ b/asc2log.c @@ -227,16 +227,29 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace memset(&cf, 0, sizeof(cf)); + /* check for valid line without symbolic name */ if (sscanf(buf, "%ld.%ld %*s %d %*s %s %hhx %hhx %x %d ", &read_tv.tv_sec, &read_tv.tv_usec, &interface, - tmp1, &brs, &esi, &dlc, &dlen) == 8) { - /* no symbolic name */ - } else if (sscanf(buf, "%ld.%ld %*s %d %*s %s %*s %hhx %hhx %x %d ", + tmp1, &brs, &esi, &dlc, &dlen) != 8) { + + /* check for valid line with a symbolic name */ + if (sscanf(buf, "%ld.%ld %*s %d %*s %s %*s %hhx %hhx %x %d ", &read_tv.tv_sec, &read_tv.tv_usec, &interface, - tmp1, &brs, &esi, &dlc, &dlen) == 8) { - /* with symbolic name */ - } else - return; /* no valid CANFD format pattern */ + tmp1, &brs, &esi, &dlc, &dlen) != 8) { + + /* no valid CANFD format pattern */ + return; + } + } + + /* check for allowed (unsigned) value ranges */ + if ((dlen > CANFD_MAX_DLEN) || (dlc > CANFD_MAX_DLC) || + (brs > 1) || (esi > 1)) + return; + + /* don't trust ASCII content - sanitize data length */ + if (dlen != can_dlc2len(can_len2dlc(dlen))) + return; get_can_id(&cf, tmp1, 16); @@ -248,14 +261,7 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace if (ptr == NULL) return; - ptr += strlen(tmp1); /* hop to the start of hex data */ - - if (dlen > CANFD_MAX_DLEN) - return; - - /* don't trust ASCII content - sanitize data length */ - if (dlen != can_dlc2len(can_len2dlc(dlen))) - return; + ptr += strlen(tmp1); /* start of ASCII hex frame data */ cf.len = dlen; From 3014d390b4b4d27d2626621c740372599bce061a Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 11:22:05 +0200 Subject: [PATCH 07/11] log2asc: support CANFD format also for Classic CAN The CANFD tagged format also supports the encapsulation of Classic CAN frames which is selected when logging on CAN FD capable CAN interfaces. With a new option '-f' this CANFD format is selected. Although this representation is even more inefficient it is seems to be the common way and increases the readability for mixed CAN/CANFD logs. Signed-off-by: Oliver Hartkopp --- log2asc.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/log2asc.c b/log2asc.c index ad9fe8e..9180144 100644 --- a/log2asc.c +++ b/log2asc.c @@ -67,6 +67,7 @@ void print_usage(char *prg) fprintf(stderr, " -O (default stdout)\n"); fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n"); fprintf(stderr, " -n (set newline to cr/lf - default lf)\n"); + fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n"); } void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) @@ -95,11 +96,18 @@ void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) } } -void canfd_asc(struct canfd_frame *cf, int devno, FILE *outfile) +void canfd_asc(struct canfd_frame *cf, int devno, int mtu, FILE *outfile) { int i; char id[10]; - unsigned int flags; + unsigned int flags = 0; + unsigned int dlen = cf->len; + + /* relevant flags in Flags field */ +#define ASC_F_RTR 0x00000010 +#define ASC_F_FDF 0x00001000 +#define ASC_F_BRS 0x00002000 +#define ASC_F_ESI 0x00004000 fprintf(outfile, "CANFD %3d Rx ", devno); /* 3 column channel number right aligned */ @@ -108,23 +116,27 @@ void canfd_asc(struct canfd_frame *cf, int devno, FILE *outfile) fprintf(outfile, "%11s ", id); fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0'); fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0'); - fprintf(outfile, "%x ", can_len2dlc(cf->len)); - fprintf(outfile, "%2d", cf->len); + fprintf(outfile, "%x ", can_len2dlc(dlen)); - for (i = 0; i < cf->len; i++) { - fprintf(outfile, " %02X", cf->data[i]); + if (mtu == CAN_MTU) { + if (cf->can_id & CAN_RTR_FLAG) { + /* no data length but dlc for RTR frames */ + dlen = 0; + flags = ASC_F_RTR; + } + } else { + flags = ASC_F_FDF; + if (cf->flags & CANFD_BRS) + flags |= ASC_F_BRS; + if (cf->flags & CANFD_ESI) + flags |= ASC_F_ESI; } - /* relevant flags in Flags field */ -#define ASC_F_FDF 0x00001000 -#define ASC_F_BRS 0x00002000 -#define ASC_F_ESI 0x00004000 + fprintf(outfile, "%2d", dlen); - flags = ASC_F_FDF; - if (cf->flags & CANFD_BRS) - flags |= ASC_F_BRS; - if (cf->flags & CANFD_ESI) - flags |= ASC_F_ESI; + for (i = 0; i < dlen; i++) { + fprintf(outfile, " %02X", cf->data[i]); + } fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags); } @@ -137,9 +149,9 @@ int main(int argc, char **argv) static struct timeval tv, start_tv; FILE *infile = stdin; FILE *outfile = stdout; - static int maxdev, devno, i, crlf, d4, opt, mtu; + static int maxdev, devno, i, crlf, fdfmt, d4, opt, mtu; - while ((opt = getopt(argc, argv, "I:O:4n?")) != -1) { + while ((opt = getopt(argc, argv, "I:O:4nf?")) != -1) { switch (opt) { case 'I': infile = fopen(optarg, "r"); @@ -161,6 +173,10 @@ int main(int argc, char **argv) crlf = 1; break; + case 'f': + fdfmt = 1; + break; + case '4': d4 = 1; break; @@ -242,10 +258,10 @@ int main(int argc, char **argv) else fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec); - if (mtu == CAN_MTU) + if ((mtu == CAN_MTU) && (fdfmt == 0)) can_asc(&cf, devno, outfile); else - canfd_asc(&cf, devno, outfile); + canfd_asc(&cf, devno, mtu, outfile); if (crlf) fprintf(outfile, "\r"); From 61dbb56ef694e3c668dd156d19652e806f610cd0 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 11:45:03 +0200 Subject: [PATCH 08/11] log2asc: support DLC values in Classic CAN RTR frames RTR frames contain a valid DLC value which has not been exposed in the ASC file format since v8.5 of the tools. So log2asc will expose this DLC value by default which can be changed by applying the '-r' option to create the former format. It can be assumed that the tools pre v8.5 will ignore the value but if not this switch will make sure to create the old format. Signed-off-by: Oliver Hartkopp --- log2asc.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/log2asc.c b/log2asc.c index 9180144..f1cab76 100644 --- a/log2asc.c +++ b/log2asc.c @@ -68,9 +68,10 @@ void print_usage(char *prg) fprintf(stderr, " -4 (reduce decimal place to 4 digits)\n"); fprintf(stderr, " -n (set newline to cr/lf - default lf)\n"); fprintf(stderr, " -f (use CANFD format also for Classic CAN)\n"); + fprintf(stderr, " -r (supress dlc for RTR frames - pre v8.5 tools)\n"); } -void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) +void can_asc(struct canfd_frame *cf, int devno, int nortrdlc, FILE *outfile) { int i; char id[10]; @@ -84,9 +85,12 @@ void can_asc(struct canfd_frame *cf, int devno, FILE *outfile) (cf->can_id & CAN_EFF_FLAG)?'x':' '); fprintf(outfile, "%-15s Rx ", id); - if (cf->can_id & CAN_RTR_FLAG) - fprintf(outfile, "r"); /* RTR frame */ - else { + if (cf->can_id & CAN_RTR_FLAG) { + if (nortrdlc) + fprintf(outfile, "r"); /* RTR frame */ + else + fprintf(outfile, "r %d", cf->len); /* RTR frame */ + } else { fprintf(outfile, "d %d", cf->len); /* data frame */ for (i = 0; i < cf->len; i++) { @@ -149,9 +153,9 @@ int main(int argc, char **argv) static struct timeval tv, start_tv; FILE *infile = stdin; FILE *outfile = stdout; - static int maxdev, devno, i, crlf, fdfmt, d4, opt, mtu; + static int maxdev, devno, i, crlf, fdfmt, nortrdlc, d4, opt, mtu; - while ((opt = getopt(argc, argv, "I:O:4nf?")) != -1) { + while ((opt = getopt(argc, argv, "I:O:4nfr?")) != -1) { switch (opt) { case 'I': infile = fopen(optarg, "r"); @@ -177,6 +181,10 @@ int main(int argc, char **argv) fdfmt = 1; break; + case 'r': + nortrdlc = 1; + break; + case '4': d4 = 1; break; @@ -259,7 +267,7 @@ int main(int argc, char **argv) fprintf(outfile, "%4ld.%06ld ", tv.tv_sec, tv.tv_usec); if ((mtu == CAN_MTU) && (fdfmt == 0)) - can_asc(&cf, devno, outfile); + can_asc(&cf, devno, nortrdlc, outfile); else canfd_asc(&cf, devno, mtu, outfile); From 7729c046c59f1efdc04d755f519d4d26c73e069f Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 12:03:35 +0200 Subject: [PATCH 09/11] cangen: support ESI bit for CAN FD frame generation The CAN FD frames support BTR and ESI as special flags. While BTR could be generated by cangen the ESI bit could not be generated so far. Signed-off-by: Oliver Hartkopp --- cangen.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/cangen.c b/cangen.c index 26d28c6..e26c08b 100644 --- a/cangen.c +++ b/cangen.c @@ -89,8 +89,10 @@ void print_usage(char *prg) fprintf(stderr, " -f (generate CAN FD CAN frames)\n"); fprintf(stderr, " -b (generate CAN FD CAN frames" " with bitrate switch (BRS))\n"); + fprintf(stderr, " -E (generate CAN FD CAN frames" + " with error state (ESI))\n"); fprintf(stderr, " -R (send RTR frame)\n"); - fprintf(stderr, " -m (mix -e -f -b -R frames)\n"); + fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n"); fprintf(stderr, " -I (CAN ID" " generation mode - see below)\n"); fprintf(stderr, " -L (CAN data length code (dlc)" @@ -145,6 +147,7 @@ int main(int argc, char **argv) unsigned char extended = 0; unsigned char canfd = 0; unsigned char brs = 0; + unsigned char esi = 0; unsigned char mix = 0; unsigned char id_mode = MODE_RANDOM; unsigned char data_mode = MODE_RANDOM; @@ -181,7 +184,7 @@ int main(int argc, char **argv) signal(SIGHUP, sigterm); signal(SIGINT, sigterm); - while ((opt = getopt(argc, argv, "ig:ebfmI:L:D:xp:n:c:vRh?")) != -1) { + while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vRh?")) != -1) { switch (opt) { case 'i': @@ -205,6 +208,11 @@ int main(int argc, char **argv) canfd = 1; break; + case 'E': + esi = 1; /* error state indicator implies CAN FD */ + canfd = 1; + break; + case 'm': mix = 1; canfd = 1; /* to switch the socket into CAN FD mode */ @@ -379,6 +387,8 @@ int main(int argc, char **argv) maxdlen = CANFD_MAX_DLEN; if (brs) frame.flags |= CANFD_BRS; + if (esi) + frame.flags |= CANFD_ESI; } else { mtu = CAN_MTU; maxdlen = CAN_MAX_DLEN; @@ -504,8 +514,10 @@ resend: i = random(); extended = i&1; canfd = i&2; - if (canfd) + if (canfd) { brs = i&4; + esi = i&8; + } rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */ } } From 9cde2ebe8f908476ea864490f6ab4ee5c5caa4ca Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 14:41:34 +0200 Subject: [PATCH 10/11] asc2log: fix date string detection The former check was too complex and did not catch all valid cases. Signed-off-by: Oliver Hartkopp --- asc2log.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/asc2log.c b/asc2log.c index 404d663..8ac7e86 100644 --- a/asc2log.c +++ b/asc2log.c @@ -318,12 +318,9 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace int get_date(struct timeval *tv, char *date) { - char ctmp[14]; - int itmp; - struct tm tms; - if (sscanf(date, "%9s %d %13s %3s %d", ctmp, &itmp, ctmp, ctmp, &itmp) == 5) { + if (strcasestr(date, " pm ") != NULL) { /* assume EN/US date due to existing am/pm field */ if (!setlocale(LC_TIME, "en_US")) { @@ -342,9 +339,6 @@ int get_date(struct timeval *tv, char *date) { } else { /* assume DE date due to non existing am/pm field */ - if (sscanf(date, "%9s %d %13s %d", ctmp, &itmp, ctmp, &itmp) != 4) - return 1; - if (!setlocale(LC_TIME, "de_DE")) { fprintf(stderr, "Setting locale to 'de_DE' failed!\n"); return 1; From 3bb659d18db1572244fd898a26f4079f973a67d7 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sun, 10 May 2020 15:09:55 +0200 Subject: [PATCH 11/11] asc2log: fix handling for RTR frames in Classic CAN mode Fix reading of the RTR representation without and with DLC (v8.5+ tools). Signed-off-by: Oliver Hartkopp --- asc2log.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/asc2log.c b/asc2log.c index 8ac7e86..4935de0 100644 --- a/asc2log.c +++ b/asc2log.c @@ -135,7 +135,7 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i int dlc = 0; int data[8]; char tmp1[BUFLEN]; - int i, found; + int i, items, found; /* 0.002367 1 390x Rx d 8 17 00 14 00 C0 00 08 00 */ @@ -143,26 +143,30 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i if (base == 'h') { /* check for CAN frames with hexadecimal values */ - if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x", - &read_tv.tv_sec, &read_tv.tv_usec, &interface, - tmp1, &rtr, &dlc, - &data[0], &data[1], &data[2], &data[3], - &data[4], &data[5], &data[6], &data[7] - ) == dlc + 6 ) { + items = sscanf(buf, "%ld.%ld %d %s %*s %c %d %x %x %x %x %x %x %x %x", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &rtr, &dlc, + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7]); + if ((items == dlc + 6 ) || /* data frame */ + ((items == 5) && (rtr == 'r')) || /* RTR without DLC */ + ((items == 6) && (rtr == 'r'))) { /* RTR with DLC */ found = 1; get_can_id(&cf, tmp1, 16); } } else { /* check for CAN frames with decimal values */ - if (sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d", - &read_tv.tv_sec, &read_tv.tv_usec, &interface, - tmp1, &rtr, &dlc, - &data[0], &data[1], &data[2], &data[3], - &data[4], &data[5], &data[6], &data[7] - ) == dlc + 6 ) { + items = sscanf(buf, "%ld.%ld %d %s %*s %c %d %d %d %d %d %d %d %d %d", + &read_tv.tv_sec, &read_tv.tv_usec, &interface, + tmp1, &rtr, &dlc, + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7]); + if ((items == dlc + 6 ) || /* data frame */ + ((items == 5) && (rtr == 'r')) || /* RTR without DLC */ + ((items == 6) && (rtr == 'r'))) { /* RTR with DLC */ found = 1; get_can_id(&cf, tmp1, 10); }