From 0e9c53f6d3ce362b2a99b0f14a3ee7d33a081ad0 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 24 Jan 2025 14:33:59 +0100 Subject: [PATCH] asc2log: add CAN XL support for CAN XL message events Signed-off-by: Oliver Hartkopp --- asc2log.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 211 insertions(+), 9 deletions(-) diff --git a/asc2log.c b/asc2log.c index 535629e..060c4d3 100644 --- a/asc2log.c +++ b/asc2log.c @@ -58,7 +58,16 @@ #include "lib.h" -#define BUFLEN 400 /* CAN FD mode lines can be pretty long */ +#define BUFLEN 6500 /* CAN XL mode lines can be pretty long */ + +/* 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 +#define ASC_F_XLF 0x00400000 +#define ASC_F_RES 0x00800000 +#define ASC_F_SEC 0x01000000 extern int optind, opterr, optopt; @@ -345,12 +354,6 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, 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) { cf.flags = CANFD_FDF; if (flags & ASC_F_BRS) @@ -383,6 +386,203 @@ static void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, /* No support for really strange CANFD ErrorFrames format m( */ } +static void eval_canxl_cc(char* buf, struct timeval *date_tvp, char timestamps, + int dplace, FILE *outfile) +{} + +static void eval_canxl_fd(char* buf, struct timeval *date_tvp, char timestamps, + int dplace, FILE *outfile) +{} + +static void eval_canxl_xl(char* buf, struct timeval *date_tvp, char timestamps, + int dplace, FILE *outfile) +{ + int interface; + static struct timeval tv; /* current frame timestamp */ + static struct timeval read_tv; /* frame timestamp from ASC file */ + struct canxl_frame cf = { 0 }; + unsigned char sdt, vcid, secbit, ctmp; + unsigned int af, sbc, pcrc, flags; + int dlc, dlen = 0; + char tmp1[BUFLEN]; + char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ + char *extra_info; + char *ptr; + int i; + unsigned long long sec, usec; + + /* + * 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \ + * e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \ + * ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \ + * 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \ + * 000000000a00001 + */ + + /* check for valid line without symbolic name */ + if (sscanf(buf, + "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ + "%*s %*s %*s %s " /* frame format, msg dur, bit count, ID */ + "%hhx %hhx %x %d " /* SDT, SEC, DLC, Datalen */ + "%x %x %hhx %x ", /* stuff bit count, crc, VCID, AF */ + &sec, &usec, &interface, dir, + tmp1, + &sdt, &secbit, &dlc, &dlen, + &sbc, &pcrc, &vcid, &af) != 13) { + /* check for valid line with a symbolic name */ + if (sscanf(buf, + "%llu.%llu %*s %d %4s " /* time, CANXL, channel, direction */ + "%*s %*s %*s %s " /* frame format, msg dur, bit count, ID */ + "%*s %hhx %hhx %x %d " /* sym name, SDT, SEC, DLC, Datalen */ + "%x %x %hhx %x ", /* stuff bit count, crc, VCID, AF */ + &sec, &usec, &interface, dir, + tmp1, + &sdt, &secbit, &dlc, &dlen, + &sbc, &pcrc, &vcid, &af) != 13) { + + /* no valid CANXL format pattern */ + return; + } + } + + read_tv.tv_sec = sec; + read_tv.tv_usec = usec; + + /* check for allowed (unsigned) value ranges */ + if ((dlen > CANXL_MAX_DLEN) || (dlc > CANXL_MAX_DLC) || + (sbc > 7) || (secbit > 1)) + return; + + cf.sdt = sdt; + cf.af = af; + + if (strlen(dir) != 2) /* "Rx" or "Tx" */ + return; + + /* check for signed integer overflow */ + if (dplace == 4 && read_tv.tv_usec >= INT_MAX / 100) + return; + + /* check for signed integer overflow */ + if (dplace == 5 && read_tv.tv_usec >= INT_MAX / 10) + return; + + if (dir[0] == 'R') + extra_info = " R\n"; + else + extra_info = " T\n"; + + /* don't trust ASCII content - sanitize data length */ + if (dlen != dlc + 1) + return; + + get_can_id(&cf.prio, tmp1, 16); + + if ((cf.prio & CANXL_PRIO_MASK) != cf.prio) + return; + + if (vcid) + cf.prio |= (vcid << CANXL_VCID_OFFSET); + + /* now search for the beginning of the data[] content */ + sprintf(tmp1, " %x %04x %02x %08x ", sbc, pcrc, vcid, af); + + /* search for the pattern generated by real data */ + ptr = strcasestr(buf, tmp1); + if (ptr == NULL) + return; + + ptr += strlen(tmp1); /* start of ASCII hex frame data */ + + 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 FCRC to get Flags value */ + if (sscanf(ptr, "%*x %x ", &flags) != 1) + return; + + /* mandatory for CAN XL frames */ + if (!(flags & ASC_F_XLF)) + return; + + /* mark as CAN XL */ + cf.flags = CANXL_XLF; + + if (flags & ASC_F_SEC) + cf.flags |= CANXL_SEC; + + if (flags & ASC_F_RES) + cf.flags |= CANXL_RRS; + + calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); + prframe(outfile, &tv, interface, (cu_t *)&cf, extra_info); + fflush(outfile); + + /* No support for CAN XL ErrorFrames */ +} + +static void eval_canxl(char* buf, struct timeval *date_tvp, char timestamps, + int dplace, FILE *outfile) +{ + int interface; + char dir[5]; /* 'Rx'/'Tx'/'TxRq' plus terminating zero */ + char frfo[5]; /* frame format 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' plus terminating zero */ + unsigned long long sec, usec; + + /* + * The CANXL format is mainly in hex representation but + * and probably some content we skip anyway. Check out the new spec: + * CAN, Log & Trigger ASC Logging Format Spec V 1.4.17 of 2024-05-21 + */ + + /* + * This is a CAN XL ("XLFF") example for the CANXL Message Event: + * + * 59.171614 CANXL 2 Rx XLFF 984438 4656 432 msgCanXlTest1 \ + * e0 0 1fe 511 1 1f96 00 00000000 e1 89 e8 c2 b9 6d 5a f1 c5 97 ( .. ) \ + * ( .. ) c7 e3 4e f6 bf 12cfbd62 02503000 00000000 000000050005000e \ + * 0000000000a00010 0000000a000a001d 0000000000a00002 000000100010000f \ + * 000000000a00001 + */ + + /* check for valid line until frame format tag */ + if (sscanf(buf, "%llu.%llu %*s %d %4s %4s ", + &sec, &usec, &interface, dir, frfo) != 5) + return; /* no valid CANXL format pattern */ + + if (strlen(dir) != 2) /* "Rx" or "Tx" */ + return; + + if (strlen(frfo) != 4) /* 'CBFF'/'CEFF'/'FBFF'/'FEFF'/'XLFF' */ + return; + + if (!strncmp(frfo, "XLFF", 4)) + eval_canxl_xl(buf, date_tvp, timestamps, dplace, outfile); + else if (!strncmp(frfo, "FBFF", 4)) + eval_canxl_fd(buf, date_tvp, timestamps, dplace, outfile); + else if (!strncmp(frfo, "FEFF", 4)) + eval_canxl_fd(buf, date_tvp, timestamps, dplace, outfile); + else if (!strncmp(frfo, "CBFF", 4)) + eval_canxl_cc(buf, date_tvp, timestamps, dplace, outfile); + else if (!strncmp(frfo, "CEFF", 4)) + eval_canxl_cc(buf, date_tvp, timestamps, dplace, outfile); +} + static int get_date(struct timeval *tv, char *date) { struct tm tms; @@ -550,9 +750,11 @@ int main(int argc, char **argv) * So try to get CAN frames and ErrorFrames and convert them. */ - /* check classic CAN format or the CANFD tag which can take both types */ + /* check classic CAN format or the CANFD/CANXL tag which can take different types */ if (sscanf(buf, "%llu.%llu %s ", &sec, &usec, tmp1) == 3){ - if (!strncmp(tmp1, "CANFD", 5)) + if (!strncmp(tmp1, "CANXL", 5)) + eval_canxl(buf, &date_tv, timestamps, dplace, outfile); + else if (!strncmp(tmp1, "CANFD", 5)) eval_canfd(buf, &date_tv, timestamps, dplace, outfile); else eval_can(buf, &date_tv, timestamps, base, dplace, outfile);