]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - can-utils/lib.c
Add kernel version depency for Kernel 3.1.x which extended __rtnl_register().
[socketcan-devel.git] / can-utils / lib.c
1 /*
2  *  $Id$
3  */
4
5 /*
6  * lib.c - library for command line tools
7  *
8  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of Volkswagen nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * Alternatively, provided that this notice is retained in full, this
24  * software may be distributed under the terms of the GNU General
25  * Public License ("GPL") version 2, in which case the provisions of the
26  * GPL apply INSTEAD OF those given above.
27  *
28  * The provided data structures and external interfaces from this code
29  * are not restricted to be used by modules with a GPL compatible license.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
37  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
41  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
42  * DAMAGE.
43  *
44  * Send feedback to <socketcan-users@lists.berlios.de>
45  *
46  */
47
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdint.h>
51
52 #include <sys/socket.h> /* for sa_family_t */
53 #include <linux/can.h>
54 #include <linux/can/error.h>
55
56 #include "lib.h"
57
58 #define CANID_DELIM '#'
59 #define DATA_SEPERATOR '.'
60
61 #define MAX_CANFRAME      "12345678#01.23.45.67.89.AB.CD.EF"
62 #define MAX_LONG_CANFRAME_SIZE 256
63
64 unsigned char asc2nibble(char c) {
65
66         if ((c >= '0') && (c <= '9'))
67                 return c - '0';
68
69         if ((c >= 'A') && (c <= 'F'))
70                 return c - 'A' + 10;
71
72         if ((c >= 'a') && (c <= 'f'))
73                 return c - 'a' + 10;
74
75         return 16; /* error */
76 }
77
78 int hexstring2candata(char *arg, struct can_frame *cf) {
79
80         int len = strlen(arg);
81         int i;
82         unsigned char tmp;
83
84         if (!len || len%2 || len > 16)
85                 return 1;
86
87         for (i=0; i < len/2; i++) {
88
89                 tmp = asc2nibble(*(arg+(2*i)));
90                 if (tmp > 0x0F)
91                         return 1;
92
93                 cf->data[i] = (tmp << 4);
94
95                 tmp = asc2nibble(*(arg+(2*i)+1));
96                 if (tmp > 0x0F)
97                         return 1;
98
99                 cf->data[i] |= tmp;
100         }
101
102         return 0;
103 }
104
105 int parse_canframe(char *cs, struct can_frame *cf) {
106         /* documentation see lib.h */
107
108         int i, idx, dlc, len;
109         unsigned char tmp;
110
111         len = strlen(cs);
112         //printf("'%s' len %d\n", cs, len);
113
114         memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */
115
116         if (len < 4)
117                 return 1;
118
119         if (cs[3] == CANID_DELIM) { /* 3 digits */
120
121                 idx = 4;
122                 for (i=0; i<3; i++){
123                         if ((tmp = asc2nibble(cs[i])) > 0x0F)
124                                 return 1;
125                         cf->can_id |= (tmp << (2-i)*4);
126                 }
127
128         } else if (cs[8] == CANID_DELIM) { /* 8 digits */
129
130                 idx = 9;
131                 for (i=0; i<8; i++){
132                         if ((tmp = asc2nibble(cs[i])) > 0x0F)
133                                 return 1;
134                         cf->can_id |= (tmp << (7-i)*4);
135                 }
136                 if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
137                         cf->can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
138
139         } else
140                 return 1;
141
142         if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
143                 cf->can_id |= CAN_RTR_FLAG;
144                 return 0;
145         }
146
147         for (i=0, dlc=0; i<8; i++){
148
149                 if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
150                         idx++;
151
152                 if(idx >= len) /* end of string => end of data */
153                         break;
154
155                 if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
156                         return 1;
157                 cf->data[i] = (tmp << 4);
158                 if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
159                         return 1;
160                 cf->data[i] |= tmp;
161                 dlc++;
162         }
163
164         cf->can_dlc = dlc;
165
166         return 0;
167 }
168
169 void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep) {
170         /* documentation see lib.h */
171
172         char buf[sizeof(MAX_CANFRAME)+1]; /* max length */
173
174         sprint_canframe(buf, cf, sep);
175         fprintf(stream, "%s", buf);
176         if (eol)
177                 fprintf(stream, "%s", eol);
178 }
179
180 void sprint_canframe(char *buf , struct can_frame *cf, int sep) {
181         /* documentation see lib.h */
182
183         int i,offset;
184         int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc;
185
186         if (cf->can_id & CAN_ERR_FLAG) {
187                 sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
188                 offset = 9;
189         } else if (cf->can_id & CAN_EFF_FLAG) {
190                 sprintf(buf, "%08X#", cf->can_id & CAN_EFF_MASK);
191                 offset = 9;
192         } else {
193                 sprintf(buf, "%03X#", cf->can_id & CAN_SFF_MASK);
194                 offset = 4;
195         }
196
197         if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */
198                 sprintf(buf+offset, "R");
199         else
200                 for (i = 0; i < dlc; i++) {
201                         sprintf(buf+offset, "%02X", cf->data[i]);
202                         offset += 2;
203                         if (sep && (i+1 < dlc))
204                                 sprintf(buf+offset++, ".");
205                 }
206
207
208 }
209
210 void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view) {
211         /* documentation see lib.h */
212
213         char buf[MAX_LONG_CANFRAME_SIZE];
214
215         sprint_long_canframe(buf, cf, view);
216         fprintf(stream, "%s", buf);
217         if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) {
218                 snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
219                 fprintf(stream, "\n\t%s", buf);
220         }
221         if (eol)
222                 fprintf(stream, "%s", eol);
223 }
224
225 void sprint_long_canframe(char *buf , struct can_frame *cf, int view) {
226         /* documentation see lib.h */
227
228         int i, j, dlen, offset;
229         int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc;
230
231         if (cf->can_id & CAN_ERR_FLAG) {
232                 sprintf(buf, "%8X  ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
233                 offset = 10;
234         } else if (cf->can_id & CAN_EFF_FLAG) {
235                 sprintf(buf, "%8X  ", cf->can_id & CAN_EFF_MASK);
236                 offset = 10;
237         } else {
238                 sprintf(buf, "%3X  ", cf->can_id & CAN_SFF_MASK);
239                 offset = 5;
240         }
241
242         sprintf(buf+offset, "[%d]", dlc);
243         offset += 3;
244
245         if (cf->can_id & CAN_RTR_FLAG) { /* there are no ERR frames with RTR */
246                 sprintf(buf+offset, " remote request");
247                 return;
248         }
249
250         if (view & CANLIB_VIEW_BINARY) {
251                 dlen = 9; /* _10101010 */
252                 if (view & CANLIB_VIEW_SWAP) {
253                         for (i = dlc - 1; i >= 0; i--) {
254                                 buf[offset++] = (i == dlc-1)?' ':SWAP_DELIMITER;
255                                 for (j = 7; j >= 0; j--)
256                                         buf[offset++] = (1<<j & cf->data[i])?'1':'0';
257                         }
258                 } else {
259                         for (i = 0; i < dlc; i++) {
260                                 buf[offset++] = ' ';
261                                 for (j = 7; j >= 0; j--)
262                                         buf[offset++] = (1<<j & cf->data[i])?'1':'0';
263                         }
264                 }
265                 buf[offset] = 0; /* terminate string */
266         } else {
267                 dlen = 3; /* _AA */
268                 if (view & CANLIB_VIEW_SWAP) {
269                         for (i = dlc - 1; i >= 0; i--) {
270                                 sprintf(buf+offset, "%c%02X",
271                                         (i == dlc-1)?' ':SWAP_DELIMITER,
272                                         cf->data[i]);
273                                 offset += dlen;
274                         }
275                 } else {
276                         for (i = 0; i < dlc; i++) {
277                                 sprintf(buf+offset, " %02X", cf->data[i]);
278                                 offset += dlen;
279                         }
280                 }
281         }
282
283         if (cf->can_id & CAN_ERR_FLAG)
284                 sprintf(buf+offset, "%*s", dlen*(8-dlc)+13, "ERRORFRAME");
285         else if (view & CANLIB_VIEW_ASCII) {
286                 j = dlen*(8-dlc)+4;
287                 if (view & CANLIB_VIEW_SWAP) {
288                         sprintf(buf+offset, "%*s", j, "`");
289                         offset += j;
290                         for (i = dlc - 1; i >= 0; i--)
291                                 if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
292                                         buf[offset++] = cf->data[i];
293                                 else
294                                         buf[offset++] = '.';
295
296                         sprintf(buf+offset, "`");
297                 } else {
298                         sprintf(buf+offset, "%*s", j, "'");
299                         offset += j;
300                         for (i = 0; i < dlc; i++)
301                                 if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
302                                         buf[offset++] = cf->data[i];
303                                 else
304                                         buf[offset++] = '.';
305
306                         sprintf(buf+offset, "'");
307                 }
308         }
309 }
310
311 static const char *error_classes[] = {
312         "tx-timeout",
313         "lost-arbitration",
314         "controller-problem",
315         "protocol-violation",
316         "transceiver-status",
317         "no-acknowledgement-on-tx",
318         "bus-off",
319         "bus-error",
320         "restarted-after-bus-off",
321 };
322
323 static const char *controller_problems[] = {
324         "rx-overflow",
325         "tx-overflow",
326         "rx-error-warning",
327         "tx-error-warning",
328         "rx-error-passive",
329         "tx-error-passive",
330 };
331
332 static const char *protocol_violation_types[] = {
333         "single-bit-error",
334         "frame-format-error",
335         "bit-stuffing-error",
336         "tx-dominant-bit-error",
337         "tx-recessive-bit-error",
338         "bus-overload",
339         "back-to-error-active",
340         "error-on-tx",
341 };
342
343 static const char *protocol_violation_locations[] = {
344         "unspecified",
345         "unspecified",
346         "id.28-to-id.28",
347         "start-of-frame",
348         "bit-srtr",
349         "bit-ide",
350         "id.20-to-id.18",
351         "id.17-to-id.13",
352         "crc-sequence",
353         "reserved-bit-0",
354         "data-field",
355         "data-length-code",
356         "bit-rtr",
357         "reserved-bit-1",
358         "id.4-to-id.0",
359         "id.12-to-id.5",
360         "unspecified",
361         "active-error-flag",
362         "intermission",
363         "tolerate-dominant-bits",
364         "unspecified",
365         "unspecified",
366         "passive-error-flag",
367         "error-delimiter",
368         "crc-delimiter",
369         "acknowledge-slot",
370         "end-of-frame",
371         "acknowledge-delimiter",
372         "overload-flag",
373         "unspecified",
374         "unspecified",
375         "unspecified",
376 };
377
378 #ifndef ARRAY_SIZE
379 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
380 #endif
381
382 static int snprintf_error_data(char *buf, size_t len, uint8_t err,
383                                const char **arr, int arr_len)
384 {
385         int i, n = 0, count = 0;
386
387         if (!err || len <= 0)
388                 return 0;
389
390         for (i = 0; i < arr_len; i++) {
391                 if (err & (1 << i)) {
392                         if (count)
393                                 n += snprintf(buf + n, len - n, ",");
394                         n += snprintf(buf + n, len - n, "%s", arr[i]);
395                         count++;
396                 }
397         }
398
399         return n;
400 }
401
402 static int snprintf_error_lostarb(char *buf, size_t len, struct can_frame *cf)
403 {
404         if (len <= 0)
405                 return 0;
406         return snprintf(buf, len, "{at bit %d}", cf->data[0]);
407 }
408
409 static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf)
410 {
411         int n = 0;
412
413         if (len <= 0)
414                 return 0;
415
416         n += snprintf(buf + n, len - n, "{");
417         n += snprintf_error_data(buf + n, len - n, cf->data[1],
418                                 controller_problems,
419                                 ARRAY_SIZE(controller_problems));
420         n += snprintf(buf + n, len - n, "}");
421
422         return n;
423 }
424
425 static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf)
426 {
427         int n = 0;
428
429         if (len <= 0)
430                 return 0;
431
432         n += snprintf(buf + n, len - n, "{{");
433         n += snprintf_error_data(buf + n, len - n, cf->data[2],
434                                 protocol_violation_types,
435                                 ARRAY_SIZE(protocol_violation_types));
436         n += snprintf(buf + n, len - n, "}{");
437         if (cf->data[3] > 0 &&
438             cf->data[3] < ARRAY_SIZE(protocol_violation_locations))
439                 n += snprintf(buf + n, len - n, "%s",
440                               protocol_violation_locations[cf->data[3]]);
441         n += snprintf(buf + n, len - n, "}}");
442
443         return n;
444 }
445
446 void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf,
447                               char* sep)
448 {
449         canid_t class, mask;
450         int i, n = 0, classes = 0;
451         char *defsep = ",";
452
453         if (!(cf->can_id & CAN_ERR_FLAG))
454                 return;
455
456         class = cf->can_id & CAN_EFF_MASK;
457         if (class > (1 << ARRAY_SIZE(error_classes))) {
458                 fprintf(stderr, "Error class %#x is invalid\n", class);
459                 return;
460         }
461
462         if (!sep)
463                 sep = defsep;
464
465         for (i = 0; i < ARRAY_SIZE(error_classes); i++) {
466                 mask = 1 << i;
467                 if (class & mask) {
468                         if (classes)
469                                 n += snprintf(buf + n, len - n, "%s", sep);
470                         n += snprintf(buf + n, len - n, "%s", error_classes[i]);
471                         if (mask == CAN_ERR_LOSTARB)
472                                 n += snprintf_error_lostarb(buf + n, len - n,
473                                                            cf);
474                         if (mask == CAN_ERR_CRTL)
475                                 n += snprintf_error_ctrl(buf + n, len - n, cf);
476                         if (mask == CAN_ERR_PROT)
477                                 n += snprintf_error_prot(buf + n, len - n, cf);
478                         classes++;
479                 }
480         }
481
482         if (cf->data[6] || cf->data[7]) {
483                 n += snprintf(buf + n, len - n, "%s", sep);
484                 n += snprintf(buf + n, len - n, "error-counter-tx-rx{{%d}{%d}}",
485                               cf->data[6], cf->data[7]);
486         }
487 }