On 02/13/2011 04:01 PM, Wolfgang Grandegger wrote: > If "candump" is called with the option "-e", the error messages are > dumped in human readable format:
\o/ - I wanted to have something like this a looong time ago..
>
>
> # 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 sprintf_can_error_frame()
> to do the formatting. It could be used for other purposes as well.
From the signature it's more a s"n"printf function...
>
> Signed-off-by: Wolfgang Grandegger <[email protected]>
>
> ---
> can-utils/candump.c | 7 +
> can-utils/lib.c | 189
> +++++++++++++++++++++++++++++++++++++++++++++++++++-
> can-utils/lib.h | 7 +
> 3 files changed, 199 insertions(+), 4 deletions(-)
>
> Index: trunk/can-utils/candump.c
> ===================================================================
> --- trunk.orig/can-utils/candump.c
> +++ trunk/can-utils/candump.c
> @@ -121,6 +121,7 @@ void print_usage(char *prg)
> fprintf(stderr, " -n <count> (terminate after receiption of
> <count> CAN frames)\n");
> fprintf(stderr, " -r <size> (set socket receive buffer to
> <size>)\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: <ifname>[,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) {
> Index: trunk/can-utils/lib.c
> ===================================================================
> --- trunk.orig/can-utils/lib.c
> +++ trunk/can-utils/lib.c
> @@ -47,9 +47,11 @@
>
> #include <stdio.h>
> #include <string.h>
> +#include <stdint.h>
>
> #include <sys/socket.h> /* for sa_family_t */
> #include <linux/can.h>
> +#include <linux/can/error.h>
>
> #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
> 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) {
> + sprintf_can_error_frame(cf, buf, MAX_LONG_CANFRAME_SIZE,
> "\n\t");
sizeof(buf) or ARRAY_SIZE(buf), please
> + fprintf(stream, "\n\t%s", buf);
> + }
> if (eol)
> fprintf(stream, "%s", eol);
> }
> @@ -299,6 +305,183 @@ void sprint_long_canframe(char *buf , st
>
> sprintf(buf+offset, "'");
> }
> - }
> + }
> +}
> +
> +static const char *error_classes[] = {
> + "tx-timeout",
> + "lost-arbitration",
> + "controller-problem",
> + "protocol-violation",
> + "transceiver-status",
> + "no-ack-on-tx",
> + "buf-off",
> + "bus-error",
> + "recovered-from-bus-error"
> +};
> +
> +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-overoad",
> + "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"
> +};
Please add a "," to the last element.
> +
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
> +#endif
> +
> +static int sprintf_error_data(uint8_t err, const char **arr,
> + int arr_len, char *buf, int 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(struct can_frame *cf, char *buf, int len)
> +{
> + if (len <= 0)
> + return 0;
> + return snprintf(buf, len, "{at bit %d}", cf->data[0]);
> +}
> +
> +static int sprintf_error_ctrl(struct can_frame *cf, char *buf, int len)
> +{
> + int n = 0;
> +
> + if (len <= 0)
> + return 0;
> +
> + n += snprintf(buf + n, len - n, "{");
> + n += sprintf_error_data(cf->data[1], controller_problems,
> + ARRAY_SIZE(controller_problems),
> + buf + n, len - n);
> + n += snprintf(buf + n, len - n, "}");
> +
> + return n;
> }
>
> +static int sprintf_error_prot(struct can_frame *cf, char *buf, int len)
looking at the signature of snprintf:
int snprintf(char *str, size_t size, const char *format, ...);
Then len is not an int, but a size_t. Maybe make the can frame the last
parameter not the first.
> +{
> + int n = 0;
> +
> + if (len <= 0)
> + return 0;
> +
> + n += snprintf(buf + n, len - n, "{{");
> + n += sprintf_error_data(cf->data[2],
> + protocol_violation_types,
> + ARRAY_SIZE(protocol_violation_types),
> + buf + n, len - n);
> + 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 sprintf_can_error_frame(struct can_frame *cf, char *buf, int len, char*
> sep)
The same comment applied here, too
> +{
> + uint32_t class, mask;
We have the "canid" typedef.
> + 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(cf, buf + n,
> + len - n);
> + if (mask == CAN_ERR_CRTL)
> + n += sprintf_error_ctrl(cf, buf + n, len - n);
> + if (mask == CAN_ERR_PROT)
> + n += sprintf_error_prot(cf, buf + n, len - n);
> + 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{%d}rx{%d}}",
> + cf->data[6], cf->data[7]);
> + }
> +}
> Index: trunk/can-utils/lib.h
> ===================================================================
> --- trunk.orig/can-utils/lib.h
> +++ trunk/can-utils/lib.h
> @@ -127,6 +127,7 @@ void sprint_canframe(char *buf , struct
> #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 , st
> * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
> *
> */
> +
> +void sprintf_can_error_frame(struct can_frame *cf, char *buf, int len,
> + char *sep);
> +/*
> + * Creates a CAN error frame output in user readable format.
> + */
> _______________________________________________
> Socketcan-core mailing list
> [email protected]
> https://lists.berlios.de/mailman/listinfo/socketcan-core
regards, Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Socketcan-core mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-core
