From 796475677af173599db655064413f0692c15df3e Mon Sep 17 00:00:00 2001 From: Wolfgang Grandegger Date: Mon, 14 Feb 2011 15:49:27 +0000 Subject: [PATCH] candump: add option -e to dump error messages in human readable format If "candump" is called with the option "-e", the error messages are dumped in human readable format: # candump -e any,0:0,#FFFFFFFF ... can0 20000088 [8] 00 00 80 19 00 00 00 00 ERRORFRAME protocol-violation{{error-on-tx}{acknowledge-slot}} bus-error error-counter{tx{128}rx{97}} ... can0 2000008C [8] 00 08 80 19 00 00 00 00 ERRORFRAME controller-problem{tx-error-warning} protocol-violation{{error-on-tx}{acknowledge-slot}} bus-error error-counter{tx{128}rx{97}} "candump" actually calles a library function snprintf_can_error_frame() to do the formatting. It could be used for other purposes as well. Signed-off-by: Wolfgang Grandegger Acked-by: Kurt Van Dijck --- candump.c | 7 ++- lib.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- lib.h | 7 +++ 3 files changed, 199 insertions(+), 4 deletions(-) diff --git a/candump.c b/candump.c index 888c0fb..985463b 100644 --- a/candump.c +++ b/candump.c @@ -121,6 +121,7 @@ void print_usage(char *prg) fprintf(stderr, " -n (terminate after receiption of CAN frames)\n"); 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, "\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"); @@ -235,7 +236,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:h?")) != -1) { + while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:ldLn:r:he?")) != -1) { switch (opt) { case 't': timestamp = optarg[0]; @@ -263,6 +264,10 @@ int main(int argc, char **argv) view |= CANLIB_VIEW_SWAP; break; + case 'e': + view |= CANLIB_VIEW_ERROR; + break; + case 's': silent = atoi(optarg); if (silent > SILENT_ON) { diff --git a/lib.c b/lib.c index 0b91488..ba7972e 100644 --- a/lib.c +++ b/lib.c @@ -47,9 +47,11 @@ #include #include +#include #include /* for sa_family_t */ #include +#include #include "lib.h" @@ -57,7 +59,7 @@ #define DATA_SEPERATOR '.' #define MAX_CANFRAME "12345678#01.23.45.67.89.AB.CD.EF" -#define MAX_LONG_CANFRAME "12345678 [8] 10101010 10101010 10101010 10101010 10101010 10101010 10101010 10101010 '........'" +#define MAX_LONG_CANFRAME_SIZE 256 unsigned char asc2nibble(char c) { @@ -208,10 +210,14 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep) { void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view) { /* documentation see lib.h */ - char buf[sizeof(MAX_LONG_CANFRAME)+1]; /* max length */ + char buf[MAX_LONG_CANFRAME_SIZE]; sprint_long_canframe(buf, cf, view); fprintf(stream, "%s", buf); + if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) { + snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t"); + fprintf(stream, "\n\t%s", buf); + } if (eol) fprintf(stream, "%s", eol); } @@ -299,6 +305,183 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) { sprintf(buf+offset, "'"); } - } + } +} + +static const char *error_classes[] = { + "tx-timeout", + "lost-arbitration", + "controller-problem", + "protocol-violation", + "transceiver-status", + "no-acknowledgement-on-tx", + "bus-off", + "bus-error", + "restarted-from-bus-off", +}; + +static const char *controller_problems[] = { + "rx-overflow", + "tx-overflow", + "rx-error-warning", + "tx-error-warning", + "rx-error-passive", + "tx-error-passive", +}; + +static const char *protocol_violation_types[] = { + "single-bit-error", + "frame-format-error", + "bit-stuffing-error", + "tx-dominant-bit-error", + "tx-recessive-bit-error", + "bus-overload", + "back-to-error-active", + "error-on-tx", +}; + +static const char *protocol_violation_locations[] = { + "unspecified", + "unspecified", + "id.28-to-id.28", + "start-of-frame", + "bit-srtr", + "bit-ide", + "id.20-to-id.18", + "id.17-to-id.13", + "crc-sequence", + "reserved-bit-0", + "data-field", + "data-length-code", + "bit-rtr", + "reserved-bit-1", + "id.4-to-id.0", + "id.12-to-id.5", + "unspecified", + "active-error-flag", + "intermission", + "tolerate-dominant-bits", + "unspecified", + "unspecified", + "passive-error-flag", + "error-delimiter", + "crc-delimiter", + "acknowledge-slot", + "end-of-frame", + "acknowledge-delimiter", + "overload-flag", + "unspecified", + "unspecified", + "unspecified", +}; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +static int sprintf_error_data(char *buf, size_t len, uint8_t err, + const char **arr, int arr_len) +{ + int i, n = 0, count = 0; + + if (!err || len <= 0) + return 0; + + for (i = 0; i < arr_len; i++) { + if (err & (1 << i)) { + if (count) + n += snprintf(buf + n, len - n, ","); + n += snprintf(buf + n, len - n, "%s", arr[i]); + count++; + } + } + + return n; +} + +static int sprintf_error_lostarb(char *buf, size_t len, struct can_frame *cf) +{ + if (len <= 0) + return 0; + return snprintf(buf, len, "{at bit %d}", cf->data[0]); +} + +static int sprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf) +{ + int n = 0; + + if (len <= 0) + return 0; + + n += snprintf(buf + n, len - n, "{"); + n += sprintf_error_data(buf + n, len - n, cf->data[1], + controller_problems, + ARRAY_SIZE(controller_problems)); + n += snprintf(buf + n, len - n, "}"); + + return n; } +static int sprintf_error_prot(char *buf, size_t len, struct can_frame *cf) +{ + int n = 0; + + if (len <= 0) + return 0; + + n += snprintf(buf + n, len - n, "{{"); + n += sprintf_error_data(buf + n, len - n, cf->data[2], + protocol_violation_types, + ARRAY_SIZE(protocol_violation_types)); + n += snprintf(buf + n, len - n, "}{"); + if (cf->data[3] > 0 && + cf->data[3] < ARRAY_SIZE(protocol_violation_locations)) + n += snprintf(buf + n, len - n, "%s", + protocol_violation_locations[cf->data[3]]); + n += snprintf(buf + n, len - n, "}}"); + + return n; +} + +void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf, + char* sep) +{ + canid_t class, mask; + int i, n = 0, classes = 0; + char *defsep = ","; + + if (!(cf->can_id & CAN_ERR_FLAG)) + return; + + class = cf->can_id & CAN_EFF_MASK; + if (class > (1 << ARRAY_SIZE(error_classes))) { + fprintf(stderr, "Error class %#x is invalid\n", class); + return; + } + + if (!sep) + sep = defsep; + + for (i = 0; i < ARRAY_SIZE(error_classes); i++) { + mask = 1 << i; + if (class & mask) { + if (classes) + n += snprintf(buf + n, len - n, "%s", sep); + n += snprintf(buf + n, len - n, "%s", error_classes[i]); + if (mask == CAN_ERR_LOSTARB) + n += sprintf_error_lostarb(buf + n, len - n, + cf); + if (mask == CAN_ERR_CRTL) + n += sprintf_error_ctrl(buf + n, len - n, cf); + if (mask == CAN_ERR_PROT) + n += sprintf_error_prot(buf + n, len - n, cf); + classes++; + } + } + + if (cf->data[6] || cf->data[7]) { + n += snprintf(buf + n, len - n, "%s", sep); + n += snprintf(buf + n, len - n, "error-counter-tx-rx{{%d}{%d}}", + cf->data[6], cf->data[7]); + } +} diff --git a/lib.h b/lib.h index cae3d8a..88ecfef 100644 --- a/lib.h +++ b/lib.h @@ -127,6 +127,7 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep); #define CANLIB_VIEW_ASCII 0x1 #define CANLIB_VIEW_BINARY 0x2 #define CANLIB_VIEW_SWAP 0x4 +#define CANLIB_VIEW_ERROR 0x8 #define SWAP_DELIMITER '`' @@ -146,3 +147,9 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view); * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR * */ + +void snprintf_can_error_frame(char *buf, int len, struct can_frame *cf, + char *sep); +/* + * Creates a CAN error frame output in user readable format. + */ -- 2.7.4