Compare commits
8 Commits
dacd9da569
...
887b93c31b
| Author | SHA1 | Date |
|---|---|---|
|
|
887b93c31b | |
|
|
7939678070 | |
|
|
88a0417a6b | |
|
|
65e715d56d | |
|
|
374fecde09 | |
|
|
bfbf0c851f | |
|
|
0cfff2e5da | |
|
|
1e2c8fea4c |
|
|
@ -72,6 +72,9 @@
|
||||||
#ifndef SO_TIMESTAMPING
|
#ifndef SO_TIMESTAMPING
|
||||||
#define SO_TIMESTAMPING 37
|
#define SO_TIMESTAMPING 37
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SCM_TIMESTAMPING
|
||||||
|
#define SCM_TIMESTAMPING SO_TIMESTAMPING
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
#define TIMESTAMPSZ 50 /* string 'absolute with date' requires max 49 bytes */
|
||||||
|
|
||||||
|
|
@ -807,13 +810,13 @@ int main(int argc, char **argv)
|
||||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||||
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
cmsg && (cmsg->cmsg_level == SOL_SOCKET);
|
||||||
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
cmsg = CMSG_NXTHDR(&msg,cmsg)) {
|
||||||
if (cmsg->cmsg_type == SO_TIMESTAMP) {
|
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv));
|
||||||
ts.tv_sec = tv.tv_sec;
|
ts.tv_sec = tv.tv_sec;
|
||||||
ts.tv_nsec = tv.tv_usec;
|
ts.tv_nsec = tv.tv_usec;
|
||||||
ts.tv_nsec *= 1000;
|
ts.tv_nsec *= 1000;
|
||||||
} else if (cmsg->cmsg_type == SO_TIMESTAMPING) {
|
} else if (cmsg->cmsg_type == SCM_TIMESTAMPING) {
|
||||||
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
struct timespec *stamp = (struct timespec *)CMSG_DATA(cmsg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
110
cangen.c
110
cangen.c
|
|
@ -180,7 +180,7 @@ static void print_usage(char *prg)
|
||||||
fprintf(stderr, " -X (generate CAN XL CAN frames)\n");
|
fprintf(stderr, " -X (generate CAN XL CAN frames)\n");
|
||||||
fprintf(stderr, " -R (generate RTR frames)\n");
|
fprintf(stderr, " -R (generate RTR frames)\n");
|
||||||
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
|
fprintf(stderr, " -8 (allow DLC values greater then 8 for Classic CAN frames)\n");
|
||||||
fprintf(stderr, " -m (mix -e -f -b -E -R -X frames)\n");
|
fprintf(stderr, " -m (mix CC [-e -R] FD [-f -b -E] XL [-X] on capable devices)\n");
|
||||||
fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\n");
|
fprintf(stderr, " -I <mode> (CAN ID generation mode - see below)\n");
|
||||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
fprintf(stderr, " -L <mode> (CAN data length code (dlc) generation mode - see below)\n");
|
||||||
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
||||||
|
|
@ -339,10 +339,9 @@ resend:
|
||||||
nbytes = sendmsg(fd, &msg, 0);
|
nbytes = sendmsg(fd, &msg, 0);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
ret = -errno;
|
ret = -errno;
|
||||||
if (ret != -ENOBUFS) {
|
if (ret != -ENOBUFS)
|
||||||
perror("write");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
if (!ignore_enobufs && !timeout) {
|
if (!ignore_enobufs && !timeout) {
|
||||||
perror("write");
|
perror("write");
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -455,6 +454,9 @@ int main(int argc, char **argv)
|
||||||
unsigned char extended = 0;
|
unsigned char extended = 0;
|
||||||
unsigned char canfd = 0;
|
unsigned char canfd = 0;
|
||||||
unsigned char canxl = 0;
|
unsigned char canxl = 0;
|
||||||
|
unsigned char mixcc = 1; /* mix default */
|
||||||
|
unsigned char mixfd = 1; /* mix default */
|
||||||
|
unsigned char mixxl = 1; /* mix default */
|
||||||
unsigned char brs = 0;
|
unsigned char brs = 0;
|
||||||
unsigned char esi = 0;
|
unsigned char esi = 0;
|
||||||
unsigned char mix = 0;
|
unsigned char mix = 0;
|
||||||
|
|
@ -574,7 +576,6 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
mix = 1;
|
mix = 1;
|
||||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
|
||||||
view |= CANLIB_VIEW_INDENT_SFF;
|
view |= CANLIB_VIEW_INDENT_SFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -777,34 +778,32 @@ int main(int argc, char **argv)
|
||||||
&loopback, sizeof(loopback));
|
&loopback, sizeof(loopback));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canfd || canxl) {
|
/* get CAN netdevice MTU for frame type capabilities */
|
||||||
|
|
||||||
/* check if the frame fits into the CAN netdevice */
|
|
||||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||||
perror("SIOCGIFMTU");
|
perror("SIOCGIFMTU");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canfd) {
|
/* check CAN XL support */
|
||||||
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
if (ifr.ifr_mtu < (int)CANXL_MIN_MTU) {
|
||||||
cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len));
|
mixxl = 0;
|
||||||
} else {
|
if (canxl) {
|
||||||
/* limit fixed CAN XL data length to 64 */
|
|
||||||
if (cu.fd.len > CANFD_MAX_DLEN)
|
|
||||||
cu.fd.len = CANFD_MAX_DLEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canxl && (ifr.ifr_mtu < (int)CANXL_MIN_MTU)) {
|
|
||||||
printf("CAN interface not CAN XL capable - sorry.\n");
|
printf("CAN interface not CAN XL capable - sorry.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (canfd && (ifr.ifr_mtu < (int)CANFD_MTU)) {
|
/* check CAN FD support */
|
||||||
|
if (ifr.ifr_mtu < (int)CANFD_MTU) {
|
||||||
|
mixfd = 0;
|
||||||
|
if (canfd) {
|
||||||
printf("CAN interface not CAN FD capable - sorry.\n");
|
printf("CAN interface not CAN FD capable - sorry.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ifr.ifr_mtu == (int)CANFD_MTU) {
|
/* enable CAN FD on the socket */
|
||||||
|
if (mixfd) {
|
||||||
/* interface is ok - try to switch the socket into CAN FD mode */
|
/* interface is ok - try to switch the socket into CAN FD mode */
|
||||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES,
|
||||||
&enable_canfx, sizeof(enable_canfx))){
|
&enable_canfx, sizeof(enable_canfx))){
|
||||||
|
|
@ -813,7 +812,8 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU) {
|
/* enable CAN XL on the socket */
|
||||||
|
if (mixxl) {
|
||||||
/* interface is ok - try to switch the socket into CAN XL mode */
|
/* interface is ok - try to switch the socket into CAN XL mode */
|
||||||
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
|
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_XL_FRAMES,
|
||||||
&enable_canfx, sizeof(enable_canfx))){
|
&enable_canfx, sizeof(enable_canfx))){
|
||||||
|
|
@ -828,6 +828,16 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sanitize given values */
|
||||||
|
if (canfd || canxl) {
|
||||||
|
if (canfd) {
|
||||||
|
/* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */
|
||||||
|
cu.fd.len = can_fd_dlc2len(can_fd_len2dlc(cu.fd.len));
|
||||||
|
} else {
|
||||||
|
/* limit fixed CAN XL data length to 64 */
|
||||||
|
if (cu.fd.len > CANFD_MAX_DLEN)
|
||||||
|
cu.fd.len = CANFD_MAX_DLEN;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* sanitize Classical CAN 2.0 frame length */
|
/* sanitize Classical CAN 2.0 frame length */
|
||||||
if (len8_dlc) {
|
if (len8_dlc) {
|
||||||
|
|
@ -1040,8 +1050,31 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = do_send_one(s, &cu, mtu, polltimeout);
|
ret = do_send_one(s, &cu, mtu, polltimeout);
|
||||||
if (ret)
|
if ((ret == -EINVAL) && mix) {
|
||||||
|
/* mix mode: disable unsupported CAN frame type */
|
||||||
|
switch (mtu) {
|
||||||
|
case CAN_MTU:
|
||||||
|
mixcc = 0;
|
||||||
|
break;
|
||||||
|
case CANFD_MTU:
|
||||||
|
mixfd = 0;
|
||||||
|
break;
|
||||||
|
case CANXL_MTU:
|
||||||
|
mixxl = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf ("mix mode: unknown MTU");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
if (!mixcc && !mixfd && !mixxl) {
|
||||||
|
printf ("mix mode: no valid CAN frame types\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (ret) {
|
||||||
|
/* other error than -ENOBUFS and -EINVAL */
|
||||||
|
perror("write");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (burst_sent_count >= burst_count)
|
if (burst_sent_count >= burst_count)
|
||||||
burst_sent_count = 0;
|
burst_sent_count = 0;
|
||||||
|
|
@ -1082,18 +1115,41 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mix) {
|
if (mix) {
|
||||||
|
canfd = 0;
|
||||||
|
canxl = 0;
|
||||||
i = random();
|
i = random();
|
||||||
extended = i & 1;
|
extended = i & 1;
|
||||||
|
if (mixfd) {
|
||||||
canfd = i & 2;
|
canfd = i & 2;
|
||||||
if (canfd) {
|
if (canfd) {
|
||||||
brs = i & 4;
|
brs = i & 4;
|
||||||
esi = i & 8;
|
esi = i & 8;
|
||||||
}
|
}
|
||||||
/* generate CAN XL traffic if the interface is capable */
|
}
|
||||||
if (ifr.ifr_mtu >= (int)CANXL_MIN_MTU)
|
if (mixxl) {
|
||||||
canxl = ((i & 96) == 96);
|
if (mixfd)
|
||||||
|
canxl = ((i & 96) == 96); /* 1/4 */
|
||||||
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */
|
else
|
||||||
|
canxl = ((i & 32) == 32); /* 1/2 */
|
||||||
|
}
|
||||||
|
if (mixcc) {
|
||||||
|
rtr_frame = ((i & 24) == 24); /* reduce RTR to 1/4 */
|
||||||
|
} else {
|
||||||
|
/* no CC frames allowed - CAN XL-only mode? */
|
||||||
|
if (!canxl && !canfd) {
|
||||||
|
/* force XL or FD frames */
|
||||||
|
if (mixxl)
|
||||||
|
canxl = 1;
|
||||||
|
else if (mixfd) {
|
||||||
|
canfd = 1;
|
||||||
|
brs = i & 4;
|
||||||
|
esi = i & 8;
|
||||||
|
} else {
|
||||||
|
printf ("mix mode: no valid CAN frame types\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@
|
||||||
#include <linux/can.h>
|
#include <linux/can.h>
|
||||||
#include <linux/can/isotp.h>
|
#include <linux/can/isotp.h>
|
||||||
#include <linux/sockios.h>
|
#include <linux/sockios.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define NO_CAN_ID 0xFFFFFFFFU
|
#define NO_CAN_ID 0xFFFFFFFFU
|
||||||
|
|
||||||
|
|
@ -66,6 +67,8 @@
|
||||||
#define FORMAT_ASCII 2
|
#define FORMAT_ASCII 2
|
||||||
#define FORMAT_DEFAULT (FORMAT_ASCII | FORMAT_HEX)
|
#define FORMAT_DEFAULT (FORMAT_ASCII | FORMAT_HEX)
|
||||||
|
|
||||||
|
#define PDU_BUF_SIZE 4096
|
||||||
|
|
||||||
void print_usage(char *prg)
|
void print_usage(char *prg)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
fprintf(stderr, "\nUsage: %s [options] <CAN interface>\n", prg);
|
||||||
|
|
@ -79,6 +82,7 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
|
fprintf(stderr, " -f <format> (1 = HEX, 2 = ASCII, 3 = HEX & ASCII - default: %d)\n", FORMAT_DEFAULT);
|
||||||
fprintf(stderr, " -L (set link layer options for CAN FD)\n");
|
fprintf(stderr, " -L (set link layer options for CAN FD)\n");
|
||||||
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
|
fprintf(stderr, " -h <len> (head: print only first <len> bytes)\n");
|
||||||
|
fprintf(stderr, " -i (ignore syscall errors to receive malformed PDUs)\n");
|
||||||
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -189,15 +193,16 @@ int main(int argc, char **argv)
|
||||||
int head = 0;
|
int head = 0;
|
||||||
int timestamp = 0;
|
int timestamp = 0;
|
||||||
int format = FORMAT_DEFAULT;
|
int format = FORMAT_DEFAULT;
|
||||||
|
int ignore_errors = 0;
|
||||||
canid_t src = NO_CAN_ID;
|
canid_t src = NO_CAN_ID;
|
||||||
canid_t dst = NO_CAN_ID;
|
canid_t dst = NO_CAN_ID;
|
||||||
extern int optind, opterr, optopt;
|
extern int optind, opterr, optopt;
|
||||||
static struct timeval tv, last_tv;
|
static struct timeval tv, last_tv;
|
||||||
|
|
||||||
unsigned char buffer[4096];
|
unsigned char buffer[PDU_BUF_SIZE];
|
||||||
int nbytes;
|
int nbytes;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L?")) != -1) {
|
while ((opt = getopt(argc, argv, "s:d:x:X:h:ct:f:L?i")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 's':
|
case 's':
|
||||||
src = strtoul(optarg, NULL, 16);
|
src = strtoul(optarg, NULL, 16);
|
||||||
|
|
@ -249,6 +254,10 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
ignore_errors = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
print_usage(basename(argv[0]));
|
print_usage(basename(argv[0]));
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -367,31 +376,37 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(s, &rdfs)) {
|
if (FD_ISSET(s, &rdfs)) {
|
||||||
nbytes = read(s, buffer, 4096);
|
nbytes = read(s, buffer, PDU_BUF_SIZE);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
perror("read socket s");
|
perror("read socket s");
|
||||||
r = 1;
|
r = 1;
|
||||||
|
if(!ignore_errors)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (nbytes > 4095) {
|
if (nbytes > (PDU_BUF_SIZE - 1)) {
|
||||||
r = 1;
|
r = 1;
|
||||||
|
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if(nbytes > 0)
|
||||||
printbuf(buffer, nbytes, color?2:0, timestamp, format,
|
printbuf(buffer, nbytes, color?2:0, timestamp, format,
|
||||||
&tv, &last_tv, dst, s, if_name, head);
|
&tv, &last_tv, dst, s, if_name, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(t, &rdfs)) {
|
if (FD_ISSET(t, &rdfs)) {
|
||||||
nbytes = read(t, buffer, 4096);
|
nbytes = read(t, buffer, PDU_BUF_SIZE);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
perror("read socket t");
|
perror("read socket t");
|
||||||
r = 1;
|
r = 1;
|
||||||
|
if(!ignore_errors)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (nbytes > 4095) {
|
if (nbytes > (PDU_BUF_SIZE - 1)) {
|
||||||
r = 1;
|
r = 1;
|
||||||
|
fprintf(stderr, "PDU length %d longer than PDU buffer: %s\n", nbytes, strerror(errno));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if(nbytes > 0)
|
||||||
printbuf(buffer, nbytes, color?1:0, timestamp, format,
|
printbuf(buffer, nbytes, color?1:0, timestamp, format,
|
||||||
&tv, &last_tv, src, t, if_name, head);
|
&tv, &last_tv, src, t, if_name, head);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
lib.c
7
lib.c
|
|
@ -83,8 +83,8 @@ static inline void _put_id(char *buf, int end_offset, canid_t id)
|
||||||
|
|
||||||
/* CAN DLC to real data length conversion helpers */
|
/* CAN DLC to real data length conversion helpers */
|
||||||
|
|
||||||
static const unsigned char dlc2len[] = {0, 1, 2, 3, 4, 5, 6, 7,
|
static const unsigned char dlc2len[] = {
|
||||||
8, 12, 16, 20, 24, 32, 48, 64};
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
|
||||||
|
|
||||||
/* get data length from raw data length code (DLC) */
|
/* get data length from raw data length code (DLC) */
|
||||||
unsigned char can_fd_dlc2len(unsigned char dlc)
|
unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||||
|
|
@ -92,7 +92,8 @@ unsigned char can_fd_dlc2len(unsigned char dlc)
|
||||||
return dlc2len[dlc & 0x0F];
|
return dlc2len[dlc & 0x0F];
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char len2dlc[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
static const unsigned char len2dlc[] = {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||||
9, 9, 9, 9, /* 9 - 12 */
|
9, 9, 9, 9, /* 9 - 12 */
|
||||||
10, 10, 10, 10, /* 13 - 16 */
|
10, 10, 10, 10, /* 13 - 16 */
|
||||||
11, 11, 11, 11, /* 17 - 20 */
|
11, 11, 11, 11, /* 17 - 20 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue