asc2log: support CANFD tagged asc file content

Handles CANFD asc files with classic CAN and CAN FD frames.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
pull/203/head
Oliver Hartkopp 2020-05-09 18:42:55 +02:00
parent 3c8197e4d1
commit df0b25c17e
1 changed files with 120 additions and 15 deletions

129
asc2log.c
View File

@ -70,7 +70,7 @@ void print_usage(char *prg)
fprintf(stderr, "\t-O <outfile>\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;
else
for (i = 0; i < dlc; i++)
cf.data[i] = data[i] & 0xFFU;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf);
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN);
fflush(outfile);
return;
}
@ -193,16 +196,118 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i
memset(&cf, 0, sizeof(cf));
/* do not know more than 'Error' */
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
cf.can_dlc = CAN_ERR_DLC;
cf.len = CAN_ERR_DLC;
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
prframe(outfile, &tv, interface, &cf);
prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN);
fflush(outfile);
}
}
}
void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, char base, int dplace, FILE *outfile) {
void eval_canfd(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 canfd_frame cf;
unsigned char brs, esi, ctmp;
unsigned int flags;
int dlc, dlen = 0;
char tmp1[BUFLEN];
char *ptr;
int i;
/* The CANFD format is mainly in hex representation but <DataLength>
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);
}