asc2log: add CAN XL support for CAN XL message events

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
pull/573/head
Oliver Hartkopp 2025-01-24 14:33:59 +01:00
parent 99c5c14790
commit 0e9c53f6d3
1 changed files with 211 additions and 9 deletions

220
asc2log.c
View File

@ -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 <DataLength>
* 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);