Merge pull request #504 from hartkopp/master
can-utils: support CAN XL
This patch set adds support for CAN XL including VCIDs (Linux v6.9+)
Tools that completely support CAN XL:
candump
cangen
canlogserver
canplayer
cansend
log2long
CC/FD-only tools that have been adapted to the lib.[ch] changes:
log2asc
asc2log
Main changes:
lib/cangen: add documentation for CAN XL ASCII representation
lib: remove separate maxdlen parameter as every needed info is part of the CAN frame now
lib: remove fprint functions and only support sprint
lib: rework for static single buffer to contain a complete ASCII CAN XL frame
lib: introduce a CAN frame unit type to contain CAN CC/FD/XL frames in one union
canplayer/log2asc/log2long: make sscanf() buffer length aware
cangen: fix views for some features for long CAN frame output
general cleanups and buffer overflow safety measures
pull/506/head
commit
6d47f5c22b
46
asc2log.c
46
asc2log.c
|
|
@ -62,7 +62,7 @@
|
||||||
|
|
||||||
extern int optind, opterr, optopt;
|
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, "%s - convert ASC logfile to compact CAN frame logfile.\n", prg);
|
||||||
fprintf(stderr, "Usage: %s\n", prg);
|
fprintf(stderr, "Usage: %s\n", prg);
|
||||||
|
|
@ -71,7 +71,10 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, "\t-O <outfile>\t(default stdout)\n");
|
fprintf(stderr, "\t-O <outfile>\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);
|
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
|
else
|
||||||
fprintf(file, "canX ");
|
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') {
|
if (idstring[strlen(idstring)-1] == 'x') {
|
||||||
cf->can_id = CAN_EFF_FLAG;
|
cf->can_id = CAN_EFF_FLAG;
|
||||||
idstring[strlen(idstring)-1] = 0;
|
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);
|
cf->can_id |= strtoul(idstring, NULL, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
static void calc_tv(struct timeval *tv, struct timeval *read_tv,
|
||||||
struct timeval *date_tv, char timestamps, int dplace) {
|
struct timeval *date_tv, char timestamps, int dplace)
|
||||||
|
{
|
||||||
if (dplace == 4) /* shift values having only 4 decimal places */
|
if (dplace == 4) /* shift values having only 4 decimal places */
|
||||||
read_tv->tv_usec *= 100; /* and need for 6 */
|
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;
|
int interface;
|
||||||
static struct timeval tv; /* current frame timestamp */
|
static struct timeval tv; /* current frame timestamp */
|
||||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
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 */
|
struct can_frame *ccf = (struct can_frame *)&cf; /* for len8_dlc */
|
||||||
char rtr;
|
char rtr;
|
||||||
int dlc = 0;
|
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"))) {
|
if (!strncmp(tmp1, "ErrorFrame", strlen("ErrorFrame"))) {
|
||||||
|
|
||||||
memset(&cf, 0, sizeof(cf));
|
|
||||||
/* do not know more than 'Error' */
|
/* do not know more than 'Error' */
|
||||||
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
cf.can_id = (CAN_ERR_FLAG | CAN_ERR_BUSERROR);
|
||||||
cf.len = CAN_ERR_DLC;
|
cf.len = CAN_ERR_DLC;
|
||||||
|
|
||||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
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);
|
fflush(outfile);
|
||||||
return;
|
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;
|
cf.data[i] = data[i] & 0xFFU;
|
||||||
|
|
||||||
calc_tv(&tv, &read_tv, date_tvp, timestamps, dplace);
|
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);
|
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;
|
int interface;
|
||||||
static struct timeval tv; /* current frame timestamp */
|
static struct timeval tv; /* current frame timestamp */
|
||||||
static struct timeval read_tv; /* frame timestamp from ASC file */
|
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
|
#define ASC_F_ESI 0x00004000
|
||||||
|
|
||||||
if (flags & ASC_F_FDF) {
|
if (flags & ASC_F_FDF) {
|
||||||
dlen = CANFD_MAX_DLEN;
|
cf.flags = CANFD_FDF;
|
||||||
if (flags & ASC_F_BRS)
|
if (flags & ASC_F_BRS)
|
||||||
cf.flags |= CANFD_BRS;
|
cf.flags |= CANFD_BRS;
|
||||||
if (flags & ASC_F_ESI)
|
if (flags & ASC_F_ESI)
|
||||||
cf.flags |= CANFD_ESI;
|
cf.flags |= CANFD_ESI;
|
||||||
} else {
|
} else {
|
||||||
/* yes. The 'CANFD' format supports classic CAN content! */
|
/* yes. The 'CANFD' format supports classic CAN content! */
|
||||||
dlen = CAN_MAX_DLEN;
|
|
||||||
if (flags & ASC_F_RTR) {
|
if (flags & ASC_F_RTR) {
|
||||||
cf.can_id |= CAN_RTR_FLAG;
|
cf.can_id |= CAN_RTR_FLAG;
|
||||||
/* dlen is always 0 for classic CAN RTR frames
|
/* 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);
|
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);
|
fflush(outfile);
|
||||||
|
|
||||||
/* No support for really strange CANFD ErrorFrames format m( */
|
/* 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;
|
struct tm tms;
|
||||||
unsigned int msecs = 0;
|
unsigned int msecs = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ static unsigned char bargraph;
|
||||||
static enum cfl_mode mode = CFL_WORSTCASE;
|
static enum cfl_mode mode = CFL_WORSTCASE;
|
||||||
static char *prg;
|
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, "%s - monitor CAN bus load.\n", prg);
|
||||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||||
|
|
@ -124,13 +124,13 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sigterm(int signo)
|
static void sigterm(int signo)
|
||||||
{
|
{
|
||||||
running = 0;
|
running = 0;
|
||||||
signal_num = signo;
|
signal_num = signo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printstats(int signo)
|
static void printstats(int signo)
|
||||||
{
|
{
|
||||||
int i, j, percent;
|
int i, j, percent;
|
||||||
|
|
||||||
|
|
|
||||||
143
candump.c
143
candump.c
|
|
@ -109,7 +109,7 @@ static char *progname;
|
||||||
static char devname[MAXIFNAMES][IFNAMSIZ + 1];
|
static char devname[MAXIFNAMES][IFNAMSIZ + 1];
|
||||||
static int dindex[MAXIFNAMES];
|
static int dindex[MAXIFNAMES];
|
||||||
static int max_devname_len; /* to prevent frazzled device name output */
|
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
|
#define MAXANI 4
|
||||||
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
|
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
|
||||||
|
|
@ -220,12 +220,16 @@ static int idx2dindex(int ifidx, int socket)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
|
static int sprint_timestamp(char *ts_buffer, const char timestamp,
|
||||||
struct timeval *const last_tv, char *ts_buffer)
|
const struct timeval *tv, struct timeval *const last_tv)
|
||||||
{
|
{
|
||||||
|
int numchars = 0;
|
||||||
|
|
||||||
switch (timestamp) {
|
switch (timestamp) {
|
||||||
case 'a': /* absolute with 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;
|
break;
|
||||||
|
|
||||||
case 'A': /* absolute with date */
|
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);
|
tm = *localtime(&tv->tv_sec);
|
||||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
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;
|
break;
|
||||||
|
|
||||||
|
|
@ -252,7 +257,9 @@ static inline void sprint_timestamp(const char timestamp, const struct timeval *
|
||||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||||
if (diff.tv_sec < 0)
|
if (diff.tv_sec < 0)
|
||||||
diff.tv_sec = diff.tv_usec = 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')
|
if (timestamp == 'd')
|
||||||
*last_tv = *tv; /* update for delta calculation */
|
*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 */
|
default: /* no timestamp output */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (numchars <= 0) {
|
||||||
|
ts_buffer[0] = 0; /* empty terminated string */
|
||||||
|
numchars = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
|
return numchars;
|
||||||
struct timeval *const last_tv)
|
|
||||||
{
|
|
||||||
static char buffer[TIMESTAMPSZ];
|
|
||||||
|
|
||||||
sprint_timestamp(timestamp, tv, last_tv, buffer);
|
|
||||||
printf("%s", buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
|
@ -301,6 +306,11 @@ int main(int argc, char **argv)
|
||||||
struct sockaddr_can addr = {
|
struct sockaddr_can addr = {
|
||||||
.can_family = AF_CAN,
|
.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)) +
|
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) +
|
||||||
CMSG_SPACE(3 * sizeof(struct timespec)) +
|
CMSG_SPACE(3 * sizeof(struct timespec)) +
|
||||||
CMSG_SPACE(sizeof(__u32))];
|
CMSG_SPACE(sizeof(__u32))];
|
||||||
|
|
@ -309,14 +319,16 @@ int main(int argc, char **argv)
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
struct can_filter *rfilter;
|
struct can_filter *rfilter;
|
||||||
can_err_mask_t err_mask;
|
can_err_mask_t err_mask;
|
||||||
struct canfd_frame frame;
|
static cu_t cu; /* union for CAN CC/FD/XL frames */
|
||||||
int nbytes, i, maxdlen;
|
int nbytes, i;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct timeval tv, last_tv;
|
struct timeval tv, last_tv;
|
||||||
int timeout_ms = -1; /* default to no timeout */
|
int timeout_ms = -1; /* default to no timeout */
|
||||||
FILE *logfile = NULL;
|
FILE *logfile = NULL;
|
||||||
char fname[83]; /* suggested by -Wformat-overflow= */
|
char fname[83]; /* suggested by -Wformat-overflow= */
|
||||||
const char *logname = NULL;
|
const char *logname = NULL;
|
||||||
|
static char afrbuf[AFRSZ]; /* ASCII CAN frame buffer size */
|
||||||
|
static int alen;
|
||||||
|
|
||||||
signal(SIGTERM, sigterm);
|
signal(SIGTERM, sigterm);
|
||||||
signal(SIGHUP, sigterm);
|
signal(SIGHUP, sigterm);
|
||||||
|
|
@ -589,7 +601,13 @@ int main(int argc, char **argv)
|
||||||
} /* if (nptr) */
|
} /* if (nptr) */
|
||||||
|
|
||||||
/* try to switch the socket into CAN FD mode */
|
/* 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) {
|
if (rcvbuf_size) {
|
||||||
int curr_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 */
|
/* 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_name = &addr;
|
||||||
msg.msg_iov = &iov;
|
msg.msg_iov = &iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
@ -719,7 +737,7 @@ int main(int argc, char **argv)
|
||||||
char *extra_info = "";
|
char *extra_info = "";
|
||||||
|
|
||||||
/* these settings may be modified by recvmsg() */
|
/* these settings may be modified by recvmsg() */
|
||||||
iov.iov_len = sizeof(frame);
|
iov.iov_len = sizeof(cu);
|
||||||
msg.msg_namelen = sizeof(addr);
|
msg.msg_namelen = sizeof(addr);
|
||||||
msg.msg_controllen = sizeof(ctrlmsg);
|
msg.msg_controllen = sizeof(ctrlmsg);
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
|
|
@ -736,15 +754,29 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((size_t)nbytes == CAN_MTU)
|
/* mark dual-use struct canfd_frame */
|
||||||
maxdlen = CAN_MAX_DLEN;
|
if (nbytes < CANXL_HDR_SIZE + CANXL_MIN_DLEN) {
|
||||||
else if ((size_t)nbytes == CANFD_MTU)
|
fprintf(stderr, "read: no CAN frame\n");
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
|
||||||
return 1;
|
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))
|
if (count && (--count == 0))
|
||||||
running = 0;
|
running = 0;
|
||||||
|
|
||||||
|
|
@ -786,7 +818,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* once we detected a EFF frame indent SFF frames accordingly */
|
/* 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;
|
view |= CANLIB_VIEW_INDENT_SFF;
|
||||||
|
|
||||||
if (extra_msg_info) {
|
if (extra_msg_info) {
|
||||||
|
|
@ -796,32 +828,29 @@ int main(int argc, char **argv)
|
||||||
extra_info = " R";
|
extra_info = " R";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log) {
|
/* build common log format output */
|
||||||
char buf[CL_CFSZ]; /* max length */
|
if ((log) || ((logfrmt) && (silent == SILENT_OFF))) {
|
||||||
char ts_buf[TIMESTAMPSZ];
|
|
||||||
|
|
||||||
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
|
alen = sprint_timestamp(afrbuf, logtimestamp,
|
||||||
|
&tv, &last_tv);
|
||||||
|
|
||||||
/* log CAN frame with absolute timestamp & device */
|
alen += sprintf(afrbuf + alen, "%*s ",
|
||||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
max_devname_len, devname[idx]);
|
||||||
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
|
|
||||||
max_devname_len, devname[idx], buf,
|
alen += snprintf_canframe(afrbuf + alen, sizeof(afrbuf) - alen, &cu, 0);
|
||||||
extra_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((logfrmt) && (silent == SILENT_OFF)) {
|
/* write CAN frame in log file style to logfile */
|
||||||
char buf[CL_CFSZ]; /* max length */
|
if (log)
|
||||||
|
fprintf(logfile, "%s%s\n", afrbuf, extra_info);
|
||||||
|
|
||||||
/* print CAN frame in log file style to stdout */
|
/* print CAN frame in log file style to stdout */
|
||||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
if ((logfrmt) && (silent == SILENT_OFF)) {
|
||||||
print_timestamp(logtimestamp, &tv, &last_tv);
|
printf("%s%s\n", afrbuf, extra_info);
|
||||||
|
|
||||||
printf("%*s %s%s\n",
|
|
||||||
max_devname_len, devname[idx], buf,
|
|
||||||
extra_info);
|
|
||||||
goto out_fflush; /* no other output to stdout */
|
goto out_fflush; /* no other output to stdout */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* print only animation */
|
||||||
if (silent != SILENT_OFF) {
|
if (silent != SILENT_OFF) {
|
||||||
if (silent == SILENT_ANI) {
|
if (silent == SILENT_ANI) {
|
||||||
printf("%c\b", anichar[silentani %= MAXANI]);
|
printf("%c\b", anichar[silentani %= MAXANI]);
|
||||||
|
|
@ -830,25 +859,33 @@ int main(int argc, char **argv)
|
||||||
goto out_fflush; /* no other output to stdout */
|
goto out_fflush; /* no other output to stdout */
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
/* print (colored) long CAN frame style to stdout */
|
||||||
print_timestamp(timestamp, &tv, &last_tv);
|
alen = sprintf(afrbuf, " %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
||||||
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
|
alen += sprint_timestamp(afrbuf + alen, timestamp, &tv, &last_tv);
|
||||||
printf("%*s", max_devname_len, devname[idx]);
|
alen += sprintf(afrbuf + alen, " %s%*s",
|
||||||
|
(color && (color < 3)) ? col_on[idx % MAXCOL] : "",
|
||||||
|
max_devname_len, devname[idx]);
|
||||||
|
|
||||||
if (extra_msg_info) {
|
if (extra_msg_info) {
|
||||||
if (msg.msg_flags & MSG_DONTROUTE)
|
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
|
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);
|
if ((view & CANLIB_VIEW_ERROR) && (cu.fd.can_id & CAN_ERR_FLAG)) {
|
||||||
|
alen += sprintf(afrbuf + alen, "\n\t");
|
||||||
printf("%s", (color > 1) ? col_off : "");
|
alen += snprintf_can_error_frame(afrbuf + alen,
|
||||||
printf("\n");
|
sizeof(afrbuf) - alen,
|
||||||
|
&cu.fd, "\n\t");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s%s\n", afrbuf, (color > 1) ? col_off : "");
|
||||||
out_fflush:
|
out_fflush:
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
333
cangen.c
333
cangen.c
|
|
@ -177,12 +177,17 @@ static void print_usage(char *prg)
|
||||||
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
||||||
fprintf(stderr, " -b (generate CAN FD CAN frames with bitrate switch (BRS))\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, " -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, " -R (generate RTR frames)\n");
|
||||||
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN 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 <mode> (CAN ID generation mode - see below)\n");
|
fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\n");
|
||||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
||||||
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
||||||
|
fprintf(stderr, " -F <mode> (CAN XL Flags generation mode - see below, no e/o mode)\n");
|
||||||
|
fprintf(stderr, " -S <mode> (CAN XL SDT generation mode - see below, no e/o mode)\n");
|
||||||
|
fprintf(stderr, " -A <mode> (CAN XL AF generation mode - see below, no e/o mode)\n");
|
||||||
|
fprintf(stderr, " -V <mode> (CAN XL VCID generation mode - see below, no e/o mode)\n");
|
||||||
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
|
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
|
||||||
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
|
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
|
||||||
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
|
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
|
||||||
|
|
@ -293,12 +298,11 @@ static int setsockopt_txtime(int fd)
|
||||||
return 0;
|
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 };
|
uint8_t control[CMSG_SPACE(sizeof(uint64_t))] = { 0 };
|
||||||
struct iovec iov = {
|
struct iovec iov = {
|
||||||
.iov_base = buf,
|
.iov_base = cu,
|
||||||
.iov_len = len,
|
|
||||||
};
|
};
|
||||||
struct msghdr msg = {
|
struct msghdr msg = {
|
||||||
.msg_iov = &iov,
|
.msg_iov = &iov,
|
||||||
|
|
@ -307,6 +311,12 @@ static int do_send_one(int fd, void *buf, size_t len, int timeout)
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
int ret;
|
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) {
|
if (use_so_txtime) {
|
||||||
struct cmsghdr *cm;
|
struct cmsghdr *cm;
|
||||||
uint64_t tdeliver;
|
uint64_t tdeliver;
|
||||||
|
|
@ -443,20 +453,31 @@ int main(int argc, char **argv)
|
||||||
unsigned long polltimeout = 0;
|
unsigned long polltimeout = 0;
|
||||||
unsigned char extended = 0;
|
unsigned char extended = 0;
|
||||||
unsigned char canfd = 0;
|
unsigned char canfd = 0;
|
||||||
|
unsigned char canxl = 0;
|
||||||
unsigned char brs = 0;
|
unsigned char brs = 0;
|
||||||
unsigned char esi = 0;
|
unsigned char esi = 0;
|
||||||
unsigned char mix = 0;
|
unsigned char mix = 0;
|
||||||
unsigned char id_mode = MODE_RANDOM;
|
unsigned char id_mode = MODE_RANDOM;
|
||||||
unsigned char data_mode = MODE_RANDOM;
|
unsigned char data_mode = MODE_RANDOM;
|
||||||
unsigned char dlc_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 loopback_disable = 0;
|
||||||
unsigned char verbose = 0;
|
unsigned char verbose = 0;
|
||||||
unsigned char rtr_frame = 0;
|
unsigned char rtr_frame = 0;
|
||||||
unsigned char len8_dlc = 0;
|
unsigned char len8_dlc = 0;
|
||||||
|
unsigned char view = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
unsigned long burst_sent_count = 0;
|
unsigned long burst_sent_count = 0;
|
||||||
int mtu, maxdlen;
|
int mtu, maxdlen;
|
||||||
uint64_t incdata = 0;
|
uint64_t incdata = 0;
|
||||||
|
__u8 *data; /* base pointer for CC/FD or XL data */
|
||||||
int incdlc = 0;
|
int incdlc = 0;
|
||||||
unsigned long rnd;
|
unsigned long rnd;
|
||||||
unsigned char fixdata[CANFD_MAX_DLEN];
|
unsigned char fixdata[CANFD_MAX_DLEN];
|
||||||
|
|
@ -466,10 +487,13 @@ int main(int argc, char **argv)
|
||||||
int s; /* socket */
|
int s; /* socket */
|
||||||
|
|
||||||
struct sockaddr_can addr = { 0 };
|
struct sockaddr_can addr = { 0 };
|
||||||
static struct canfd_frame frame;
|
struct can_raw_vcid_options vcid_opts = {
|
||||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
.flags = CAN_RAW_XL_VCID_TX_PASS,
|
||||||
|
};
|
||||||
|
static cu_t cu;
|
||||||
int i;
|
int i;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr = { 0 };
|
||||||
|
const int enable_canfx = 1;
|
||||||
|
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -488,7 +512,7 @@ int main(int argc, char **argv)
|
||||||
{ 0, 0, 0, 0 },
|
{ 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) {
|
switch (opt) {
|
||||||
case 'g':
|
case 'g':
|
||||||
gap = strtod(optarg, NULL);
|
gap = strtod(optarg, NULL);
|
||||||
|
|
@ -516,6 +540,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
extended = 1;
|
extended = 1;
|
||||||
|
view |= CANLIB_VIEW_INDENT_SFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
@ -532,17 +557,23 @@ int main(int argc, char **argv)
|
||||||
canfd = 1;
|
canfd = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'X':
|
||||||
|
canxl = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'R':
|
case 'R':
|
||||||
rtr_frame = 1;
|
rtr_frame = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '8':
|
case '8':
|
||||||
len8_dlc = 1;
|
len8_dlc = 1;
|
||||||
|
view |= CANLIB_VIEW_LEN8_DLC;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
mix = 1;
|
mix = 1;
|
||||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||||
|
view |= CANLIB_VIEW_INDENT_SFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
|
|
@ -556,7 +587,7 @@ int main(int argc, char **argv)
|
||||||
id_mode = MODE_RANDOM_ODD;
|
id_mode = MODE_RANDOM_ODD;
|
||||||
} else {
|
} else {
|
||||||
id_mode = MODE_FIX;
|
id_mode = MODE_FIX;
|
||||||
frame.can_id = strtoul(optarg, NULL, 16);
|
cu.fd.can_id = strtoul(optarg, NULL, 16);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -567,7 +598,7 @@ int main(int argc, char **argv)
|
||||||
dlc_mode = MODE_INCREMENT;
|
dlc_mode = MODE_INCREMENT;
|
||||||
} else {
|
} else {
|
||||||
dlc_mode = MODE_FIX;
|
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;
|
break;
|
||||||
|
|
||||||
|
|
@ -586,6 +617,59 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 'p':
|
||||||
polltimeout = strtoul(optarg, NULL, 10);
|
polltimeout = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
@ -627,10 +711,13 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (verbose > 2)
|
||||||
|
view |= CANLIB_VIEW_ASCII;
|
||||||
|
|
||||||
ts_gap = double_to_timespec(gap / 1000);
|
ts_gap = double_to_timespec(gap / 1000);
|
||||||
|
|
||||||
/* recognize obviously missing commandline option */
|
/* 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");
|
printf("The given CAN-ID is greater than 0x7FF and the '-e' option is not set.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -670,8 +757,7 @@ int main(int argc, char **argv)
|
||||||
&loopback, sizeof(loopback));
|
&loopback, sizeof(loopback));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canfd) {
|
if (canfd || canxl) {
|
||||||
const int enable_canfd = 1;
|
|
||||||
|
|
||||||
/* check if the frame fits into the CAN netdevice */
|
/* check if the frame fits into the CAN netdevice */
|
||||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||||
|
|
@ -679,31 +765,61 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifr.ifr_mtu != CANFD_MTU && ifr.ifr_mtu != CANXL_MTU) {
|
if (canfd) {
|
||||||
printf("CAN interface is only Classical CAN capable - sorry.\n");
|
/* 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canfd && (ifr.ifr_mtu < CANFD_MTU)) {
|
||||||
|
printf("CAN interface not CAN FD capable - sorry.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifr.ifr_mtu == CANFD_MTU) {
|
||||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
/* 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))) {
|
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||||
|
&enable_canfx, sizeof(enable_canfx))){
|
||||||
printf("error when enabling CAN FD support\n");
|
printf("error when enabling CAN FD support\n");
|
||||||
return 1;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
|
||||||
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
|
|
||||||
} else {
|
} else {
|
||||||
/* sanitize Classical CAN 2.0 frame length */
|
/* sanitize Classical CAN 2.0 frame length */
|
||||||
if (len8_dlc) {
|
if (len8_dlc) {
|
||||||
if (frame.len > CAN_MAX_RAW_DLC)
|
if (cu.cc.len > CAN_MAX_RAW_DLC)
|
||||||
frame.len = CAN_MAX_RAW_DLC;
|
cu.cc.len = CAN_MAX_RAW_DLC;
|
||||||
|
|
||||||
if (frame.len > CAN_MAX_DLEN)
|
if (cu.cc.len > CAN_MAX_DLEN)
|
||||||
ccf->len8_dlc = frame.len;
|
cu.cc.len8_dlc = cu.cc.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.len > CAN_MAX_DLEN)
|
if (cu.cc.len > CAN_MAX_DLEN)
|
||||||
frame.len = CAN_MAX_DLEN;
|
cu.cc.len = CAN_MAX_DLEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
|
@ -722,96 +838,107 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
frame.flags = 0;
|
cu.fd.flags = 0;
|
||||||
|
|
||||||
if (count && (--count == 0))
|
if (count && (--count == 0))
|
||||||
running = 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;
|
mtu = CANFD_MTU;
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
maxdlen = CANFD_MAX_DLEN;
|
||||||
|
data = cu.fd.data; /* fill CAN CC/FD data */
|
||||||
|
cu.fd.flags = CANFD_FDF;
|
||||||
if (brs)
|
if (brs)
|
||||||
frame.flags |= CANFD_BRS;
|
cu.fd.flags |= CANFD_BRS;
|
||||||
if (esi)
|
if (esi)
|
||||||
frame.flags |= CANFD_ESI;
|
cu.fd.flags |= CANFD_ESI;
|
||||||
} else {
|
} else {
|
||||||
mtu = CAN_MTU;
|
mtu = CAN_MTU;
|
||||||
maxdlen = CAN_MAX_DLEN;
|
maxdlen = CAN_MAX_DLEN;
|
||||||
|
data = cu.cc.data; /* fill CAN CC/FD data */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id_mode == MODE_RANDOM)
|
if (id_mode == MODE_RANDOM)
|
||||||
frame.can_id = random();
|
cu.fd.can_id = random();
|
||||||
else if (id_mode == MODE_RANDOM_EVEN)
|
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)
|
else if (id_mode == MODE_RANDOM_ODD)
|
||||||
frame.can_id = random() | 0x1;
|
cu.fd.can_id = random() | 0x1;
|
||||||
|
|
||||||
if (extended) {
|
if (extended) {
|
||||||
frame.can_id &= CAN_EFF_MASK;
|
cu.fd.can_id &= CAN_EFF_MASK;
|
||||||
frame.can_id |= CAN_EFF_FLAG;
|
cu.fd.can_id |= CAN_EFF_FLAG;
|
||||||
} else
|
} else {
|
||||||
frame.can_id &= CAN_SFF_MASK;
|
cu.fd.can_id &= CAN_SFF_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
if (rtr_frame && !canfd)
|
if (rtr_frame && !canfd && !canxl)
|
||||||
frame.can_id |= CAN_RTR_FLAG;
|
cu.fd.can_id |= CAN_RTR_FLAG;
|
||||||
|
|
||||||
if (dlc_mode == MODE_RANDOM) {
|
if (dlc_mode == MODE_RANDOM) {
|
||||||
if (canfd)
|
if (canxl)
|
||||||
frame.len = can_fd_dlc2len(random() & 0xF);
|
cu.fd.len = CANXL_MIN_DLEN + (random() & 0x3F);
|
||||||
|
else if (canfd)
|
||||||
|
cu.fd.len = can_fd_dlc2len(random() & 0xF);
|
||||||
else {
|
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? */
|
/* generate Classic CAN len8 DLCs? */
|
||||||
if (len8_dlc)
|
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 {
|
} else {
|
||||||
ccf->len8_dlc = 0;
|
cu.cc.len8_dlc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_mode == MODE_INCREMENT && !frame.len)
|
if (data_mode == MODE_INCREMENT && !cu.cc.len)
|
||||||
frame.len = 1; /* min dlc value for incr. data */
|
cu.cc.len = 1; /* min dlc value for incr. data */
|
||||||
|
|
||||||
if (data_mode == MODE_RANDOM) {
|
if (data_mode == MODE_RANDOM) {
|
||||||
rnd = random();
|
rnd = random();
|
||||||
memcpy(&frame.data[0], &rnd, 4);
|
memcpy(&data[0], &rnd, 4);
|
||||||
rnd = random();
|
rnd = random();
|
||||||
memcpy(&frame.data[4], &rnd, 4);
|
memcpy(&data[4], &rnd, 4);
|
||||||
|
|
||||||
/* omit extra random number generation for CAN FD */
|
/* omit extra random number generation for CAN FD */
|
||||||
if (canfd && frame.len > 8) {
|
if ((canfd || canxl) && cu.fd.len > 8) {
|
||||||
memcpy(&frame.data[8], &frame.data[0], 8);
|
memcpy(&data[8], &data[0], 8);
|
||||||
memcpy(&frame.data[16], &frame.data[0], 16);
|
memcpy(&data[16], &data[0], 16);
|
||||||
memcpy(&frame.data[32], &frame.data[0], 32);
|
memcpy(&data[32], &data[0], 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_mode == MODE_RANDOM_FIX) {
|
if (data_mode == MODE_RANDOM_FIX) {
|
||||||
int i;
|
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)) {
|
if (rand_position[i] == (NIBBLE_H | NIBBLE_L)) {
|
||||||
frame.data[i] = random();
|
data[i] = random();
|
||||||
} else if (rand_position[i] == NIBBLE_H) {
|
} 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) {
|
} 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)
|
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 */
|
/* set unused payload data to zero like the CAN driver does it on rx */
|
||||||
if (frame.len < maxdlen)
|
if (cu.fd.len < maxdlen)
|
||||||
memset(&frame.data[frame.len], 0, maxdlen - frame.len);
|
memset(&data[cu.fd.len], 0, maxdlen - cu.fd.len);
|
||||||
|
|
||||||
if (!use_so_txtime &&
|
if (!use_so_txtime &&
|
||||||
(ts.tv_sec || ts.tv_nsec) &&
|
(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) {
|
if (verbose) {
|
||||||
|
static char afrbuf[AFRSZ]; /* ASCII CAN frame buffer size */
|
||||||
|
|
||||||
printf(" %s ", argv[optind]);
|
printf(" %s ", argv[optind]);
|
||||||
|
|
||||||
if (verbose > 1)
|
if (verbose > 1)
|
||||||
fprint_long_canframe(stdout, &frame, "\n", (verbose > 2) ? 1 : 0, maxdlen);
|
snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, view);
|
||||||
else
|
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)
|
if (ret)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -843,26 +1024,30 @@ int main(int argc, char **argv)
|
||||||
burst_sent_count = 0;
|
burst_sent_count = 0;
|
||||||
burst_sent_count++;
|
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)
|
if (id_mode == MODE_INCREMENT)
|
||||||
frame.can_id++;
|
cu.cc.can_id++;
|
||||||
|
|
||||||
if (dlc_mode == MODE_INCREMENT) {
|
if (dlc_mode == MODE_INCREMENT) {
|
||||||
incdlc++;
|
incdlc++;
|
||||||
incdlc %= CAN_MAX_RAW_DLC + 1;
|
incdlc %= CAN_MAX_RAW_DLC + 1;
|
||||||
|
|
||||||
if (canfd && !mix)
|
if ((canfd || canxl) && !mix)
|
||||||
frame.len = can_fd_dlc2len(incdlc);
|
cu.fd.len = can_fd_dlc2len(incdlc);
|
||||||
else if (len8_dlc) {
|
else if (len8_dlc) {
|
||||||
if (incdlc > CAN_MAX_DLEN) {
|
if (incdlc > CAN_MAX_DLEN) {
|
||||||
frame.len = CAN_MAX_DLEN;
|
cu.cc.len = CAN_MAX_DLEN;
|
||||||
ccf->len8_dlc = incdlc;
|
cu.cc.len8_dlc = incdlc;
|
||||||
} else {
|
} else {
|
||||||
frame.len = incdlc;
|
cu.cc.len = incdlc;
|
||||||
ccf->len8_dlc = 0;
|
cu.cc.len8_dlc = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
incdlc %= CAN_MAX_DLEN + 1;
|
incdlc %= CAN_MAX_DLEN + 1;
|
||||||
frame.len = incdlc;
|
cu.fd.len = incdlc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -870,7 +1055,7 @@ int main(int argc, char **argv)
|
||||||
incdata++;
|
incdata++;
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
frame.data[i] = incdata >> i * 8;
|
data[i] = incdata >> i * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mix) {
|
if (mix) {
|
||||||
|
|
@ -881,6 +1066,10 @@ int main(int argc, char **argv)
|
||||||
brs = i & 4;
|
brs = i & 4;
|
||||||
esi = i & 8;
|
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 */
|
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
cangw.c
28
cangw.c
|
|
@ -82,8 +82,8 @@ struct fdmodattr {
|
||||||
#define NLMSG_TAIL(nmsg) \
|
#define NLMSG_TAIL(nmsg) \
|
||||||
((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
((struct rtattr *)(((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
|
||||||
|
|
||||||
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
static int addattr_l(struct nlmsghdr *n, int maxlen, int type,
|
||||||
int alen)
|
const void *data, int alen)
|
||||||
{
|
{
|
||||||
int len = RTA_LENGTH(alen);
|
int len = RTA_LENGTH(alen);
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
|
|
@ -101,7 +101,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printfilter(const void *data)
|
static void printfilter(const void *data)
|
||||||
{
|
{
|
||||||
struct can_filter *filter = (struct can_filter *)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);
|
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;
|
struct modattr mod;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -137,7 +137,7 @@ void printmod(const char *type, const void *data)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printfdmod(const char *type, const void *data)
|
static void printfdmod(const char *type, const void *data)
|
||||||
{
|
{
|
||||||
struct fdmodattr mod;
|
struct fdmodattr mod;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -166,14 +166,14 @@ void printfdmod(const char *type, const void *data)
|
||||||
printf(" ");
|
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 ",
|
printf("-x %d:%d:%d:%02X ",
|
||||||
cs_xor->from_idx, cs_xor->to_idx,
|
cs_xor->from_idx, cs_xor->to_idx,
|
||||||
cs_xor->result_idx, cs_xor->init_xor_val);
|
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;
|
int i;
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ void print_cs_crc8_profile(struct cgw_csum_crc8 *cs_crc8)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
|
static void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -220,7 +220,7 @@ void print_cs_crc8(struct cgw_csum_crc8 *cs_crc8)
|
||||||
print_cs_crc8_profile(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, "%s - manage PF_CAN netlink gateway.\n", prg);
|
||||||
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
|
fprintf(stderr, "\nUsage: %s [options]\n\n", prg);
|
||||||
|
|
@ -279,7 +279,7 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int b64hex(char *asc, unsigned char *bin, int len)
|
static int b64hex(char *asc, unsigned char *bin, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -290,7 +290,7 @@ int b64hex(char *asc, unsigned char *bin, int len)
|
||||||
return 0;
|
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;
|
int ret = 1;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
@ -329,7 +329,7 @@ int parse_crc8_profile(char *optarg, struct cgw_csum_crc8 *crc8)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_mod(char *optarg, struct modattr *modmsg)
|
static int parse_mod(char *optarg, struct modattr *modmsg)
|
||||||
{
|
{
|
||||||
char *ptr, *nptr;
|
char *ptr, *nptr;
|
||||||
char hexdata[(CAN_MAX_DLEN * 2) + 1] = {0};
|
char hexdata[(CAN_MAX_DLEN * 2) + 1] = {0};
|
||||||
|
|
@ -397,7 +397,7 @@ int parse_mod(char *optarg, struct modattr *modmsg)
|
||||||
return 0; /* ok */
|
return 0; /* ok */
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
|
static int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
|
||||||
{
|
{
|
||||||
char *ptr, *nptr;
|
char *ptr, *nptr;
|
||||||
char hexdata[(CANFD_MAX_DLEN * 2) + 1] = {0};
|
char hexdata[(CANFD_MAX_DLEN * 2) + 1] = {0};
|
||||||
|
|
@ -470,7 +470,7 @@ int parse_fdmod(char *optarg, struct fdmodattr *modmsg)
|
||||||
return 0; /* ok */
|
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() */
|
char ifname[IF_NAMESIZE]; /* interface name for if_indextoname() */
|
||||||
struct rtcanmsg *rtc;
|
struct rtcanmsg *rtc;
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,6 @@
|
||||||
#define ANYDEV "any"
|
#define ANYDEV "any"
|
||||||
#define ANL "\r\n" /* newline in ASC mode */
|
#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
|
#define DEFPORT 28700
|
||||||
|
|
||||||
static char devname[MAXDEV][IFNAMSIZ+1];
|
static char devname[MAXDEV][IFNAMSIZ+1];
|
||||||
|
|
@ -86,7 +83,7 @@ extern int optind, opterr, optopt;
|
||||||
static volatile int running = 1;
|
static volatile int running = 1;
|
||||||
static volatile sig_atomic_t signal_num;
|
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, "%s - log CAN frames and serves them.\n", prg);
|
||||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||||
|
|
@ -110,7 +107,7 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx2dindex(int ifidx, int socket)
|
static int idx2dindex(int ifidx, int socket)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct ifreq ifr;
|
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
|
* This is a Signalhandler. When we get a signal, that a child
|
||||||
* terminated, we wait for it, so the zombie will disappear.
|
* terminated, we wait for it, so the zombie will disappear.
|
||||||
*/
|
*/
|
||||||
void childdied(int i)
|
static void childdied(int i)
|
||||||
{
|
{
|
||||||
wait(NULL);
|
wait(NULL);
|
||||||
}
|
}
|
||||||
|
|
@ -168,13 +165,12 @@ void childdied(int i)
|
||||||
/*
|
/*
|
||||||
* This is a Signalhandler for a caught SIGTERM
|
* This is a Signalhandler for a caught SIGTERM
|
||||||
*/
|
*/
|
||||||
void shutdown_gra(int i)
|
static void shutdown_gra(int i)
|
||||||
{
|
{
|
||||||
running = 0;
|
running = 0;
|
||||||
signal_num = i;
|
signal_num = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct sigaction signalaction;
|
struct sigaction signalaction;
|
||||||
|
|
@ -189,17 +185,22 @@ int main(int argc, char **argv)
|
||||||
int opt, ret;
|
int opt, ret;
|
||||||
int currmax = 1; /* we assume at least one can bus ;-) */
|
int currmax = 1; /* we assume at least one can bus ;-) */
|
||||||
struct sockaddr_can addr;
|
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 can_filter rfilter;
|
||||||
struct canfd_frame frame;
|
static cu_t cu; /* union for CAN CC/FD/XL frames */
|
||||||
const int canfd_on = 1;
|
const int canfx_on = 1;
|
||||||
int nbytes, i, j, maxdlen;
|
int nbytes, i, j;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int port = DEFPORT;
|
int port = DEFPORT;
|
||||||
struct sockaddr_in inaddr;
|
struct sockaddr_in inaddr;
|
||||||
struct sockaddr_in clientaddr;
|
struct sockaddr_in clientaddr;
|
||||||
socklen_t sin_size = sizeof(clientaddr);
|
socklen_t sin_size = sizeof(clientaddr);
|
||||||
char temp[BUFSZ];
|
static char afrbuf[AFRSZ];
|
||||||
|
|
||||||
sigemptyset(&sigset);
|
sigemptyset(&sigset);
|
||||||
signalaction.sa_handler = &childdied;
|
signalaction.sa_handler = &childdied;
|
||||||
|
|
@ -345,7 +346,13 @@ int main(int argc, char **argv)
|
||||||
&err_mask[i], sizeof(err_mask[i]));
|
&err_mask[i], sizeof(err_mask[i]));
|
||||||
|
|
||||||
/* try to switch the socket into CAN FD mode */
|
/* 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]);
|
j = strlen(argv[optind+i]);
|
||||||
|
|
||||||
|
|
@ -394,42 +401,54 @@ int main(int argc, char **argv)
|
||||||
socklen_t len = sizeof(addr);
|
socklen_t len = sizeof(addr);
|
||||||
int idx;
|
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) {
|
(struct sockaddr*)&addr, &len)) < 0) {
|
||||||
perror("read");
|
perror("read");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((size_t)nbytes == CAN_MTU)
|
if (nbytes < CANXL_HDR_SIZE + CANXL_MIN_DLEN) {
|
||||||
maxdlen = CAN_MAX_DLEN;
|
fprintf(stderr, "read: no CAN frame\n");
|
||||||
else if ((size_t)nbytes == CANFD_MTU)
|
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
|
||||||
return 1;
|
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)
|
if (ioctl(s[i], SIOCGSTAMP, &tv) < 0)
|
||||||
perror("SIOCGSTAMP");
|
perror("SIOCGSTAMP");
|
||||||
|
|
||||||
|
|
||||||
idx = idx2dindex(addr.can_ifindex, s[i]);
|
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]);
|
(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);
|
snprintf_canframe(afrbuf + strlen(afrbuf), sizeof(afrbuf) - strlen(afrbuf), &cu, 0);
|
||||||
strcat(temp, "\n");
|
strcat(afrbuf, "\n");
|
||||||
|
|
||||||
if (write(accsocket, temp, strlen(temp)) < 0) {
|
if (write(accsocket, afrbuf, strlen(afrbuf)) < 0) {
|
||||||
perror("writeaccsock");
|
perror("writeaccsock");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* print CAN frame in log file style to stdout */
|
/* print CAN frame in log file style to stdout */
|
||||||
printf("(%lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
printf("%s", afrbuf);
|
||||||
printf("%*s ", max_devname_len, devname[idx]);
|
|
||||||
fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
67
canplayer.c
67
canplayer.c
|
|
@ -61,21 +61,35 @@
|
||||||
#define DEFAULT_GAP 1 /* ms */
|
#define DEFAULT_GAP 1 /* ms */
|
||||||
#define DEFAULT_LOOPS 1 /* only one replay */
|
#define DEFAULT_LOOPS 1 /* only one replay */
|
||||||
#define CHANNELS 20 /* anyone using more than 20 CAN interfaces at a time? */
|
#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 */
|
#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 {
|
struct assignment {
|
||||||
char txif[IFNAMSIZ];
|
char txif[IFNAMSIZ];
|
||||||
int txifidx;
|
int txifidx;
|
||||||
char rxif[IFNAMSIZ];
|
char rxif[IFNAMSIZ];
|
||||||
};
|
};
|
||||||
static struct assignment asgn[CHANNELS];
|
static struct assignment asgn[CHANNELS];
|
||||||
const int canfd_on = 1;
|
const int canfx_on = 1;
|
||||||
|
|
||||||
extern int optind, opterr, optopt;
|
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, "%s - replay a compact CAN frame logfile to CAN devices.\n", prg);
|
||||||
fprintf(stderr, "\nUsage: %s <options> [interface assignment]*\n\n", prg);
|
fprintf(stderr, "\nUsage: %s <options> [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);
|
return timeval_compare(&cmp, today);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_txidx(char *logif_name)
|
static int get_txidx(char *logif_name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -175,7 +189,7 @@ int get_txidx(char *logif_name)
|
||||||
return asgn[i].txifidx; /* return interface index */
|
return asgn[i].txifidx; /* return interface index */
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_txname(char *logif_name)
|
static char *get_txname(char *logif_name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -192,7 +206,8 @@ char *get_txname(char *logif_name)
|
||||||
return asgn[i].txif; /* return interface 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;
|
struct ifreq ifr;
|
||||||
int i;
|
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)
|
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;
|
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;
|
static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
|
||||||
struct timespec sleep_ts;
|
struct timespec sleep_ts;
|
||||||
int s; /* CAN_RAW socket */
|
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);
|
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
||||||
|
|
||||||
/* try to switch the socket into CAN FD mode */
|
/* 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) {
|
if (loopback_disable) {
|
||||||
int loopback = 0;
|
int loopback = 0;
|
||||||
|
|
@ -417,7 +441,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
eof = 0;
|
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");
|
fprintf(stderr, "incorrect line format in logfile\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -446,7 +470,7 @@ int main(int argc, char **argv)
|
||||||
if (interactive)
|
if (interactive)
|
||||||
getchar();
|
getchar();
|
||||||
|
|
||||||
/* log_tv/device/ascframe are valid here */
|
/* log_tv/device/afrbuf are valid here */
|
||||||
|
|
||||||
if (strlen(device) >= IFNAMSIZ) {
|
if (strlen(device) >= IFNAMSIZ) {
|
||||||
fprintf(stderr, "log interface name '%s' too long!", device);
|
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 */
|
} 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) {
|
if (!txmtu) {
|
||||||
fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe);
|
fprintf(stderr, "wrong CAN frame format: '%s'!", afrbuf);
|
||||||
return 1;
|
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_family = AF_CAN;
|
||||||
addr.can_ifindex = txidx; /* send via this interface */
|
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");
|
perror("sendto");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("%s (%s) ", get_txname(device), device);
|
printf("%s (%s) ", get_txname(device), device);
|
||||||
|
snprintf_long_canframe(afrbuf, sizeof(afrbuf), &cu, CANLIB_VIEW_INDENT_SFF);
|
||||||
if (txmtu == CAN_MTU)
|
printf("%s\n", afrbuf);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count && (--count == 0))
|
if (count && (--count == 0))
|
||||||
|
|
@ -510,7 +535,7 @@ int main(int argc, char **argv)
|
||||||
break;
|
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");
|
fprintf(stderr, "incorrect line format in logfile\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
72
cansend.c
72
cansend.c
|
|
@ -64,11 +64,13 @@ static void print_usage(char *prg)
|
||||||
"Usage: %s <device> <can_frame>.\n"
|
"Usage: %s <device> <can_frame>.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"<can_frame>:\n"
|
"<can_frame>:\n"
|
||||||
" <can_id>#{data} for Classical CAN 2.0 data frames\n"
|
" <can_id>#{data} for CAN CC (Classical CAN 2.0B) data frames\n"
|
||||||
" <can_id>#R{len} for Classical CAN 2.0 data frames\n"
|
" <can_id>#R{len} for CAN CC (Classical CAN 2.0B) data frames\n"
|
||||||
" <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n"
|
" <can_id>#{data}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n"
|
||||||
" <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n"
|
" <can_id>#R{len}_{dlc} for CAN CC (Classical CAN 2.0B) data frames\n"
|
||||||
" <can_id>##<flags>{data} for CAN FD frames\n\n"
|
" <can_id>##<flags>{data} for CAN FD frames\n"
|
||||||
|
" <vcid><prio>#<flags>:<sdt>:<af>#<data> for CAN XL frames\n"
|
||||||
|
"\n"
|
||||||
"<can_id>:\n"
|
"<can_id>:\n"
|
||||||
" 3 (SFF) or 8 (EFF) hex chars\n"
|
" 3 (SFF) or 8 (EFF) hex chars\n"
|
||||||
"{data}:\n"
|
"{data}:\n"
|
||||||
|
|
@ -80,9 +82,23 @@ static void print_usage(char *prg)
|
||||||
"<flags>:\n"
|
"<flags>:\n"
|
||||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n"
|
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"<vcid>:\n"
|
||||||
|
" 2 hex chars - virtual CAN network identifier (00 .. FF)\n"
|
||||||
|
"<prio>:\n"
|
||||||
|
" 3 hex chars - 11 bit priority value (000 .. 7FF)\n"
|
||||||
|
"<flags>:\n"
|
||||||
|
" 2 hex chars values (00 .. FF) which defines canxl_frame.flags\n"
|
||||||
|
"<sdt>:\n"
|
||||||
|
" 2 hex chars values (00 .. FF) which defines canxl_frame.sdt\n"
|
||||||
|
"<af>:\n"
|
||||||
|
" 8 hex chars - 32 bit acceptance field (canxl_frame.af)\n"
|
||||||
|
"<data>:\n"
|
||||||
|
" 1..2048 ASCII hex-values (optionally separated by '.')\n"
|
||||||
|
"\n"
|
||||||
"Examples:\n"
|
"Examples:\n"
|
||||||
" 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\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",
|
"\n",
|
||||||
prg, prg);
|
prg, prg);
|
||||||
}
|
}
|
||||||
|
|
@ -92,9 +108,12 @@ int main(int argc, char **argv)
|
||||||
int s; /* can raw socket */
|
int s; /* can raw socket */
|
||||||
int required_mtu;
|
int required_mtu;
|
||||||
int mtu;
|
int mtu;
|
||||||
int enable_canfd = 1;
|
int enable_canfx = 1;
|
||||||
struct sockaddr_can addr;
|
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;
|
struct ifreq ifr;
|
||||||
|
|
||||||
/* check command line options */
|
/* check command line options */
|
||||||
|
|
@ -104,7 +123,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse CAN frame */
|
/* parse CAN frame */
|
||||||
required_mtu = parse_canframe(argv[2], &frame);
|
required_mtu = parse_canframe(argv[2], &cu);
|
||||||
if (!required_mtu) {
|
if (!required_mtu) {
|
||||||
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
|
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
|
|
@ -137,21 +156,38 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
mtu = ifr.ifr_mtu;
|
mtu = ifr.ifr_mtu;
|
||||||
|
|
||||||
if (mtu != CANFD_MTU && mtu != CANXL_MTU) {
|
if (mtu == CANFD_MTU) {
|
||||||
printf("CAN interface is only Classical CAN capable - sorry.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||||
&enable_canfd, sizeof(enable_canfd))){
|
&enable_canfx, sizeof(enable_canfx))){
|
||||||
printf("error when enabling CAN FD support\n");
|
printf("error when enabling CAN FD support\n");
|
||||||
return 1;
|
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 */
|
/* 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 (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
|
* disable default receive filter on this RAW socket This is
|
||||||
|
|
@ -167,7 +203,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send frame */
|
/* send frame */
|
||||||
if (write(s, &frame, required_mtu) != required_mtu) {
|
if (write(s, &cu, required_mtu) != required_mtu) {
|
||||||
perror("write");
|
perror("write");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
394
lib.c
394
lib.c
|
|
@ -55,6 +55,7 @@
|
||||||
|
|
||||||
#define CANID_DELIM '#'
|
#define CANID_DELIM '#'
|
||||||
#define CC_DLC_DELIM '_'
|
#define CC_DLC_DELIM '_'
|
||||||
|
#define XL_HDR_DELIM ':'
|
||||||
#define DATA_SEPERATOR '.'
|
#define DATA_SEPERATOR '.'
|
||||||
|
|
||||||
const char hex_asc_upper[] = "0123456789ABCDEF";
|
const char hex_asc_upper[] = "0123456789ABCDEF";
|
||||||
|
|
@ -153,77 +154,126 @@ int hexstring2data(char *arg, unsigned char *data, int maxdlen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_canframe(char *cs, struct canfd_frame *cf)
|
int parse_canframe(char *cs, cu_t *cu)
|
||||||
{
|
{
|
||||||
/* documentation see lib.h */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
int i, idx, dlen, len;
|
int i, idx, dlen, len;
|
||||||
int maxdlen = CAN_MAX_DLEN;
|
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;
|
canid_t tmp;
|
||||||
|
|
||||||
len = strlen(cs);
|
len = strlen(cs);
|
||||||
//printf("'%s' len %d\n", cs, len);
|
//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)
|
if (len < 4)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (cs[3] == CANID_DELIM) { /* 3 digits */
|
if (cs[3] == CANID_DELIM) { /* 3 digits SFF */
|
||||||
|
|
||||||
idx = 4;
|
idx = 4;
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||||
return 0;
|
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;
|
idx = 9;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||||
return 0;
|
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? */
|
if (!(cu->cc.can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
|
||||||
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
|
cu->cc.can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
|
||||||
|
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((cs[idx] == 'R') || (cs[idx] == 'r')) { /* RTR frame */
|
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 */
|
/* check for optional DLC value for CAN 2.0B frames */
|
||||||
if (cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
|
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 */
|
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||||
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||||
tmp = asc2nibble(cs[idx]);
|
tmp = asc2nibble(cs[idx]);
|
||||||
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
|
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC))
|
||||||
struct can_frame *ccf = (struct can_frame *)cf;
|
cu->cc.len8_dlc = tmp;
|
||||||
|
|
||||||
ccf->len8_dlc = tmp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return mtu;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
|
if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
|
||||||
|
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
maxdlen = CANFD_MAX_DLEN;
|
||||||
ret = CANFD_MTU;
|
mtu = CANFD_MTU;
|
||||||
|
|
||||||
/* CAN FD frame <canid>##<flags><data>* */
|
/* CAN FD frame <canid>##<flags><data>* */
|
||||||
if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F)
|
if ((tmp = asc2nibble(cs[idx + 1])) > 0x0F)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cf->flags = tmp;
|
cu->fd.flags = tmp;
|
||||||
|
cu->fd.flags |= CANFD_FDF; /* dual-use */
|
||||||
idx += 2;
|
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++) {
|
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)
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
||||||
return 0;
|
return 0;
|
||||||
cf->data[i] = (tmp << 4);
|
data[i] = tmp << 4;
|
||||||
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
||||||
return 0;
|
return 0;
|
||||||
cf->data[i] |= tmp;
|
data[i] |= tmp;
|
||||||
dlen++;
|
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 */
|
/* 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)) {
|
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||||
unsigned char dlc = asc2nibble(cs[idx]);
|
unsigned char dlc = asc2nibble(cs[idx]);
|
||||||
|
|
||||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC))
|
||||||
struct can_frame *ccf = (struct can_frame *)cf;
|
cu->cc.len8_dlc = dlc;
|
||||||
|
|
||||||
ccf->len8_dlc = dlc;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fprint_canframe(FILE *stream, struct canfd_frame *cf, char *eol, int sep, int maxdlen)
|
int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep)
|
||||||
{
|
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
/* documentation see lib.h */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
|
unsigned char is_canfd = cu->fd.flags;
|
||||||
int i, offset;
|
int i, offset;
|
||||||
int len = (cf->len > maxdlen) ? maxdlen : cf->len;
|
int len;
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG) {
|
/* ensure space for string termination */
|
||||||
put_eff_id(buf, cf->can_id & (CAN_ERR_MASK | CAN_ERR_FLAG));
|
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] = '#';
|
buf[8] = '#';
|
||||||
offset = 9;
|
offset = 9;
|
||||||
} else if (cf->can_id & CAN_EFF_FLAG) {
|
} else if (cu->fd.can_id & CAN_EFF_FLAG) {
|
||||||
put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
|
put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK);
|
||||||
buf[8] = '#';
|
buf[8] = '#';
|
||||||
offset = 9;
|
offset = 9;
|
||||||
} else {
|
} else {
|
||||||
put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
|
put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK);
|
||||||
buf[3] = '#';
|
buf[3] = '#';
|
||||||
offset = 4;
|
offset = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
|
/* CAN CC frames may have RTR enabled. There are no ERR frames with RTR */
|
||||||
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
if (!is_canfd && cu->fd.can_id & CAN_RTR_FLAG) {
|
||||||
buf[offset++] = 'R';
|
buf[offset++] = 'R';
|
||||||
/* print a given CAN 2.0B DLC if it's not zero */
|
/* print a given CAN 2.0B DLC if it's not zero */
|
||||||
if (cf->len && cf->len <= CAN_MAX_DLEN) {
|
if (len && len <= CAN_MAX_DLEN) {
|
||||||
buf[offset++] = hex_asc_upper_lo(cf->len);
|
buf[offset++] = hex_asc_upper_lo(cu->fd.len);
|
||||||
|
|
||||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||||
if (cf->len == CAN_MAX_DLEN) {
|
if (len == CAN_MAX_DLEN) {
|
||||||
struct can_frame *ccf = (struct can_frame *)cf;
|
if ((cu->cc.len8_dlc > CAN_MAX_DLEN) && (cu->cc.len8_dlc <= CAN_MAX_RAW_DLC)) {
|
||||||
|
|
||||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
|
|
||||||
buf[offset++] = CC_DLC_DELIM;
|
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;
|
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 */
|
/* add CAN FD specific escape char and flags */
|
||||||
buf[offset++] = '#';
|
buf[offset++] = '#';
|
||||||
buf[offset++] = hex_asc_upper_lo(cf->flags);
|
buf[offset++] = hex_asc_upper_lo(cu->fd.flags);
|
||||||
if (sep && len)
|
if (sep && len)
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* data */
|
||||||
for (i = 0; i < len; i++) {
|
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;
|
offset += 2;
|
||||||
if (sep && (i + 1 < len))
|
if (sep && (i + 1 < len))
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||||
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
|
if (!is_canfd && (len == CAN_MAX_DLEN)) {
|
||||||
struct can_frame *ccf = (struct can_frame *)cf;
|
unsigned char dlc = cu->cc.len8_dlc;
|
||||||
unsigned char dlc = ccf->len8_dlc;
|
|
||||||
|
|
||||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||||
buf[offset++] = CC_DLC_DELIM;
|
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;
|
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 */
|
/* 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);
|
/* ensure space for string termination */
|
||||||
fprintf(stream, "%s", buf);
|
if (size < 1)
|
||||||
if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) {
|
return size;
|
||||||
snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
|
|
||||||
fprintf(stream, "\n\t%s", buf);
|
/* handle CAN XL frames */
|
||||||
}
|
if (cu->xl.flags & CANXL_XLF) {
|
||||||
if (eol)
|
len = cu->xl.len;
|
||||||
fprintf(stream, "%s", eol);
|
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdlen)
|
if (view & CANLIB_VIEW_INDENT_SFF) {
|
||||||
{
|
memset(buf, ' ', 5);
|
||||||
/* documentation see lib.h */
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int i, j, dlen, offset;
|
/* print prio and CAN XL header content */
|
||||||
int len = (cf->len > maxdlen) ? maxdlen : cf->len;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
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 */
|
/* initialize space for CAN-ID and length information */
|
||||||
memset(buf, ' ', 15);
|
memset(buf, ' ', 15);
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG) {
|
if (cu->cc.can_id & CAN_ERR_FLAG) {
|
||||||
put_eff_id(buf, cf->can_id & (CAN_ERR_MASK | CAN_ERR_FLAG));
|
put_eff_id(buf, cu->cc.can_id & (CAN_ERR_MASK | CAN_ERR_FLAG));
|
||||||
offset = 10;
|
offset = 10;
|
||||||
} else if (cf->can_id & CAN_EFF_FLAG) {
|
} else if (cu->fd.can_id & CAN_EFF_FLAG) {
|
||||||
put_eff_id(buf, cf->can_id & CAN_EFF_MASK);
|
put_eff_id(buf, cu->fd.can_id & CAN_EFF_MASK);
|
||||||
offset = 10;
|
offset = 10;
|
||||||
} else {
|
} else {
|
||||||
if (view & CANLIB_VIEW_INDENT_SFF) {
|
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;
|
offset = 10;
|
||||||
} else {
|
} else {
|
||||||
put_sff_id(buf, cf->can_id & CAN_SFF_MASK);
|
put_sff_id(buf, cu->fd.can_id & CAN_SFF_MASK);
|
||||||
offset = 5;
|
offset = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The len value is sanitized by maxdlen (see above) */
|
/* The len value is sanitized (see above) */
|
||||||
if (maxdlen == CAN_MAX_DLEN) {
|
if (!is_canfd) {
|
||||||
if (view & CANLIB_VIEW_LEN8_DLC) {
|
if (view & CANLIB_VIEW_LEN8_DLC) {
|
||||||
struct can_frame *ccf = (struct can_frame *)cf;
|
unsigned char dlc = cu->cc.len8_dlc;
|
||||||
unsigned char dlc = ccf->len8_dlc;
|
|
||||||
|
|
||||||
/* fall back to len if we don't have a valid DLC > 8 */
|
/* fall back to len if we don't have a valid DLC > 8 */
|
||||||
if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
|
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 */
|
/* standard CAN frames may have RTR enabled */
|
||||||
if (cf->can_id & CAN_RTR_FLAG) {
|
if (cu->fd.can_id & CAN_RTR_FLAG) {
|
||||||
sprintf(buf + offset + 5, " remote request");
|
offset += sprintf(buf + offset + 5, " remote request");
|
||||||
return;
|
return offset + 5;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buf[offset] = '[';
|
buf[offset] = '[';
|
||||||
|
|
@ -417,22 +581,22 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl
|
||||||
offset += 5;
|
offset += 5;
|
||||||
|
|
||||||
if (view & CANLIB_VIEW_BINARY) {
|
if (view & CANLIB_VIEW_BINARY) {
|
||||||
dlen = 9; /* _10101010 */
|
/* _10101010 - dlen = 9, see above */
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
for (i = len - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
buf[offset++] = (i == len - 1) ? ' ' : SWAP_DELIMITER;
|
buf[offset++] = (i == len - 1) ? ' ' : SWAP_DELIMITER;
|
||||||
for (j = 7; j >= 0; j--)
|
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 {
|
} else {
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
buf[offset++] = ' ';
|
buf[offset++] = ' ';
|
||||||
for (j = 7; j >= 0; j--)
|
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 {
|
} else {
|
||||||
dlen = 3; /* _AA */
|
/* _AA - dlen = 3, see above */
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
for (i = len - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
if (i == len - 1)
|
if (i == len - 1)
|
||||||
|
|
@ -440,13 +604,13 @@ void sprint_long_canframe(char *buf, struct canfd_frame *cf, int view, int maxdl
|
||||||
else
|
else
|
||||||
buf[offset++] = SWAP_DELIMITER;
|
buf[offset++] = SWAP_DELIMITER;
|
||||||
|
|
||||||
put_hex_byte(buf + offset, cf->data[i]);
|
put_hex_byte(buf + offset, cu->fd.data[i]);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
buf[offset++] = ' ';
|
buf[offset++] = ' ';
|
||||||
put_hex_byte(buf + offset, cf->data[i]);
|
put_hex_byte(buf + offset, cu->fd.data[i]);
|
||||||
offset += 2;
|
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?
|
* Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
|
||||||
*/
|
*/
|
||||||
if (len > CAN_MAX_DLEN)
|
if (len > CAN_MAX_DLEN)
|
||||||
return;
|
return offset;
|
||||||
|
|
||||||
if (cf->can_id & CAN_ERR_FLAG)
|
if (cu->fd.can_id & CAN_ERR_FLAG)
|
||||||
sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME");
|
offset += sprintf(buf + offset, "%*s", dlen * (8 - len) + 13, "ERRORFRAME");
|
||||||
else if (view & CANLIB_VIEW_ASCII) {
|
else if (view & CANLIB_VIEW_ASCII) {
|
||||||
j = dlen * (8 - len) + 4;
|
j = dlen * (8 - len) + 4;
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
sprintf(buf + offset, "%*s", j, "`");
|
sprintf(buf + offset, "%*s", j, "`");
|
||||||
offset += j;
|
offset += j;
|
||||||
for (i = len - 1; i >= 0; i--)
|
for (i = len - 1; i >= 0; i--)
|
||||||
if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
|
if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F))
|
||||||
buf[offset++] = cf->data[i];
|
buf[offset++] = cu->fd.data[i];
|
||||||
else
|
else
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
|
|
||||||
sprintf(buf + offset, "`");
|
offset += sprintf(buf + offset, "`");
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf + offset, "%*s", j, "'");
|
sprintf(buf + offset, "%*s", j, "'");
|
||||||
offset += j;
|
offset += j;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
|
if ((cu->fd.data[i] > 0x1F) && (cu->fd.data[i] < 0x7F))
|
||||||
buf[offset++] = cf->data[i];
|
buf[offset++] = cu->fd.data[i];
|
||||||
else
|
else
|
||||||
buf[offset++] = '.';
|
buf[offset++] = '.';
|
||||||
|
|
||||||
sprintf(buf + offset, "'");
|
offset += sprintf(buf + offset, "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *error_classes[] = {
|
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;
|
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)
|
const char* sep)
|
||||||
{
|
{
|
||||||
canid_t class, mask;
|
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 = ",";
|
char *defsep = ",";
|
||||||
|
|
||||||
if (!(cf->can_id & CAN_ERR_FLAG))
|
if (!(cf->can_id & CAN_ERR_FLAG))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
class = cf->can_id & CAN_EFF_MASK;
|
class = cf->can_id & CAN_EFF_MASK;
|
||||||
if (class > (1 << ARRAY_SIZE(error_classes))) {
|
if (class > (1 << ARRAY_SIZE(error_classes))) {
|
||||||
fprintf(stderr, "Error class %#x is invalid\n", class);
|
fprintf(stderr, "Error class %#x is invalid\n", class);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sep)
|
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/ */
|
/* Fix for potential buffer overflow https://lgtm.com/rules/1505913226124/ */
|
||||||
tmp_n = snprintf(buf + n, len - n, "%s", sep);
|
tmp_n = snprintf(buf + n, len - n, "%s", sep);
|
||||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
||||||
return;
|
buf[0] = 0; /* empty terminated string */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
n += tmp_n;
|
n += tmp_n;
|
||||||
}
|
}
|
||||||
tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
|
tmp_n = snprintf(buf + n, len - n, "%s", error_classes[i]);
|
||||||
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
if (tmp_n < 0 || (size_t)tmp_n >= len - n) {
|
||||||
return;
|
buf[0] = 0; /* empty terminated string */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
n += tmp_n;
|
n += tmp_n;
|
||||||
if (mask == CAN_ERR_LOSTARB)
|
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(buf + n, len - n, "%serror-counter-tx-rx", sep);
|
||||||
n += snprintf_error_cnt(buf + n, len - n, cf);
|
n += snprintf_error_cnt(buf + n, len - n, cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t timespec_diff_ms(struct timespec *ts1,
|
int64_t timespec_diff_ms(struct timespec *ts1,
|
||||||
|
|
|
||||||
88
lib.h
88
lib.h
|
|
@ -46,6 +46,7 @@
|
||||||
#define CAN_UTILS_LIB_H
|
#define CAN_UTILS_LIB_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -55,17 +56,21 @@ __attribute__((format (printf, 1, 2)))
|
||||||
static inline int pr_debug(const char* fmt, ...) {return 0;}
|
static inline int pr_debug(const char* fmt, ...) {return 0;}
|
||||||
#endif
|
#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")
|
* The buffer size for ASCII CAN frame string representations
|
||||||
#define CL_BINDATA sizeof(".10101010")
|
* covers also the 'long' CAN frame output from sprint_long_canframe()
|
||||||
|
* including (swapped) binary represetations, timestamps, netdevice names,
|
||||||
/* CAN FD ASCII hex short representation with DATA_SEPERATORs */
|
* lengths and error message details as the CAN XL data is cropped to 64
|
||||||
#define CL_CFSZ (2*CL_ID + 64*CL_DATA)
|
* byte (the 'long' CAN frame output is only for display on terminals).
|
||||||
|
*/
|
||||||
/* CAN FD ASCII hex long representation with binary output */
|
#define AFRSZ 6300 /* 3*2048 (data) + 22 (timestamp) + 18 (netdev) + ID/HDR */
|
||||||
#define CL_LONGCFSZ (2*CL_ID + sizeof(" [255] ") + (64*CL_BINDATA))
|
|
||||||
|
|
||||||
/* CAN DLC to real data length conversion helpers especially for CAN FD */
|
/* 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, cu_t *cu);
|
||||||
int parse_canframe(char *cs, struct canfd_frame *cf);
|
|
||||||
/*
|
/*
|
||||||
* 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 <can_id>#{R{len}|data}{_len8_dlc}
|
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
|
||||||
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
|
* - {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
|
* - {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 '.'
|
* - {data} has 0 to 64 hex-values that can (optionally) be separated by '.'
|
||||||
* - return value on successful parsing: CANFD_MTU
|
* - return value on successful parsing: CANFD_MTU
|
||||||
*
|
*
|
||||||
|
* CAN XL frames
|
||||||
|
* - string layout <vcid><prio>#<flags>:<sdt>:<af>#{data}
|
||||||
|
* - <vcid> a two ASCII Hex value (00 .. FF) which defines the VCID
|
||||||
|
* - <prio> a three ASCII Hex value (000 .. 7FF) which defines the 11 bit PRIO
|
||||||
|
* - <flags> a two ASCII Hex value (00 .. FF) which defines canxl_frame.flags
|
||||||
|
* - <sdt> a two ASCII Hex value (00 .. FF) which defines canxl_frame.sdt
|
||||||
|
* - <af> 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
|
* Return value on detected problems: 0
|
||||||
*
|
*
|
||||||
* <can_id> can have 3 (standard frame format) or 8 (extended frame format)
|
* <can_id> 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
|
* 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:
|
* Simple facts on this compact ASCII CAN frame representation:
|
||||||
*
|
*
|
||||||
* - 3 digits: standard frame format
|
* - 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
|
* - CAN FD frames do not have a RTR bit
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen);
|
int snprintf_canframe(char *buf, size_t size, cu_t *cu, int sep);
|
||||||
void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in compact format.
|
* Creates a CAN frame hexadecimal output in compact format.
|
||||||
* The CAN data[] is separated by '.' when sep != 0.
|
* The CAN data[] is separated by '.' when sep != 0.
|
||||||
*
|
*
|
||||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
* A CAN XL frame is detected when CANXL_XLF is set in the struct
|
||||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
* cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD)
|
||||||
* maxdlen = 64 -> CAN FD frame
|
* 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
|
* 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
|
* 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
|
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
|
||||||
* 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
|
* 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
|
||||||
* 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
|
* 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
|
||||||
*
|
* 45123#81:00:12345678#11223344.556677 -> CAN XL frame with len = 7,
|
||||||
* Examples:
|
* VCID = 0x45, PRIO = 0x123, flags = 0x81, sdt = 0x00, af = 0x12345678
|
||||||
*
|
|
||||||
* fprint_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
|
|
||||||
* fprint_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -195,14 +211,15 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||||
|
|
||||||
#define SWAP_DELIMITER '`'
|
#define SWAP_DELIMITER '`'
|
||||||
|
|
||||||
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);
|
||||||
void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen);
|
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in user readable format.
|
* 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:
|
* A CAN XL frame is detected when CANXL_XLF is set in the struct
|
||||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
* cu.canxl_frame.flags. Otherwise the type of the CAN frame (CAN CC/FD)
|
||||||
* maxdlen = 64 -> CAN FD frame
|
* 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 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
|
||||||
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
|
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
|
||||||
|
|
@ -210,21 +227,16 @@ 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
|
* 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)
|
* 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
|
* 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 == 0
|
||||||
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
|
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
|
||||||
*
|
*
|
||||||
* Examples:
|
* 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.
|
||||||
* // 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);
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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);
|
const char *sep);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN error frame output in user readable format.
|
* Creates a CAN error frame output in user readable format.
|
||||||
|
|
|
||||||
53
log2asc.c
53
log2asc.c
|
|
@ -54,11 +54,9 @@
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#define BUFSZ 400 /* for one line in the logfile */
|
|
||||||
|
|
||||||
extern int optind, opterr, optopt;
|
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, "%s - convert compact CAN frame logfile to ASC logfile.\n", prg);
|
||||||
fprintf(stderr, "Usage: %s <options> [can-interfaces]\n", prg);
|
fprintf(stderr, "Usage: %s <options> [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");
|
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;
|
int i;
|
||||||
char id[10];
|
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;
|
int i;
|
||||||
char id[10];
|
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);
|
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)
|
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;
|
static struct timeval tv, start_tv;
|
||||||
FILE *infile = stdin;
|
FILE *infile = stdin;
|
||||||
FILE *outfile = stdout;
|
FILE *outfile = stdout;
|
||||||
|
|
@ -261,14 +277,14 @@ int main(int argc, char **argv)
|
||||||
if (buf[0] != '(')
|
if (buf[0] != '(')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sscanf(buf, "(%llu.%llu) %s %s %s", &sec, &usec,
|
if (sscanf(buf, "(%llu.%llu) %21s %6299s %19s", &sec, &usec,
|
||||||
device, ascframe, extra_info) != 5) {
|
device, afrbuf, extra_info) != 5) {
|
||||||
|
|
||||||
/* do not evaluate the extra info */
|
/* do not evaluate the extra info */
|
||||||
extra_info[0] = 0;
|
extra_info[0] = 0;
|
||||||
|
|
||||||
if (sscanf(buf, "(%llu.%llu) %s %s", &sec, &usec,
|
if (sscanf(buf, "(%llu.%llu) %21s %6299s", &sec, &usec,
|
||||||
device, ascframe) != 4) {
|
device, afrbuf) != 4) {
|
||||||
fprintf(stderr, "incorrect line format in logfile\n");
|
fprintf(stderr, "incorrect line format in logfile\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -294,12 +310,17 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devno) { /* only convert for selected CAN devices */
|
if (devno) { /* only convert for selected CAN devices */
|
||||||
mtu = parse_canframe(ascframe, &cf);
|
|
||||||
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU))
|
mtu = parse_canframe(afrbuf, &cu);
|
||||||
|
|
||||||
|
/* convert only CAN CC and CAN FD frames */
|
||||||
|
if ((mtu != CAN_MTU) && (mtu != CANFD_MTU)) {
|
||||||
|
printf("no valid CAN CC/FD frame\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* we don't support error message frames in CAN FD */
|
/* we don't support error message frames in CAN FD */
|
||||||
if ((mtu == CANFD_MTU) && (cf.can_id & CAN_ERR_FLAG))
|
if ((mtu == CANFD_MTU) && (cu.cc.can_id & CAN_ERR_FLAG))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
||||||
|
|
@ -315,9 +336,9 @@ int main(int argc, char **argv)
|
||||||
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
|
fprintf(outfile, "%4llu.%06llu ", (unsigned long long)tv.tv_sec, (unsigned long long)tv.tv_usec);
|
||||||
|
|
||||||
if ((mtu == CAN_MTU) && (fdfmt == 0))
|
if ((mtu == CAN_MTU) && (fdfmt == 0))
|
||||||
can_asc(&cf, devno, nortrdlc, extra_info, outfile);
|
can_asc(&cu.fd, devno, nortrdlc, extra_info, outfile);
|
||||||
else
|
else
|
||||||
canfd_asc(&cf, devno, mtu, extra_info, outfile);
|
canfd_asc(&cu.fd, devno, mtu, extra_info, outfile);
|
||||||
|
|
||||||
if (crlf)
|
if (crlf)
|
||||||
fprintf(outfile, "\r");
|
fprintf(outfile, "\r");
|
||||||
|
|
|
||||||
57
log2long.c
57
log2long.c
|
|
@ -43,40 +43,61 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <linux/can.h>
|
#include <linux/can.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
|
||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
|
||||||
#define COMMENTSZ 200
|
#define DEVSZ 22
|
||||||
#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
|
#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)
|
int main(void)
|
||||||
{
|
{
|
||||||
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
static char buf[BUFSZ], timestamp[TIMESZ], device[DEVSZ], afrbuf[AFRSZ];
|
||||||
struct canfd_frame cf;
|
static cu_t cu;
|
||||||
int mtu, maxdlen;
|
int mtu;
|
||||||
|
|
||||||
while (fgets(buf, BUFSZ-1, stdin)) {
|
while (fgets(buf, BUFSZ-1, stdin)) {
|
||||||
if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
mtu = parse_canframe(ascframe, &cf);
|
if (strlen(buf) >= BUFSZ-2) {
|
||||||
if (mtu == CAN_MTU)
|
fprintf(stderr, "line too long for input buffer\n");
|
||||||
maxdlen = CAN_MAX_DLEN;
|
|
||||||
else if (mtu == CANFD_MTU)
|
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprint_long_canframe(ascframe, &cf,
|
if (sscanf(buf, "%21s %21s %6299s", timestamp, device, afrbuf) != 3)
|
||||||
(CANLIB_VIEW_INDENT_SFF | CANLIB_VIEW_ASCII),
|
return 1;
|
||||||
maxdlen); /* with ASCII output */
|
|
||||||
|
|
||||||
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;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@
|
||||||
#define DEVICE_NAME_PTMX "/dev/ptmx"
|
#define DEVICE_NAME_PTMX "/dev/ptmx"
|
||||||
|
|
||||||
/* read data from pty, send CAN frames to CAN socket and answer commands */
|
/* 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;
|
unsigned int nbytes;
|
||||||
char cmd;
|
char cmd;
|
||||||
|
|
@ -313,7 +314,7 @@ rx_out:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read CAN frames from CAN interface and write it to the pty */
|
/* 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;
|
int nbytes;
|
||||||
char cmd;
|
char cmd;
|
||||||
|
|
@ -365,7 +366,7 @@ int can2pty(int pty, int socket, int *tstamp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int check_select_stdin(void)
|
static int check_select_stdin(void)
|
||||||
{
|
{
|
||||||
fd_set rdfs;
|
fd_set rdfs;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue