mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-20 14:29:55 +02:00
Compare commits
22
Commits
v2020.11.0
...
v2020.12.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb66451df2 | ||
|
|
682e01a40a | ||
|
|
280ea436d4 | ||
|
|
33de12680a | ||
|
|
bfaa44fa91 | ||
|
|
305b2e8b79 | ||
|
|
15f3a2e385 | ||
|
|
aa6411075f | ||
|
|
51d675368d | ||
|
|
639498bc80 | ||
|
|
333e631286 | ||
|
|
6a14256323 | ||
|
|
c3d9cc2027 | ||
|
|
972054446a | ||
|
|
6799180bd0 | ||
|
|
11edd1d05e | ||
|
|
a272fd2082 | ||
|
|
1ba0c576ae | ||
|
|
b70d8c050f | ||
|
|
c398e56afb | ||
|
|
d0ad168953 | ||
|
|
c3348ed51e |
@@ -270,7 +270,7 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace
|
||||
extra_info = " T\n";
|
||||
|
||||
/* don't trust ASCII content - sanitize data length */
|
||||
if (dlen != can_dlc2len(can_len2dlc(dlen)))
|
||||
if (dlen != can_fd_dlc2len(can_fd_len2dlc(dlen)))
|
||||
return;
|
||||
|
||||
get_can_id(&cf, tmp1, 16);
|
||||
@@ -327,6 +327,15 @@ void eval_canfd(char* buf, struct timeval *date_tvp, char timestamps, int dplace
|
||||
/* dlen is always 0 for classic CAN RTR frames
|
||||
but the DLC value is valid in RTR cases */
|
||||
cf.len = dlc;
|
||||
/* sanitize payload length value */
|
||||
if (dlc > CAN_MAX_DLEN)
|
||||
cf.len = CAN_MAX_DLEN;
|
||||
}
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((cf.len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)&cf;
|
||||
|
||||
ccf->len8_dlc = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
@@ -72,9 +73,10 @@
|
||||
#endif
|
||||
|
||||
/* from #include <linux/net_tstamp.h> - since Linux 2.6.30 */
|
||||
#define SOF_TIMESTAMPING_SOFTWARE (1<<4)
|
||||
#define SOF_TIMESTAMPING_RX_SOFTWARE (1<<3)
|
||||
#define SOF_TIMESTAMPING_RAW_HARDWARE (1<<6)
|
||||
#define SOF_TIMESTAMPING_SOFTWARE (1 << 4)
|
||||
#define SOF_TIMESTAMPING_RX_SOFTWARE (1 << 3)
|
||||
#define SOF_TIMESTAMPING_RAW_HARDWARE (1 << 6)
|
||||
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
||||
|
||||
#define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */
|
||||
#define MAXIFNAMES 30 /* size of receive name index to omit ioctls */
|
||||
@@ -85,36 +87,41 @@
|
||||
#define SILENT_INI 42 /* detect user setting on commandline */
|
||||
#define SILENT_OFF 0 /* no silent mode */
|
||||
#define SILENT_ANI 1 /* silent mode with animation */
|
||||
#define SILENT_ON 2 /* silent mode (completely silent) */
|
||||
#define SILENT_ON 2 /* silent mode (completely silent) */
|
||||
|
||||
#define BOLD ATTBOLD
|
||||
#define RED ATTBOLD FGRED
|
||||
#define GREEN ATTBOLD FGGREEN
|
||||
#define YELLOW ATTBOLD FGYELLOW
|
||||
#define BLUE ATTBOLD FGBLUE
|
||||
#define MAGENTA ATTBOLD FGMAGENTA
|
||||
#define CYAN ATTBOLD FGCYAN
|
||||
#define BOLD ATTBOLD
|
||||
#define RED (ATTBOLD FGRED)
|
||||
#define GREEN (ATTBOLD FGGREEN)
|
||||
#define YELLOW (ATTBOLD FGYELLOW)
|
||||
#define BLUE (ATTBOLD FGBLUE)
|
||||
#define MAGENTA (ATTBOLD FGMAGENTA)
|
||||
#define CYAN (ATTBOLD FGCYAN)
|
||||
|
||||
const char col_on [MAXCOL][19] = {BLUE, RED, GREEN, BOLD, MAGENTA, CYAN};
|
||||
const char col_off [] = ATTRESET;
|
||||
static const char col_on[MAXCOL][19] = { BLUE, RED, GREEN, BOLD, MAGENTA, CYAN };
|
||||
static const char col_off[] = ATTRESET;
|
||||
|
||||
struct if_info { /* bundled information per open socket */
|
||||
int s; /* socket */
|
||||
char *cmdlinename;
|
||||
__u32 dropcnt;
|
||||
__u32 last_dropcnt;
|
||||
};
|
||||
static struct if_info sock_info[MAXSOCK];
|
||||
|
||||
static char *cmdlinename[MAXSOCK];
|
||||
static __u32 dropcnt[MAXSOCK];
|
||||
static __u32 last_dropcnt[MAXSOCK];
|
||||
static char devname[MAXIFNAMES][IFNAMSIZ+1];
|
||||
static int dindex[MAXIFNAMES];
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
const int canfd_on = 1;
|
||||
static int dindex[MAXIFNAMES];
|
||||
static int max_devname_len; /* to prevent frazzled device name output */
|
||||
static const int canfd_on = 1;
|
||||
|
||||
#define MAXANI 4
|
||||
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
|
||||
const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"};
|
||||
static const char anichar[MAXANI] = { '|', '/', '-', '\\' };
|
||||
static const char extra_m_info[4][4] = { "- -", "B -", "- E", "B E" };
|
||||
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static volatile int running = 1;
|
||||
|
||||
void print_usage(char *prg)
|
||||
static void print_usage(char *prg)
|
||||
{
|
||||
fprintf(stderr, "%s - dump CAN bus traffic.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
|
||||
@@ -134,6 +141,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
|
||||
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
|
||||
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
|
||||
fprintf(stderr, " -8 (display raw DLC values in {} for Classical CAN)\n");
|
||||
fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n");
|
||||
fprintf(stderr, " -T <msecs> (terminate after <msecs> without any reception)\n");
|
||||
fprintf(stderr, "\n");
|
||||
@@ -159,17 +167,18 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void sigterm(int signo)
|
||||
static void sigterm(int signo)
|
||||
{
|
||||
running = 0;
|
||||
}
|
||||
|
||||
int idx2dindex(int ifidx, int socket) {
|
||||
static int idx2dindex(int ifidx, int socket)
|
||||
{
|
||||
|
||||
int i;
|
||||
struct ifreq ifr;
|
||||
|
||||
for (i=0; i < MAXIFNAMES; i++) {
|
||||
for (i = 0; i < MAXIFNAMES; i++) {
|
||||
if (dindex[i] == ifidx)
|
||||
return i;
|
||||
}
|
||||
@@ -177,7 +186,7 @@ int idx2dindex(int ifidx, int socket) {
|
||||
/* create new interface index cache entry */
|
||||
|
||||
/* remove index cache zombies first */
|
||||
for (i=0; i < MAXIFNAMES; i++) {
|
||||
for (i = 0; i < MAXIFNAMES; i++) {
|
||||
if (dindex[i]) {
|
||||
ifr.ifr_ifindex = dindex[i];
|
||||
if (ioctl(socket, SIOCGIFNAME, &ifr) < 0)
|
||||
@@ -185,13 +194,13 @@ int idx2dindex(int ifidx, int socket) {
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i < MAXIFNAMES; i++)
|
||||
for (i = 0; i < MAXIFNAMES; i++)
|
||||
if (!dindex[i]) /* free entry */
|
||||
break;
|
||||
|
||||
if (i == MAXIFNAMES) {
|
||||
fprintf(stderr, "Interface index cache only supports %d interfaces.\n",
|
||||
MAXIFNAMES);
|
||||
MAXIFNAMES);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -213,11 +222,69 @@ int idx2dindex(int ifidx, int socket) {
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void sprint_timestamp(const char timestamp, const struct timeval *tv,
|
||||
struct timeval *const last_tv, char *ts_buffer)
|
||||
{
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
sprintf(ts_buffer, "(%010lu.%06lu) ", tv->tv_sec, tv->tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv->tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
sprintf(ts_buffer, "(%s.%06lu) ", timestring, tv->tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv->tv_sec == 0) /* first init */
|
||||
*last_tv = *tv;
|
||||
diff.tv_sec = tv->tv_sec - last_tv->tv_sec;
|
||||
diff.tv_usec = tv->tv_usec - last_tv->tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
sprintf(ts_buffer, "(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
*last_tv = *tv; /* update for delta calculation */
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void print_timestamp(const char timestamp, const struct timeval *tv,
|
||||
struct timeval *const last_tv)
|
||||
{
|
||||
static char buffer[TIMESTAMPSZ];
|
||||
|
||||
sprint_timestamp(timestamp, tv, last_tv, buffer);
|
||||
printf("%s", buffer);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fd_set rdfs;
|
||||
int s[MAXSOCK];
|
||||
int fd_epoll;
|
||||
struct epoll_event events_pending[MAXSOCK];
|
||||
struct epoll_event event_setup = {
|
||||
.events = EPOLLIN, /* prepare the common part */
|
||||
};
|
||||
unsigned char timestamp = 0;
|
||||
unsigned char logtimestamp = 'a';
|
||||
unsigned char hwtimestamp = 0;
|
||||
unsigned char down_causes_exit = 1;
|
||||
unsigned char dropmonitor = 0;
|
||||
@@ -230,12 +297,12 @@ int main(int argc, char **argv)
|
||||
unsigned char logfrmt = 0;
|
||||
int count = 0;
|
||||
int rcvbuf_size = 0;
|
||||
int opt, ret;
|
||||
int opt, num_events;
|
||||
int currmax, numfilter;
|
||||
int join_filter;
|
||||
char *ptr, *nptr;
|
||||
struct sockaddr_can addr;
|
||||
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3*sizeof(struct timespec) + sizeof(__u32))];
|
||||
char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3 * sizeof(struct timespec) + sizeof(__u32))];
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
@@ -245,26 +312,30 @@ int main(int argc, char **argv)
|
||||
int nbytes, i, maxdlen;
|
||||
struct ifreq ifr;
|
||||
struct timeval tv, last_tv;
|
||||
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
|
||||
int timeout_ms = -1; /* default to no timeout */
|
||||
FILE *logfile = NULL;
|
||||
|
||||
signal(SIGTERM, sigterm);
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_sec = 0;
|
||||
last_tv.tv_usec = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:heT:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "t:HciaSs:lDdxLn:r:he8T:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
timestamp = optarg[0];
|
||||
logtimestamp = optarg[0];
|
||||
if ((timestamp != 'a') && (timestamp != 'A') &&
|
||||
(timestamp != 'd') && (timestamp != 'z')) {
|
||||
fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n",
|
||||
basename(argv[0]), optarg[0]);
|
||||
basename(argv[0]), optarg[0]);
|
||||
timestamp = 0;
|
||||
}
|
||||
if ((logtimestamp != 'a') && (logtimestamp != 'z')) {
|
||||
logtimestamp = 'a';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
@@ -291,6 +362,10 @@ int main(int argc, char **argv)
|
||||
view |= CANLIB_VIEW_ERROR;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
view |= CANLIB_VIEW_LEN8_DLC;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
silent = atoi(optarg);
|
||||
if (silent > SILENT_ON) {
|
||||
@@ -337,14 +412,11 @@ int main(int argc, char **argv)
|
||||
|
||||
case 'T':
|
||||
errno = 0;
|
||||
timeout_config.tv_usec = strtol(optarg, NULL, 0);
|
||||
timeout_ms = strtol(optarg, NULL, 0);
|
||||
if (errno != 0) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
timeout_config.tv_sec = timeout_config.tv_usec / 1000;
|
||||
timeout_config.tv_usec = (timeout_config.tv_usec % 1000) * 1000;
|
||||
timeout_current = &timeout;
|
||||
break;
|
||||
default:
|
||||
print_usage(basename(argv[0]));
|
||||
@@ -357,9 +429,9 @@ int main(int argc, char **argv)
|
||||
print_usage(basename(argv[0]));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
if (logfrmt && view) {
|
||||
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n");
|
||||
fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP/RAWDLC options!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@@ -378,8 +450,14 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i=0; i < currmax; i++) {
|
||||
fd_epoll = epoll_create(1);
|
||||
if (fd_epoll < 0) {
|
||||
perror("epoll_create");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < currmax; i++) {
|
||||
struct if_info* obj = &sock_info[i];
|
||||
ptr = argv[optind+i];
|
||||
nptr = strchr(ptr, ',');
|
||||
|
||||
@@ -387,13 +465,19 @@ int main(int argc, char **argv)
|
||||
printf("open %d '%s'.\n", i, ptr);
|
||||
#endif
|
||||
|
||||
s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (s[i] < 0) {
|
||||
obj->s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||
if (obj->s < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */
|
||||
event_setup.data.ptr = obj; /* remember the instance as private data */
|
||||
if (epoll_ctl(fd_epoll, EPOLL_CTL_ADD, obj->s, &event_setup)) {
|
||||
perror("failed to add socket to epoll");
|
||||
return 1;
|
||||
}
|
||||
|
||||
obj->cmdlinename = ptr; /* save pointer to cmdline name of this socket */
|
||||
|
||||
if (nptr)
|
||||
nbytes = nptr - ptr; /* interface name is up the first ',' */
|
||||
@@ -418,7 +502,7 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
if (strcmp(ANYDEV, ifr.ifr_name) != 0) {
|
||||
if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) {
|
||||
if (ioctl(obj->s, SIOCGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOCGIFINDEX");
|
||||
exit(1);
|
||||
}
|
||||
@@ -451,44 +535,44 @@ int main(int argc, char **argv)
|
||||
|
||||
while (nptr) {
|
||||
|
||||
ptr = nptr+1; /* hop behind the ',' */
|
||||
ptr = nptr + 1; /* hop behind the ',' */
|
||||
nptr = strchr(ptr, ','); /* update exit condition */
|
||||
|
||||
if (sscanf(ptr, "%x:%x",
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_mask) == 2) {
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr+8) == ':')
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr + 8) == ':')
|
||||
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
|
||||
numfilter++;
|
||||
} else if (sscanf(ptr, "%x~%x",
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_id,
|
||||
&rfilter[numfilter].can_mask) == 2) {
|
||||
rfilter[numfilter].can_id |= CAN_INV_FILTER;
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr+8) == '~')
|
||||
rfilter[numfilter].can_id |= CAN_INV_FILTER;
|
||||
rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG;
|
||||
if (*(ptr + 8) == '~')
|
||||
rfilter[numfilter].can_id |= CAN_EFF_FLAG;
|
||||
numfilter++;
|
||||
} else if (*ptr == 'j' || *ptr == 'J') {
|
||||
join_filter = 1;
|
||||
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
|
||||
} else if (sscanf(ptr, "#%x", &err_mask) != 1) {
|
||||
fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (err_mask)
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||
&err_mask, sizeof(err_mask));
|
||||
|
||||
if (join_filter && setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
|
||||
if (join_filter && setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,
|
||||
&join_filter, sizeof(join_filter)) < 0) {
|
||||
perror("setsockopt CAN_RAW_JOIN_FILTERS not supported by your Linux Kernel");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (numfilter)
|
||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
setsockopt(obj->s, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
rfilter, numfilter * sizeof(struct can_filter));
|
||||
|
||||
free(rfilter);
|
||||
@@ -496,26 +580,25 @@ int main(int argc, char **argv)
|
||||
} /* if (nptr) */
|
||||
|
||||
/* 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(obj->s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
|
||||
|
||||
if (rcvbuf_size) {
|
||||
|
||||
int curr_rcvbuf_size;
|
||||
socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size);
|
||||
|
||||
/* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUFFORCE,
|
||||
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
|
||||
#ifdef DEBUG
|
||||
printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n");
|
||||
#endif
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
|
||||
&rcvbuf_size, sizeof(rcvbuf_size)) < 0) {
|
||||
perror("setsockopt SO_RCVBUF");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF,
|
||||
if (getsockopt(obj->s, SOL_SOCKET, SO_RCVBUF,
|
||||
&curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) {
|
||||
perror("getsockopt SO_RCVBUF");
|
||||
return 1;
|
||||
@@ -523,28 +606,27 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Only print a warning the first time we detect the adjustment */
|
||||
/* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */
|
||||
if (!i && curr_rcvbuf_size < rcvbuf_size*2)
|
||||
if (!i && curr_rcvbuf_size < rcvbuf_size * 2)
|
||||
fprintf(stderr, "The socket receive buffer size was "
|
||||
"adjusted due to /proc/sys/net/core/rmem_max.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (timestamp || log || logfrmt) {
|
||||
|
||||
if (hwtimestamp) {
|
||||
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE | \
|
||||
const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE);
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING,
|
||||
×tamping_flags, sizeof(timestamping_flags)) < 0) {
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
×tamping_flags, sizeof(timestamping_flags)) < 0) {
|
||||
perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
const int timestamp_on = 1;
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_TIMESTAMP,
|
||||
×tamp_on, sizeof(timestamp_on)) < 0) {
|
||||
perror("setsockopt SO_TIMESTAMP");
|
||||
return 1;
|
||||
@@ -553,17 +635,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (dropmonitor) {
|
||||
|
||||
const int dropmonitor_on = 1;
|
||||
|
||||
if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL,
|
||||
if (setsockopt(obj->s, SOL_SOCKET, SO_RXQ_OVFL,
|
||||
&dropmonitor_on, sizeof(dropmonitor_on)) < 0) {
|
||||
perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
if (bind(obj->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
@@ -610,205 +691,159 @@ int main(int argc, char **argv)
|
||||
|
||||
while (running) {
|
||||
|
||||
FD_ZERO(&rdfs);
|
||||
for (i=0; i<currmax; i++)
|
||||
FD_SET(s[i], &rdfs);
|
||||
|
||||
if (timeout_current)
|
||||
*timeout_current = timeout_config;
|
||||
|
||||
if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)) <= 0) {
|
||||
//perror("select");
|
||||
if ((num_events = epoll_wait(fd_epoll, events_pending, currmax, timeout_ms)) <= 0) {
|
||||
//perror("epoll_wait");
|
||||
running = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
|
||||
for (i = 0; i < num_events; i++) { /* check waiting CAN RAW sockets */
|
||||
struct if_info* obj = events_pending[i].data.ptr;
|
||||
int idx;
|
||||
char *extra_info = "";
|
||||
|
||||
if (FD_ISSET(s[i], &rdfs)) {
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
int idx;
|
||||
char *extra_info = "";
|
||||
nbytes = recvmsg(obj->s, &msg, 0);
|
||||
idx = idx2dindex(addr.can_ifindex, obj->s);
|
||||
|
||||
/* these settings may be modified by recvmsg() */
|
||||
iov.iov_len = sizeof(frame);
|
||||
msg.msg_namelen = sizeof(addr);
|
||||
msg.msg_controllen = sizeof(ctrlmsg);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
nbytes = recvmsg(s[i], &msg, 0);
|
||||
idx = idx2dindex(addr.can_ifindex, s[i]);
|
||||
|
||||
if (nbytes < 0) {
|
||||
if ((errno == ENETDOWN) && !down_causes_exit) {
|
||||
fprintf(stderr, "%s: interface down\n", devname[idx]);
|
||||
continue;
|
||||
}
|
||||
perror("read");
|
||||
return 1;
|
||||
if (nbytes < 0) {
|
||||
if ((errno == ENETDOWN) && !down_causes_exit) {
|
||||
fprintf(stderr, "%s: interface down\n", devname[idx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((size_t)nbytes == CAN_MTU)
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
else if ((size_t)nbytes == CANFD_MTU)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
else {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count && (--count == 0))
|
||||
running = 0;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
||||
|
||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||
|
||||
/*
|
||||
* stamp[0] is the software timestamp
|
||||
* stamp[1] is deprecated
|
||||
* stamp[2] is the raw hardware timestamp
|
||||
* See chapter 2.1.2 Receive timestamps in
|
||||
* linux/Documentation/networking/timestamping.txt
|
||||
*/
|
||||
tv.tv_sec = stamp[2].tv_sec;
|
||||
tv.tv_usec = stamp[2].tv_nsec/1000;
|
||||
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
|
||||
memcpy(&dropcnt[i], CMSG_DATA(cmsg), sizeof(__u32));
|
||||
}
|
||||
|
||||
/* check for (unlikely) dropped frames on this specific socket */
|
||||
if (dropcnt[i] != last_dropcnt[i]) {
|
||||
|
||||
__u32 frames = dropcnt[i] - last_dropcnt[i];
|
||||
|
||||
if (silent != SILENT_ON)
|
||||
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
|
||||
|
||||
if (log)
|
||||
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], dropcnt[i]);
|
||||
|
||||
last_dropcnt[i] = dropcnt[i];
|
||||
}
|
||||
|
||||
/* once we detected a EFF frame indent SFF frames accordingly */
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
|
||||
if (extra_msg_info) {
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
extra_info = " T";
|
||||
else
|
||||
extra_info = " R";
|
||||
}
|
||||
|
||||
if (log) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* log CAN frame with absolute timestamp & device */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
fprintf(logfile, "(%010lu.%06lu) %*s %s%s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
}
|
||||
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
printf("(%010lu.%06lu) %*s %s%s\n",
|
||||
tv.tv_sec, tv.tv_usec,
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
if (silent != SILENT_OFF){
|
||||
if (silent == SILENT_ANI) {
|
||||
printf("%c\b", anichar[silentani%=MAXANI]);
|
||||
silentani++;
|
||||
}
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
printf(" %s", (color>2)?col_on[idx%MAXCOL]:"");
|
||||
|
||||
switch (timestamp) {
|
||||
|
||||
case 'a': /* absolute with timestamp */
|
||||
printf("(%010lu.%06lu) ", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
|
||||
case 'A': /* absolute with date */
|
||||
{
|
||||
struct tm tm;
|
||||
char timestring[25];
|
||||
|
||||
tm = *localtime(&tv.tv_sec);
|
||||
strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
printf("(%s.%06lu) ", timestring, tv.tv_usec);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': /* delta */
|
||||
case 'z': /* starting with zero */
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
if (last_tv.tv_sec == 0) /* first init */
|
||||
last_tv = tv;
|
||||
diff.tv_sec = tv.tv_sec - last_tv.tv_sec;
|
||||
diff.tv_usec = tv.tv_usec - last_tv.tv_usec;
|
||||
if (diff.tv_usec < 0)
|
||||
diff.tv_sec--, diff.tv_usec += 1000000;
|
||||
if (diff.tv_sec < 0)
|
||||
diff.tv_sec = diff.tv_usec = 0;
|
||||
printf("(%03lu.%06lu) ", diff.tv_sec, diff.tv_usec);
|
||||
|
||||
if (timestamp == 'd')
|
||||
last_tv = tv; /* update for delta calculation */
|
||||
}
|
||||
break;
|
||||
|
||||
default: /* no timestamp output */
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:"");
|
||||
printf("%*s", max_devname_len, devname[idx]);
|
||||
|
||||
if (extra_msg_info) {
|
||||
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
printf (" TX %s", extra_m_info[frame.flags & 3]);
|
||||
else
|
||||
printf (" RX %s", extra_m_info[frame.flags & 3]);
|
||||
}
|
||||
|
||||
printf("%s ", (color==1)?col_off:"");
|
||||
|
||||
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
|
||||
|
||||
printf("%s", (color>1)?col_off:"");
|
||||
printf("\n");
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
|
||||
out_fflush:
|
||||
if ((size_t)nbytes == CAN_MTU)
|
||||
maxdlen = CAN_MAX_DLEN;
|
||||
else if ((size_t)nbytes == CANFD_MTU)
|
||||
maxdlen = CANFD_MAX_DLEN;
|
||||
else {
|
||||
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (count && (--count == 0))
|
||||
running = 0;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
||||
|
||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||
|
||||
/*
|
||||
* stamp[0] is the software timestamp
|
||||
* stamp[1] is deprecated
|
||||
* stamp[2] is the raw hardware timestamp
|
||||
* See chapter 2.1.2 Receive timestamps in
|
||||
* linux/Documentation/networking/timestamping.txt
|
||||
*/
|
||||
tv.tv_sec = stamp[2].tv_sec;
|
||||
tv.tv_usec = stamp[2].tv_nsec/1000;
|
||||
} else if (cmsg->cmsg_type == SO_RXQ_OVFL)
|
||||
memcpy(&obj->dropcnt, CMSG_DATA(cmsg), sizeof(__u32));
|
||||
}
|
||||
|
||||
/* check for (unlikely) dropped frames on this specific socket */
|
||||
if (obj->dropcnt != obj->last_dropcnt) {
|
||||
|
||||
__u32 frames = obj->dropcnt - obj->last_dropcnt;
|
||||
|
||||
if (silent != SILENT_ON)
|
||||
printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
|
||||
|
||||
if (log)
|
||||
fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n",
|
||||
frames, (frames > 1)?"s":"", devname[idx], obj->dropcnt);
|
||||
|
||||
obj->last_dropcnt = obj->dropcnt;
|
||||
}
|
||||
|
||||
/* once we detected a EFF frame indent SFF frames accordingly */
|
||||
if (frame.can_id & CAN_EFF_FLAG)
|
||||
view |= CANLIB_VIEW_INDENT_SFF;
|
||||
|
||||
if (extra_msg_info) {
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
extra_info = " T";
|
||||
else
|
||||
extra_info = " R";
|
||||
}
|
||||
|
||||
if (log) {
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
char ts_buf[TIMESTAMPSZ];
|
||||
|
||||
sprint_timestamp(logtimestamp, &tv, &last_tv, ts_buf);
|
||||
|
||||
/* log CAN frame with absolute timestamp & device */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
fprintf(logfile, "%s%*s %s%s\n", ts_buf,
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
}
|
||||
|
||||
if ((logfrmt) && (silent == SILENT_OFF)){
|
||||
char buf[CL_CFSZ]; /* max length */
|
||||
|
||||
/* print CAN frame in log file style to stdout */
|
||||
sprint_canframe(buf, &frame, 0, maxdlen);
|
||||
print_timestamp(logtimestamp, &tv, &last_tv);
|
||||
|
||||
printf("%*s %s%s\n",
|
||||
max_devname_len, devname[idx], buf,
|
||||
extra_info);
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
if (silent != SILENT_OFF){
|
||||
if (silent == SILENT_ANI) {
|
||||
printf("%c\b", anichar[silentani %= MAXANI]);
|
||||
silentani++;
|
||||
}
|
||||
goto out_fflush; /* no other output to stdout */
|
||||
}
|
||||
|
||||
printf(" %s", (color > 2) ? col_on[idx % MAXCOL] : "");
|
||||
print_timestamp(timestamp, &tv, &last_tv);
|
||||
printf(" %s", (color && (color < 3)) ? col_on[idx % MAXCOL] : "");
|
||||
printf("%*s", max_devname_len, devname[idx]);
|
||||
|
||||
if (extra_msg_info) {
|
||||
|
||||
if (msg.msg_flags & MSG_DONTROUTE)
|
||||
printf (" TX %s", extra_m_info[frame.flags & 3]);
|
||||
else
|
||||
printf (" RX %s", extra_m_info[frame.flags & 3]);
|
||||
}
|
||||
|
||||
printf("%s ", (color == 1) ? col_off : "");
|
||||
|
||||
fprint_long_canframe(stdout, &frame, NULL, view, maxdlen);
|
||||
|
||||
printf("%s", (color > 1) ? col_off : "");
|
||||
printf("\n");
|
||||
|
||||
out_fflush:
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<currmax; i++)
|
||||
close(s[i]);
|
||||
for (i = 0; i < currmax; i++)
|
||||
close(sock_info[i].s);
|
||||
|
||||
close(fd_epoll);
|
||||
|
||||
if (log)
|
||||
fclose(logfile);
|
||||
|
||||
@@ -92,7 +92,8 @@ void print_usage(char *prg)
|
||||
" with bitrate switch (BRS))\n");
|
||||
fprintf(stderr, " -E (generate CAN FD CAN frames"
|
||||
" with error state (ESI))\n");
|
||||
fprintf(stderr, " -R (send RTR frame)\n");
|
||||
fprintf(stderr, " -R (generate RTR frames)\n");
|
||||
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
|
||||
fprintf(stderr, " -m (mix -e -f -b -E -R frames)\n");
|
||||
fprintf(stderr, " -I <mode> (CAN ID"
|
||||
" generation mode - see below)\n");
|
||||
@@ -113,9 +114,9 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -v (increment verbose level for "
|
||||
"printing sent CAN frames)\n\n");
|
||||
fprintf(stderr, "Generation modes:\n");
|
||||
fprintf(stderr, " 'r' => random values (default)\n");
|
||||
fprintf(stderr, " 'i' => increment values\n");
|
||||
fprintf(stderr, " <hexvalue> => fix value using <hexvalue>\n\n");
|
||||
fprintf(stderr, " 'r' => random values (default)\n");
|
||||
fprintf(stderr, " 'i' => increment values\n");
|
||||
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
|
||||
fprintf(stderr, "When incrementing the CAN data the data length code "
|
||||
"minimum is set to 1.\n");
|
||||
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
|
||||
@@ -156,6 +157,7 @@ int main(int argc, char **argv)
|
||||
unsigned char loopback_disable = 0;
|
||||
unsigned char verbose = 0;
|
||||
unsigned char rtr_frame = 0;
|
||||
unsigned char len8_dlc = 0;
|
||||
int count = 0;
|
||||
unsigned long burst_sent_count = 0;
|
||||
int mtu, maxdlen;
|
||||
@@ -170,6 +172,7 @@ int main(int argc, char **argv)
|
||||
|
||||
struct sockaddr_can addr;
|
||||
static struct canfd_frame frame;
|
||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
||||
int nbytes;
|
||||
int i;
|
||||
struct ifreq ifr;
|
||||
@@ -185,7 +188,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGHUP, sigterm);
|
||||
signal(SIGINT, sigterm);
|
||||
|
||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vRh?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
|
||||
switch (opt) {
|
||||
|
||||
case 'i':
|
||||
@@ -271,6 +274,10 @@ int main(int argc, char **argv)
|
||||
rtr_frame = 1;
|
||||
break;
|
||||
|
||||
case '8':
|
||||
len8_dlc = 1;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
polltimeout = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
@@ -360,11 +367,19 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||
frame.len = can_dlc2len(can_len2dlc(frame.len));
|
||||
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
|
||||
} else {
|
||||
/* sanitize CAN 2.0 frame length */
|
||||
if (frame.len > 8)
|
||||
frame.len = 8;
|
||||
/* sanitize Classical CAN 2.0 frame length */
|
||||
if (len8_dlc) {
|
||||
if (frame.len > CAN_MAX_RAW_DLC)
|
||||
frame.len = CAN_MAX_RAW_DLC;
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN)
|
||||
ccf->len8_dlc = frame.len;
|
||||
}
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN)
|
||||
frame.len = CAN_MAX_DLEN;
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
@@ -410,11 +425,19 @@ int main(int argc, char **argv)
|
||||
if (dlc_mode == MODE_RANDOM) {
|
||||
|
||||
if (canfd)
|
||||
frame.len = can_dlc2len(random() & 0xF);
|
||||
frame.len = can_fd_dlc2len(random() & 0xF);
|
||||
else {
|
||||
frame.len = random() & 0xF;
|
||||
if (frame.len & 8)
|
||||
|
||||
if (frame.len > CAN_MAX_DLEN) {
|
||||
/* generate Classic CAN len8 DLCs? */
|
||||
if (len8_dlc)
|
||||
ccf->len8_dlc = frame.len;
|
||||
|
||||
frame.len = 8; /* for about 50% of the frames */
|
||||
} else {
|
||||
ccf->len8_dlc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,12 +516,20 @@ resend:
|
||||
if (dlc_mode == MODE_INCREMENT) {
|
||||
|
||||
incdlc++;
|
||||
incdlc %= CAN_MAX_RAW_DLC + 1;
|
||||
|
||||
if (canfd && !mix) {
|
||||
incdlc &= 0xF;
|
||||
frame.len = can_dlc2len(incdlc);
|
||||
if (canfd && !mix)
|
||||
frame.len = can_fd_dlc2len(incdlc);
|
||||
else if (len8_dlc) {
|
||||
if (incdlc > CAN_MAX_DLEN) {
|
||||
frame.len = CAN_MAX_DLEN;
|
||||
ccf->len8_dlc = incdlc;
|
||||
} else {
|
||||
frame.len = incdlc;
|
||||
ccf->len8_dlc = 0;
|
||||
}
|
||||
} else {
|
||||
incdlc %= 9;
|
||||
incdlc %= CAN_MAX_DLEN + 1;
|
||||
frame.len = incdlc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -u <uid> (user defined modification identifier)\n");
|
||||
fprintf(stderr, " -l <hops> (limit the number of frame hops / routings)\n");
|
||||
fprintf(stderr, " -f <filter> (set CAN filter)\n");
|
||||
fprintf(stderr, " -m <mod> (set Classic CAN frame modifications)\n");
|
||||
fprintf(stderr, " -m <mod> (set Classical CAN frame modifications)\n");
|
||||
fprintf(stderr, " -M <MOD> (set CAN FD frame modifications)\n");
|
||||
fprintf(stderr, " -x <from_idx>:<to_idx>:<result_idx>:<init_xor_val> (XOR checksum)\n");
|
||||
fprintf(stderr, " -c <from>:<to>:<result>:<init_val>:<xor_val>:<crctab[256]> (CRC8 cs)\n");
|
||||
@@ -251,12 +251,12 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " <can_id>:<can_mask> (matches when <received_can_id> & mask == can_id & mask)\n");
|
||||
fprintf(stderr, " <can_id>~<can_mask> (matches when <received_can_id> & mask != can_id & mask)\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<mod> is a CAN frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<mod> is a Classical CAN frame modification instruction consisting of\n");
|
||||
fprintf(stderr, "<instruction>:<can_frame-elements>:<can_id>.<can_dlc>.<can_data>\n");
|
||||
fprintf(stderr, " <instruction> is one of 'AND' 'OR' 'XOR' 'SET'\n");
|
||||
fprintf(stderr, " <can_frame-elements> is _one_ or _more_ of 'I'dentifier 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " <can_id> is an u32 value containing the CAN Identifier\n");
|
||||
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code (0 .. 8)\n");
|
||||
fprintf(stderr, " <can_dlc> is an u8 value containing the data length code in hex (0 .. F)\n");
|
||||
fprintf(stderr, " <can_data> is always eight(!) u8 values containing the CAN frames data\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "<MOD> is a CAN FD frame modification instruction consisting of\n");
|
||||
@@ -265,7 +265,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " <canfd_frame-elements> is _one_ or _more_ of 'I'd 'F'lags 'L'ength 'D'ata\n");
|
||||
fprintf(stderr, " <can_id> is an u32 value containing the CAN FD Identifier\n");
|
||||
fprintf(stderr, " <flags> is an u8 value containing CAN FD flags (CANFD_BRS, CANFD_ESI)\n");
|
||||
fprintf(stderr, " <len> is an u8 value containing the data length (0 .. 64)\n");
|
||||
fprintf(stderr, " <len> is an u8 value containing the data length in hex (0 .. 40)\n");
|
||||
fprintf(stderr, " <can_data> is always 64(!) u8 values containing the CAN FD frames data\n");
|
||||
fprintf(stderr, "The max. four modifications are performed in the order AND -> OR -> XOR -> SET\n");
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ void childdied(int i)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a Signalhandler for a cought SIGTERM
|
||||
* This is a Signalhandler for a caught SIGTERM
|
||||
*/
|
||||
void shutdown_gra(int i)
|
||||
{
|
||||
|
||||
@@ -61,8 +61,10 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, "%s - send CAN-frames via CAN_RAW sockets.\n", prg);
|
||||
fprintf(stderr, "\nUsage: %s <device> <can_frame>.\n", prg);
|
||||
fprintf(stderr, "\n<can_frame>:\n");
|
||||
fprintf(stderr, " <can_id>#{data} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for 'classic' CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#{data} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#{data}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>#R{len}_{dlc} for Classical CAN 2.0 data frames\n");
|
||||
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||
fprintf(stderr, "<can_id>:\n"
|
||||
" 3 (SFF) or 8 (EFF) hex chars\n");
|
||||
@@ -70,11 +72,13 @@ void print_usage(char *prg)
|
||||
" 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')\n");
|
||||
fprintf(stderr, "{len}:\n"
|
||||
" an optional 0..8 value as RTR frames can contain a valid dlc field\n");
|
||||
fprintf(stderr, "_{dlc}:\n"
|
||||
" an optional 9..F data length code value when payload length is 8\n");
|
||||
fprintf(stderr, "<flags>:\n"
|
||||
" a single ASCII Hex value (0 .. F) which defines canfd_frame.flags\n\n");
|
||||
fprintf(stderr, "Examples:\n");
|
||||
fprintf(stderr, " 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311223344 /\n"
|
||||
" 1F334455#1122334455667788 / 123#R / 00000123#R3\n\n");
|
||||
" 1F334455#1122334455667788_B / 123#R / 00000123#R3 / 333#R8_E\n\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +147,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||
frame.len = can_dlc2len(can_len2dlc(frame.len));
|
||||
frame.len = can_fd_dlc2len(can_fd_len2dlc(frame.len));
|
||||
}
|
||||
|
||||
/* disable default receive filter on this RAW socket */
|
||||
|
||||
+1
-1
@@ -844,7 +844,7 @@ int sniftab_index(canid_t id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= idx; i++)
|
||||
for (i = 0; i < idx; i++)
|
||||
if (id == sniftab[i].current.can_id)
|
||||
return i;
|
||||
|
||||
|
||||
+24
-14
@@ -84,6 +84,7 @@ typedef __u32 can_err_mask_t;
|
||||
|
||||
/* CAN payload length and DLC definitions according to ISO 11898-1 */
|
||||
#define CAN_MAX_DLC 8
|
||||
#define CAN_MAX_RAW_DLC 15
|
||||
#define CAN_MAX_DLEN 8
|
||||
|
||||
/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
|
||||
@@ -91,23 +92,32 @@ typedef __u32 can_err_mask_t;
|
||||
#define CANFD_MAX_DLEN 64
|
||||
|
||||
/**
|
||||
* struct can_frame - basic CAN frame structure
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @can_dlc: frame payload length in byte (0 .. 8) aka data length code
|
||||
* N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
|
||||
* mapping of the 'data length code' to the real payload length
|
||||
* @__pad: padding
|
||||
* @__res0: reserved / padding
|
||||
* @__res1: reserved / padding
|
||||
* @data: CAN frame payload (up to 8 byte)
|
||||
* struct can_frame - Classical CAN frame structure (aka CAN 2.0B)
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
* @len: CAN frame payload length in byte (0 .. 8)
|
||||
* @can_dlc: deprecated name for CAN frame payload length in byte (0 .. 8)
|
||||
* @__pad: padding
|
||||
* @__res0: reserved / padding
|
||||
* @len8_dlc: optional DLC value (9 .. 15) at 8 byte payload length
|
||||
* len8_dlc contains values from 9 .. 15 when the payload length is
|
||||
* 8 bytes but the DLC value (see ISO 11898-1) is greater then 8.
|
||||
* CAN_CTRLMODE_CC_LEN8_DLC flag has to be enabled in CAN driver.
|
||||
* @data: CAN frame payload (up to 8 byte)
|
||||
*/
|
||||
struct can_frame {
|
||||
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
__u8 can_dlc; /* frame payload length in byte (0 .. CAN_MAX_DLEN) */
|
||||
__u8 __pad; /* padding */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 __res1; /* reserved / padding */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
union {
|
||||
/* CAN frame payload length in byte (0 .. CAN_MAX_DLEN)
|
||||
* was previously named can_dlc so we need to carry that
|
||||
* name for legacy support
|
||||
*/
|
||||
__u8 len;
|
||||
__u8 can_dlc; /* deprecated */
|
||||
};
|
||||
__u8 __pad; /* padding */
|
||||
__u8 __res0; /* reserved / padding */
|
||||
__u8 len8_dlc; /* optional DLC for 8 byte payload length (9 .. 15) */
|
||||
__u8 data[CAN_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -98,8 +98,8 @@ enum {
|
||||
|
||||
/* CAN frame elements that are affected by curr. 3 CAN frame modifications */
|
||||
#define CGW_MOD_ID 0x01
|
||||
#define CGW_MOD_DLC 0x02 /* contains the data length in bytes */
|
||||
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD length representation */
|
||||
#define CGW_MOD_DLC 0x02 /* Classical CAN data length code */
|
||||
#define CGW_MOD_LEN CGW_MOD_DLC /* CAN FD (plain) data length */
|
||||
#define CGW_MOD_DATA 0x04
|
||||
#define CGW_MOD_FLAGS 0x08 /* CAN FD flags */
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ struct can_isotp_ll_options {
|
||||
#define CAN_ISOTP_FORCE_RXSTMIN 0x100 /* ignore CFs depending on rx stmin */
|
||||
#define CAN_ISOTP_RX_EXT_ADDR 0x200 /* different rx extended addressing */
|
||||
#define CAN_ISOTP_WAIT_TX_DONE 0x400 /* wait for tx completion */
|
||||
|
||||
#define CAN_ISOTP_SF_BROADCAST 0x800 /* 1-to-N functional addressing */
|
||||
|
||||
/* default values */
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ struct can_ctrlmode {
|
||||
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
|
||||
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
|
||||
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
|
||||
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
|
||||
|
||||
/*
|
||||
* CAN device statistics
|
||||
|
||||
+8
-2
@@ -72,6 +72,7 @@ void print_usage(char *prg)
|
||||
fprintf(stderr, " -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
|
||||
fprintf(stderr, " -D <len> (send a fixed PDU with len bytes - no STDIN data)\n");
|
||||
fprintf(stderr, " -b (block until the PDU transmission is completed)\n");
|
||||
fprintf(stderr, " -S (SF broadcast mode for functional addressing)\n");
|
||||
fprintf(stderr, " -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
|
||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||
fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
|
||||
@@ -94,7 +95,7 @@ int main(int argc, char **argv)
|
||||
|
||||
addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
|
||||
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bL:?")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:D:bSL:?")) != -1) {
|
||||
switch (opt) {
|
||||
case 's':
|
||||
addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
|
||||
@@ -181,6 +182,10 @@ int main(int argc, char **argv)
|
||||
opts.flags |= CAN_ISOTP_WAIT_TX_DONE;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
opts.flags |= CAN_ISOTP_SF_BROADCAST;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if (sscanf(optarg, "%hhu:%hhu:%hhu",
|
||||
&llopts.mtu,
|
||||
@@ -207,7 +212,8 @@ int main(int argc, char **argv)
|
||||
|
||||
if ((argc - optind != 1) ||
|
||||
(addr.can_addr.tp.tx_id == NO_CAN_ID) ||
|
||||
(addr.can_addr.tp.rx_id == NO_CAN_ID)) {
|
||||
((addr.can_addr.tp.rx_id == NO_CAN_ID) &&
|
||||
(!(opts.flags & CAN_ISOTP_SF_BROADCAST)))) {
|
||||
print_usage(basename(argv[0]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/errqueue.h>
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "lib.h"
|
||||
|
||||
#define CANID_DELIM '#'
|
||||
#define CC_DLC_DELIM '_'
|
||||
#define DATA_SEPERATOR '.'
|
||||
|
||||
const char hex_asc_upper[] = "0123456789ABCDEF";
|
||||
@@ -83,10 +84,10 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
|
||||
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64};
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
unsigned char can_dlc2len(unsigned char can_dlc)
|
||||
/* get data length from raw data length code (DLC) */
|
||||
unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||
{
|
||||
return dlc2len[can_dlc & 0x0F];
|
||||
return dlc2len[dlc & 0x0F];
|
||||
}
|
||||
|
||||
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
@@ -101,7 +102,7 @@ static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
15, 15, 15, 15, 15, 15, 15, 15}; /* 57 - 64 */
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
unsigned char can_len2dlc(unsigned char len)
|
||||
unsigned char can_fd_len2dlc(unsigned char len)
|
||||
{
|
||||
if (len > 64)
|
||||
return 0xF;
|
||||
@@ -195,9 +196,19 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
|
||||
/* check for optional DLC value for CAN 2.0B frames */
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx])) <= CAN_MAX_DLC)
|
||||
if(cs[++idx] && (tmp = asc2nibble(cs[idx++])) <= CAN_MAX_DLEN) {
|
||||
cf->len = tmp;
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if ((tmp == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
tmp = asc2nibble(cs[idx]);
|
||||
if ((tmp > CAN_MAX_DLEN) && (tmp <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -232,6 +243,17 @@ int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||
}
|
||||
cf->len = dlen;
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (dlen == CAN_MAX_DLEN) && (cs[idx++] == CC_DLC_DELIM)) {
|
||||
unsigned char dlc = asc2nibble(cs[idx]);
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
ccf->len8_dlc = dlc;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -270,9 +292,20 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
||||
if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
|
||||
buf[offset++] = 'R';
|
||||
/* print a given CAN 2.0B DLC if it's not zero */
|
||||
if (cf->len && cf->len <= CAN_MAX_DLC)
|
||||
if (cf->len && cf->len <= CAN_MAX_DLEN) {
|
||||
buf[offset++] = hex_asc_upper_lo(cf->len);
|
||||
|
||||
/* check for optional raw DLC value for CAN 2.0B frames */
|
||||
if (cf->len == CAN_MAX_DLEN) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(ccf->len8_dlc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
return;
|
||||
}
|
||||
@@ -292,6 +325,17 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
|
||||
buf[offset++] = '.';
|
||||
}
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((maxdlen == CAN_MAX_DLEN) && (len == CAN_MAX_DLEN)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
unsigned char dlc = ccf->len8_dlc;
|
||||
|
||||
if ((dlc > CAN_MAX_DLEN) && (dlc <= CAN_MAX_RAW_DLC)) {
|
||||
buf[offset++] = CC_DLC_DELIM;
|
||||
buf[offset++] = hex_asc_upper_lo(dlc);
|
||||
}
|
||||
}
|
||||
|
||||
buf[offset] = 0;
|
||||
}
|
||||
|
||||
@@ -337,9 +381,23 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
|
||||
/* The len value is sanitized by maxdlen (see above) */
|
||||
if (maxdlen == CAN_MAX_DLEN) {
|
||||
buf[offset + 1] = '[';
|
||||
buf[offset + 2] = len + '0';
|
||||
buf[offset + 3] = ']';
|
||||
if (view & CANLIB_VIEW_LEN8_DLC) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
unsigned char dlc = ccf->len8_dlc;
|
||||
|
||||
/* fall back to len if we don't have a valid DLC > 8 */
|
||||
if (!((len == CAN_MAX_DLEN) && (dlc > CAN_MAX_DLEN) &&
|
||||
(dlc <= CAN_MAX_RAW_DLC)))
|
||||
dlc = len;
|
||||
|
||||
buf[offset + 1] = '{';
|
||||
buf[offset + 2] = hex_asc_upper[dlc];
|
||||
buf[offset + 3] = '}';
|
||||
} else {
|
||||
buf[offset + 1] = '[';
|
||||
buf[offset + 2] = len + '0';
|
||||
buf[offset + 3] = ']';
|
||||
}
|
||||
|
||||
/* standard CAN frames may have RTR enabled */
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
|
||||
@@ -61,11 +61,11 @@
|
||||
|
||||
/* CAN DLC to real data length conversion helpers especially for CAN FD */
|
||||
|
||||
/* get data length from can_dlc with sanitized can_dlc */
|
||||
unsigned char can_dlc2len(unsigned char can_dlc);
|
||||
/* get data length from raw data length code (DLC) */
|
||||
unsigned char can_fd_dlc2len(unsigned char dlc);
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
unsigned char can_len2dlc(unsigned char len);
|
||||
unsigned char can_fd_len2dlc(unsigned char len);
|
||||
|
||||
unsigned char asc2nibble(char c);
|
||||
/*
|
||||
@@ -99,10 +99,11 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||
/*
|
||||
* Transfers a valid ASCII string describing a CAN frame into struct canfd_frame.
|
||||
*
|
||||
* CAN 2.0 frames
|
||||
* - string layout <can_id>#{R{len}|data}
|
||||
* CAN 2.0 frames (aka Classical CAN)
|
||||
* - string layout <can_id>#{R{len}|data}{_len8_dlc}
|
||||
* - {data} has 0 to 8 hex-values that can (optionally) be separated by '.'
|
||||
* - {len} can take values from 0 to 8 and can be omitted if zero
|
||||
* - {_len8_dlc} can take hex values from '_9' to '_F' when len is CAN_MAX_DLEN
|
||||
* - return value on successful parsing: CAN_MTU
|
||||
*
|
||||
* CAN FD frames
|
||||
@@ -124,10 +125,12 @@ int parse_canframe(char *cs, struct canfd_frame *cf);
|
||||
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R0 -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||
* 123#R7 -> standard CAN-Id = 0x123, len = 7, RTR-frame
|
||||
* 123#R8_9 -> standard CAN-Id = 0x123, len = 8, dlc = 9, RTR-frame
|
||||
* 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
|
||||
*
|
||||
* 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
|
||||
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#1122334455667788_E -> standard CAN-Id = 0x123, len = 8, dlc = 14
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
|
||||
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
|
||||
@@ -155,10 +158,11 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||
* The CAN data[] is separated by '.' when sep != 0.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 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
|
||||
* 12345678#R -> extended CAN-Id = 0x12345678, RTR, len = 0
|
||||
* 12345678#R5 -> extended CAN-Id = 0x12345678, RTR, len = 5
|
||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
|
||||
@@ -178,6 +182,7 @@ void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||
#define CANLIB_VIEW_SWAP 0x4
|
||||
#define CANLIB_VIEW_ERROR 0x8
|
||||
#define CANLIB_VIEW_INDENT_SFF 0x10
|
||||
#define CANLIB_VIEW_LEN8_DLC 0x20
|
||||
|
||||
#define SWAP_DELIMITER '`'
|
||||
|
||||
@@ -187,14 +192,15 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
* Creates a CAN frame hexadecimal output in user readable format.
|
||||
*
|
||||
* The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
|
||||
* maxdlen = 8 -> CAN2.0 frame
|
||||
* maxdlen = 8 -> CAN2.0 frame (aka Classical CAN)
|
||||
* maxdlen = 64 -> CAN FD frame
|
||||
*
|
||||
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, dlc = 3, data
|
||||
* 12345678 [3] 11 22 33 -> extended CAN-Id = 0x12345678, len = 3, data
|
||||
* 12345678 [0] remote request -> extended CAN-Id = 0x12345678, RTR
|
||||
* 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output)
|
||||
* 321 {B} 11 22 33 44 55 66 77 88 -> Classical CAN with raw '{DLC}' value B
|
||||
* 20001111 [7] C6 23 7B 32 69 98 3C ERRORFRAME -> (CAN_ERR_FLAG set)
|
||||
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, dlc = 3
|
||||
* 12345678 [03] 11 22 33 -> CAN FD with extended CAN-Id = 0x12345678, len = 3
|
||||
*
|
||||
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == 0
|
||||
* 123 [3] 11 22 33 -> CANLIB_VIEW_INDENT_SFF == set
|
||||
@@ -204,7 +210,7 @@ void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxd
|
||||
* // CAN FD frame with eol to STDOUT
|
||||
* fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
|
||||
*
|
||||
* // CAN 2.0 frame without eol to STDERR
|
||||
* // Classical CAN 2.0 frame without eol to STDERR
|
||||
* fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -116,6 +116,7 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL
|
||||
char *dir = "Rx";
|
||||
unsigned int flags = 0;
|
||||
unsigned int dlen = cf->len;
|
||||
unsigned int dlc = can_fd_len2dlc(dlen);
|
||||
|
||||
/* relevant flags in Flags field */
|
||||
#define ASC_F_RTR 0x00000010
|
||||
@@ -137,7 +138,16 @@ void canfd_asc(struct canfd_frame *cf, int devno, int mtu, char *extra_info, FIL
|
||||
fprintf(outfile, "%11s ", id);
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_BRS)?'1':'0');
|
||||
fprintf(outfile, "%c ", (cf->flags & CANFD_ESI)?'1':'0');
|
||||
fprintf(outfile, "%x ", can_len2dlc(dlen));
|
||||
|
||||
/* check for extra DLC when having a Classic CAN with 8 bytes payload */
|
||||
if ((mtu == CAN_MTU) && (dlen == CAN_MAX_DLEN)) {
|
||||
struct can_frame *ccf = (struct can_frame *)cf;
|
||||
|
||||
if ((ccf->len8_dlc > CAN_MAX_DLEN) && (ccf->len8_dlc <= CAN_MAX_RAW_DLC))
|
||||
dlc = ccf->len8_dlc;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%x ", dlc);
|
||||
|
||||
if (mtu == CAN_MTU) {
|
||||
if (cf->can_id & CAN_RTR_FLAG) {
|
||||
|
||||
Reference in New Issue
Block a user