diff --git a/asc2log.c b/asc2log.c index 4eb3609..210e008 100644 --- a/asc2log.c +++ b/asc2log.c @@ -62,7 +62,7 @@ extern int optind, opterr, optopt; -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - convert ASC logfile to compact CAN frame logfile.\n", prg); fprintf(stderr, "Usage: %s\n", prg); @@ -71,7 +71,10 @@ void print_usage(char *prg) fprintf(stderr, "\t-O \t(default stdout)\n"); } -void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, unsigned int max_dlen, char *extra_info) { +static void prframe(FILE *file, struct timeval *tv, int dev, + struct canfd_frame *cf, char *extra_info) +{ + static char abuf[BUFLEN]; fprintf(file, "(%llu.%06llu) ", (unsigned long long)tv->tv_sec, (unsigned long long)tv->tv_usec); @@ -80,11 +83,12 @@ void prframe(FILE *file, struct timeval *tv, int dev, struct canfd_frame *cf, un else fprintf(file, "canX "); - fprint_canframe(file, cf, extra_info, 0, max_dlen); + snprintf_canframe(abuf, sizeof(abuf), (cu_t *)cf, 0); + fprintf(file, "%s%s", abuf, extra_info); } -void get_can_id(struct canfd_frame *cf, char *idstring, int base) { - +static void get_can_id(struct canfd_frame *cf, char *idstring, int base) +{ if (idstring[strlen(idstring)-1] == 'x') { cf->can_id = CAN_EFF_FLAG; idstring[strlen(idstring)-1] = 0; @@ -94,9 +98,9 @@ void get_can_id(struct canfd_frame *cf, char *idstring, int base) { cf->can_id |= strtoul(idstring, NULL, base); } -void calc_tv(struct timeval *tv, struct timeval *read_tv, - struct timeval *date_tv, char timestamps, int dplace) { - +static void calc_tv(struct timeval *tv, struct timeval *read_tv, + struct timeval *date_tv, char timestamps, int dplace) +{ if (dplace == 4) /* shift values having only 4 decimal places */ read_tv->tv_usec *= 100; /* and need for 6 */ @@ -126,12 +130,13 @@ 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) { - +static 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 canfd_frame cf; + struct canfd_frame cf = { 0 }; struct can_frame *ccf = (struct can_frame *)&cf; /* for len8_dlc */ char rtr; int dlc = 0; @@ -152,13 +157,12 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) { - memset(&cf, 0, sizeof(cf)); /* do not know more than 'Error' */ cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR); cf.len = CAN_ERR_DLC; calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); - prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, "\n"); + prframe(outfile, &tv, interface, &cf, "\n"); fflush(outfile); return; } @@ -232,13 +236,14 @@ void eval_can(char* buf, struct timeval *date_tvp, char timestamps, char base, i cf.data[i] = data[i] & 0xFFU; calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); - prframe(outfile, &tv, interface, &cf, CAN_MAX_DLEN, extra_info); + prframe(outfile, &tv, interface, &cf, extra_info); fflush(outfile); } } -void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace, FILE *outfile) { - +static 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 */ @@ -343,14 +348,13 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace #define ASC_F_ESI 0x00004000 if (flags & ASC_F_FDF) { - dlen = CANFD_MAX_DLEN; + cf.flags = CANFD_FDF; 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 @@ -369,14 +373,14 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace } calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace); - prframe(outfile, &tv, interface, &cf, dlen, extra_info); + prframe(outfile, &tv, interface, &cf, extra_info); fflush(outfile); /* No support for really strange CANFD ErrorFrames format m( */ } -int get_date(struct timeval *tv, char *date) { - +static int get_date(struct timeval *tv, char *date) +{ struct tm tms; unsigned int msecs = 0; diff --git a/canbusload.c b/canbusload.c index 4409a4b..d2906ae 100644 --- a/canbusload.c +++ b/canbusload.c @@ -94,7 +94,7 @@ static unsigned char bargraph; static enum cfl_mode mode = CFL_WORSTCASE; static char *prg; -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - monitor CAN bus load.\n", prg); fprintf(stderr, "\nUsage: %s [options] +\n", prg); @@ -124,13 +124,13 @@ void print_usage(char *prg) fprintf(stderr, "\n"); } -void sigterm(int signo) +static void sigterm(int signo) { running = 0; signal_num = signo; } -void printstats(int signo) +static void printstats(int signo) { int i, j, percent; diff --git a/candump.c b/candump.c index 334e202..2c57b8d 100644 --- a/candump.c +++ b/candump.c @@ -109,7 +109,7 @@ static char *progname; static char devname[MAXIFNAMES][IFNAMSIZ + 1]; static int dindex[MAXIFNAMES]; static int max_devname_len; /* to prevent frazzled device name output */ -static const int canfd_on = 1; +static const int canfx_on = 1; #define MAXANI 4 static const char anichar[MAXANI] = { '|', '/', '-', '\\' }; @@ -220,12 +220,16 @@ static int idx2dindex(int ifidx, int socket) return i; } -static inline void sprint_timestamp(const char timestamp, const struct timeval *tv, - struct timeval *const last_tv, char *ts_buffer) +static int sprint_timestamp(char *ts_buffer, const char timestamp, + const struct timeval *tv, struct timeval *const last_tv) { + int numchars = 0; + switch (timestamp) { case 'a': /* absolute with timestamp */ - sprintf(ts_buffer, "(%010llu.%06llu) ", (unsigned long long)tv->tv_sec, (unsigned long long)tv->tv_usec); + numchars = sprintf(ts_buffer, "(%010llu.%06llu) ", + (unsigned long long)tv->tv_sec, + (unsigned long long)tv->tv_usec); break; case 'A': /* absolute with date */ @@ -235,7 +239,8 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval * tm = *localtime(&tv->tv_sec); strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm); - sprintf(ts_buffer, "(%s.%06llu) ", timestring, (unsigned long long)tv->tv_usec); + numchars = sprintf(ts_buffer, "(%s.%06llu) ", timestring, + (unsigned long long)tv->tv_usec); } break; @@ -252,7 +257,9 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval * diff.tv_sec--, diff.tv_usec += 1000000; if (diff.tv_sec < 0) diff.tv_sec = diff.tv_usec = 0; - sprintf(ts_buffer, "(%03llu.%06llu) ", (unsigned long long)diff.tv_sec, (unsigned long long)diff.tv_usec); + numchars = sprintf(ts_buffer, "(%03llu.%06llu) ", + (unsigned long long)diff.tv_sec, + (unsigned long long)diff.tv_usec); if (timestamp == 'd') *last_tv = *tv; /* update for delta calculation */ @@ -262,15 +269,13 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval * default: /* no timestamp output */ break; } -} -static inline void print_timestamp(const char timestamp, const struct timeval *tv, - struct timeval *const last_tv) -{ - static char buffer[TIMESTAMPSZ]; + if (numchars <= 0) { + ts_buffer[0] = 0; /* empty terminated string */ + numchars = 0; + } - sprint_timestamp(timestamp, tv, last_tv, buffer); - printf("%s", buffer); + return numchars; } int main(int argc, char **argv) @@ -301,6 +306,11 @@ int main(int argc, char **argv) struct sockaddr_can addr = { .can_family = AF_CAN, }; + struct can_raw_vcid_options vcid_opts = { + .flags = CAN_RAW_XL_VCID_RX_FILTER, + .rx_vcid = 0, + .rx_vcid_mask = 0, + }; char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(3 * sizeof(struct timespec)) + CMSG_SPACE(sizeof(__u32))]; @@ -309,14 +319,16 @@ int main(int argc, char **argv) struct cmsghdr *cmsg; struct can_filter *rfilter; can_err_mask_t err_mask; - struct canfd_frame frame; - int nbytes, i, maxdlen; + static cu_t cu; /* union for CAN CC/FD/XL frames */ + int nbytes, i; struct ifreq ifr; struct timeval tv, last_tv; int timeout_ms = -1; /* default to no timeout */ FILE *logfile = NULL; char fname[83]; /* suggested by -Wformat-overflow= */ const char *logname = NULL; + static char afrbuf[AFRSZ]; /* ASCII CAN frame buffer size */ + static int alen; signal(SIGTERM, sigterm); signal(SIGHUP, sigterm); @@ -589,7 +601,13 @@ int main(int argc, char **argv) } /* if (nptr) */ /* try to switch the socket into CAN FD mode */ - setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to switch the socket into CAN XL mode */ + setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to enable the CAN XL VCID pass through mode */ + setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, &vcid_opts, sizeof(vcid_opts)); if (rcvbuf_size) { int curr_rcvbuf_size; @@ -693,7 +711,7 @@ int main(int argc, char **argv) } /* these settings are static and can be held out of the hot path */ - iov.iov_base = &frame; + iov.iov_base = &cu; msg.msg_name = &addr; msg.msg_iov = &iov; msg.msg_iovlen = 1; @@ -719,7 +737,7 @@ int main(int argc, char **argv) char *extra_info = ""; /* these settings may be modified by recvmsg() */ - iov.iov_len = sizeof(frame); + iov.iov_len = sizeof(cu); msg.msg_namelen = sizeof(addr); msg.msg_controllen = sizeof(ctrlmsg); msg.msg_flags = 0; @@ -736,15 +754,29 @@ int main(int argc, char **argv) return 1; } - 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"); + /* mark dual-use struct canfd_frame */ + if (nbytes < CANXL_HDR_SIZE + CANXL_MIN_DLEN) { + fprintf(stderr, "read: no CAN frame\n"); return 1; } + if (cu.xl.flags & CANXL_XLF) { + if (nbytes != CANXL_HDR_SIZE + cu.xl.len) { + printf("nbytes = %d\n", nbytes); + fprintf(stderr, "read: no CAN XL frame\n"); + return 1; + } + } else { + if (nbytes == CAN_MTU) + cu.fd.flags = 0; + else if (nbytes == CANFD_MTU) + cu.fd.flags |= CANFD_FDF; + else { + fprintf(stderr, "read: incomplete CAN CC/FD frame\n"); + return 1; + } + } + if (count && (--count == 0)) running = 0; @@ -786,7 +818,7 @@ int main(int argc, char **argv) } /* once we detected a EFF frame indent SFF frames accordingly */ - if (frame.can_id & CAN_EFF_FLAG) + if (cu.fd.can_id & CAN_EFF_FLAG) view |= CANLIB_VIEW_INDENT_SFF; if (extra_msg_info) { @@ -796,32 +828,29 @@ int main(int argc, char **argv) extra_info = " R"; } - if (log) { - char buf[CL_CFSZ]; /* max length */ - char ts_buf[TIMESTAMPSZ]; + /* build common log format output */ + if ((log) || ((logfrmt) && (silent == SILENT_OFF))) { - sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf); + alen = sprint_timestamp(afrbuf, logtimestamp, + &tv, &last_tv); - /* log CAN frame with absolute timestamp & device */ - sprint_canframe(buf, &frame, 0, maxdlen); - fprintf(logfile, "%s%*s %s%s\n", ts_buf, - max_devname_len, devname[idx], buf, - extra_info); + alen += sprintf(afrbuf + alen, "%*s ", + max_devname_len, devname[idx]); + + alen += snprintf_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, 0); } + /* write CAN frame in log file style to logfile */ + if (log) + fprintf(logfile, "%s%s\n", afrbuf, extra_info); + + /* print CAN frame in log file style to stdout */ if ((logfrmt) && (silent == SILENT_OFF)) { - char buf[CL_CFSZ]; /* max length */ - - /* print CAN frame in log file style to stdout */ - sprint_canframe(buf, &frame, 0, maxdlen); - print_timestamp(logtimestamp, &tv, &last_tv); - - printf("%*s %s%s\n", - max_devname_len, devname[idx], buf, - extra_info); + printf("%s%s\n", afrbuf, extra_info); goto out_fflush; /* no other output to stdout */ } + /* print only animation */ if (silent != SILENT_OFF) { if (silent == SILENT_ANI) { printf("%c\b", anichar[silentani %= MAXANI]); @@ -830,25 +859,33 @@ int main(int argc, char **argv) goto out_fflush; /* no other output to stdout */ } - printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : ""); - print_timestamp(timestamp, &tv, &last_tv); - printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : ""); - printf("%*s", max_devname_len, devname[idx]); + /* print (colored) long CAN frame style to stdout */ + alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : ""); + alen += sprint_timestamp(afrbuf + alen, timestamp, &tv, &last_tv); + alen += sprintf(afrbuf + alen, " %s%*s", + (color && (color < 3)) ? col_on[idx % MAXCOL] : "", + max_devname_len, devname[idx]); if (extra_msg_info) { if (msg.msg_flags & MSG_DONTROUTE) - printf(" TX %s", extra_m_info[frame.flags & 3]); + alen += sprintf(afrbuf + alen, " TX %s", + extra_m_info[cu.fd.flags & 3]); else - printf(" RX %s", extra_m_info[frame.flags & 3]); + alen += sprintf(afrbuf + alen, " RX %s", + extra_m_info[cu.fd.flags & 3]); } - printf("%s ", (color == 1) ? col_off : ""); + alen += sprintf(afrbuf + alen, "%s ", (color == 1) ? col_off : ""); + alen += snprintf_long_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, view); - fprint_long_canframe(stdout, &frame, NULL, view, maxdlen); - - printf("%s", (color > 1) ? col_off : ""); - printf("\n"); + if ((view & CANLIB_VIEW_ERROR) && (cu.fd.can_id & CAN_ERR_FLAG)) { + alen += sprintf(afrbuf + alen, "\n\t"); + alen += snprintf_can_error_frame(afrbuf + alen, + sizeof(afrbuf) - alen, + &cu.fd, "\n\t"); + } + printf("%s%s\n", afrbuf, (color > 1) ? col_off : ""); out_fflush: fflush(stdout); } diff --git a/cangen.c b/cangen.c index 0614f42..4e27261 100644 --- a/cangen.c +++ b/cangen.c @@ -177,12 +177,17 @@ static 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, " -X (generate CAN XL CAN frames)\n"); fprintf(stderr, " -R (generate RTR frames)\n"); fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n"); - fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n"); + fprintf(stderr, " -m (mix -e -f -b -E -R -X frames)\n"); fprintf(stderr, " -I (CAN ID generation mode - see below)\n"); fprintf(stderr, " -L (CAN data length code (dlc) generation mode - see below)\n"); fprintf(stderr, " -D (CAN data (payload) generation mode - see below)\n"); + fprintf(stderr, " -F (CAN XL Flags generation mode - see below, no e/o mode)\n"); + fprintf(stderr, " -S (CAN XL SDT generation mode - see below, no e/o mode)\n"); + fprintf(stderr, " -A (CAN XL AF generation mode - see below, no e/o mode)\n"); + fprintf(stderr, " -V (CAN XL VCID generation mode - see below, no e/o mode)\n"); fprintf(stderr, " -p (poll on -ENOBUFS to write frames with ms)\n"); fprintf(stderr, " -n (terminate after CAN frames - default infinite)\n"); fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n"); @@ -293,12 +298,11 @@ static int setsockopt_txtime(int fd) return 0; } -static int do_send_one(int fd, void *buf, size_t len, int timeout) +static int do_send_one(int fd, cu_t *cu, size_t len, int timeout) { uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 }; struct iovec iov = { - .iov_base = buf, - .iov_len = len, + .iov_base = cu, }; struct msghdr msg = { .msg_iov = &iov, @@ -307,6 +311,12 @@ static int do_send_one(int fd, void *buf, size_t len, int timeout) ssize_t nbytes; int ret; + /* CAN XL frames need real frame length for sending */ + if (len == CANXL_MTU) + len = CANXL_HDR_SIZE + cu->xl.len; + + iov.iov_len = len; + if (use_so_txtime) { struct cmsghdr *cm; uint64_t tdeliver; @@ -443,20 +453,31 @@ int main(int argc, char **argv) unsigned long polltimeout = 0; unsigned char extended = 0; unsigned char canfd = 0; + unsigned char canxl = 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; unsigned char dlc_mode = MODE_RANDOM; + __u8 xl_flags = 0; + __u8 xl_sdt = 0; + __u32 xl_af = 0; + __u8 xl_vcid = 0; + unsigned char xl_flags_mode = MODE_RANDOM; + unsigned char xl_sdt_mode = MODE_RANDOM; + unsigned char xl_af_mode = MODE_RANDOM; + unsigned char xl_vcid_mode = MODE_RANDOM; unsigned char loopback_disable = 0; unsigned char verbose = 0; unsigned char rtr_frame = 0; unsigned char len8_dlc = 0; + unsigned char view = 0; int count = 0; unsigned long burst_sent_count = 0; int mtu, maxdlen; uint64_t incdata = 0; + __u8 *data; /* base pointer for CC/FD or XL data */ int incdlc = 0; unsigned long rnd; unsigned char fixdata[CANFD_MAX_DLEN]; @@ -466,10 +487,13 @@ int main(int argc, char **argv) int s; /* socket */ struct sockaddr_can addr = { 0 }; - static struct canfd_frame frame; - struct can_frame *ccf = (struct can_frame *)&frame; + struct can_raw_vcid_options vcid_opts = { + .flags = CAN_RAW_XL_VCID_TX_PASS, + }; + static cu_t cu; int i; - struct ifreq ifr; + struct ifreq ifr = { 0 }; + const int enable_canfx = 1; struct timeval now; int ret; @@ -488,7 +512,7 @@ int main(int argc, char **argv) { 0, 0, 0, 0 }, }; - while ((opt = getopt_long(argc, argv, "g:atefbER8mI:L:D:p:n:ixc:vh?", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "g:atefbEXR8mI:L:D:F:S:A:V:p:n:ixc:vh?", long_options, NULL)) != -1) { switch (opt) { case 'g': gap = strtod(optarg, NULL); @@ -516,6 +540,7 @@ int main(int argc, char **argv) break; case 'e': extended = 1; + view |= CANLIB_VIEW_INDENT_SFF; break; case 'f': @@ -532,17 +557,23 @@ int main(int argc, char **argv) canfd = 1; break; + case 'X': + canxl = 1; + break; + case 'R': rtr_frame = 1; break; case '8': len8_dlc = 1; + view |= CANLIB_VIEW_LEN8_DLC; break; case 'm': mix = 1; canfd = 1; /* to switch the socket into CAN FD mode */ + view |= CANLIB_VIEW_INDENT_SFF; break; case 'I': @@ -556,7 +587,7 @@ int main(int argc, char **argv) id_mode = MODE_RANDOM_ODD; } else { id_mode = MODE_FIX; - frame.can_id = strtoul(optarg, NULL, 16); + cu.fd.can_id = strtoul(optarg, NULL, 16); } break; @@ -567,7 +598,7 @@ int main(int argc, char **argv) dlc_mode = MODE_INCREMENT; } else { dlc_mode = MODE_FIX; - frame.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */ + cu.fd.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */ } break; @@ -586,6 +617,59 @@ int main(int argc, char **argv) } break; + case 'F': + if (optarg[0] == 'r') { + xl_flags_mode = MODE_RANDOM; + } else if (optarg[0] == 'i') { + xl_flags_mode = MODE_INCREMENT; + } else { + xl_flags_mode = MODE_FIX; + if (sscanf(optarg, "%hhx", &xl_flags) != 1) { + printf("Bad xl_flags definition '%s'.\n", optarg); + exit(1); + } + } + break; + + case 'S': + if (optarg[0] == 'r') { + xl_sdt_mode = MODE_RANDOM; + } else if (optarg[0] == 'i') { + xl_sdt_mode = MODE_INCREMENT; + } else { + xl_sdt_mode = MODE_FIX; + if (sscanf(optarg, "%hhx", &xl_sdt) != 1) { + printf("Bad xl_sdt definition '%s'.\n", optarg); + exit(1); + } + } + break; + + case 'A': + if (optarg[0] == 'r') { + xl_af_mode = MODE_RANDOM; + } else if (optarg[0] == 'i') { + xl_af_mode = MODE_INCREMENT; + } else { + xl_af_mode = MODE_FIX; + xl_af = strtoul(optarg, NULL, 16); + } + break; + + case 'V': + if (optarg[0] == 'r') { + xl_vcid_mode = MODE_RANDOM; + } else if (optarg[0] == 'i') { + xl_vcid_mode = MODE_INCREMENT; + } else { + xl_vcid_mode = MODE_FIX; + if (sscanf(optarg, "%hhx", &xl_vcid) != 1) { + printf("Bad xl_vcid definition '%s'.\n", optarg); + exit(1); + } + } + break; + case 'p': polltimeout = strtoul(optarg, NULL, 10); break; @@ -627,10 +711,13 @@ int main(int argc, char **argv) return 1; } + if (verbose > 2) + view |= CANLIB_VIEW_ASCII; + ts_gap = double_to_timespec(gap / 1000); /* recognize obviously missing commandline option */ - if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) { + if (id_mode == MODE_FIX && cu.fd.can_id > 0x7FF && !extended) { printf("The given CAN-ID is greater than 0x7FF and the '-e' option is not set.\n"); return 1; } @@ -670,8 +757,7 @@ int main(int argc, char **argv) &loopback, sizeof(loopback)); } - if (canfd) { - const int enable_canfd = 1; + if (canfd || canxl) { /* check if the frame fits into the CAN netdevice */ if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { @@ -679,31 +765,61 @@ int main(int argc, char **argv) return 1; } - if (ifr.ifr_mtu != CANFD_MTU && ifr.ifr_mtu != CANXL_MTU) { - printf("CAN interface is only Classical CAN capable - sorry.\n"); + if (canfd) { + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); + } else { + /* limit fixed CAN XL data length to 64 */ + if (cu.fd.len > CANFD_MAX_DLEN) + cu.fd.len = CANFD_MAX_DLEN; + } + + if (canxl && (ifr.ifr_mtu < CANXL_MIN_MTU)) { + printf("CAN interface not CAN XL 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"); + if (canfd && (ifr.ifr_mtu < CANFD_MTU)) { + printf("CAN interface not CAN FD capable - sorry.\n"); return 1; } - /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ - frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len)); + if (ifr.ifr_mtu == CANFD_MTU) { + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN FD support\n"); + return 1; + } + } + + if (ifr.ifr_mtu >= CANXL_MIN_MTU) { + /* interface is ok - try to switch the socket into CAN XL mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN XL support\n"); + return 1; + } + /* try to enable the CAN XL VCID pass through mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, + &vcid_opts, sizeof(vcid_opts))) { + printf("error when enabling CAN XL VCID pass through\n"); + return 1; + } + } + } else { /* sanitize Classical CAN 2.0 frame length */ if (len8_dlc) { - if (frame.len > CAN_MAX_RAW_DLC) - frame.len = CAN_MAX_RAW_DLC; + if (cu.cc.len > CAN_MAX_RAW_DLC) + cu.cc.len = CAN_MAX_RAW_DLC; - if (frame.len > CAN_MAX_DLEN) - ccf->len8_dlc = frame.len; + if (cu.cc.len > CAN_MAX_DLEN) + cu.cc.len8_dlc = cu.cc.len; } - if (frame.len > CAN_MAX_DLEN) - frame.len = CAN_MAX_DLEN; + if (cu.cc.len > CAN_MAX_DLEN) + cu.cc.len = CAN_MAX_DLEN; } if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { @@ -722,96 +838,107 @@ int main(int argc, char **argv) return 1; while (running) { - frame.flags = 0; + cu.fd.flags = 0; if (count && (--count == 0)) running = 0; - if (canfd) { + if (canxl) { + mtu = CANXL_MTU; + maxdlen = CANFD_MAX_DLEN; /* generate up to 64 byte */ + extended = 0; /* prio has only 11 bit ID content */ + data = cu.xl.data; /* fill CAN XL data */ + } else if (canfd) { mtu = CANFD_MTU; maxdlen = CANFD_MAX_DLEN; + data = cu.fd.data; /* fill CAN CC/FD data */ + cu.fd.flags = CANFD_FDF; if (brs) - frame.flags |= CANFD_BRS; + cu.fd.flags |= CANFD_BRS; if (esi) - frame.flags |= CANFD_ESI; + cu.fd.flags |= CANFD_ESI; } else { mtu = CAN_MTU; maxdlen = CAN_MAX_DLEN; + data = cu.cc.data; /* fill CAN CC/FD data */ } if (id_mode == MODE_RANDOM) - frame.can_id = random(); + cu.fd.can_id = random(); else if (id_mode == MODE_RANDOM_EVEN) - frame.can_id = random() & ~0x1; + cu.fd.can_id = random() & ~0x1; else if (id_mode == MODE_RANDOM_ODD) - frame.can_id = random() | 0x1; + cu.fd.can_id = random() | 0x1; if (extended) { - frame.can_id &= CAN_EFF_MASK; - frame.can_id |= CAN_EFF_FLAG; - } else - frame.can_id &= CAN_SFF_MASK; + cu.fd.can_id &= CAN_EFF_MASK; + cu.fd.can_id |= CAN_EFF_FLAG; + } else { + cu.fd.can_id &= CAN_SFF_MASK; + } - if (rtr_frame && !canfd) - frame.can_id |= CAN_RTR_FLAG; + if (rtr_frame && !canfd && !canxl) + cu.fd.can_id |= CAN_RTR_FLAG; if (dlc_mode == MODE_RANDOM) { - if (canfd) - frame.len = can_fd_dlc2len(random() & 0xF); + if (canxl) + cu.fd.len = CANXL_MIN_DLEN + (random() & 0x3F); + else if (canfd) + cu.fd.len = can_fd_dlc2len(random() & 0xF); else { - frame.len = random() & 0xF; + cu.cc.len = random() & 0xF; - if (frame.len > CAN_MAX_DLEN) { + if (cu.cc.len > CAN_MAX_DLEN) { /* generate Classic CAN len8 DLCs? */ if (len8_dlc) - ccf->len8_dlc = frame.len; + cu.cc.len8_dlc = cu.cc.len; - frame.len = 8; /* for about 50% of the frames */ + cu.cc.len = 8; /* for about 50% of the frames */ } else { - ccf->len8_dlc = 0; + cu.cc.len8_dlc = 0; } } } - if (data_mode == MODE_INCREMENT && !frame.len) - frame.len = 1; /* min dlc value for incr. data */ + if (data_mode == MODE_INCREMENT && !cu.cc.len) + cu.cc.len = 1; /* min dlc value for incr. data */ if (data_mode == MODE_RANDOM) { rnd = random(); - memcpy(&frame.data[0], &rnd, 4); + memcpy(&data[0], &rnd, 4); rnd = random(); - memcpy(&frame.data[4], &rnd, 4); + memcpy(&data[4], &rnd, 4); /* 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 ((canfd || canxl) && cu.fd.len > 8) { + memcpy(&data[8], &data[0], 8); + memcpy(&data[16], &data[0], 16); + memcpy(&data[32], &data[0], 32); } } if (data_mode == MODE_RANDOM_FIX) { int i; - memcpy(frame.data, fixdata, CANFD_MAX_DLEN); + memcpy(data, fixdata, CANFD_MAX_DLEN); - for (i = 0; i < frame.len; i++) { + for (i = 0; i < cu.fd.len; i++) { if (rand_position[i] == (NIBBLE_H | NIBBLE_L)) { - frame.data[i] = random(); + data[i] = random(); } else if (rand_position[i] == NIBBLE_H) { - frame.data[i] = (frame.data[i] & 0x0f) | (random() & 0xf0); + data[i] = (data[i] & 0x0f) | (random() & 0xf0); } else if (rand_position[i] == NIBBLE_L) { - frame.data[i] = (frame.data[i] & 0xf0) | (random() & 0x0f); + data[i] = (data[i] & 0xf0) | (random() & 0x0f); } } } if (data_mode == MODE_FIX) - memcpy(frame.data, fixdata, CANFD_MAX_DLEN); + memcpy(data, fixdata, CANFD_MAX_DLEN); /* set unused payload data to zero like the CAN driver does it on rx */ - if (frame.len < maxdlen) - memset(&frame.data[frame.len], 0, maxdlen - frame.len); + if (cu.fd.len < maxdlen) + memset(&data[cu.fd.len], 0, maxdlen - cu.fd.len); if (!use_so_txtime && (ts.tv_sec || ts.tv_nsec) && @@ -826,16 +953,70 @@ int main(int argc, char **argv) } } + if (canxl) { + /* convert some CAN FD frame content into a CAN XL frame */ + if (cu.fd.len < CANXL_MIN_DLEN) { + cu.fd.len = CANXL_MIN_DLEN; + data[0] = 0xCC; /* default filler */ + } + cu.xl.len = cu.fd.len; + + rnd = random(); + + if (xl_flags_mode == MODE_RANDOM) { + cu.xl.flags = rnd & CANXL_SEC; + } else if (xl_flags_mode == MODE_FIX) { + cu.xl.flags = xl_flags; + } else if (xl_flags_mode == MODE_INCREMENT) { + xl_flags ^= CANXL_SEC; + cu.xl.flags = (xl_flags & CANXL_SEC); + } + + /* mark CAN XL frame */ + cu.xl.flags |= CANXL_XLF; + + if (xl_sdt_mode == MODE_RANDOM) { + cu.xl.sdt = rnd & 0xFF; + } else if (xl_sdt_mode == MODE_FIX) { + cu.xl.sdt = xl_sdt; + } else if (xl_sdt_mode == MODE_INCREMENT) { + xl_sdt++; + cu.xl.sdt = xl_sdt; + } + + if (xl_af_mode == MODE_RANDOM) { + cu.xl.af = rnd; + } else if (xl_af_mode == MODE_FIX) { + cu.xl.af = xl_af; + } else if (xl_af_mode == MODE_INCREMENT) { + xl_af++; + cu.xl.af = xl_af; + } + + if (xl_vcid_mode == MODE_RANDOM) { + cu.xl.prio |= rnd & CANXL_VCID_MASK; + } else if (xl_vcid_mode == MODE_FIX) { + cu.xl.prio |= xl_vcid << CANXL_VCID_OFFSET; + } else if (xl_vcid_mode == MODE_INCREMENT) { + xl_vcid++; + cu.xl.prio |= xl_vcid << CANXL_VCID_OFFSET; + } + } + if (verbose) { + static char afrbuf[AFRSZ]; /* ASCII CAN frame buffer size */ + printf(" %s ", argv[optind]); if (verbose > 1) - fprint_long_canframe(stdout, &frame, "\n", (verbose > 2) ? 1 : 0, maxdlen); + snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, view); else - fprint_canframe(stdout, &frame, "\n", 1, maxdlen); + snprintf_canframe(afrbuf, sizeof(afrbuf), &cu, 1); + + printf("%s\n", afrbuf); } - ret = do_send_one(s, &frame, mtu, polltimeout); + ret = do_send_one(s, &cu, mtu, polltimeout); if (ret) return 1; @@ -843,26 +1024,30 @@ int main(int argc, char **argv) burst_sent_count = 0; burst_sent_count++; + /* restore some CAN FD frame content from CAN XL frame */ + if (canxl) + cu.fd.len = cu.xl.len; + if (id_mode == MODE_INCREMENT) - frame.can_id++; + cu.cc.can_id++; if (dlc_mode == MODE_INCREMENT) { incdlc++; incdlc %= CAN_MAX_RAW_DLC + 1; - if (canfd && !mix) - frame.len = can_fd_dlc2len(incdlc); + if ((canfd || canxl) && !mix) + cu.fd.len = can_fd_dlc2len(incdlc); else if (len8_dlc) { if (incdlc > CAN_MAX_DLEN) { - frame.len = CAN_MAX_DLEN; - ccf->len8_dlc = incdlc; + cu.cc.len = CAN_MAX_DLEN; + cu.cc.len8_dlc = incdlc; } else { - frame.len = incdlc; - ccf->len8_dlc = 0; + cu.cc.len = incdlc; + cu.cc.len8_dlc = 0; } } else { incdlc %= CAN_MAX_DLEN + 1; - frame.len = incdlc; + cu.fd.len = incdlc; } } @@ -870,7 +1055,7 @@ int main(int argc, char **argv) incdata++; for (i = 0; i < 8; i++) - frame.data[i] = incdata >> i * 8; + data[i] = incdata >> i * 8; } if (mix) { @@ -881,6 +1066,10 @@ int main(int argc, char **argv) brs = i & 4; esi = i & 8; } + /* generate CAN XL traffic if the interface is capable */ + if (ifr.ifr_mtu >= CANXL_MIN_MTU) + canxl = ((i & 96) == 96); + rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */ } } diff --git a/cangw.c b/cangw.c index f7a6678..f99a956 100644 --- a/cangw.c +++ b/cangw.c @@ -82,8 +82,8 @@ struct fdmodattr { #define NLMSG_TAIL(nmsg) \ ((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) -int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, - int alen) +static int addattr_l(struct nlmsghdr *n, int maxlen, int type, + const void *data, int alen) { int len = RTA_LENGTH(alen); struct rtattr *rta; @@ -101,7 +101,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, return 0; } -void printfilter(const void *data) +static void printfilter(const void *data) { struct can_filter *filter = (struct can_filter *)data; @@ -111,7 +111,7 @@ void printfilter(const void *data) printf("-f %03X:%X ", filter->can_id, filter->can_mask); } -void printmod(const char *type, const void *data) +static void printmod(const char *type, const void *data) { struct modattr mod; int i; @@ -137,7 +137,7 @@ void printmod(const char *type, const void *data) printf(" "); } -void printfdmod(const char *type, const void *data) +static void printfdmod(const char *type, const void *data) { struct fdmodattr mod; int i; @@ -166,14 +166,14 @@ void printfdmod(const char *type, const void *data) printf(" "); } -void print_cs_xor(struct cgw_csum_xor *cs_xor) +static void print_cs_xor(struct cgw_csum_xor *cs_xor) { printf("-x %d:%d:%d:%02X ", cs_xor->from_idx, cs_xor->to_idx, cs_xor->result_idx, cs_xor->init_xor_val); } -void print_cs_crc8_profile(struct cgw_csum_crc8 *cs_crc8) +static void print_cs_crc8_profile(struct cgw_csum_crc8 *cs_crc8) { int i; @@ -202,7 +202,7 @@ void print_cs_crc8_profile(struct cgw_csum_crc8 *cs_crc8) printf(" "); } -void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8) +static void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8) { int i; @@ -220,7 +220,7 @@ void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8) print_cs_crc8_profile(cs_crc8); } -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - manage PF_CAN netlink gateway.\n", prg); fprintf(stderr, "\nUsage: %s [options]\n\n", prg); @@ -279,7 +279,7 @@ void print_usage(char *prg) fprintf(stderr, "\n"); } -int b64hex(char *asc, unsigned char *bin, int len) +static int b64hex(char *asc, unsigned char *bin, int len) { int i; @@ -290,7 +290,7 @@ int b64hex(char *asc, unsigned char *bin, int len) return 0; } -int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8) +static int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8) { int ret = 1; char *ptr; @@ -329,7 +329,7 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8) return ret; } -int parse_mod(char *optarg, struct modattr *modmsg) +static int parse_mod(char *optarg, struct modattr *modmsg) { char *ptr, *nptr; char hexdata[(CAN_MAX_DLEN * 2) + 1] = {0}; @@ -397,7 +397,7 @@ int parse_mod(char *optarg, struct modattr *modmsg) return 0; /* ok */ } -int parse_fdmod(char *optarg, struct fdmodattr *modmsg) +static int parse_fdmod(char *optarg, struct fdmodattr *modmsg) { char *ptr, *nptr; char hexdata[(CANFD_MAX_DLEN * 2) + 1] = {0}; @@ -470,7 +470,7 @@ int parse_fdmod(char *optarg, struct fdmodattr *modmsg) return 0; /* ok */ } -int parse_rtlist(char *prgname, unsigned char *rxbuf, int len) +static int parse_rtlist(char *prgname, unsigned char *rxbuf, int len) { char ifname[IF_NAMESIZE]; /* interface name for if_indextoname() */ struct rtcanmsg *rtc; diff --git a/canlogserver.c b/canlogserver.c index 23478b7..4d9cba8 100644 --- a/canlogserver.c +++ b/canlogserver.c @@ -72,9 +72,6 @@ #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]; @@ -86,7 +83,7 @@ extern int optind, opterr, optopt; static volatile int running = 1; static volatile sig_atomic_t signal_num; -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - log CAN frames and serves them.\n", prg); fprintf(stderr, "\nUsage: %s [options] +\n", prg); @@ -110,7 +107,7 @@ void print_usage(char *prg) fprintf(stderr, "\n"); } -int idx2dindex(int ifidx, int socket) +static int idx2dindex(int ifidx, int socket) { int i; struct ifreq ifr; @@ -160,7 +157,7 @@ int idx2dindex(int ifidx, int socket) * This is a Signalhandler. When we get a signal, that a child * terminated, we wait for it, so the zombie will disappear. */ -void childdied(int i) +static void childdied(int i) { wait(NULL); } @@ -168,13 +165,12 @@ void childdied(int i) /* * This is a Signalhandler for a caught SIGTERM */ -void shutdown_gra(int i) +static void shutdown_gra(int i) { running = 0; signal_num = i; } - int main(int argc, char **argv) { struct sigaction signalaction; @@ -189,17 +185,22 @@ int main(int argc, char **argv) int opt, ret; int currmax = 1; /* we assume at least one can bus ;-) */ struct sockaddr_can addr; + struct can_raw_vcid_options vcid_opts = { + .flags = CAN_RAW_XL_VCID_RX_FILTER, + .rx_vcid = 0, + .rx_vcid_mask = 0, + }; struct can_filter rfilter; - struct canfd_frame frame; - const int canfd_on = 1; - int nbytes, i, j, maxdlen; + static cu_t cu; /* union for CAN CC/FD/XL frames */ + const int canfx_on = 1; + int nbytes, i, j; struct ifreq ifr; struct timeval tv; int port = DEFPORT; struct sockaddr_in inaddr; struct sockaddr_in clientaddr; socklen_t sin_size = sizeof(clientaddr); - char temp[BUFSZ]; + static char afrbuf[AFRSZ]; sigemptyset(&sigset); signalaction.sa_handler = &childdied; @@ -345,7 +346,13 @@ int main(int argc, char **argv) &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)); + setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to switch the socket into CAN XL mode */ + setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_XL_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to enable the CAN XL VCID pass through mode */ + setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, &vcid_opts, sizeof(vcid_opts)); j = strlen(argv[optind+i]); @@ -394,42 +401,54 @@ int main(int argc, char **argv) socklen_t len = sizeof(addr); int idx; - if ((nbytes = recvfrom(s[i], &frame, CANFD_MTU, 0, + if ((nbytes = recvfrom(s[i], &cu, sizeof(cu), 0, (struct sockaddr*)&addr, &len)) < 0) { perror("read"); return 1; } - 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"); + if (nbytes < CANXL_HDR_SIZE + CANXL_MIN_DLEN) { + fprintf(stderr, "read: no CAN frame\n"); return 1; } + if (cu.xl.flags & CANXL_XLF) { + if (nbytes != CANXL_HDR_SIZE + cu.xl.len) { + printf("nbytes = %d\n", nbytes); + fprintf(stderr, "read: no CAN XL frame\n"); + return 1; + } + } else { + /* mark dual-use struct canfd_frame */ + if (nbytes == CAN_MTU) { + cu.fd.flags = 0; + } else if (nbytes == CANFD_MTU) { + cu.fd.flags |= CANFD_FDF; + } else { + fprintf(stderr, "read: incomplete CAN CC/FD frame\n"); + return 1; + } + } + if (ioctl(s[i], SIOCGSTAMP, &tv) < 0) perror("SIOCGSTAMP"); idx = idx2dindex(addr.can_ifindex, s[i]); - sprintf(temp, "(%llu.%06llu) %*s ", + sprintf(afrbuf, "(%llu.%06llu) %*s ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec, max_devname_len, devname[idx]); - sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen); - strcat(temp, "\n"); + snprintf_canframe(afrbuf + strlen(afrbuf), sizeof(afrbuf) - strlen(afrbuf), &cu, 0); + strcat(afrbuf, "\n"); - if (write(accsocket, temp, strlen(temp)) < 0) { + if (write(accsocket, afrbuf, strlen(afrbuf)) < 0) { perror("writeaccsock"); return 1; } #if 0 /* print CAN frame in log file style to stdout */ - printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec); - printf("%*s ", max_devname_len, devname[idx]); - fprint_canframe(stdout, &frame, "\n", 0, maxdlen); + printf("%s", afrbuf); #endif } diff --git a/canplayer.c b/canplayer.c index e1b7ce3..eb9c569 100644 --- a/canplayer.c +++ b/canplayer.c @@ -61,21 +61,35 @@ #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 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 */ +#if (IFNAMSIZ != 16) +#error "IFNAMSIZ value does not to DEVSZ calculation!" +#endif + +#define DEVSZ 22 /* IFNAMSZ + 6 */ +#define TIMESZ sizeof("(1345212884.318850) ") +#define BUFSZ (TIMESZ + DEVSZ + AFRSZ) + +/* adapt sscanf() functions below on error */ +#if (AFRSZ != 6300) +#error "AFRSZ value does not fit sscanf restrictions!" +#endif +#if (DEVSZ != 22) +#error "DEVSZ value does not fit sscanf restrictions!" +#endif + struct assignment { char txif[IFNAMSIZ]; int txifidx; char rxif[IFNAMSIZ]; }; static struct assignment asgn[CHANNELS]; -const int canfd_on = 1; +const int canfx_on = 1; extern int optind, opterr, optopt; -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg); fprintf(stderr, "\nUsage: %s [interface assignment]*\n\n", prg); @@ -158,7 +172,7 @@ static inline int frames_to_send(struct timeval *today, struct timeval *diff, st return timeval_compare(&cmp, today); } -int get_txidx(char *logif_name) +static int get_txidx(char *logif_name) { int i; @@ -175,7 +189,7 @@ int get_txidx(char *logif_name) return asgn[i].txifidx; /* return interface index */ } -char *get_txname(char *logif_name) +static char *get_txname(char *logif_name) { int i; @@ -192,7 +206,8 @@ char *get_txname(char *logif_name) return asgn[i].txif; /* return interface name */ } -int add_assignment(char *mode, int socket, char *txname, char *rxname, int verbose) +static int add_assignment(char *mode, int socket, char *txname, + char *rxname, int verbose) { struct ifreq ifr; int i; @@ -239,9 +254,12 @@ int add_assignment(char *mode, int socket, char *txname, char *rxname, int verbo int main(int argc, char **argv) { - static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; + static char buf[BUFSZ], device[DEVSZ], afrbuf[AFRSZ]; struct sockaddr_can addr; - static struct canfd_frame frame; + struct can_raw_vcid_options vcid_opts = { + .flags = CAN_RAW_XL_VCID_TX_PASS, + }; + static cu_t cu; static struct timeval today_tv, log_tv, last_log_tv, diff_tv; struct timespec sleep_ts; int s; /* CAN_RAW socket */ @@ -360,7 +378,13 @@ int main(int argc, char **argv) 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)); + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to switch the socket into CAN XL mode */ + setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, &canfx_on, sizeof(canfx_on)); + + /* try to enable the CAN XL VCID pass through mode */ + setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, &vcid_opts, sizeof(vcid_opts)); if (loopback_disable) { int loopback = 0; @@ -417,7 +441,7 @@ int main(int argc, char **argv) eof = 0; - if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, ascframe) != 4) { + if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec, device, afrbuf) != 4) { fprintf(stderr, "incorrect line format in logfile\n"); return 1; } @@ -446,7 +470,7 @@ int main(int argc, char **argv) if (interactive) getchar(); - /* log_tv/device/ascframe are valid here */ + /* log_tv/device/afrbuf are valid here */ if (strlen(device) >= IFNAMSIZ) { fprintf(stderr, "log interface name '%s' too long!", device); @@ -470,27 +494,28 @@ int main(int argc, char **argv) } else if (txidx > 0) { /* only send to valid CAN devices */ - txmtu = parse_canframe(ascframe, &frame); + txmtu = parse_canframe(afrbuf, &cu); /* dual-use frame */ if (!txmtu) { - fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe); + fprintf(stderr, "wrong CAN frame format: '%s'!", afrbuf); return 1; } + /* CAN XL frames need real frame length for sending */ + if (txmtu == CANXL_MTU) + txmtu = CANXL_HDR_SIZE + cu.xl.len; + addr.can_family = AF_CAN; addr.can_ifindex = txidx; /* send via this interface */ - if (sendto(s, &frame, txmtu, 0, (struct sockaddr *)&addr, sizeof(addr)) != txmtu) { + if (sendto(s, &cu, txmtu, 0, (struct sockaddr *)&addr, sizeof(addr)) != txmtu) { perror("sendto"); return 1; } if (verbose) { printf("%s (%s) ", get_txname(device), device); - - if (txmtu == CAN_MTU) - fprint_long_canframe(stdout, &frame, "\n", CANLIB_VIEW_INDENT_SFF, CAN_MAX_DLEN); - else - fprint_long_canframe(stdout, &frame, "\n", CANLIB_VIEW_INDENT_SFF, CANFD_MAX_DLEN); + snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, CANLIB_VIEW_INDENT_SFF); + printf("%s\n", afrbuf); } if (count && (--count == 0)) @@ -510,7 +535,7 @@ int main(int argc, char **argv) break; } - if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, ascframe) != 4) { + if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, device, afrbuf) != 4) { fprintf(stderr, "incorrect line format in logfile\n"); return 1; } diff --git a/cansend.c b/cansend.c index c2eb30c..2749482 100644 --- a/cansend.c +++ b/cansend.c @@ -64,11 +64,13 @@ static void print_usage(char *prg) "Usage: %s .\n" "\n" ":\n" - " #{data} for Classical CAN 2.0 data frames\n" - " #R{len} for Classical CAN 2.0 data frames\n" - " #{data}_{dlc} for Classical CAN 2.0 data frames\n" - " #R{len}_{dlc} for Classical CAN 2.0 data frames\n" - " ##{data} for CAN FD frames\n\n" + " #{data} for CAN CC (Classical CAN 2.0B) data frames\n" + " #R{len} for CAN CC (Classical CAN 2.0B) data frames\n" + " #{data}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n" + " #R{len}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n" + " ##{data} for CAN FD frames\n" + " #::# for CAN XL frames\n" + "\n" ":\n" " 3 (SFF) or 8 (EFF) hex chars\n" "{data}:\n" @@ -80,9 +82,23 @@ static void print_usage(char *prg) ":\n" " a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n" "\n" + ":\n" + " 2 hex chars - virtual CAN network identifier (00 .. FF)\n" + ":\n" + " 3 hex chars - 11 bit priority value (000 .. 7FF)\n" + ":\n" + " 2 hex chars values (00 .. FF) which defines canxl_frame.flags\n" + ":\n" + " 2 hex chars values (00 .. FF) which defines canxl_frame.sdt\n" + ":\n" + " 8 hex chars - 32 bit acceptance field (canxl_frame.af)\n" + ":\n" + " 1..2048 ASCII hex-values (optionally separated by '.')\n" + "\n" "Examples:\n" " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n" - " 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n" + " 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E /\n" + " 45123#81:00:12345678#11223344.556677 / 00242#81:07:40000123#112233\n" "\n", prg, prg); } @@ -92,9 +108,12 @@ int main(int argc, char **argv) int s; /* can raw socket */ int required_mtu; int mtu; - int enable_canfd = 1; + int enable_canfx = 1; struct sockaddr_can addr; - struct canfd_frame frame; + struct can_raw_vcid_options vcid_opts = { + .flags = CAN_RAW_XL_VCID_TX_PASS, + }; + static cu_t cu; struct ifreq ifr; /* check command line options */ @@ -104,7 +123,7 @@ int main(int argc, char **argv) } /* parse CAN frame */ - required_mtu = parse_canframe(argv[2], &frame); + required_mtu = parse_canframe(argv[2], &cu); if (!required_mtu) { fprintf(stderr, "\nWrong CAN-frame format!\n\n"); print_usage(argv[0]); @@ -137,22 +156,39 @@ int main(int argc, char **argv) } mtu = ifr.ifr_mtu; - if (mtu != CANFD_MTU && mtu != CANXL_MTU) { - printf("CAN interface is only Classical CAN capable - sorry.\n"); - return 1; + if (mtu == CANFD_MTU) { + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN FD support\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; + if (mtu >= CANXL_MIN_MTU) { + /* interface is ok - try to switch the socket into CAN XL mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES, + &enable_canfx, sizeof(enable_canfx))){ + printf("error when enabling CAN XL support\n"); + return 1; + } + /* try to enable the CAN XL VCID pass through mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_VCID_OPTS, + &vcid_opts, sizeof(vcid_opts))) { + printf("error when enabling CAN XL VCID pass through\n"); + return 1; + } } - - /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ - frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len)); } + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + if (required_mtu == CANFD_MTU) + cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len)); + + /* CAN XL frames need real frame length for sending */ + if (required_mtu == CANXL_MTU) + required_mtu = CANXL_HDR_SIZE + cu.xl.len; + /* * disable default receive filter on this RAW socket This is * obsolete as we do not read from the socket at all, but for @@ -167,7 +203,7 @@ int main(int argc, char **argv) } /* send frame */ - if (write(s, &frame, required_mtu) != required_mtu) { + if (write(s, &cu, required_mtu) != required_mtu) { perror("write"); return 1; } diff --git a/lib.c b/lib.c index 260d908..1c2ec0c 100644 --- a/lib.c +++ b/lib.c @@ -55,6 +55,7 @@ #define CANID_DELIM '#' #define CC_DLC_DELIM '_' +#define XL_HDR_DELIM ':' #define DATA_SEPERATOR '.' const char hex_asc_upper[] = "0123456789ABCDEF"; @@ -153,77 +154,126 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen) return 0; } -int parse_canframe(char *cs, struct canfd_frame *cf) +int parse_canframe(char *cs, cu_t *cu) { /* documentation see lib.h */ int i, idx, dlen, len; int maxdlen = CAN_MAX_DLEN; - int ret = CAN_MTU; + int mtu = CAN_MTU; + __u8 *data = cu->fd.data; /* fill CAN CC/FD data by default */ canid_t tmp; len = strlen(cs); //printf("'%s' len %d\n", cs, len); - memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */ + memset(cu, 0, sizeof(*cu)); /* init CAN CC/FD/XL frame, e.g. LEN = 0 */ if (len < 4) return 0; - if (cs[3] == CANID_DELIM) { /* 3 digits */ + if (cs[3] == CANID_DELIM) { /* 3 digits SFF */ idx = 4; for (i = 0; i < 3; i++) { if ((tmp = asc2nibble(cs[i])) > 0x0F) return 0; - cf->can_id |= (tmp << (2 - i) * 4); + cu->cc.can_id |= tmp << (2 - i) * 4; } - } else if (cs[8] == CANID_DELIM) { /* 8 digits */ + } else if (cs[5] == CANID_DELIM) { /* 5 digits CAN XL VCID/PRIO*/ + + idx = 6; + for (i = 0; i < 5; i++) { + if ((tmp = asc2nibble(cs[i])) > 0x0F) + return 0; + cu->xl.prio |= tmp << (4 - i) * 4; + } + + /* the VCID starts at bit position 16 */ + tmp = (cu->xl.prio << 4) & CANXL_VCID_MASK; + cu->xl.prio &= CANXL_PRIO_MASK; + cu->xl.prio |= tmp; + + } else if (cs[8] == CANID_DELIM) { /* 8 digits EFF */ idx = 9; for (i = 0; i < 8; i++) { if ((tmp = asc2nibble(cs[i])) > 0x0F) return 0; - cf->can_id |= (tmp << (7 - i) * 4); + cu->cc.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 */ + if (!(cu->cc.can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */ + cu->cc.can_id |= CAN_EFF_FLAG; /* then it is an extended frame */ } else return 0; if ((cs[idx] == 'R') || (cs[idx] == 'r')) { /* RTR frame */ - cf->can_id |= CAN_RTR_FLAG; + cu->cc.can_id |= CAN_RTR_FLAG; /* check for optional DLC value for CAN 2.0B frames */ if (cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) { - cf->len = tmp; + cu->cc.len = tmp; /* check for optional raw DLC value for CAN 2.0B frames */ if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) { tmp = asc2nibble(cs[idx]); - if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) { - struct can_frame *ccf = (struct can_frame *)cf; - - ccf->len8_dlc = tmp; - } + if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) + cu->cc.len8_dlc = tmp; } } - return ret; + return mtu; } if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */ - maxdlen = CANFD_MAX_DLEN; - ret = CANFD_MTU; + mtu = CANFD_MTU; /* CAN FD frame ##* */ if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F) return 0; - cf->flags = tmp; + cu->fd.flags = tmp; + cu->fd.flags |= CANFD_FDF; /* dual-use */ idx += 2; + + } else if (cs[idx + 14] == CANID_DELIM) { /* CAN XL frame '#80:00:11223344#' */ + maxdlen = CANXL_MAX_DLEN; + mtu = CANXL_MTU; + data = cu->xl.data; /* fill CAN XL data */ + + if ((cs[idx + 2] != XL_HDR_DELIM) || (cs[idx + 5] != XL_HDR_DELIM)) + return 0; + + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 0; + cu->xl.flags = tmp << 4; + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 0; + cu->xl.flags |= tmp; + + /* force CAN XL flag if it was missing in the ASCII string */ + cu->xl.flags |= CANXL_XLF; + + idx++; /* skip XL_HDR_DELIM */ + + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 0; + cu->xl.sdt = tmp << 4; + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 0; + cu->xl.sdt |= tmp; + + idx++; /* skip XL_HDR_DELIM */ + + for (i = 0; i < 8; i++) { + if ((tmp = asc2nibble(cs[idx++])) > 0x0F) + return 0; + cu->xl.af |= tmp << (7 - i) * 4; + } + + idx++; /* skip CANID_DELIM */ } for (i = 0, dlen = 0; i < maxdlen; i++) { @@ -235,102 +285,141 @@ int parse_canframe(char *cs, struct canfd_frame *cf) if ((tmp = asc2nibble(cs[idx++])) > 0x0F) return 0; - cf->data[i] = (tmp << 4); + data[i] = tmp << 4; if ((tmp = asc2nibble(cs[idx++])) > 0x0F) return 0; - cf->data[i] |= tmp; + data[i] |= tmp; dlen++; } - cf->len = dlen; + + if (mtu == CANXL_MTU) + cu->xl.len = dlen; + else + cu->fd.len = dlen; /* check for extra DLC when having a Classic CAN with 8 bytes payload */ if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) { unsigned char dlc = asc2nibble(cs[idx]); - if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) { - struct can_frame *ccf = (struct can_frame *)cf; - - ccf->len8_dlc = dlc; - } + if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) + cu->cc.len8_dlc = dlc; } - return ret; + return mtu; } -void fprint_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int sep, int maxdlen) -{ - /* documentation see lib.h */ - - char buf[CL_CFSZ]; /* max length */ - - sprint_canframe(buf, cf, sep, maxdlen); - fprintf(stream, "%s", buf); - if (eol) - fprintf(stream, "%s", eol); -} - -void sprint_canframe(char *buf, struct canfd_frame *cf, int sep, int maxdlen) +int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep) { /* documentation see lib.h */ + unsigned char is_canfd = cu->fd.flags; int i, offset; - int len = (cf->len > maxdlen) ? maxdlen : cf->len; + int len; - if (cf->can_id & CAN_ERR_FLAG) { - put_eff_id(buf, cf->can_id & (CAN_ERR_MASK | CAN_ERR_FLAG)); + /* ensure space for string termination */ + if (size < 1) + return size; + + /* handle CAN XL frames */ + if (cu->xl.flags & CANXL_XLF) { + len = cu->xl.len; + + /* check if the CAN frame fits into the provided buffer */ + if (sizeof("00123#11:22:12345678#") + 2 * len + (sep ? len : 0) > size - 1) { + /* mark buffer overflow in output */ + memset(buf, '-', size - 1); + buf[size - 1] = 0; + return size; + } + + /* print prio and CAN XL header content */ + offset = sprintf(buf, "%02X%03X#%02X:%02X:%08X#", + (canid_t)(cu->xl.prio & CANXL_VCID_MASK) >> CANXL_VCID_OFFSET, + (canid_t)(cu->xl.prio & CANXL_PRIO_MASK), + cu->xl.flags, cu->xl.sdt, cu->xl.af); + + /* data */ + for (i = 0; i < len; i++) { + put_hex_byte(buf + offset, cu->xl.data[i]); + offset += 2; + if (sep && (i + 1 < len)) + buf[offset++] = '.'; + } + + buf[offset] = 0; + + return offset; + } + + /* handle CAN CC/FD frames - ensure max length values */ + if (is_canfd) + len = (cu->fd.len > CANFD_MAX_DLEN) ? CANFD_MAX_DLEN : cu->fd.len; + else + len = (cu->fd.len > CAN_MAX_DLEN) ? CAN_MAX_DLEN : cu->fd.len; + + /* check if the CAN frame fits into the provided buffer */ + if (sizeof("12345678#_F") + 2 * len + (sep ? len : 0) + \ + (cu->fd.can_id & CAN_RTR_FLAG ? 2 : 0) > size - 1) { + /* mark buffer overflow in output */ + memset(buf, '-', size - 1); + buf[size - 1] = 0; + return size; + } + + if (cu->fd.can_id & CAN_ERR_FLAG) { + put_eff_id(buf, cu->fd.can_id & (CAN_ERR_MASK | CAN_ERR_FLAG)); buf[8] = '#'; offset = 9; - } else if (cf->can_id & CAN_EFF_FLAG) { - put_eff_id(buf, cf->can_id & CAN_EFF_MASK); + } else if (cu->fd.can_id & CAN_EFF_FLAG) { + put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK); buf[8] = '#'; offset = 9; } else { - put_sff_id(buf, cf->can_id & CAN_SFF_MASK); + put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK); buf[3] = '#'; offset = 4; } - /* 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) { + /* CAN CC frames may have RTR enabled. There are no ERR frames with RTR */ + if (!is_canfd && cu->fd.can_id & CAN_RTR_FLAG) { buf[offset++] = 'R'; /* print a given CAN 2.0B DLC if it's not zero */ - if (cf->len && cf->len <= CAN_MAX_DLEN) { - buf[offset++] = hex_asc_upper_lo(cf->len); + if (len && len <= CAN_MAX_DLEN) { + buf[offset++] = hex_asc_upper_lo(cu->fd.len); /* check for optional raw DLC value for CAN 2.0B frames */ - if (cf->len == CAN_MAX_DLEN) { - struct can_frame *ccf = (struct can_frame *)cf; - - if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) { + if (len == CAN_MAX_DLEN) { + if ((cu->cc.len8_dlc > CAN_MAX_DLEN) && (cu->cc.len8_dlc <= CAN_MAX_RAW_DLC)) { buf[offset++] = CC_DLC_DELIM; - buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc); + buf[offset++] = hex_asc_upper_lo(cu->cc.len8_dlc); } } } buf[offset] = 0; - return; + return offset; } - if (maxdlen == CANFD_MAX_DLEN) { + /* any CAN FD flags */ + if (is_canfd) { /* add CAN FD specific escape char and flags */ buf[offset++] = '#'; - buf[offset++] = hex_asc_upper_lo(cf->flags); + buf[offset++] = hex_asc_upper_lo(cu->fd.flags); if (sep && len) buf[offset++] = '.'; } + /* data */ for (i = 0; i < len; i++) { - put_hex_byte(buf + offset, cf->data[i]); + put_hex_byte(buf + offset, cu->fd.data[i]); offset += 2; if (sep && (i + 1 < len)) buf[offset++] = '.'; } /* check for extra DLC when having a Classic CAN with 8 bytes payload */ - if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) { - struct can_frame *ccf = (struct can_frame *)cf; - unsigned char dlc = ccf->len8_dlc; + if (!is_canfd && (len == CAN_MAX_DLEN)) { + unsigned char dlc = cu->cc.len8_dlc; if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) { buf[offset++] = CC_DLC_DELIM; @@ -339,55 +428,130 @@ void sprint_canframe(char *buf, struct canfd_frame *cf, int sep, int maxdlen) } buf[offset] = 0; + + return offset; } -void fprint_long_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int view, int maxdlen) +int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view) { /* documentation see lib.h */ - char buf[CL_LONGCFSZ]; + unsigned char is_canfd = cu->fd.flags; + int i, j, dlen, offset, maxsize; + int len; - 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"); - fprintf(stream, "\n\t%s", buf); + /* ensure space for string termination */ + if (size < 1) + return size; + + /* handle CAN XL frames */ + if (cu->xl.flags & CANXL_XLF) { + len = cu->xl.len; + + /* crop to CANFD_MAX_DLEN */ + if (len > CANFD_MAX_DLEN) + dlen = CANFD_MAX_DLEN; + else + dlen = len; + + /* check if the CAN frame fits into the provided buffer */ + if (sizeof(".....123 [2048] (00|11:22:12345678) ...") + 3 * dlen > size - 1) { + /* mark buffer overflow in output */ + memset(buf, '-', size - 1); + buf[size - 1] = 0; + return size; + } + + if (view & CANLIB_VIEW_INDENT_SFF) { + memset(buf, ' ', 5); + put_sff_id(buf + 5, cu->xl.prio & CANXL_PRIO_MASK); + offset = 8; + } else { + put_sff_id(buf, cu->xl.prio & CANXL_PRIO_MASK); + offset = 3; + } + + /* print prio and CAN XL header content */ + offset += sprintf(buf + offset, " [%04d] (%02X|%02X:%02X:%08X) ", + len, + (canid_t)(cu->xl.prio & CANXL_VCID_MASK) >> CANXL_VCID_OFFSET, + cu->xl.flags, cu->xl.sdt, cu->xl.af); + + for (i = 0; i < dlen; i++) { + put_hex_byte(buf + offset, cu->xl.data[i]); + offset += 2; + if (i + 1 < dlen) + buf[offset++] = ' '; + } + + /* indicate cropped output */ + if (cu->xl.len > dlen) + offset += sprintf(buf + offset, " ..."); + + buf[offset] = 0; + + return offset; } - if (eol) - fprintf(stream, "%s", eol); -} -void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdlen) -{ - /* documentation see lib.h */ + /* ensure max length values */ + if (is_canfd) + len = (cu->fd.len > CANFD_MAX_DLEN) ? CANFD_MAX_DLEN : cu->fd.len; + else + len = (cu->fd.len > CAN_MAX_DLEN) ? CAN_MAX_DLEN : cu->fd.len; - int i, j, dlen, offset; - int len = (cf->len > maxdlen) ? maxdlen : cf->len; + /* check if the CAN frame fits into the provided buffer */ + maxsize = sizeof("12345678 [12] "); + if (view & CANLIB_VIEW_BINARY) + dlen = 9; /* _10101010 */ + else + dlen = 3; /* _AA */ + + if (cu->fd.can_id & CAN_RTR_FLAG) { + maxsize += sizeof(" remote request"); + } else { + maxsize += len * dlen; + + if (len <= CAN_MAX_DLEN) { + if (cu->fd.can_id & CAN_ERR_FLAG) { + maxsize += sizeof(" ERRORFRAME"); + maxsize += (8 - len) * dlen; + } else if (view & CANLIB_VIEW_ASCII) { + maxsize += sizeof(" 'a.b.CDEF'"); + maxsize += (8 - len) * dlen; + } + } + } + + if (maxsize > size - 1) { + /* mark buffer overflow in output */ + memset(buf, '-', size - 1); + buf[size - 1] = 0; + return size; + } /* initialize space for CAN-ID and length information */ memset(buf, ' ', 15); - if (cf->can_id & CAN_ERR_FLAG) { - put_eff_id(buf, cf->can_id & (CAN_ERR_MASK | CAN_ERR_FLAG)); + if (cu->cc.can_id & CAN_ERR_FLAG) { + put_eff_id(buf, cu->cc.can_id & (CAN_ERR_MASK | CAN_ERR_FLAG)); offset = 10; - } else if (cf->can_id & CAN_EFF_FLAG) { - put_eff_id(buf, cf->can_id & CAN_EFF_MASK); + } else if (cu->fd.can_id & CAN_EFF_FLAG) { + put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK); offset = 10; } else { if (view & CANLIB_VIEW_INDENT_SFF) { - put_sff_id(buf + 5, cf->can_id & CAN_SFF_MASK); + put_sff_id(buf + 5, cu->fd.can_id & CAN_SFF_MASK); offset = 10; } else { - put_sff_id(buf, cf->can_id & CAN_SFF_MASK); + put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK); offset = 5; } } - /* The len value is sanitized by maxdlen (see above) */ - if (maxdlen == CAN_MAX_DLEN) { + /* The len value is sanitized (see above) */ + if (!is_canfd) { if (view & CANLIB_VIEW_LEN8_DLC) { - struct can_frame *ccf = (struct can_frame *)cf; - unsigned char dlc = ccf->len8_dlc; + unsigned char dlc = cu->cc.len8_dlc; /* fall back to len if we don't have a valid DLC > 8 */ if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && @@ -404,9 +568,9 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl } /* standard CAN frames may have RTR enabled */ - if (cf->can_id & CAN_RTR_FLAG) { - sprintf(buf + offset + 5, " remote request"); - return; + if (cu->fd.can_id & CAN_RTR_FLAG) { + offset += sprintf(buf + offset + 5, " remote request"); + return offset + 5; } } else { buf[offset] = '['; @@ -417,22 +581,22 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl offset += 5; if (view & CANLIB_VIEW_BINARY) { - dlen = 9; /* _10101010 */ + /* _10101010 - dlen = 9, see above */ if (view & CANLIB_VIEW_SWAP) { for (i = len - 1; i >= 0; i--) { buf[offset++] = (i == len - 1) ? ' ' : SWAP_DELIMITER; for (j = 7; j >= 0; j--) - buf[offset++] = (1 << j & cf->data[i]) ? '1' : '0'; + buf[offset++] = (1 << j & cu->fd.data[i]) ? '1' : '0'; } } else { for (i = 0; i < len; i++) { buf[offset++] = ' '; for (j = 7; j >= 0; j--) - buf[offset++] = (1 << j & cf->data[i]) ? '1' : '0'; + buf[offset++] = (1 << j & cu->fd.data[i]) ? '1' : '0'; } } } else { - dlen = 3; /* _AA */ + /* _AA - dlen = 3, see above */ if (view & CANLIB_VIEW_SWAP) { for (i = len - 1; i >= 0; i--) { if (i == len - 1) @@ -440,13 +604,13 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl else buf[offset++] = SWAP_DELIMITER; - put_hex_byte(buf + offset, cf->data[i]); + put_hex_byte(buf + offset, cu->fd.data[i]); offset += 2; } } else { for (i = 0; i < len; i++) { buf[offset++] = ' '; - put_hex_byte(buf + offset, cf->data[i]); + put_hex_byte(buf + offset, cu->fd.data[i]); offset += 2; } } @@ -460,34 +624,36 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl * Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console? */ if (len > CAN_MAX_DLEN) - return; + return offset; - if (cf->can_id & CAN_ERR_FLAG) - sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME"); + if (cu->fd.can_id & CAN_ERR_FLAG) + offset += sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME"); else if (view & CANLIB_VIEW_ASCII) { j = dlen * (8 - len) + 4; if (view & CANLIB_VIEW_SWAP) { sprintf(buf + offset, "%*s", j, "`"); offset += j; for (i = len - 1; i >= 0; i--) - if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) - buf[offset++] = cf->data[i]; + if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F)) + buf[offset++] = cu->fd.data[i]; else buf[offset++] = '.'; - sprintf(buf + offset, "`"); + offset += sprintf(buf + offset, "`"); } else { sprintf(buf + offset, "%*s", j, "'"); offset += j; for (i = 0; i < len; i++) - if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F)) - buf[offset++] = cf->data[i]; + if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F)) + buf[offset++] = cu->fd.data[i]; else buf[offset++] = '.'; - sprintf(buf + offset, "'"); + offset += sprintf(buf + offset, "'"); } } + + return offset; } static const char *error_classes[] = { @@ -651,7 +817,7 @@ static int snprintf_error_cnt(char *buf, size_t len, const struct canfd_frame *c return n; } -void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf, +int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf, const char* sep) { canid_t class, mask; @@ -659,12 +825,12 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c char *defsep = ","; if (!(cf->can_id & CAN_ERR_FLAG)) - return; + return 0; class = cf->can_id & CAN_EFF_MASK; if (class > (1 << ARRAY_SIZE(error_classes))) { fprintf(stderr, "Error class %#x is invalid\n", class); - return; + return 0; } if (!sep) @@ -678,13 +844,15 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c /* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */ tmp_n = snprintf(buf + n, len - n, "%s", sep); if (tmp_n < 0 || (size_t)tmp_n >= len - n) { - return; + buf[0] = 0; /* empty terminated string */ + return 0; } n += tmp_n; } tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]); if (tmp_n < 0 || (size_t)tmp_n >= len - n) { - return; + buf[0] = 0; /* empty terminated string */ + return 0; } n += tmp_n; if (mask == CAN_ERR_LOSTARB) @@ -704,6 +872,8 @@ void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *c n += snprintf(buf + n, len - n, "%serror-counter-tx-rx", sep); n += snprintf_error_cnt(buf + n, len - n, cf); } + + return n; } int64_t timespec_diff_ms(struct timespec *ts1, diff --git a/lib.h b/lib.h index 0efd1cb..1ab0324 100644 --- a/lib.h +++ b/lib.h @@ -46,6 +46,7 @@ #define CAN_UTILS_LIB_H #include +#include #include #ifdef DEBUG @@ -55,17 +56,21 @@ __attribute__((format (printf, 1, 2))) static inline int pr_debug(const char* fmt, ...) {return 0;} #endif -/* buffer sizes for CAN frame string representations */ +/* CAN CC/FD/XL frame union */ +typedef union { + struct can_frame cc; + struct canfd_frame fd; + struct canxl_frame xl; +} cu_t; -#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)) +/* + * The buffer size for ASCII CAN frame string representations + * covers also the 'long' CAN frame output from sprint_long_canframe() + * including (swapped) binary represetations, timestamps, netdevice names, + * lengths and error message details as the CAN XL data is cropped to 64 + * byte (the 'long' CAN frame output is only for display on terminals). + */ +#define AFRSZ 6300 /* 3*2048 (data) + 22 (timestamp) + 18 (netdev) + ID/HDR */ /* CAN DLC to real data length conversion helpers especially for CAN FD */ @@ -103,12 +108,12 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen); * */ -struct canfd_frame; -int parse_canframe(char *cs, struct canfd_frame *cf); +int parse_canframe(char *cs, cu_t *cu); /* - * Transfers a valid ASCII string describing a CAN frame into struct canfd_frame. + * Transfers a valid ASCII string describing a CAN frame into the CAN union + * containing CAN CC/FD/XL structs. * - * CAN 2.0 frames (aka Classical CAN) + * CAN CC frames (aka Classical CAN, CAN 2.0B) * - string layout #{R{len}|data}{_len8_dlc} * - {data} has 0 to 8 hex-values that can (optionally) be separated by '.' * - {len} can take values from 0 to 8 and can be omitted if zero @@ -121,6 +126,16 @@ int parse_canframe(char *cs, struct canfd_frame *cf); * - {data} has 0 to 64 hex-values that can (optionally) be separated by '.' * - return value on successful parsing: CANFD_MTU * + * CAN XL frames + * - string layout #::#{data} + * - a two ASCII Hex value (00 .. FF) which defines the VCID + * - a three ASCII Hex value (000 .. 7FF) which defines the 11 bit PRIO + * - a two ASCII Hex value (00 .. FF) which defines canxl_frame.flags + * - a two ASCII Hex value (00 .. FF) which defines canxl_frame.sdt + * - a 8 digit ASCII Hex value which defines the 32 bit canxl_frame.af + * - {data} has 1 to 2048 hex-values that can (optionally) be separated by '.' + * - return value on successful parsing: CANXL_MTU + * * Return value on detected problems: 0 * * can have 3 (standard frame format) or 8 (extended frame format) @@ -151,6 +166,9 @@ int parse_canframe(char *cs, struct canfd_frame *cf); * ^^ * CAN FD extension to handle the canfd_frame.flags content * + * 45123#81:00:12345678#11223344.556677 -> CAN XL frame with len = 7, + * VCID = 0x45, PRIO = 0x123, flags = 0x81, sdt = 0x00, af = 0x12345678 + * * Simple facts on this compact ASCII CAN frame representation: * * - 3 digits: standard frame format @@ -160,15 +178,16 @@ int parse_canframe(char *cs, struct canfd_frame *cf); * - CAN FD frames do not have a RTR bit */ -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); +int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep); /* * Creates a CAN frame hexadecimal output in compact format. * The CAN data[] is separated by '.' when sep != 0. * - * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen: - * maxdlen = 8 -> CAN2.0 frame (aka Classical CAN) - * maxdlen = 64 -> CAN FD frame + * A CAN XL frame is detected when CANXL_XLF is set in the struct + * cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD) + * is specified by the dual-use struct cu.canfd_frame.flags element: + * w/o CAN FD flags (== 0) -> CAN CC frame (aka Classical CAN, CAN2.0B) + * with CAN FD flags (!= 0) -> CAN FD frame (with CANFD_[FDF/BRS/ESI]) * * 12345678#112233 -> extended CAN-Id = 0x12345678, len = 3, data, sep = 0 * 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14, data, sep = 0 @@ -178,11 +197,8 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen); * 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: - * - * fprint_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT - * fprint_canframe(stderr, &frame, NULL, 0); // no eol to STDERR + * 45123#81:00:12345678#11223344.556677 -> CAN XL frame with len = 7, + * VCID = 0x45, PRIO = 0x123, flags = 0x81, sdt = 0x00, af = 0x12345678 * */ @@ -195,14 +211,15 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen); #define SWAP_DELIMITER '`' -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); +int snprintf_long_canframe(char *buf, size_t size, cu_t *cu, int view); /* * Creates a CAN frame hexadecimal output in user readable format. * - * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen: - * maxdlen = 8 -> CAN2.0 frame (aka Classical CAN) - * maxdlen = 64 -> CAN FD frame + * A CAN XL frame is detected when CANXL_XLF is set in the struct + * cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD) + * is specified by the dual-use struct cu.canfd_frame.flags element: + * w/o CAN FD flags (== 0) -> CAN CC frame (aka Classical CAN, CAN2.0B) + * with CAN FD flags (!= 0) -> CAN FD frame (with CANFD_[FDF/BRS/ESI]) * * 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data * 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR @@ -210,22 +227,17 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd * 321 {B} 11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B * 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set) * 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3 + * 123 [0003] (45|81:00:12345678) 11 22 33 -> CAN XL frame with VCID 0x45 * * 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == 0 * 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set * - * Examples: - * - * // CAN FD frame with eol to STDOUT - * fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN); - * - * // Classical CAN 2.0 frame without eol to STDERR - * fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN); - * + * There are no binary or ASCII view modes for CAN XL and the number of displayed + * data bytes is limited to 64 to fit terminal output use-cases. */ -void snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf, - const char *sep); +int snprintf_can_error_frame(char *buf, size_t len, const struct canfd_frame *cf, + const char *sep); /* * Creates a CAN error frame output in user readable format. */ diff --git a/log2asc.c b/log2asc.c index 0640f3c..a0a325f 100644 --- a/log2asc.c +++ b/log2asc.c @@ -54,11 +54,9 @@ #include "lib.h" -#define BUFSZ 400 /* for one line in the logfile */ - extern int optind, opterr, optopt; -void print_usage(char *prg) +static void print_usage(char *prg) { fprintf(stderr, "%s - convert compact CAN frame logfile to ASC logfile.\n", prg); fprintf(stderr, "Usage: %s [can-interfaces]\n", prg); @@ -71,7 +69,8 @@ void print_usage(char *prg) fprintf(stderr, " -r (suppress dlc for RTR frames - pre v8.5 tools)\n"); } -void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc, char *extra_info, FILE *outfile) +static void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc, + char *extra_info, FILE *outfile) { int i; char id[10]; @@ -118,7 +117,8 @@ void can_asc(struct canfd_frame *cfd, int devno, int nortrdlc, char *extra_info, } } -void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FILE *outfile) +static void canfd_asc(struct canfd_frame *cf, int devno, int mtu, + char *extra_info, FILE *outfile) { int i; char id[10]; @@ -181,11 +181,27 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL fprintf(outfile, " %8d %4d %8X 0 0 0 0 0", 130000, 130, flags); } +#define DEVSZ 22 +#define EXTRASZ 20 +#define TIMESZ sizeof("(1345212884.318850) ") +#define BUFSZ (DEVSZ + AFRSZ + EXTRASZ + TIMESZ) + +/* adapt sscanf() functions below on error */ +#if (AFRSZ != 6300) +#error "AFRSZ value does not fit sscanf restrictions!" +#endif +#if (DEVSZ != 22) +#error "DEVSZ value does not fit sscanf restrictions!" +#endif +#if (EXTRASZ != 20) +#error "EXTRASZ value does not fit sscanf restrictions!" +#endif + int main(int argc, char **argv) { - static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], extra_info[BUFSZ]; + static char buf[BUFSZ], device[DEVSZ], afrbuf[AFRSZ], extra_info[EXTRASZ]; - struct canfd_frame cf; + static cu_t cu; static struct timeval tv, start_tv; FILE *infile = stdin; FILE *outfile = stdout; @@ -261,14 +277,14 @@ int main(int argc, char **argv) if (buf[0] != '(') continue; - if (sscanf(buf, "(%llu.%llu) %s %s %s", &sec, &usec, - device, ascframe, extra_info) != 5) { + if (sscanf(buf, "(%llu.%llu) %21s %6299s %19s", &sec, &usec, + device, afrbuf, extra_info) != 5) { /* do not evaluate the extra info */ extra_info[0] = 0; - if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec, - device, ascframe) != 4) { + if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec, + device, afrbuf) != 4) { fprintf(stderr, "incorrect line format in logfile\n"); return 1; } @@ -286,20 +302,25 @@ int main(int argc, char **argv) (crlf)?"\r\n":"\n"); } - for (i=0, devno=0; i +#include #include #include #include "lib.h" -#define COMMENTSZ 200 -#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */ +#define DEVSZ 22 +#define TIMESZ 22 /* sizeof("(1345212884.318850) ") */ +#define BUFSZ (DEVSZ + AFRSZ + TIMESZ) + +/* adapt sscanf() functions below on error */ +#if (AFRSZ != 6300) +#error "AFRSZ value does not fit sscanf restrictions!" +#endif +#if (DEVSZ != 22) +#error "DEVSZ value does not fit sscanf restrictions!" +#endif +#if (TIMESZ != 22) +#error "TIMESZ value does not fit sscanf restrictions!" +#endif int main(void) { - char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ]; - struct canfd_frame cf; - int mtu, maxdlen; + static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ]; + static cu_t cu; + int mtu; while (fgets(buf, BUFSZ-1, stdin)) { - if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3) - return 1; - 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"); + if (strlen(buf) >= BUFSZ-2) { + fprintf(stderr, "line too long for input buffer\n"); return 1; } - sprint_long_canframe(ascframe, &cf, - (CANLIB_VIEW_INDENT_SFF | CANLIB_VIEW_ASCII), - maxdlen); /* with ASCII output */ + if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3) + return 1; - printf("%s %s %s\n", timestamp, device, ascframe); + mtu = parse_canframe(afrbuf, &cu); + + /* mark dual-use struct canfd_frame - no CAN_XL support */ + if (mtu == CAN_MTU) + cu.fd.flags = 0; + else if (mtu == CANFD_MTU) + cu.fd.flags |= CANFD_FDF; + else { + fprintf(stderr, "read: no valid CAN CC/FD frame\n"); + return 1; + } + + /* with ASCII output */ + snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, + (CANLIB_VIEW_INDENT_SFF | CANLIB_VIEW_ASCII)); + + printf("%s %s %s\n", timestamp, device, afrbuf); } return 0; diff --git a/slcanpty.c b/slcanpty.c index 393d67b..76699be 100644 --- a/slcanpty.c +++ b/slcanpty.c @@ -50,7 +50,8 @@ #define DEVICE_NAME_PTMX "/dev/ptmx" /* read data from pty, send CAN frames to CAN socket and answer commands */ -int pty2can(int pty, int socket, struct can_filter *fi, int *is_open, int *tstamp) +static int pty2can(int pty, int socket, struct can_filter *fi, + int *is_open, int *tstamp) { unsigned int nbytes; char cmd; @@ -313,7 +314,7 @@ rx_out: } /* read CAN frames from CAN interface and write it to the pty */ -int can2pty(int pty, int socket, int *tstamp) +static int can2pty(int pty, int socket, int *tstamp) { int nbytes; char cmd; @@ -365,7 +366,7 @@ int can2pty(int pty, int socket, int *tstamp) return 0; } -int check_select_stdin(void) +static int check_select_stdin(void) { fd_set rdfs; struct timeval timeout;