]> rtime.felk.cvut.cz Git - sojka/can-utils.git/commitdiff
canfd: upgrade tools to support CAN FD for Linux 3.6
authorOliver Hartkopp <socketcan@hartkopp.net>
Wed, 14 Nov 2012 18:47:21 +0000 (19:47 +0100)
committerOliver Hartkopp <socketcan@hartkopp.net>
Wed, 14 Nov 2012 18:47:21 +0000 (19:47 +0100)
This is a major upgrade of the basic tools to handle CAN FD frames.
The library to parse and print CAN frames and logfiles has been extended.

In detail:

 asc2log.c      |    5 +
 candump.c      |   24 ++++---
 cangen.c       |  172 +++++++++++++++++++++++++++++++++------------------
 canlogserver.c |   28 +++++---
 canplayer.c    |   25 ++++---
 cansend.c      |   55 ++++++++++++----
 lib.c          |  189 ++++++++++++++++++++++++++++++++++++++-------------------
 lib.h          |  109 ++++++++++++++++++++++++--------
 log2asc.c      |    8 +-
 log2long.c     |   26 ++++++-
 10 files changed, 440 insertions(+), 201 deletions(-)

asc2log.c / log2asc.c
- updates for new lib functions
- still can only handle CAN2.0 frames (no new info about ASC file layout)

log2long.c / canlogserver.c / canplayer.c
- updates for new lib functions to handle CAN FD

lib.h / lib.c
- reworked lib functions to handle CAN FD
- parse_canframe() now returns CAN_MTU and CANFD_MTU on success, 0 at failure
- added can_dlc2len() and can_len2dlc() helpers
- moved hexstring2candata to hexstring2data to support simple byte buffers
- in the long CAN frame representation use %03X/%08X instead of %3X/%8X
- introduced unified buffer size definitions for ASCII CAN frames
- updated documentation

cangen.c
- support CAN FD frames (added -f option to create CAN FD frames)
- added -m option ('mix') to create random extended / RTR / CAN FD frames
- fixed the 'fixed data' option which was zero'ing the payload by the time
- updated help text

candump.c
- support CAN FD frames (print, bridge, log)
- distinguish frame types by length info: [0] = CAN2.0 [00] = CAN FD frame

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
asc2log.c
candump.c
cangen.c
canlogserver.c
canplayer.c
cansend.c
lib.c
lib.h
log2asc.c
log2long.c

index 8c0e0a5e5441d1e8c7cfd376c325a658ab1321c8..cc0a7c3439b935891476b3954b875071055afe1e 100644 (file)
--- a/asc2log.c
+++ b/asc2log.c
@@ -73,11 +73,14 @@ void print_usage(char *prg)
 void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
 
        fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
+
        if (dev > 0)
                fprintf(file, "can%d ", dev-1);
        else
                fprintf(file, "canX ");
-       fprint_canframe(file, cf, "\n", 0);
+
+       /* no CAN FD support so far */
+       fprint_canframe(file, (struct canfd_frame *)cf, "\n", 0, CAN_MAX_DLEN);
 }
 
 void get_can_id(struct can_frame *cf, char *idstring, int base) {
index ac51192354b06d76a91d4b4fcbd08ed5e80f9401..11be0aeef1f3084357ec73996e568161a3055bea 100644 (file)
--- a/candump.c
+++ b/candump.c
@@ -95,6 +95,7 @@ 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] = {'|', '/', '-', '\\'};
@@ -223,8 +224,8 @@ 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;
        FILE *logfile = NULL;
@@ -483,6 +484,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;
@@ -611,7 +615,11 @@ int main(int argc, char **argv)
                                        return 1;
                                }
 
-                               if ((size_t)nbytes < sizeof(struct can_frame)) {
+                               if ((size_t)nbytes == CAN_MTU)
+                                       maxdlen = CAN_MAX_DLEN;
+                               else if ((size_t)nbytes == CANFD_MTU)
+                                       maxdlen = CANFD_MAX_DLEN;
+                               else {
                                        fprintf(stderr, "read: incomplete CAN frame\n");
                                        return 1;
                                }
@@ -623,11 +631,11 @@ int main(int argc, char **argv)
                                        if (bridge_delay)
                                                usleep(bridge_delay);
 
-                                       nbytes = write(bridge, &frame, sizeof(struct can_frame));
+                                       nbytes = write(bridge, &frame, nbytes);
                                        if (nbytes < 0) {
                                                perror("bridge write");
                                                return 1;
-                                       } else if ((size_t)nbytes < sizeof(struct can_frame)) {
+                                       } else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) {
                                                fprintf(stderr,"bridge write: incomplete CAN frame\n");
                                                return 1;
                                        }
@@ -670,14 +678,14 @@ int main(int argc, char **argv)
                                        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);
+                                       fprint_canframe(logfile, &frame, "\n", 0, maxdlen);
                                }
 
                                if (logfrmt) {
                                        /* 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);
+                                       fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
                                        goto out_fflush; /* no other output to stdout */
                                }
 
@@ -736,7 +744,7 @@ int main(int argc, char **argv)
                                printf("%*s", max_devname_len, devname[idx]);
                                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");
index efb8251a4b45a522308dc6eb9cd47a7e78224ea6..6cf6c0783da46cfaa764962dec8114eee4d3a804 100644 (file)
--- a/cangen.c
+++ b/cangen.c
@@ -87,6 +87,9 @@ void print_usage(char *prg)
                "- default: %d ms)\n", DEFAULT_GAP);
        fprintf(stderr, "         -e            (generate extended frame mode "
                "(EFF) CAN frames)\n");
+       fprintf(stderr, "         -f            (generate CAN FD CAN frames)\n");
+       fprintf(stderr, "         -R            (send RTR frame)\n");
+       fprintf(stderr, "         -m            (mix -e -f -R frames)\n");
        fprintf(stderr, "         -I <mode>     (CAN ID"
                " generation mode - see below)\n");
        fprintf(stderr, "         -L <mode>     (CAN data length code (dlc)"
@@ -101,7 +104,6 @@ void print_usage(char *prg)
                " write() syscalls)\n");
        fprintf(stderr, "         -x            (disable local loopback of "
                "generated CAN frames)\n");
-       fprintf(stderr, "         -R            (send RTR frame)\n");
        fprintf(stderr, "         -v            (increment verbose level for "
                "printing sent CAN frames)\n\n");
        fprintf(stderr, "Generation modes:\n");
