canfd: upgrade tools to support CAN FD for Linux 3.6
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>
pull/7/head
parent
a2b13452c7
commit
e7631bd7f9
|
|
@ -73,11 +73,14 @@ void print_usage(char *prg)
|
||||||
void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
|
void prframe(FILE *file, struct timeval *tv, int dev, struct can_frame *cf) {
|
||||||
|
|
||||||
fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
fprintf(file, "(%ld.%06ld) ", tv->tv_sec, tv->tv_usec);
|
||||||
|
|
||||||
if (dev > 0)
|
if (dev > 0)
|
||||||
fprintf(file, "can%d ", dev-1);
|
fprintf(file, "can%d ", dev-1);
|
||||||
else
|
else
|
||||||
fprintf(file, "canX ");
|
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) {
|
void get_can_id(struct can_frame *cf, char *idstring, int base) {
|
||||||
|
|
|
||||||
24
candump.c
24
candump.c
|
|
@ -95,6 +95,7 @@ static __u32 last_dropcnt[MAXSOCK];
|
||||||
static char devname[MAXIFNAMES][IFNAMSIZ+1];
|
static char devname[MAXIFNAMES][IFNAMSIZ+1];
|
||||||
static int dindex[MAXIFNAMES];
|
static int dindex[MAXIFNAMES];
|
||||||
static int max_devname_len; /* to prevent frazzled device name output */
|
static int max_devname_len; /* to prevent frazzled device name output */
|
||||||
|
const int canfd_on = 1;
|
||||||
|
|
||||||
#define MAXANI 4
|
#define MAXANI 4
|
||||||
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
|
const char anichar[MAXANI] = {'|', '/', '-', '\\'};
|
||||||
|
|
@ -223,8 +224,8 @@ int main(int argc, char **argv)
|
||||||
struct cmsghdr *cmsg;
|
struct cmsghdr *cmsg;
|
||||||
struct can_filter *rfilter;
|
struct can_filter *rfilter;
|
||||||
can_err_mask_t err_mask;
|
can_err_mask_t err_mask;
|
||||||
struct can_frame frame;
|
struct canfd_frame frame;
|
||||||
int nbytes, i;
|
int nbytes, i, maxdlen;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct timeval tv, last_tv;
|
struct timeval tv, last_tv;
|
||||||
FILE *logfile = NULL;
|
FILE *logfile = NULL;
|
||||||
|
|
@ -483,6 +484,9 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
} /* if (nptr) */
|
} /* 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) {
|
if (rcvbuf_size) {
|
||||||
|
|
||||||
int curr_rcvbuf_size;
|
int curr_rcvbuf_size;
|
||||||
|
|
@ -611,7 +615,11 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
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");
|
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -623,11 +631,11 @@ int main(int argc, char **argv)
|
||||||
if (bridge_delay)
|
if (bridge_delay)
|
||||||
usleep(bridge_delay);
|
usleep(bridge_delay);
|
||||||
|
|
||||||
nbytes = write(bridge, &frame, sizeof(struct can_frame));
|
nbytes = write(bridge, &frame, nbytes);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
perror("bridge write");
|
perror("bridge write");
|
||||||
return 1;
|
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");
|
fprintf(stderr,"bridge write: incomplete CAN frame\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -670,14 +678,14 @@ int main(int argc, char **argv)
|
||||||
fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||||
fprintf(logfile, "%*s ", max_devname_len, devname[idx]);
|
fprintf(logfile, "%*s ", max_devname_len, devname[idx]);
|
||||||
/* without seperator as logfile use-case is parsing */
|
/* without seperator as logfile use-case is parsing */
|
||||||
fprint_canframe(logfile, &frame, "\n", 0);
|
fprint_canframe(logfile, &frame, "\n", 0, maxdlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logfrmt) {
|
if (logfrmt) {
|
||||||
/* print CAN frame in log file style to stdout */
|
/* print CAN frame in log file style to stdout */
|
||||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||||
printf("%*s ", max_devname_len, devname[idx]);
|
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 */
|
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", max_devname_len, devname[idx]);
|
||||||
printf("%s ", (color==1)?col_off:"");
|
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("%s", (color>1)?col_off:"");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
|
||||||
154
cangen.c
154
cangen.c
|
|
@ -87,6 +87,9 @@ void print_usage(char *prg)
|
||||||
"- default: %d ms)\n", DEFAULT_GAP);
|
"- default: %d ms)\n", DEFAULT_GAP);
|
||||||
fprintf(stderr, " -e (generate extended frame mode "
|
fprintf(stderr, " -e (generate extended frame mode "
|
||||||
"(EFF) CAN frames)\n");
|
"(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"
|
fprintf(stderr, " -I <mode> (CAN ID"
|
||||||
" generation mode - see below)\n");
|
" generation mode - see below)\n");
|
||||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
|
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
|
||||||
|
|
@ -101,7 +104,6 @@ void print_usage(char *prg)
|
||||||
" write() syscalls)\n");
|
" write() syscalls)\n");
|
||||||
fprintf(stderr, " -x (disable local loopback of "
|
fprintf(stderr, " -x (disable local loopback of "
|
||||||
"generated CAN frames)\n");
|
"generated CAN frames)\n");
|
||||||
fprintf(stderr, " -R (send RTR frame)\n");
|
|
||||||
fprintf(stderr, " -v (increment verbose level for "
|
fprintf(stderr, " -v (increment verbose level for "
|
||||||
"printing sent CAN frames)\n\n");
|
"printing sent CAN frames)\n\n");
|
||||||
fprintf(stderr, "Generation modes:\n");
|
fprintf(stderr, "Generation modes:\n");
|
||||||
|
|
@ -137,6 +139,8 @@ int main(int argc, char **argv)
|
||||||
unsigned long polltimeout = 0;
|
unsigned long polltimeout = 0;
|
||||||
unsigned char ignore_enobufs = 0;
|
unsigned char ignore_enobufs = 0;
|
||||||
unsigned char extended = 0;
|
unsigned char extended = 0;
|
||||||
|
unsigned char canfd = 0;
|
||||||
|
unsigned char mix = 0;
|
||||||
unsigned char id_mode = MODE_RANDOM;
|
unsigned char id_mode = MODE_RANDOM;
|
||||||
unsigned char data_mode = MODE_RANDOM;
|
unsigned char data_mode = MODE_RANDOM;
|
||||||
unsigned char dlc_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 verbose = 0;
|
||||||
unsigned char rtr_frame = 0;
|
unsigned char rtr_frame = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
int mtu, maxdlen;
|
||||||
uint64_t incdata = 0;
|
uint64_t incdata = 0;
|
||||||
|
int incdlc = 0;
|
||||||
|
unsigned char fixdata[CANFD_MAX_DLEN];
|
||||||
|
|
||||||
int opt;
|
int opt;
|
||||||
int s; /* socket */
|
int s; /* socket */
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
|
|
||||||
struct sockaddr_can addr;
|
struct sockaddr_can addr;
|
||||||
static struct can_frame frame;
|
static struct canfd_frame frame;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
int i;
|
int i;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
@ -167,7 +174,7 @@ int main(int argc, char **argv)
|
||||||
signal(SIGHUP, sigterm);
|
signal(SIGHUP, sigterm);
|
||||||
signal(SIGINT, 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) {
|
switch (opt) {
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
|
|
@ -182,6 +189,15 @@ int main(int argc, char **argv)
|
||||||
extended = 1;
|
extended = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
canfd = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
mix = 1;
|
||||||
|
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||||
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
if (optarg[0] == 'r') {
|
if (optarg[0] == 'r') {
|
||||||
id_mode = MODE_RANDOM;
|
id_mode = MODE_RANDOM;
|
||||||
|
|
@ -200,7 +216,7 @@ int main(int argc, char **argv)
|
||||||
dlc_mode = MODE_INCREMENT;
|
dlc_mode = MODE_INCREMENT;
|
||||||
} else {
|
} else {
|
||||||
dlc_mode = MODE_FIX;
|
dlc_mode = MODE_FIX;
|
||||||
frame.can_dlc = atoi(optarg)%9;
|
frame.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -211,7 +227,7 @@ int main(int argc, char **argv)
|
||||||
data_mode = MODE_INCREMENT;
|
data_mode = MODE_INCREMENT;
|
||||||
} else {
|
} else {
|
||||||
data_mode = MODE_FIX;
|
data_mode = MODE_FIX;
|
||||||
if (hexstring2candata(optarg, &frame)) {
|
if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) {
|
||||||
printf ("wrong fix data definition\n");
|
printf ("wrong fix data definition\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -259,30 +275,13 @@ int main(int argc, char **argv)
|
||||||
ts.tv_sec = gap / 1000;
|
ts.tv_sec = gap / 1000;
|
||||||
ts.tv_nsec = ((int)(gap * 1000000)) % 1000000000;
|
ts.tv_nsec = ((int)(gap * 1000000)) % 1000000000;
|
||||||
|
|
||||||
if (id_mode == MODE_FIX) {
|
|
||||||
|
|
||||||
/* recognize obviously missing commandline option */
|
/* recognize obviously missing commandline option */
|
||||||
if ((frame.can_id > 0x7FF) && !extended) {
|
if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) {
|
||||||
printf("The given CAN-ID is greater than 0x7FF and "
|
printf("The given CAN-ID is greater than 0x7FF and "
|
||||||
"the '-e' option is not set.\n");
|
"the '-e' option is not set.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extended)
|
|
||||||
frame.can_id &= CAN_EFF_MASK;
|
|
||||||
else
|
|
||||||
frame.can_id &= CAN_SFF_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
if (strlen(argv[optind]) >= IFNAMSIZ) {
|
||||||
printf("Name of CAN device '%s' is too long!\n\n", argv[optind]);
|
printf("Name of CAN device '%s' is too long!\n\n", argv[optind]);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -315,6 +314,34 @@ int main(int argc, char **argv)
|
||||||
&loopback, sizeof(loopback));
|
&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) {
|
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
perror("bind");
|
perror("bind");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -330,8 +357,15 @@ int main(int argc, char **argv)
|
||||||
if (count && (--count == 0))
|
if (count && (--count == 0))
|
||||||
running = 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();
|
frame.can_id = random();
|
||||||
|
|
||||||
if (extended) {
|
if (extended) {
|
||||||
|
|
@ -339,42 +373,57 @@ int main(int argc, char **argv)
|
||||||
frame.can_id |= CAN_EFF_FLAG;
|
frame.can_id |= CAN_EFF_FLAG;
|
||||||
} else
|
} else
|
||||||
frame.can_id &= CAN_SFF_MASK;
|
frame.can_id &= CAN_SFF_MASK;
|
||||||
}
|
|
||||||
|
if (rtr_frame && !canfd)
|
||||||
|
frame.can_id |= CAN_RTR_FLAG;
|
||||||
|
|
||||||
if (dlc_mode == MODE_RANDOM) {
|
if (dlc_mode == MODE_RANDOM) {
|
||||||
|
|
||||||
frame.can_dlc = random() & 0xF;
|
if (canfd)
|
||||||
|
frame.len = can_dlc2len(random() & 0xF);
|
||||||
if (frame.can_dlc & 8)
|
else {
|
||||||
frame.can_dlc = 8; /* for about 50% of the frames */
|
frame.len = random() & 0xF;
|
||||||
|
if (frame.len & 8)
|
||||||
if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
|
frame.len = 8; /* for about 50% of the frames */
|
||||||
frame.can_dlc = 1; /* min dlc value for incr. data */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_mode == MODE_INCREMENT && !frame.len)
|
||||||
|
frame.len = 1; /* min dlc value for incr. data */
|
||||||
|
|
||||||
if (data_mode == MODE_RANDOM) {
|
if (data_mode == MODE_RANDOM) {
|
||||||
|
|
||||||
/* that's what the 64 bit alignment of data[] is for ... :) */
|
/* that's what the 64 bit alignment of data[] is for ... :) */
|
||||||
*(unsigned long*)(&frame.data[0]) = random();
|
*(unsigned long*)(&frame.data[0]) = random();
|
||||||
*(unsigned long*)(&frame.data[4]) = 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 */
|
/* set unused payload data to zero like the CAN driver does it on rx */
|
||||||
if (frame.can_dlc < 8)
|
if (frame.len < maxdlen)
|
||||||
memset(&frame.data[frame.can_dlc], 0, 8 - frame.can_dlc);
|
memset(&frame.data[frame.len], 0, maxdlen - frame.len);
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
||||||
printf(" %s ", argv[optind]);
|
printf(" %s ", argv[optind]);
|
||||||
|
|
||||||
if (verbose > 1)
|
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
|
else
|
||||||
fprint_canframe(stdout, &frame, "\n", 1);
|
fprint_canframe(stdout, &frame, "\n", 1, maxdlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
resend:
|
resend:
|
||||||
nbytes = write(s, &frame, sizeof(struct can_frame));
|
nbytes = write(s, &frame, mtu);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
if (errno != ENOBUFS) {
|
if (errno != ENOBUFS) {
|
||||||
perror("write");
|
perror("write");
|
||||||
|
|
@ -394,7 +443,7 @@ resend:
|
||||||
} else
|
} else
|
||||||
enobufs_count++;
|
enobufs_count++;
|
||||||
|
|
||||||
} else if (nbytes < sizeof(struct can_frame)) {
|
} else if (nbytes < mtu) {
|
||||||
fprintf(stderr, "write: incomplete CAN frame\n");
|
fprintf(stderr, "write: incomplete CAN frame\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -403,24 +452,20 @@ resend:
|
||||||
if (nanosleep(&ts, NULL))
|
if (nanosleep(&ts, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (id_mode == MODE_INCREMENT) {
|
if (id_mode == MODE_INCREMENT)
|
||||||
|
|
||||||
frame.can_id++;
|
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) {
|
if (dlc_mode == MODE_INCREMENT) {
|
||||||
|
|
||||||
frame.can_dlc++;
|
incdlc++;
|
||||||
frame.can_dlc %= 9;
|
|
||||||
|
|
||||||
if ((data_mode == MODE_INCREMENT) && !frame.can_dlc)
|
if (canfd && !mix) {
|
||||||
frame.can_dlc = 1; /* min dlc value for incr. data */
|
incdlc &= 0xF;
|
||||||
|
frame.len = can_dlc2len(incdlc);
|
||||||
|
} else {
|
||||||
|
incdlc %= 9;
|
||||||
|
frame.len = incdlc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_mode == MODE_INCREMENT) {
|
if (data_mode == MODE_INCREMENT) {
|
||||||
|
|
@ -430,6 +475,13 @@ resend:
|
||||||
for (i=0; i<8 ;i++)
|
for (i=0; i<8 ;i++)
|
||||||
frame.data[i] = (incdata >> i*8) & 0xFFULL;
|
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)
|
if (enobufs_count)
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,9 @@
|
||||||
#define ANYDEV "any"
|
#define ANYDEV "any"
|
||||||
#define ANL "\r\n" /* newline in ASC mode */
|
#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
|
#define DEFPORT 28700
|
||||||
|
|
||||||
static char devname[MAXDEV][IFNAMSIZ+1];
|
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 ;-) */
|
int currmax = 1; /* we assume at least one can bus ;-) */
|
||||||
struct sockaddr_can addr;
|
struct sockaddr_can addr;
|
||||||
struct can_filter rfilter;
|
struct can_filter rfilter;
|
||||||
struct can_frame frame;
|
struct canfd_frame frame;
|
||||||
int nbytes, i, j;
|
const int canfd_on = 1;
|
||||||
|
int nbytes, i, j, maxdlen;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct timeval tv, last_tv;
|
struct timeval tv, last_tv;
|
||||||
int port = DEFPORT;
|
int port = DEFPORT;
|
||||||
struct sockaddr_in inaddr;
|
struct sockaddr_in inaddr;
|
||||||
struct sockaddr_in clientaddr;
|
struct sockaddr_in clientaddr;
|
||||||
socklen_t sin_size = sizeof(clientaddr);
|
socklen_t sin_size = sizeof(clientaddr);
|
||||||
char temp[128];
|
char temp[BUFSZ];
|
||||||
|
|
||||||
sigemptyset(&sigset);
|
sigemptyset(&sigset);
|
||||||
signalaction.sa_handler = &childdied;
|
signalaction.sa_handler = &childdied;
|
||||||
|
|
@ -339,6 +343,9 @@ int main(int argc, char **argv)
|
||||||
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,
|
||||||
&err_mask[i], sizeof(err_mask[i]));
|
&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]);
|
j = strlen(argv[optind+i]);
|
||||||
|
|
||||||
if (!(j < IFNAMSIZ)) {
|
if (!(j < IFNAMSIZ)) {
|
||||||
|
|
@ -387,14 +394,17 @@ int main(int argc, char **argv)
|
||||||
socklen_t len = sizeof(addr);
|
socklen_t len = sizeof(addr);
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
if ((nbytes = recvfrom(s[i], &frame,
|
if ((nbytes = recvfrom(s[i], &frame, CANFD_MTU, 0,
|
||||||
sizeof(struct can_frame), 0,
|
|
||||||
(struct sockaddr*)&addr, &len)) < 0) {
|
(struct sockaddr*)&addr, &len)) < 0) {
|
||||||
perror("read");
|
perror("read");
|
||||||
return 1;
|
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");
|
fprintf(stderr, "read: incomplete CAN frame\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -407,7 +417,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
sprintf(temp, "(%ld.%06ld) %*s ",
|
sprintf(temp, "(%ld.%06ld) %*s ",
|
||||||
tv.tv_sec, tv.tv_usec, max_devname_len, devname[idx]);
|
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");
|
strcat(temp, "\n");
|
||||||
|
|
||||||
if (write(accsocket, temp, strlen(temp)) < 0) {
|
if (write(accsocket, temp, strlen(temp)) < 0) {
|
||||||
|
|
@ -415,13 +425,11 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* printf("%s\n",temp2); */
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* print CAN frame in log file style to stdout */
|
/* print CAN frame in log file style to stdout */
|
||||||
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec);
|
||||||
printf("%*s ", max_devname_len, devname[idx]);
|
printf("%*s ", max_devname_len, devname[idx]);
|
||||||
fprint_canframe(stdout, &frame, "\n", 0);
|
fprint_canframe(stdout, &frame, "\n", 0, maxdlen);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
25
canplayer.c
25
canplayer.c
|
|
@ -64,7 +64,8 @@
|
||||||
#define DEFAULT_GAP 1 /* ms */
|
#define DEFAULT_GAP 1 /* ms */
|
||||||
#define DEFAULT_LOOPS 1 /* only one replay */
|
#define DEFAULT_LOOPS 1 /* only one replay */
|
||||||
#define CHANNELS 20 /* anyone using more than 20 CAN interfaces at a time? */
|
#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 */
|
#define STDOUTIDX 65536 /* interface index for printing on stdout - bigger than max uint16 */
|
||||||
|
|
||||||
struct assignment {
|
struct assignment {
|
||||||
|
|
@ -73,6 +74,7 @@ struct assignment {
|
||||||
char rxif[IFNAMSIZ];
|
char rxif[IFNAMSIZ];
|
||||||
};
|
};
|
||||||
static struct assignment asgn[CHANNELS];
|
static struct assignment asgn[CHANNELS];
|
||||||
|
const int canfd_on = 1;
|
||||||
|
|
||||||
extern int optind, opterr, optopt;
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
|
|
@ -236,7 +238,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
||||||
struct sockaddr_can addr;
|
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;
|
static struct timeval today_tv, log_tv, last_log_tv, diff_tv;
|
||||||
struct timespec sleep_ts;
|
struct timespec sleep_ts;
|
||||||
int s; /* CAN_RAW socket */
|
int s; /* CAN_RAW socket */
|
||||||
|
|
@ -249,7 +251,7 @@ int main(int argc, char **argv)
|
||||||
static int loops = DEFAULT_LOOPS;
|
static int loops = DEFAULT_LOOPS;
|
||||||
int assignments; /* assignments defined on the commandline */
|
int assignments; /* assignments defined on the commandline */
|
||||||
int txidx; /* sendto() interface index */
|
int txidx; /* sendto() interface index */
|
||||||
int eof, nbytes, i, j;
|
int eof, txmtu, i, j;
|
||||||
char *fret;
|
char *fret;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "I:l:tg:s:xv?")) != -1) {
|
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 */
|
/* disable unneeded default receive filter on this RAW socket */
|
||||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
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) {
|
if (loopback_disable) {
|
||||||
int loopback = 0;
|
int loopback = 0;
|
||||||
|
|
||||||
|
|
@ -432,7 +437,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
} else if (txidx > 0) { /* only send to valid CAN devices */
|
} 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);
|
fprintf(stderr, "wrong CAN frame format: '%s'!", ascframe);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -440,17 +446,18 @@ int main(int argc, char **argv)
|
||||||
addr.can_family = AF_CAN;
|
addr.can_family = AF_CAN;
|
||||||
addr.can_ifindex = txidx; /* send via this interface */
|
addr.can_ifindex = txidx; /* send via this interface */
|
||||||
|
|
||||||
nbytes = sendto(s, &frame, sizeof(struct can_frame), 0,
|
if (sendto(s, &frame, txmtu, 0, (struct sockaddr*)&addr, sizeof(addr)) != txmtu) {
|
||||||
(struct sockaddr*)&addr, sizeof(addr));
|
|
||||||
|
|
||||||
if (nbytes != sizeof(struct can_frame)) {
|
|
||||||
perror("sendto");
|
perror("sendto");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("%s (%s) ", get_txname(device), device);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
55
cansend.c
55
cansend.c
|
|
@ -62,9 +62,11 @@
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int s; /* can raw socket */
|
int s; /* can raw socket */
|
||||||
int nbytes;
|
int required_mtu;
|
||||||
|
int mtu;
|
||||||
|
int enable_canfd = 1;
|
||||||
struct sockaddr_can addr;
|
struct sockaddr_can addr;
|
||||||
struct can_frame frame;
|
struct canfd_frame frame;
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
||||||
/* check command line options */
|
/* check command line options */
|
||||||
|
|
@ -74,14 +76,18 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse CAN frame */
|
/* parse CAN frame */
|
||||||
if (parse_canframe(argv[2], &frame)){
|
required_mtu = parse_canframe(argv[2], &frame);
|
||||||
fprintf(stderr, "\nWrong CAN-frame format!\n\n");
|
if (!required_mtu){
|
||||||
fprintf(stderr, "Try: <can_id>#{R|data}\n");
|
fprintf(stderr, "\nWrong CAN-frame format! Try:\n\n");
|
||||||
fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n");
|
fprintf(stderr, " <can_id>#{R|data} for CAN 2.0 frames\n");
|
||||||
fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)");
|
fprintf(stderr, " <can_id>##<flags>{data} for CAN FD frames\n\n");
|
||||||
fprintf(stderr, " be seperated by '.'\n\n");
|
fprintf(stderr, "<can_id> can have 3 (SFF) or 8 (EFF) hex chars\n");
|
||||||
fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / ");
|
fprintf(stderr, "{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally");
|
||||||
fprintf(stderr, "5AA# /\n 1F334455#1122334455667788 / 123#R ");
|
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");
|
fprintf(stderr, "for remote transmission request.\n\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -101,6 +107,31 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
addr.can_ifindex = ifr.ifr_ifindex;
|
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 */
|
/* disable default receive filter on this RAW socket */
|
||||||
/* This is obsolete as we do not read from the socket at all, but for */
|
/* 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 */
|
/* 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 */
|
/* send frame */
|
||||||
if ((nbytes = write(s, &frame, sizeof(frame))) != sizeof(frame)) {
|
if (write(s, &frame, required_mtu) != required_mtu) {
|
||||||
perror("write");
|
perror("write");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//fprint_long_canframe(stdout, &frame, "\n", 0);
|
|
||||||
|
|
||||||
close(s);
|
close(s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
187
lib.c
187
lib.c
|
|
@ -58,8 +58,36 @@
|
||||||
#define CANID_DELIM '#'
|
#define CANID_DELIM '#'
|
||||||
#define DATA_SEPERATOR '.'
|
#define DATA_SEPERATOR '.'
|
||||||
|
|
||||||
#define MAX_CANFRAME "12345678#01.23.45.67.89.AB.CD.EF"
|
/* CAN DLC to real data length conversion helpers */
|
||||||
#define MAX_LONG_CANFRAME_SIZE 256
|
|
||||||
|
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) {
|
unsigned char asc2nibble(char c) {
|
||||||
|
|
||||||
|
|
@ -75,53 +103,57 @@ unsigned char asc2nibble(char c) {
|
||||||
return 16; /* error */
|
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 len = strlen(arg);
|
||||||
int i;
|
int i;
|
||||||
unsigned char tmp;
|
unsigned char tmp;
|
||||||
|
|
||||||
if (!len || len%2 || len > 16)
|
if (!len || len%2 || len > maxdlen*2)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
memset(data, 0, maxdlen);
|
||||||
|
|
||||||
for (i=0; i < len/2; i++) {
|
for (i=0; i < len/2; i++) {
|
||||||
|
|
||||||
tmp = asc2nibble(*(arg+(2*i)));
|
tmp = asc2nibble(*(arg+(2*i)));
|
||||||
if (tmp > 0x0F)
|
if (tmp > 0x0F)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
cf->data[i] = (tmp << 4);
|
data[i] = (tmp << 4);
|
||||||
|
|
||||||
tmp = asc2nibble(*(arg+(2*i)+1));
|
tmp = asc2nibble(*(arg+(2*i)+1));
|
||||||
if (tmp > 0x0F)
|
if (tmp > 0x0F)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
cf->data[i] |= tmp;
|
data[i] |= tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_canframe(char *cs, struct can_frame *cf) {
|
int parse_canframe(char *cs, struct canfd_frame *cf) {
|
||||||
/* documentation see lib.h */
|
/* 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;
|
unsigned char tmp;
|
||||||
|
|
||||||
len = strlen(cs);
|
len = strlen(cs);
|
||||||
//printf("'%s' len %d\n", cs, len);
|
//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)
|
if (len < 4)
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
if (cs[3] == CANID_DELIM) { /* 3 digits */
|
if (cs[3] == CANID_DELIM) { /* 3 digits */
|
||||||
|
|
||||||
idx = 4;
|
idx = 4;
|
||||||
for (i=0; i<3; i++){
|
for (i=0; i<3; i++){
|
||||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||||
return 1;
|
return 0;
|
||||||
cf->can_id |= (tmp << (2-i)*4);
|
cf->can_id |= (tmp << (2-i)*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,21 +162,34 @@ int parse_canframe(char *cs, struct can_frame *cf) {
|
||||||
idx = 9;
|
idx = 9;
|
||||||
for (i=0; i<8; i++){
|
for (i=0; i<8; i++){
|
||||||
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
if ((tmp = asc2nibble(cs[i])) > 0x0F)
|
||||||
return 1;
|
return 0;
|
||||||
cf->can_id |= (tmp << (7-i)*4);
|
cf->can_id |= (tmp << (7-i)*4);
|
||||||
}
|
}
|
||||||
if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
|
if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe? */
|
||||||
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
|
cf->can_id |= CAN_EFF_FLAG; /* then it is an extended frame */
|
||||||
|
|
||||||
} else
|
} else
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
|
if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
|
||||||
cf->can_id |= CAN_RTR_FLAG;
|
cf->can_id |= CAN_RTR_FLAG;
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0, dlc=0; i<8; i++){
|
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, dlen=0; i < maxdlen; i++){
|
||||||
|
|
||||||
if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
|
if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
|
||||||
idx++;
|
idx++;
|
||||||
|
|
@ -153,35 +198,34 @@ int parse_canframe(char *cs, struct can_frame *cf) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
||||||
return 1;
|
return 0;
|
||||||
cf->data[i] = (tmp << 4);
|
cf->data[i] = (tmp << 4);
|
||||||
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
|
||||||
return 1;
|
|
||||||
cf->data[i] |= tmp;
|
|
||||||
dlc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cf->can_dlc = dlc;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
cf->data[i] |= tmp;
|
||||||
|
dlen++;
|
||||||
|
}
|
||||||
|
cf->len = dlen;
|
||||||
|
|
||||||
|
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 */
|
/* 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);
|
fprintf(stream, "%s", buf);
|
||||||
if (eol)
|
if (eol)
|
||||||
fprintf(stream, "%s", 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 */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
int i,offset;
|
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) {
|
if (cf->can_id & CAN_ERR_FLAG) {
|
||||||
sprintf(buf, "%08X#", cf->can_id & (CAN_ERR_MASK|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;
|
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");
|
sprintf(buf+offset, "R");
|
||||||
else
|
return;
|
||||||
for (i = 0; i < dlc; i++) {
|
}
|
||||||
sprintf(buf+offset, "%02X", cf->data[i]);
|
|
||||||
|
if (maxdlen == CANFD_MAX_DLEN) {
|
||||||
|
/* add CAN FD specific escape char and flags */
|
||||||
|
sprintf(buf+offset, "#%X", cf->flags & 0xF);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
if (sep && (i+1 < dlc))
|
if (sep && len)
|
||||||
sprintf(buf+offset++, ".");
|
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 */
|
/* 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);
|
fprintf(stream, "%s", buf);
|
||||||
if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) {
|
if ((view & CANLIB_VIEW_ERROR) && (cf->can_id & CAN_ERR_FLAG)) {
|
||||||
snprintf_can_error_frame(buf, sizeof(buf), cf, "\n\t");
|
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);
|
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 */
|
/* documentation see lib.h */
|
||||||
|
|
||||||
int i, j, dlen, offset;
|
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) {
|
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;
|
offset = 10;
|
||||||
} else if (cf->can_id & CAN_EFF_FLAG) {
|
} 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;
|
offset = 10;
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf, "%3X ", cf->can_id & CAN_SFF_MASK);
|
sprintf(buf, "%03X ", cf->can_id & CAN_SFF_MASK);
|
||||||
offset = 5;
|
offset = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buf+offset, "[%d]", dlc);
|
if (maxdlen == CAN_MAX_DLEN) {
|
||||||
offset += 3;
|
sprintf(buf+offset, " [%d] ", len);
|
||||||
|
/* standard CAN frames may have RTR enabled */
|
||||||
if (cf->can_id & CAN_RTR_FLAG) { /* there are no ERR frames with RTR */
|
if (cf->can_id & CAN_RTR_FLAG) {
|
||||||
sprintf(buf+offset, " remote request");
|
sprintf(buf+offset+5, " remote request");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sprintf(buf+offset, "[%02d] ", len);
|
||||||
|
}
|
||||||
|
offset += 5;
|
||||||
|
|
||||||
if (view & CANLIB_VIEW_BINARY) {
|
if (view & CANLIB_VIEW_BINARY) {
|
||||||
dlen = 9; /* _10101010 */
|
dlen = 9; /* _10101010 */
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
for (i = dlc - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
buf[offset++] = (i == dlc-1)?' ':SWAP_DELIMITER;
|
buf[offset++] = (i == len-1)?' ':SWAP_DELIMITER;
|
||||||
for (j = 7; j >= 0; j--)
|
for (j = 7; j >= 0; j--)
|
||||||
buf[offset++] = (1<<j & cf->data[i])?'1':'0';
|
buf[offset++] = (1<<j & cf->data[i])?'1':'0';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < dlc; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
buf[offset++] = ' ';
|
buf[offset++] = ' ';
|
||||||
for (j = 7; j >= 0; j--)
|
for (j = 7; j >= 0; j--)
|
||||||
buf[offset++] = (1<<j & cf->data[i])?'1':'0';
|
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 {
|
} else {
|
||||||
dlen = 3; /* _AA */
|
dlen = 3; /* _AA */
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
for (i = dlc - 1; i >= 0; i--) {
|
for (i = len - 1; i >= 0; i--) {
|
||||||
sprintf(buf+offset, "%c%02X",
|
sprintf(buf+offset, "%c%02X",
|
||||||
(i == dlc-1)?' ':SWAP_DELIMITER,
|
(i == len-1)?' ':SWAP_DELIMITER,
|
||||||
cf->data[i]);
|
cf->data[i]);
|
||||||
offset += dlen;
|
offset += dlen;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < dlc; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
sprintf(buf+offset, " %02X", cf->data[i]);
|
sprintf(buf+offset, " %02X", cf->data[i]);
|
||||||
offset += dlen;
|
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)
|
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) {
|
else if (view & CANLIB_VIEW_ASCII) {
|
||||||
j = dlen*(8-dlc)+4;
|
j = dlen*(8-len)+4;
|
||||||
if (view & CANLIB_VIEW_SWAP) {
|
if (view & CANLIB_VIEW_SWAP) {
|
||||||
sprintf(buf+offset, "%*s", j, "`");
|
sprintf(buf+offset, "%*s", j, "`");
|
||||||
offset += 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))
|
if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
|
||||||
buf[offset++] = cf->data[i];
|
buf[offset++] = cf->data[i];
|
||||||
else
|
else
|
||||||
|
|
@ -297,7 +362,7 @@ void sprint_long_canframe(char *buf , struct can_frame *cf, int view) {
|
||||||
} else {
|
} else {
|
||||||
sprintf(buf+offset, "%*s", j, "'");
|
sprintf(buf+offset, "%*s", j, "'");
|
||||||
offset += j;
|
offset += j;
|
||||||
for (i = 0; i < dlc; i++)
|
for (i = 0; i < len; i++)
|
||||||
if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
|
if ((cf->data[i] > 0x1F) && (cf->data[i] < 0x7F))
|
||||||
buf[offset++] = cf->data[i];
|
buf[offset++] = cf->data[i];
|
||||||
else
|
else
|
||||||
|
|
@ -399,14 +464,14 @@ static int snprintf_error_data(char *buf, size_t len, uint8_t err,
|
||||||
return n;
|
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)
|
if (len <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
return snprintf(buf, len, "{at bit %d}", cf->data[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;
|
int n = 0;
|
||||||
|
|
||||||
|
|
@ -422,7 +487,7 @@ static int snprintf_error_ctrl(char *buf, size_t len, struct can_frame *cf)
|
||||||
return n;
|
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;
|
int n = 0;
|
||||||
|
|
||||||
|
|
@ -443,7 +508,7 @@ static int snprintf_error_prot(char *buf, size_t len, struct can_frame *cf)
|
||||||
return n;
|
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)
|
char* sep)
|
||||||
{
|
{
|
||||||
canid_t class, mask;
|
canid_t class, mask;
|
||||||
|
|
|
||||||
99
lib.h
99
lib.h
|
|
@ -45,6 +45,26 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* 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);
|
unsigned char asc2nibble(char c);
|
||||||
/*
|
/*
|
||||||
* Returns the decimal value of a given ASCII hex character.
|
* 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.
|
* 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.
|
* 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.
|
* Leading zeros '00' in the ASCII hex string are interpreted.
|
||||||
|
|
@ -69,53 +89,76 @@ int hexstring2candata(char *arg, struct can_frame *cf);
|
||||||
* 0 = success
|
* 0 = success
|
||||||
* 1 = error (in length or the given characters are no ASCII hex characters)
|
* 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)
|
* 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
|
* hexadecimal chars
|
||||||
*
|
*
|
||||||
* data has 0 to 8 hex-values that can (optionally) be seperated by '.'
|
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* 123# -> standard CAN-Id = 0x123, dlc = 0
|
* 123# -> standard CAN-Id = 0x123, len = 0
|
||||||
* 12345678# -> extended CAN-Id = 0x12345678, dlc = 0
|
* 12345678# -> extended CAN-Id = 0x12345678, len = 0
|
||||||
* 123#R -> standard CAN-Id = 0x123, dlc = 0, RTR-frame
|
* 123#R -> standard CAN-Id = 0x123, len = 0, RTR-frame
|
||||||
* 7A1#r -> standard CAN-Id = 0x7A1, dlc = 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#00 -> standard CAN-Id = 0x123, len = 1, data[0] = 0x00
|
||||||
* 123#1122334455667788 -> standard CAN-Id = 0x123, dlc = 8
|
* 123#1122334455667788 -> standard CAN-Id = 0x123, len = 8
|
||||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 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, dlc = 8
|
* 123#11.2233.44556677.88 -> standard CAN-Id = 0x123, len = 8
|
||||||
* 32345678#112233 -> error frame with CAN_ERR_FLAG (0x2000000) set
|
* 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:
|
* Simple facts on this compact ASCII CAN frame representation:
|
||||||
*
|
*
|
||||||
* - 3 digits: standard frame format
|
* - 3 digits: standard frame format
|
||||||
* - 8 digits: extendend frame format OR error frame
|
* - 8 digits: extendend frame format OR error frame
|
||||||
* - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
|
* - 8 digits with CAN_ERR_FLAG (0x2000000) set: error frame
|
||||||
* - an error frame is never a RTR 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 fprint_canframe(FILE *stream , struct canfd_frame *cf, char *eol, int sep, int maxdlen);
|
||||||
void sprint_canframe(char *buf , struct can_frame *cf, int sep);
|
void sprint_canframe(char *buf , struct canfd_frame *cf, int sep, int maxdlen);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in compact format.
|
* Creates a CAN frame hexadecimal output in compact format.
|
||||||
* The CAN data[] is seperated by '.' when sep != 0.
|
* 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#112233 -> exended CAN-Id = 0x12345678, dlc = 3, data, sep = 0
|
||||||
* 12345678#R -> exended CAN-Id = 0x12345678, RTR
|
* 12345678#R -> exended CAN-Id = 0x12345678, RTR
|
||||||
* 123#11.22.33.44.55.66.77.88 -> standard CAN-Id = 0x123, dlc = 8, sep = 1
|
* 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
|
* 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:
|
* Examples:
|
||||||
*
|
*
|
||||||
|
|
@ -131,24 +174,32 @@ void sprint_canframe(char *buf , struct can_frame *cf, int sep);
|
||||||
|
|
||||||
#define SWAP_DELIMITER '`'
|
#define SWAP_DELIMITER '`'
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN frame hexadecimal output in user readable format.
|
* Creates a CAN frame hexadecimal output in user readable format.
|
||||||
*
|
*
|
||||||
|
* 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 [3] 11 22 33 -> exended CAN-Id = 0x12345678, dlc = 3, data
|
||||||
* 12345678 [0] remote request -> exended CAN-Id = 0x12345678, RTR
|
* 12345678 [0] remote request -> exended CAN-Id = 0x12345678, RTR
|
||||||
* 14B0DC51 [8] 4A 94 E8 2A EC 58 55 62 'J..*.XUb' -> (with ASCII output)
|
* 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)
|
* 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:
|
* Examples:
|
||||||
*
|
*
|
||||||
* fprint_long_canframe(stdout, &frame, "\n", 0); // with eol to STDOUT
|
* // CAN FD frame with eol to STDOUT
|
||||||
* fprint_long_canframe(stderr, &frame, NULL, 0); // no eol to STDERR
|
* 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);
|
char *sep);
|
||||||
/*
|
/*
|
||||||
* Creates a CAN error frame output in user readable format.
|
* Creates a CAN error frame output in user readable format.
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
|
static char buf[BUFSZ], device[BUFSZ], ascframe[BUFSZ], id[10];
|
||||||
|
|
||||||
struct can_frame cf;
|
struct canfd_frame cf;
|
||||||
static struct timeval tv, start_tv;
|
static struct timeval tv, start_tv;
|
||||||
FILE *infile = stdin;
|
FILE *infile = stdin;
|
||||||
FILE *outfile = stdout;
|
FILE *outfile = stdout;
|
||||||
|
|
@ -162,7 +162,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devno) { /* only convert for selected CAN devices */
|
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;
|
return 1;
|
||||||
|
|
||||||
tv.tv_sec = tv.tv_sec - start_tv.tv_sec;
|
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)
|
if (cf.can_id & CAN_RTR_FLAG)
|
||||||
fprintf(outfile, "r"); /* RTR frame */
|
fprintf(outfile, "r"); /* RTR frame */
|
||||||
else {
|
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]);
|
fprintf(outfile, " %02X", cf.data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
log2long.c
26
log2long.c
|
|
@ -52,17 +52,33 @@
|
||||||
|
|
||||||
#include "lib.h"
|
#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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char buf[100], timestamp[100], device[100], ascframe[100];
|
char buf[BUFSZ], timestamp[BUFSZ], device[BUFSZ], ascframe[BUFSZ];
|
||||||
struct can_frame cf;
|
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)
|
if (sscanf(buf, "%s %s %s", timestamp, device, ascframe) != 3)
|
||||||
return 1;
|
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;
|
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);
|
printf("%s %s %s\n", timestamp, device, ascframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue