mirror of
https://github.com/linux-can/can-utils.git
synced 2026-09-22 16:09:52 +02:00
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>
This commit is contained in:
@@ -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 (extended) {
|
||||
frame.can_id &= CAN_EFF_MASK;
|
||||
frame.can_id |= CAN_EFF_FLAG;
|
||||
} else
|
||||
frame.can_id &= CAN_SFF_MASK;
|
||||
|
||||
if (rtr_frame && !canfd)
|
||||
frame.can_id |= CAN_RTR_FLAG;
|
||||
|
||||
if (dlc_mode == MODE_RANDOM) {
|
||||
|
||||
frame.can_dlc = random() & 0xF;
|
||||
|
||||
if (frame.can_dlc & 8)
|
||||
frame.can_dlc = 8; /* for about 50% of the frames */
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user