@@ -137,6 +139,8 @@ int main(int argc, char **argv)
        unsigned long polltimeout = 0;
        unsigned char ignore_enobufs = 0;
        unsigned char extended = 0;
+       unsigned char canfd = 0;
+       unsigned char mix = 0;
        unsigned char id_mode = MODE_RANDOM;
        unsigned char data_mode = MODE_RANDOM;
        unsigned char dlc_mode = MODE_RANDOM;
@@ -144,14 +148,17 @@ int main(int argc, char **argv)
        unsigned char verbose = 0;
        unsigned char rtr_frame = 0;
        int count = 0;
+       int mtu, maxdlen;
        uint64_t incdata = 0;
+       int incdlc = 0;
+       unsigned char fixdata[CANFD_MAX_DLEN];
 
        int opt;
        int s; /* socket */
        struct pollfd fds;
 
        struct sockaddr_can addr;
-       static struct can_frame frame;
+       static struct canfd_frame frame;
        int nbytes;
        int i;
        struct ifreq ifr;
@@ -167,7 +174,7 @@ int main(int argc, char **argv)
        signal(SIGHUP, sigterm);
        signal(SIGINT, sigterm);
 
-       while ((opt = getopt(argc, argv, "ig:eI:L:D:xp:n:vRh?")) != -1) {
+       while ((opt = getopt(argc, argv, "ig:efmI:L:D:xp:n:vRh?")) != -1) {
                switch (opt) {
 
                case 'i':
@@ -182,6 +189,15 @@ int main(int argc, char **argv)
                        extended = 1;
                        break;
 
+               case 'f':
+                       canfd = 1;
+                       break;
+
+               case 'm':
+                       mix = 1;
+                       canfd = 1; /* to switch the socket into CAN FD mode */
+                       break;
+
                case 'I':
                        if (optarg[0] == 'r') {
                                id_mode = MODE_RANDOM;
@@ -200,7 +216,7 @@ int main(int argc, char **argv)
                                dlc_mode = MODE_INCREMENT;
                        } else {
                                dlc_mode = MODE_FIX;
-                               frame.can_dlc = atoi(optarg)%9;
+                               frame.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */
                        }
                        break;
 
@@ -211,7 +227,7 @@ int main(int argc, char **argv)
                                data_mode = MODE_INCREMENT;
                        } else {
                                data_mode = MODE_FIX;
-                               if (hexstring2candata(optarg, &frame)) {
+                               if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) {
                                        printf ("wrong fix data definition\n");
                                        return 1;
                                }
@@ -259,30 +275,13 @@ int main(int argc, char **argv)
        ts.tv_sec = gap / 1000;
        ts.tv_nsec = ((int)(gap * 1000000)) % 1000000000;
 
-       if (id_mode == MODE_FIX) {
-
-               /* recognize obviously missing commandline option */
-               if ((frame.can_id > 0x7FF) && !extended) {
-                       printf("The given CAN-ID is greater than 0x7FF and "
-                              "the '-e' option is not set.\n");
-                       return 1;
-               }
-
-               if (extended)
-                       frame.can_id &= CAN_EFF_MASK;
-               else
-                       frame.can_id &= CAN_SFF_MASK;
+       /* recognize obviously missing commandline option */
+       if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
+               printf("The given CAN-ID is greater than 0x7FF and "
+                      "the '-e' option is not set.\n");
+               return 1;
        }
 
-       if (rtr_frame)
-               frame.can_id |= CAN_RTR_FLAG;
-
-       if (extended)
-               frame.can_id |=  CAN_EFF_FLAG;
-
-       if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
-               frame.can_dlc = 1; /* min dlc value for incr. data */
-
        if (strlen(argv[optind]) >= IFNAMSIZ) {
                printf("Name of CAN device '%s' is too long!\n\n", argv[optind]);
                return 1;
@@ -315,6 +314,34 @@ int main(int argc, char **argv)
                           &loopback, sizeof(loopback));
        }
 
+       if (canfd) {
+               int enable_canfd = 1;
+
+               /* check if the frame fits into the CAN netdevice */
+               if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+                       perror("SIOCGIFMTU");
+                       return 1;
+               }
+
+               if (ifr.ifr_mtu != CANFD_MTU) {
+                       printf("CAN interface ist not CAN FD capable - sorry.\n");
+                       return 1;
+               }
+
+               /* interface is ok - try to switch the socket into CAN FD mode */
+               if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))){
+                       printf("error when enabling CAN FD support\n");
+                       return 1;
+               }
+
+               /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
+               frame.len = can_dlc2len(can_len2dlc(frame.len));
+       } else {
+               /* sanitize CAN 2.0 frame length */
+               if (frame.len > 8)
+                       frame.len = 8;
+       }
+
        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                perror("bind");
                return 1;
@@ -330,51 +357,73 @@ int main(int argc, char **argv)
                if (count && (--count == 0))
                        running = 0;
 
