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   |

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Socketcan-core mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-core

Reply via email to