X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-utils.git/blobdiff_plain/796475677af173599db655064413f0692c15df3e..HEAD:/candump.c diff --git a/candump.c b/candump.c index 985463b..c983b71 100644 --- a/candump.c +++ b/candump.c @@ -1,7 +1,3 @@ -/* - * $Id$ - */ - /* * candump.c * @@ -41,18 +37,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * - * Send feedback to + * Send feedback to * */ #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -63,10 +61,15 @@ #include #include +#include #include "terminal.h" #include "lib.h" +#ifndef SIOCSHWTSTAMP +# define SIOCSHWTSTAMP 0x89b0 +#endif + #define MAXSOCK 16 /* max. number of CAN interfaces given on the cmdline */ #define MAXIFNAMES 30 /* size of receive name index to omit ioctls */ #define MAXCOL 6 /* number of different colors for colorized output */ @@ -95,9 +98,11 @@ 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; #define MAXANI 4 const char anichar[MAXANI] = {'|', '/', '-', '\\'}; +const char extra_m_info[4][4] = {"- -", "B -", "- E", "B E"}; extern int optind, opterr, optopt; @@ -108,6 +113,7 @@ void print_usage(char *prg) fprintf(stderr, "\nUsage: %s [options] +\n", prg); fprintf(stderr, " (use CTRL-C to terminate %s)\n\n", prg); fprintf(stderr, "Options: -t (timestamp: (a)bsolute/(d)elta/(z)ero/(A)bsolute w date)\n"); + fprintf(stderr, " -H (use hardware timestamping)\n"); fprintf(stderr, " -c (increment color mode level)\n"); fprintf(stderr, " -i (binary output - may exceed 80 chars/line)\n"); fprintf(stderr, " -a (enable additional ASCII output)\n"); @@ -122,6 +128,8 @@ void print_usage(char *prg) fprintf(stderr, " -r (set socket receive buffer to )\n"); fprintf(stderr, " -d (monitor dropped CAN frames)\n"); fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n"); + fprintf(stderr, " -x (print extra message infos, rx/tx brs esi)\n"); + fprintf(stderr, " -T (terminate after without any reception)\n"); fprintf(stderr, "\n"); fprintf(stderr, "Up to %d CAN interfaces with optional filter sets can be specified\n", MAXSOCK); fprintf(stderr, "on the commandline in the form: [,filter]*\n"); @@ -129,6 +137,7 @@ void print_usage(char *prg) fprintf(stderr, " : (matches when & mask == can_id & mask)\n"); fprintf(stderr, " ~ (matches when & mask != can_id & mask)\n"); fprintf(stderr, " # (set error frame filter, see include/linux/can/error.h)\n"); + fprintf(stderr, " [j|J] (join the given CAN filters - logical AND semantic)\n"); fprintf(stderr, "\nCAN IDs, masks and data content are given and expected in hexadecimal values.\n"); fprintf(stderr, "When can_id and can_mask are both 8 digits, they are assumed to be 29 bit EFF.\n"); fprintf(stderr, "Without any given filter all data frames are received ('0:0' default filter).\n"); @@ -204,7 +213,9 @@ int main(int argc, char **argv) int bridge = 0; useconds_t bridge_delay = 0; unsigned char timestamp = 0; + int hw_timestamp = 0; unsigned char dropmonitor = 0; + unsigned char extra_msg_info = 0; unsigned char silent = SILENT_INI; unsigned char silentani = 0; unsigned char color = 0; @@ -215,6 +226,7 @@ int main(int argc, char **argv) int rcvbuf_size = 0; int opt, ret; int currmax, numfilter; + int join_filter; char *ptr, *nptr; struct sockaddr_can addr; char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; @@ -223,10 +235,11 @@ int main(int argc, char **argv) struct cmsghdr *cmsg; struct can_filter *rfilter; can_err_mask_t err_mask; - struct can_frame frame; - int nbytes, i; + struct canfd_frame frame; + int nbytes, i, maxdlen; struct ifreq ifr; struct timeval tv, last_tv; + struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL; FILE *logfile = NULL; signal(SIGTERM, sigterm); @@ -236,7 +249,7 @@ int main(int argc, char **argv) last_tv.tv_sec = 0; last_tv.tv_usec = 0; - while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:ldLn:r:he?")) != -1) { + while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:ldxLn:r:heT:H?")) != -1) { switch (opt) { case 't': timestamp = optarg[0]; @@ -248,6 +261,10 @@ int main(int argc, char **argv) } break; + case 'H': + hw_timestamp = 1; + break; + case 'c': color++; break; @@ -327,6 +344,10 @@ int main(int argc, char **argv) dropmonitor = 1; break; + case 'x': + extra_msg_info = 1; + break; + case 'L': logfrmt = 1; break; @@ -347,6 +368,17 @@ int main(int argc, char **argv) } break; + case 'T': + errno = 0; + timeout_config.tv_usec = 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])); exit(1); @@ -448,6 +480,7 @@ int main(int argc, char **argv) numfilter = 0; err_mask = 0; + join_filter = 0; while (nptr) { @@ -465,6 +498,8 @@ int main(int argc, char **argv) rfilter[numfilter].can_id |= CAN_INV_FILTER; rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG; numfilter++; + } else if (*ptr == 'j' || *ptr == 'J') { + join_filter = 1; } else if (sscanf(ptr, "#%x", &err_mask) != 1) { fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr); return 1; @@ -475,6 +510,12 @@ int main(int argc, char **argv) setsockopt(s[i], 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, + &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, rfilter, numfilter * sizeof(struct can_filter)); @@ -483,6 +524,9 @@ 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)); + if (rcvbuf_size) { int curr_rcvbuf_size; @@ -515,13 +559,36 @@ int main(int argc, char **argv) } if (timestamp || log || logfrmt) { + if (hw_timestamp == 0) { + const int timestamp_on = 1; - const int timestamp_on = 1; + if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP, + ×tamp_on, sizeof(timestamp_on)) < 0) { + perror("setsockopt SO_TIMESTAMP"); + return 1; + } + } else { + struct ifreq hwtstamp; + struct hwtstamp_config hwconfig; + + memset(&hwtstamp, 0, sizeof(hwtstamp)); + strncpy(hwtstamp.ifr_name, ifr.ifr_name, sizeof(hwtstamp.ifr_name)); + hwtstamp.ifr_data = (void *)&hwconfig; + memset(&hwconfig, 0, sizeof(hwconfig)); + hwconfig.tx_type = HWTSTAMP_TX_OFF; + hwconfig.rx_filter = HWTSTAMP_FILTER_ALL; + + if (ioctl(s[i], SIOCSHWTSTAMP, &hwtstamp) < 0) { + perror("SIOCSHWTSTAMP"); + return 1; + } - if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP, - ×tamp_on, sizeof(timestamp_on)) < 0) { - perror("setsockopt SO_TIMESTAMP"); - return 1; + const int so_timestamping_flags = SOF_TIMESTAMPING_RAW_HARDWARE; + + if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMPING, + &so_timestamping_flags, + sizeof(so_timestamping_flags)) < 0) + perror("setsockopt SO_TIMESTAMPING"); } } @@ -587,7 +654,10 @@ int main(int argc, char **argv) for (i=0; icmsg_type == SO_RXQ_OVFL) dropcnt[i] = *(__u32 *)CMSG_DATA(cmsg); + else if (cmsg->cmsg_type == SO_TIMESTAMPING) { + struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg); + tv.tv_sec = ts[2].tv_sec; + tv.tv_usec = ts[2].tv_nsec / 1000; + } + } /* check for (unlikely) dropped frames on this specific socket */ if (dropcnt[i] != last_dropcnt[i]) { - __u32 frames; - - if (dropcnt[i] > last_dropcnt[i]) - frames = dropcnt[i] - last_dropcnt[i]; - else - frames = 4294967295U - last_dropcnt[i] + dropcnt[i]; /* 4294967295U == UINT32_MAX */ + __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", @@ -665,19 +740,28 @@ int main(int argc, char **argv) idx = idx2dindex(addr.can_ifindex, s[i]); + /* once we detected a EFF frame indent SFF frames accordingly */ + if (frame.can_id & CAN_EFF_FLAG) + view |= CANLIB_VIEW_INDENT_SFF; + if (log) { + char buf[CL_CFSZ]; /* max length */ + /* log CAN frame with absolute timestamp & device */ - fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); - fprintf(logfile, "%*s ", max_devname_len, devname[idx]); - /* without seperator as logfile use-case is parsing */ - fprint_canframe(logfile, &frame, "\n", 0); + sprint_canframe(buf, &frame, 0, maxdlen); + fprintf(logfile, "(%010ld.%06ld) %*s %s\n", + tv.tv_sec, tv.tv_usec, + max_devname_len, devname[idx], buf); } if (logfrmt) { + char buf[CL_CFSZ]; /* max length */ + /* print CAN frame in log file style to stdout */ - printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); - printf("%*s ", max_devname_len, devname[idx]); - fprint_canframe(stdout, &frame, "\n", 0); + sprint_canframe(buf, &frame, 0, maxdlen); + printf("(%010ld.%06ld) %*s %s\n", + tv.tv_sec, tv.tv_usec, + max_devname_len, devname[idx], buf); goto out_fflush; /* no other output to stdout */ } @@ -694,7 +778,7 @@ int main(int argc, char **argv) switch (timestamp) { case 'a': /* absolute with timestamp */ - printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); + printf("(%010ld.%06ld) ", tv.tv_sec, tv.tv_usec); break; case 'A': /* absolute with date */ @@ -734,9 +818,18 @@ int main(int argc, char **argv) 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); + fprint_long_canframe(stdout, &frame, NULL, view, maxdlen); printf("%s", (color>1)?col_off:""); printf("\n");