-               if (id_mode == MODE_RANDOM) {
+               if (canfd){
+                       mtu = CANFD_MTU;
+                       maxdlen = CANFD_MAX_DLEN;
+               } else {
+                       mtu = CAN_MTU;
+                       maxdlen = CAN_MAX_DLEN;
+               }
 
+               if (id_mode == MODE_RANDOM)
                        frame.can_id = random();
 
-                       if (extended) {
-                               frame.can_id &= CAN_EFF_MASK;
-                               frame.can_id |= CAN_EFF_FLAG;
-                       } else
-                               frame.can_id &= CAN_SFF_MASK;
-               }
-
-               if (dlc_mode == MODE_RANDOM) {
+               if (extended) {
+                       frame.can_id &= CAN_EFF_MASK;
+                       frame.can_id |= CAN_EFF_FLAG;
+               } else
+                       frame.can_id &= CAN_SFF_MASK;
 
-                       frame.can_dlc = random() & 0xF;
+               if (rtr_frame && !canfd)
+                       frame.can_id |= CAN_RTR_FLAG;
 
-                       if (frame.can_dlc & 8)
-                               frame.can_dlc = 8; /* for about 50% of the frames */
+               if (dlc_mode == MODE_RANDOM) {
 
-                       if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
-                               frame.can_dlc = 1; /* min dlc value for incr. data */
+                       if (canfd)
+                               frame.len = can_dlc2len(random() & 0xF);
+                       else {
+                               frame.len = random() & 0xF;
+                               if (frame.len & 8)
+                                       frame.len = 8; /* for about 50% of the frames */
+                       }
                }
 
+               if (data_mode == MODE_INCREMENT && !frame.len)
+                       frame.len = 1; /* min dlc value for incr. data */
+
                if (data_mode == MODE_RANDOM) {
 
                        /* that's what the 64 bit alignment of data[] is for ... :) */
                        *(unsigned long*)(&frame.data[0]) = random();
                        *(unsigned long*)(&frame.data[4]) = random();
+
+                       /* omit extra random number generation for CAN FD */
+                       if (canfd && frame.len > 8) {
+                               memcpy(&frame.data[8], &frame.data[0], 8);
+                               memcpy(&frame.data[16], &frame.data[0], 16);
+                               memcpy(&frame.data[32], &frame.data[0], 32);
+                       }
                }
 
+               if (data_mode == MODE_FIX)
+                       memcpy(frame.data, fixdata, CANFD_MAX_DLEN);
+
                /* set unused payload data to zero like the CAN driver does it on rx */
-               if (frame.can_dlc < 8)
-                       memset(&frame.data[frame.can_dlc], 0, 8 - frame.can_dlc);
+               if (frame.len < maxdlen)
+                       memset(&frame.data[frame.len], 0, maxdlen - frame.len);
 
                if (verbose) {
 
                        printf("  %s  ", argv[optind]);
 
                        if (verbose > 1)
-                               fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0);
+                               fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0, maxdlen);
                        else
-                               fprint_canframe(stdout, &frame, "\n", 1);
+                               fprint_canframe(stdout, &frame, "\n", 1, maxdlen);
                }
 
 resend:
-               nbytes = write(s, &frame, sizeof(struct can_frame));
+               nbytes = write(s, &frame, mtu);
                if (nbytes < 0) {
                        if (errno != ENOBUFS) {
                                perror("write");
@@ -394,7 +443,7 @@ resend:
                        } else
                                enobufs_count++;
 
-               } else if (nbytes < sizeof(struct can_frame)) {
+               } else if (nbytes < mtu) {
                        fprintf(stderr, "write: incomplete CAN frame\n");
                        return 1;
                }
@@ -403,24 +452,20 @@ resend:
                        if (nanosleep(&ts, NULL))
                                return 1;
                    
-               if (id_mode == MODE_INCREMENT) {
-
+               if (id_mode == MODE_INCREMENT)
                        frame.can_id++;
 
-                       if (extended) {
-                               frame.can_id &= CAN_EFF_MASK;
-                               frame.can_id |= CAN_EFF_FLAG;
-                       } else
-                               frame.can_id &= CAN_SFF_MASK;
-               }
-
                if (dlc_mode == MODE_INCREMENT) {
 
-                       frame.can_dlc++;
-                       frame.can_dlc %= 9;
+                       incdlc++;
 
-                       if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
-                               frame.can_dlc = 1; /* min dlc value for incr. data */
+                       if (canfd && !mix) {
+                               incdlc &= 0xF;
+                               frame.len = can_dlc2len(incdlc);
+                       } else {
+                               incdlc %= 9;
+                               frame.len = incdlc;
+                       }
                }
 
                if (data_mode == MODE_INCREMENT) {
@@ -430,6 +475,13 @@ resend:
                        for (i=0; i<8 ;i++)
                                frame.data[i] = (incdata >> i*8) & 0xFFULL;
                }
+
+               if (mix) {
+                       i = random();
+                       extended = i&1;
+                       canfd = i&2;
+                       rtr_frame = ((i&12) == 12); /* reduce RTR frames to 1/4 */
+               }
        }
 
        if (enobufs_count)
index b6fa40305592ac548f85b7dd70acc510260a13df..6aeb150e4b089a61d593701f2a41895dfa4a6f78 100644 (file)
@@ -74,6 +74,9 @@
 #define ANYDEV "any"
 #define ANL "\r\n" /* newline in ASC mode */
 
+#define COMMENTSZ 200
+#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
+
 #define DEFPORT 28700
 
 static char devname[MAXDEV][IFNAMSIZ+1];
@@ -183,15 +186,16 @@ int main(int argc, char **argv)
        int currmax = 1; /* we assume at least one can bus ;-) */
        struct sockaddr_can addr;
        struct can_filter rfilter;
-       struct can_frame frame;
-       int nbytes, i, j;
+       struct canfd_frame frame;
+       const int canfd_on = 1;
+       int nbytes, i, j, maxdlen;
        struct ifreq ifr;
        struct timeval tv, last_tv;
        int port = DEFPORT;
        struct sockaddr_in inaddr;
        struct sockaddr_in clientaddr;
        socklen_t sin_size = sizeof(clientaddr);
-       char temp[128];
+       char temp[BUFSZ];
 
        sigemptyset(&sigset);
        signalaction.sa_handler = &childdied;
@@ -339,6 +343,9 @@ int main(int argc, char **argv)
                        setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
                                   &err_mask[i], sizeof(err_mask[i]));
 
+               /* try to switch the socket into CAN FD mode */
+               setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
+
                j = strlen(argv[optind+i]);
 
                if (!(j < IFNAMSIZ)) {
@@ -387,14 +394,17 @@ int main(int argc, char **argv)
                                socklen_t len = sizeof(addr);
                                int idx;
 
-                               if ((nbytes = recvfrom(s[i], &frame,
-                                                      sizeof(struct can_frame), 0,
+                               if ((nbytes = recvfrom(s[i], &frame, CANFD_MTU, 0,
                                                       (struct sockaddr*)&addr, &len)) < 0) {
                                        perror("read");
                                        return 1;
                                }
 
-                               if (nbytes < sizeof(struct can_frame)) {
+                               if ((size_t)nbytes == CAN_MTU)
+                                       maxdlen = CAN_MAX_DLEN;
+                               else if ((size_t)nbytes == CANFD_MTU)
+                                       maxdlen = CANFD_MAX_DLEN;
+                               else {
                                        fprintf(stderr, "read: incomplete CAN frame\n");
                                        return 1;
                                }
@@ -407,7 +417,7 @@ int main(int argc, char **argv)
 
                                sprintf(temp, "(%ld.%06ld) %*s ",
                                        tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]);
-                               sprint_canframe(temp+strlen(temp), &frame, 0); 
+                               sprint_canframe(temp+strlen(temp), &frame, 0, maxdlen); 
                                strcat(temp, "\n");
 
                                if (write(accsocket, temp, strlen(temp)) < 0) {
@@ -415,13 +425,11 @@ int main(int argc, char **argv)
                                        return 1;
                                }
                    
-                               /* printf("%s\n",temp2); */
-
 #if 0
                                /* 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);
+                               fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
 #endif
                        }
 
index b0b63334e711ceebd56dd9b1fddf535d226fb637..7952177293022a5099e03888543c2fe93da31251 100644 (file)
@@ -64,7 +64,8 @@
 #define DEFAULT_GAP    1       /* ms */
 #define DEFAULT_LOOPS  1       /* only one replay */
 #define CHANNELS       20      /* anyone using more than 20 CAN interfaces at a time? */
-#define BUFSZ          400     /* for one line in the logfile */
+#define COMMENTSZ 200
+#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
 #define STDOUTIDX      65536   /* interface index for printing on stdout - bigger than max uint16 */
 
 struct assignment {
@@ -73,6 +74,7 @@ struct assignment {
        char rxif[IFNAMSIZ];
 };
 static struct assignment asgn[CHANNELS];
+const int canfd_on = 1;
 
 extern int optind, opterr, optopt;
 
@@ -236,7 +238,7 @@ int main(int argc, char **argv)
 {
        static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
        struct sockaddr_can addr;
-       static struct can_frame frame;
+       static struct canfd_frame frame;
        static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
        struct timespec sleep_ts;
        int s; /* CAN_RAW socket */
@@ -249,7 +251,7 @@ int main(int argc, char **argv)
        static int loops = DEFAULT_LOOPS;
        int assignments; /* assignments defined on the commandline */
        int txidx;       /* sendto() interface index */
-       int eof, nbytes, i, j;
+       int eof, txmtu, i, j;
        char *fret;
 
        while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) {
@@ -333,6 +335,9 @@ int main(int argc, char **argv)
        /* disable unneeded default receive filter on this RAW socket */
        setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
 
+       /* try to switch the socket into CAN FD mode */
+       setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
+
        if (loopback_disable) {
                int loopback = 0;
 
@@ -432,7 +437,8 @@ int main(int argc, char **argv)
 
                                } else if (txidx > 0) { /* only send to valid CAN devices */
 
-                                       if (parse_canframe(ascframe, &frame)) {
+                                       txmtu = parse_canframe(ascframe, &frame);
+                                       if (!txmtu) {
                                                fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe);
                                                return 1;
                                        }
@@ -440,17 +446,18 @@ int main(int argc, char **argv)
                                        addr.can_family  = AF_CAN;
                                        addr.can_ifindex = txidx; /* send via this interface */
  
-                                       nbytes = sendto(s, &frame, sizeof(struct can_frame), 0,
-                                                       (struct sockaddr*)&addr, sizeof(addr));
-
-                                       if (nbytes != sizeof(struct can_frame)) {
+                                       if (sendto(s, &frame, txmtu, 0, (struct sockaddr*)&addr, sizeof(addr)) != txmtu) {
                                                perror("sendto");
                                                return 1;
                                        }
 
                                        if (verbose) {
                                                printf("%s (%s) ", get_txname(device), device);
-                                               fprint_long_canframe(stdout, &frame, "\n", 1);
+
+                                               if (txmtu == CAN_MTU)
+                                                       fprint_long_canframe(stdout, &frame, "\n", 0, CAN_MAX_DLEN);
+                                               else
+                                                       fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
                                        }
                                }
 
index 9be216337cfff5f5c5fa441b2532901562cf97b2..d4620e5d0a26e17670adc4163bc926c360916447 100644 (file)
--- a/cansend.c
+++ b/cansend.c
 int main(int argc, char **argv)
 {
        int s; /* can raw socket */ 
-       int nbytes;
+       int required_mtu;
+       int mtu;
+       int enable_canfd = 1;
        struct sockaddr_can addr;
-       struct can_frame frame;
+       struct canfd_frame frame;
        struct ifreq ifr;
 
        /* check command line options */
@@ -74,14 +76,18 @@ int main(int argc, char **argv)
        }
 
        /* parse CAN frame */
-       if (parse_canframe(argv[2], &frame)){
-               fprintf(stderr, "\nWrong CAN-frame format!\n\n");
-               fprintf(stderr, "Try: <can_id>#{R|data}\n");
-               fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n");
-               fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)");
-               fprintf(stderr, " be seperated by '.'\n\n");
-               fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / ");
-               fprintf(stderr, "5AA# /\n     1F334455#1122334455667788 / 123#R ");
+       required_mtu = parse_canframe(argv[2], &frame);
+       if (!required_mtu){
+               fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
+               fprintf(stderr, "    <can_id>#{R|data}          for CAN 2.0 frames\n");
+               fprintf(stderr, "    <can_id>##<flags>{data}    for CAN FD frames\n\n");
+               fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
+               fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
+               fprintf(stderr, " seperated by '.')\n");
+               fprintf(stderr, "<flags> a single ASCII Hex value (0 .. F) which defines");
+               fprintf(stderr, " canfd_frame.flags\n\n");
+               fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / ");
+               fprintf(stderr, "123##1 / 213##311\n     1F334455#1122334455667788 / 123#R ");
                fprintf(stderr, "for remote transmission request.\n\n");
                return 1;
        }
@@ -101,6 +107,31 @@ int main(int argc, char **argv)
        }
        addr.can_ifindex = ifr.ifr_ifindex;
 
+       if (required_mtu > CAN_MTU) {
+
+               /* check if the frame fits into the CAN netdevice */
+               if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
+                       perror("SIOCGIFMTU");
+                       return 1;
+               }
+               mtu = ifr.ifr_mtu;
+
+               if (mtu != CANFD_MTU) {
+                       printf("CAN interface ist not CAN FD capable - sorry.\n");
+                       return 1;
+               }
+
+               /* interface is ok - try to switch the socket into CAN FD mode */
+               if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
+                              &enable_canfd, sizeof(enable_canfd))){
+                       printf("error when enabling CAN FD support\n");
+                       return 1;
+               }
+
+               /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
+               frame.len = can_dlc2len(can_len2dlc(frame.len));
+       }
+
        /* disable default receive filter on this RAW socket */
        /* This is obsolete as we do not read from the socket at all, but for */
        /* this reason we can remove the receive list in the Kernel to save a */
@@ -113,13 +144,11 @@ int main(int argc, char **argv)
        }
 
        /* send frame */
-       if ((nbytes = write(s, &frame, sizeof(frame))) != sizeof(frame)) {
+       if (write(s, &frame, required_mtu) != required_mtu) {
                perror("write");
                return 1;
        }
 
-       //fprint_long_canframe(stdout, &frame, "\n", 0);
-
        close(s);
 
        return 0;
diff --git a/lib.c b/lib.c
index 5738f2b0f37713eca51c2e13737e81a120697240..927f064117533432c7b64bd72694ae0f7f34941d 100644 (file)
--- a/lib.c
+++ b/lib.c
 #define CANID_DELIM '#'
 #define DATA_SEPERATOR '.'
 
-#define MAX_CANFRAME      "12345678#01.23.45.67.89.AB.CD.EF"
-#define MAX_LONG_CANFRAME_SIZE 256
+/* CAN DLC to real data length conversion helpers */
+
+static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
+                                       8, 12, 16, 20, 24, 32, 48, 64};
+
+/* get data length from can_dlc with sanitized can_dlc */
+unsigned char can_dlc2len(unsigned char can_dlc)
+{
+       return dlc2len[can_dlc & 0x0F];
+}
+
+static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8,             /* 0 - 8 */
+                                       9, 9, 9, 9,                             /* 9 - 12 */
+                                       10, 10, 10, 10,                         /* 13 - 16 */
+                                       11, 11, 11, 11,                         /* 17 - 20 */
+                                       12, 12, 12, 12,                         /* 21 - 24 */
+                                       13, 13, 13, 13, 13, 13, 13, 13,         /* 25 - 32 */
+                                       14, 14, 14, 14, 14, 14, 14, 14,         /* 33 - 40 */
+                                       14, 14, 14, 14, 14, 14, 14, 14,         /* 41 - 48 */
+                                       15, 15, 15, 15, 15, 15, 15, 15,         /* 49 - 56 */
+                                       15, 15, 15, 15, 15, 15, 15, 15};        /* 57 - 64 */
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_len2dlc(unsigned char len)
+{
+       if (len > 64)
+               return 0xF;
+
+       return len2dlc[len];
+}
 
 unsigned char asc2nibble(char c) {
 
@@ -75,53 +103,57 @@ unsigned char asc2nibble(char c) {
        return 16; /* error */
 }
 
-int hexstring2candata(char *arg, struct can_frame *cf) {
+int hexstring2data(char *arg, unsigned char *data, int maxdlen) {
 
        int len = strlen(arg);
        int i;
        unsigned char tmp;
 
-       if (!len || len%2 || len > 16)
+       if (!len || len%2 || len > maxdlen*2)
                return 1;
 
+       memset(data, 0, maxdlen);
+
        for (i=0; i < len/2; i++) {
 
                tmp = asc2nibble(*(arg+(2*i)));
                if (tmp > 0x0F)
                        return 1;
 
-               cf->data[i] = (tmp << 4);
+               data[i] = (tmp << 4);
 
                tmp = asc2nibble(*(arg+(2*i)+1));
                if (tmp > 0x0F)
                        return 1;
 
-               cf->data[i] |= tmp;
+               data[i] |= tmp;
        }
 
        return 0;
 }
 
-int parse_canframe(char *cs, struct can_frame *cf) {
+int parse_canframe(char *cs, struct canfd_frame *cf) {
        /* documentation see lib.h */
 
-       int i, idx, dlc, len;
+       int i, idx, dlen, len;
+       int maxdlen = CAN_MAX_DLEN;
+       int ret = CAN_MTU;
        unsigned char tmp;
 
        len = strlen(cs);
        //printf("'%s' len %d\n", cs, len);
 
-       memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */
+       memset(cf, 0, sizeof(*cf)); /* init CAN FD frame, e.g. LEN = 0 */
 
        if (len < 4)
-               return 1;
+               return 0;
 
        if (cs[3] == CANID_DELIM) { /* 3 digits */
 
                idx = 4;
                for (i=0; i<3; i++){
                        if ((tmp = asc2nibble(cs[i])) > 0x0F)
-                               return 1;
+                               return 0;
                        cf->can_id |= (tmp << (2-i)*4);
                }
 
@@ -130,21 +162,34 @@ int parse_canframe(char *cs, struct can_frame *cf) {
                idx = 9;
                for (i=0; i<8; i++){
                        if ((tmp = asc2nibble(cs[i])) > 0x0F)
-                               return 1;
+                               return 0;
                        cf->can_id |= (tmp << (7-i)*4);
                }
                if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
                        cf->can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
 
        } else
-               return 1;
+               return 0;
 
        if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
                cf->can_id |= CAN_RTR_FLAG;
-               return 0;
+               return ret;
+       }
+
+       if (cs[idx] == CANID_DELIM) { /* CAN FD frame escape char '##' */
+
+               maxdlen = CANFD_MAX_DLEN;
+               ret = CANFD_MTU;
+
+               /* CAN FD frame <canid>##<flags><data>* */
+               if ((tmp = asc2nibble(cs[idx+1])) > 0x0F)
+                       return 0;
+
+               cf->flags = tmp;
+               idx += 2;
        }
 
-       for (i=0, dlc=0; i<8; i++){
+       for (i=0, dlen=0; i < maxdlen; i++){
 
                if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
                        idx++;
@@ -153,35 +198,34 @@ int parse_canframe(char *cs, struct can_frame *cf) {
                        break;
 
                if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
-                       return 1;
+                       return 0;
                cf->data[i] = (tmp << 4);
                if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
-                       return 1;
+                       return 0;
                cf->data[i] |= tmp;
-               dlc++;
+               dlen++;
        }
+       cf->len = dlen;
 
-       cf->can_dlc = dlc;
-
-       return 0;
+       return ret;
 }
 
-void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep) {
+void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen) {
        /* documentation see lib.h */
 
-       char buf[sizeof(MAX_CANFRAME)+1]; /* max length */
+       char buf[CL_CFSZ]; /* max length */
 
-       sprint_canframe(buf, cf, sep);
+       sprint_canframe(buf, cf, sep, maxdlen);
        fprintf(stream, "%s", buf);
        if (eol)
                fprintf(stream, "%s", eol);
 }
 
-void sprint_canframe(char *buf , struct can_frame *cf, int sep) {
+void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen) {
        /* documentation see lib.h */
 
        int i,offset;
-       int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc;
+       int len = (cf->len > maxdlen) ? maxdlen : cf->len;
 
        if (cf->can_id & CAN_ERR_FLAG) {
                sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
@@ -194,25 +238,34 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep) {
                offset = 4;
        }
 
-       if (cf->can_id & CAN_RTR_FLAG) /* there are no ERR frames with RTR */
+       /* standard CAN frames may have RTR enabled. There are no ERR frames with RTR */
+       if (maxdlen == CAN_MAX_DLEN && cf->can_id & CAN_RTR_FLAG) {
                sprintf(buf+offset, "R");
-       else
-               for (i = 0; i < dlc; i++) {
-                       sprintf(buf+offset, "%02X", cf->data[i]);
-                       offset += 2;
-                       if (sep && (i+1 < dlc))
-                               sprintf(buf+offset++, ".");
-               }
+               return;
+       }
 
+       if (maxdlen == CANFD_MAX_DLEN) {
+               /* add CAN FD specific escape char and flags */
+               sprintf(buf+offset, "#%X", cf->flags & 0xF);
+               offset += 2;
+               if (sep && len)
+                       sprintf(buf+offset++, ".");
+       }
 
+       for (i = 0; i < len; i++) {
+               sprintf(buf+offset, "%02X", cf->data[i]);
+               offset += 2;
+               if (sep && (i+1 < len))
+                       sprintf(buf+offset++, ".");
+       }
 }
 
-void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view) {
+void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen) {
        /* documentation see lib.h */
 
-       char buf[MAX_LONG_CANFRAME_SIZE];
+       char buf[CL_LONGCFSZ];
 
-       sprint_long_canframe(buf, cf, view);
+       sprint_long_canframe(buf, cf, view, maxdlen);
        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");
@@ -222,41 +275,45 @@ void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int vi
                fprintf(stream, "%s", eol);
 }
 
-void sprint_long_canframe(char *buf , struct can_frame *cf, int view) {
+void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen) {
        /* documentation see lib.h */
 
        int i, j, dlen, offset;
-       int dlc = (cf->can_dlc > 8)? 8 : cf->can_dlc;
+       int len = (cf->len > maxdlen)? maxdlen : cf->len;
 
        if (cf->can_id & CAN_ERR_FLAG) {
-               sprintf(buf, "%8X  ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
+               sprintf(buf, "%08X  ", cf->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG));
                offset = 10;
        } else if (cf->can_id & CAN_EFF_FLAG) {
-               sprintf(buf, "%8X  ", cf->can_id & CAN_EFF_MASK);
+               sprintf(buf, "%08X  ", cf->can_id & CAN_EFF_MASK);
                offset = 10;
        } else {
-               sprintf(buf, "%3X  ", cf->can_id & CAN_SFF_MASK);
+               sprintf(buf, "%03X  ", cf->can_id & CAN_SFF_MASK);
                offset = 5;
        }
 
-       sprintf(buf+offset, "[%d]", dlc);
-       offset += 3;
-
-       if (cf->can_id & CAN_RTR_FLAG) { /* there are no ERR frames with RTR */
-               sprintf(buf+offset, " remote request");
-               return;
+       if (maxdlen == CAN_MAX_DLEN) {
+               sprintf(buf+offset, " [%d] ", len);
+               /* standard CAN frames may have RTR enabled */
+               if (cf->can_id & CAN_RTR_FLAG) {
+                       sprintf(buf+offset+5, " remote request");
+                       return;
+               }
+       } else {
+               sprintf(buf+offset, "[%02d] ", len);
        }
+       offset += 5;
 
        if (view & CANLIB_VIEW_BINARY) {
                dlen = 9; /* _10101010 */
                if (view & CANLIB_VIEW_SWAP) {
-                       for (i = dlc - 1; i >= 0; i--) {
-                               buf[offset++] = (i == dlc-1)?' ':SWAP_DELIMITER;
+                       for (i = len - 1; i >= 0; i--) {
+                               buf[offset++] = (i == len-1)?' ':SWAP_DELIMITER;
                                for (j = 7; j >= 0; j--)
                                        buf[offset++] = (1<<j & cf->data[i])?'1':'0';
                        }
                } else {
-                       for (i = 0; i < dlc; i++) {
+                       for (i = 0; i < len; i++) {
                                buf[offset++] = ' ';
                                for (j = 7; j >= 0; j--)
                                        buf[offset++] = (1<<j & cf->data[i])?'1':'0';
@@ -266,28 +323,36 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) {
        } else {
                dlen = 3; /* _AA */
                if (view & CANLIB_VIEW_SWAP) {
-                       for (i = dlc - 1; i >= 0; i--) {
+                       for (i = len - 1; i >= 0; i--) {
                                sprintf(buf+offset, "%c%02X",
-                                       (i == dlc-1)?' ':SWAP_DELIMITER,
+                                       (i == len-1)?' ':SWAP_DELIMITER,
                                        cf->data[i]);
                                offset += dlen;
                        }
                } else {
-                       for (i = 0; i < dlc; i++) {
+                       for (i = 0; i < len; i++) {
                                sprintf(buf+offset, " %02X", cf->data[i]);
                                offset += dlen;
                        }
                }
        }
 
+       /*
+        * The ASCII & ERRORFRAME output is put at a fixed len behind the data.
+        * For now we support ASCII output only for payload length up to 8 bytes.
+        * Does it make sense to write 64 ASCII byte behind 64 ASCII HEX data on the console?
+        */
+       if (len > CAN_MAX_DLEN)
+               return;
+
        if (cf->can_id & CAN_ERR_FLAG)
-               sprintf(buf+offset, "%*s", dlen*(8-dlc)+13, "ERRORFRAME");
+               sprintf(buf+offset, "%*s", dlen*(8-len)+13, "ERRORFRAME");
        else if (view & CANLIB_VIEW_ASCII) {
-               j = dlen*(8-dlc)+4;
+               j = dlen*(8-len)+4;
                if (view & CANLIB_VIEW_SWAP) {
                        sprintf(buf+offset, "%*s", j, "`");
                        offset += j;
-                       for (i = dlc - 1; i >= 0; i--)
+                       for (i = len - 1; i >= 0; i--)
                                if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
                                        buf[offset++] = cf->data[i];
                                else
@@ -297,7 +362,7 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) {
                } else {
                        sprintf(buf+offset, "%*s", j, "'");
                        offset += j;
-                       for (i = 0; i < dlc; i++)
+                       for (i = 0; i < len; i++)
                                if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
                                        buf[offset++] = cf->data[i];
                                else
@@ -399,14 +464,14 @@ static int snprintf_error_data(char *buf, size_t len, uint8_t err,
        return n;
 }
 
-static int snprintf_error_lostarb(char *buf, size_t len, struct can_frame *cf)
+static int snprintf_error_lostarb(char *buf, size_t len, struct canfd_frame *cf)
 {
        if (len <= 0)
                return 0;
        return snprintf(buf, len, "{at bit %d}", cf->data[0]);
 }
 
-static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf)
+static int snprintf_error_ctrl(char *buf, size_t len, struct canfd_frame *cf)
 {
        int n = 0;
 
@@ -422,7 +487,7 @@ static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf)
        return n;
 }
 
-static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf)
+static int snprintf_error_prot(char *buf, size_t len, struct canfd_frame *cf)
 {
        int n = 0;
 
@@ -443,7 +508,7 @@ static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf)
        return n;
 }
 
-void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf,
+void snprintf_can_error_frame(char *buf, size_t len, struct canfd_frame *cf,
                              char* sep)
 {
        canid_t class, mask;
diff --git a/lib.h b/lib.h
index 8ef34bbfcfc49d5ea1c6d8cb461be22280c5d53f..695498b0ea86e4d2f7939449670ac08cc37aff67 100644 (file)
--- a/lib.h
+++ b/lib.h
  *
  */
 
+/* buffer sizes for CAN frame string representations */
+
+#define CL_ID (sizeof("12345678##1"))
+#define CL_DATA sizeof(".AA")
+#define CL_BINDATA sizeof(".10101010")
+
+ /* CAN FD ASCII hex short representation with DATA_SEPERATORs */
+#define CL_CFSZ (2*CL_ID + 64*CL_DATA)
+
+/* CAN FD ASCII hex long representation with binary output */
+#define CL_LONGCFSZ (2*CL_ID + sizeof("   [255]  ") + (64*CL_BINDATA))
+
+/* CAN DLC to real data length conversion helpers especially for CAN FD */
+
+/* get data length from can_dlc with sanitized can_dlc */
+unsigned char can_dlc2len(unsigned char can_dlc);
+
+/* map the sanitized data length to an appropriate data length code */
+unsigned char can_len2dlc(unsigned char len);
+
 unsigned char asc2nibble(char c);
 /*
  * Returns the decimal value of a given ASCII hex character.
@@ -53,9 +73,9 @@ unsigned char asc2nibble(char c);
  * On invalid characters the value 16 is returned for error handling.
  */
 
-int hexstring2candata(char *arg, struct can_frame *cf);
+int hexstring2data(char *arg, unsigned char *data, int maxdlen);
 /*
- * Converts a given ASCII hex string to values in the can_frame data[].
+ * Converts a given ASCII hex string to a (binary) byte string.
  *
  * A valid ASCII hex string consists of an even number of up to 16 chars.
  * Leading zeros '00' in the ASCII hex string are interpreted.
@@ -69,53 +89,76 @@ int hexstring2candata(char *arg, struct can_frame *cf);
  * 0 = success
  * 1 = error (in length or the given characters are no ASCII hex characters)
  *
- * Remark: The not written data[] elements remain unchanged.
+ * Remark: The not written data[] elements are initialized with zero.
  *
  */
 
-int parse_canframe(char *cs, struct can_frame *cf);
+int parse_canframe(char *cs, struct canfd_frame *cf);
 /*
- * Transfers a valid ASCII string decribing a CAN frame into struct can_frame.
+ * Transfers a valid ASCII string decribing a CAN frame into struct canfd_frame.
  *
- * <can_id>#{R|data}
+ * CAN 2.0 frames
+ * - string layout <can_id>#{R|data}
+ * - {data} has 0 to 8 hex-values that can (optionally) be seperated by '.'
+ * - return value on successful parsing: CAN_MTU
  *
- * can_id can have 3 (standard frame format) or 8 (extended frame format)
- *        hexadecimal chars
+ * CAN FD frames
+ * - string layout <can_id>##<flags>{data}
+ * - <flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
+ * - {data} has 0 to 64 hex-values that can (optionally) be seperated by '.'
+ * - return value on successful parsing: CANFD_MTU
+ *
+ * Return value on detected problems: 0
+ *
+ * <can_id> can have 3 (standard frame format) or 8 (extended frame format)
+ * hexadecimal chars
  *
- * data has 0 to 8 hex-values that can (optionally) be seperated by '.'
  *
  * Examples:
  *
- * 123# -> standard CAN-Id = 0x123, dlc = 0
- * 12345678# -> extended CAN-Id = 0x12345678, dlc = 0
- * 123#R -> standard CAN-Id = 0x123, dlc = 0, RTR-frame
- * 7A1#r -> standard CAN-Id = 0x7A1, dlc = 0, RTR-frame
+ * 123# -> standard CAN-Id = 0x123, len = 0
+ * 12345678# -> extended CAN-Id = 0x12345678, len = 0
+ * 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
+ * 7A1#r -> standard CAN-Id = 0x7A1, len = 0, RTR-frame
  *
- * 123#00 -> standard CAN-Id = 0x123, dlc = 1, data[0] = 0x00
- * 123#1122334455667788 -> standard CAN-Id = 0x123, dlc = 8
- * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8
- * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, dlc = 8
+ * 123#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
+ * 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
+ * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, len = 8
+ * 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
  * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
  *
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##1112233 -> CAN FD frame, flags = CANFD_BRS, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
+ * 123##3 -> CAN FD frame, flags = (CANFD_ESI | CANFD_BRS), len = 0
+ *     ^^
+ *     CAN FD extension to handle the canfd_frame.flags content
+ *
  * Simple facts on this compact ASCII CAN frame representation:
  *
  * - 3 digits: standard frame format
  * - 8 digits: extendend frame format OR error frame
  * - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
  * - an error frame is never a RTR frame
- * 
+ * - CAN FD frames do not have a RTR bit
  */
 
-void fprint_canframe(FILE *stream , struct can_frame *cf, char *eol, int sep);
-void sprint_canframe(char *buf , struct can_frame *cf, int sep);
+void fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen);
+void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
 /*
  * Creates a CAN frame hexadecimal output in compact format.
  * The CAN data[] is seperated by '.' when sep != 0.
  *
+ * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
+ * maxdlen = 8 -> CAN2.0 frame
+ * maxdlen = 64 -> CAN FD frame
+ *
  * 12345678#112233 -> exended CAN-Id = 0x12345678, dlc = 3, data, sep = 0
  * 12345678#R -> exended CAN-Id = 0x12345678, RTR
  * 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
  * 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
+ * 123##0112233 -> CAN FD frame standard CAN-Id = 0x123, flags = 0, len = 3
+ * 123##2112233 -> CAN FD frame, flags = CANFD_ESI, len = 3
  *
  * Examples:
  *
@@ -131,24 +174,32 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep);
 
 #define SWAP_DELIMITER '`'
 
-void fprint_long_canframe(FILE *stream , struct can_frame *cf, char *eol, int view);
-void sprint_long_canframe(char *buf , struct can_frame *cf, int view);
+void fprint_long_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int view, int maxdlen);
+void sprint_long_canframe(char *buf , struct canfd_frame *cf, int view, int maxdlen);
 /*
  * Creates a CAN frame hexadecimal output in user readable format.
  *
- * 12345678  [3] 11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data
- * 12345678  [0] remote request -> exended CAN-Id = 0x12345678, RTR
- * 14B0DC51  [8] 4A 94 E8 2A EC 58 55 62   'J..*.XUb' -> (with ASCII output)
- * 20001111  [7] C6 23 7B 32 69 98 3C      ERRORFRAME -> (CAN_ERR_FLAG set)
+ * The type of the CAN frame (CAN 2.0 / CAN FD) is specified by maxdlen:
+ * maxdlen = 8 -> CAN2.0 frame
+ * maxdlen = 64 -> CAN FD frame
+ *
+ * 12345678   [3]  11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data
+ * 12345678   [0]  remote request -> exended CAN-Id = 0x12345678, RTR
+ * 14B0DC51   [8]  4A 94 E8 2A EC 58 55 62   'J..*.XUb' -> (with ASCII output)
+ * 20001111   [7]  C6 23 7B 32 69 98 3C      ERRORFRAME -> (CAN_ERR_FLAG set)
+ * 12345678  [03]  11 22 33 -> CAN FD with exended CAN-Id = 0x12345678, dlc = 3
  *
  * Examples:
  *
- * fprint_long_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
- * fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
+ * // CAN FD frame with eol to STDOUT
+ * fprint_long_canframe(stdout, &frame, "\n", 0, CANFD_MAX_DLEN);
+ *
+ * // CAN 2.0 frame without eol to STDERR
+ * fprint_long_canframe(stderr, &frame, NULL, 0, CAN_MAX_DLEN);
  *
  */
 
-void snprintf_can_error_frame(char *buf, size_t len, struct can_frame *cf,
+void snprintf_can_error_frame(char *buf, size_t len, struct canfd_frame *cf,
                              char *sep);
 /*
  * Creates a CAN error frame output in user readable format.
index 899f0d2eaf8c429afe64fb0485beb66f4709a8a4..029cd4980f65613fe4ac7f924f1864592b4a8e9b 100644 (file)
--- a/log2asc.c
+++ b/log2asc.c
@@ -73,7 +73,7 @@ int main(int argc, char **argv)
 {
        static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
 
-       struct can_frame cf;
+       struct canfd_frame cf;
        static struct timeval tv, start_tv;
        FILE *infile = stdin;
        FILE *outfile = stdout;
@@ -162,7 +162,7 @@ int main(int argc, char **argv)
                }
 
                if (devno) { /* only convert for selected CAN devices */
-                       if (parse_canframe(ascframe, &cf))
+                       if (parse_canframe(ascframe, &cf) != CAN_MTU) /* no CAN FD support so far */
                                return 1;
 
                        tv.tv_sec  = tv.tv_sec - start_tv.tv_sec;
@@ -189,9 +189,9 @@ int main(int argc, char **argv)
                                if (cf.can_id & CAN_RTR_FLAG)
                                        fprintf(outfile, "r"); /* RTR frame */
                                else {
-                                       fprintf(outfile, "d %d", cf.can_dlc); /* data frame */
+                                       fprintf(outfile, "d %d", cf.len); /* data frame */
                    
-                                       for (i = 0; i < cf.can_dlc; i++) {
+                                       for (i = 0; i < cf.len; i++) {
                                                fprintf(outfile, " %02X", cf.data[i]);
                                        }
                                }
index 795aaa530a4a9e17ec4fb1e57010674bcc6cfe57..297d43f13d7cd0fe6fea8e27958a6a53dc7d86db 100644 (file)
 
 #include "lib.h"
 
+#define COMMENTSZ 200
+#define BUFSZ (sizeof("(1345212884.318850)") + IFNAMSIZ + 4 + CL_CFSZ + COMMENTSZ) /* for one line in the logfile */
+
 int main(int argc, char **argv)
 {
-       char buf[100], timestamp[100], device[100], ascframe[100];
-       struct can_frame cf;
+       char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
+       struct canfd_frame cf;
+       int mtu, maxdlen;
 
-       while (fgets(buf, 99, stdin)) {
+       while (fgets(buf, BUFSZ-1, stdin)) {
                if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3)
                        return 1;
-               if (parse_canframe(ascframe, &cf))
+
+               mtu = parse_canframe(ascframe, &cf);
+               if (mtu == CAN_MTU)
+                       maxdlen = CAN_MAX_DLEN;
+               else if (mtu == CANFD_MTU)
+                       maxdlen = CANFD_MAX_DLEN;
+               else {
+                       fprintf(stderr, "read: incomplete CAN frame\n");
                        return 1;
-               sprint_long_canframe(ascframe, &cf, 1); /* with ASCII output */
+               }
+
+               sprint_long_canframe(ascframe, &cf,
+                                    CANLIB_VIEW_ASCII,
+                                    maxdlen); /* with ASCII output */
+
                printf("%s  %s  %s\n", timestamp, device, ascframe);
        }