commit
abbd47bd09
173
cangen.c
173
cangen.c
|
|
@ -69,52 +69,39 @@
|
||||||
#define DEFAULT_GAP 200 /* ms */
|
#define DEFAULT_GAP 200 /* ms */
|
||||||
#define DEFAULT_BURST_COUNT 1
|
#define DEFAULT_BURST_COUNT 1
|
||||||
|
|
||||||
#define MODE_RANDOM 0
|
#define MODE_RANDOM 0
|
||||||
#define MODE_INCREMENT 1
|
#define MODE_INCREMENT 1
|
||||||
#define MODE_FIX 2
|
#define MODE_FIX 2
|
||||||
#define MODE_RANDOM_EVEN 3
|
#define MODE_RANDOM_EVEN 3
|
||||||
#define MODE_RANDOM_ODD 4
|
#define MODE_RANDOM_ODD 4
|
||||||
|
|
||||||
extern int optind, opterr, optopt;
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
static volatile int running = 1;
|
static volatile int running = 1;
|
||||||
static unsigned long long enobufs_count;
|
static unsigned long long enobufs_count;
|
||||||
|
|
||||||
void print_usage(char *prg)
|
static void print_usage(char *prg)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
|
fprintf(stderr, "%s - CAN frames generator.\n\n", prg);
|
||||||
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
|
fprintf(stderr, "Usage: %s [options] <CAN interface>\n", prg);
|
||||||
fprintf(stderr, "Options:\n");
|
fprintf(stderr, "Options:\n");
|
||||||
fprintf(stderr, " -g <ms> (gap in milli seconds "
|
fprintf(stderr, " -g <ms> (gap in milli seconds - default: %d ms)\n", DEFAULT_GAP);
|
||||||
"- default: %d ms)\n", DEFAULT_GAP);
|
fprintf(stderr, " -e (generate extended frame mode (EFF) CAN frames)\n");
|
||||||
fprintf(stderr, " -e (generate extended frame mode "
|
|
||||||
"(EFF) CAN frames)\n");
|
|
||||||
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
fprintf(stderr, " -f (generate CAN FD CAN frames)\n");
|
||||||
fprintf(stderr, " -b (generate CAN FD CAN frames"
|
fprintf(stderr, " -b (generate CAN FD CAN frames with bitrate switch (BRS))\n");
|
||||||
" with bitrate switch (BRS))\n");
|
fprintf(stderr, " -E (generate CAN FD CAN frames with error state (ESI))\n");
|
||||||
fprintf(stderr, " -E (generate CAN FD CAN frames"
|
|
||||||
" with error state (ESI))\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 frames)\n");
|
fprintf(stderr, " -m (mix -e -f -b -E -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) generation mode - see below)\n");
|
||||||
fprintf(stderr, " -L <mode> (CAN data length code (dlc)"
|
fprintf(stderr, " -D <mode> (CAN data (payload) generation mode - see below)\n");
|
||||||
" generation mode - see below)\n");
|
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames with <timeout> ms)\n");
|
||||||
fprintf(stderr, " -D <mode> (CAN data (payload)"
|
fprintf(stderr, " -n <count> (terminate after <count> CAN frames - default infinite)\n");
|
||||||
" generation mode - see below)\n");
|
fprintf(stderr, " -i (ignore -ENOBUFS return values on write() syscalls)\n");
|
||||||
fprintf(stderr, " -p <timeout> (poll on -ENOBUFS to write frames"
|
fprintf(stderr, " -x (disable local loopback of generated CAN frames)\n");
|
||||||
" with <timeout> ms)\n");
|
fprintf(stderr, " -c <count> (number of messages to send in burst, default %u)\n", DEFAULT_BURST_COUNT);
|
||||||
fprintf(stderr, " -n <count> (terminate after <count> CAN frames "
|
fprintf(stderr, " -v (increment verbose level for printing sent CAN frames)\n\n");
|
||||||
"- default infinite)\n");
|
|
||||||
fprintf(stderr, " -i (ignore -ENOBUFS return values on"
|
|
||||||
" write() syscalls)\n");
|
|
||||||
fprintf(stderr, " -x (disable local loopback of "
|
|
||||||
"generated CAN frames)\n");
|
|
||||||
fprintf(stderr, " -c <count> (number of messages to send in burst, "
|
|
||||||
"default 1)\n");
|
|
||||||
fprintf(stderr, " -v (increment verbose level for "
|
|
||||||
"printing sent CAN frames)\n\n");
|
|
||||||
fprintf(stderr, "Generation modes:\n");
|
fprintf(stderr, "Generation modes:\n");
|
||||||
fprintf(stderr, " 'r' => random values (default)\n");
|
fprintf(stderr, " 'r' => random values (default)\n");
|
||||||
fprintf(stderr, " 'e' => random values, even ID\n");
|
fprintf(stderr, " 'e' => random values, even ID\n");
|
||||||
|
|
@ -122,8 +109,7 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, " 'i' => increment values\n");
|
fprintf(stderr, " 'i' => increment values\n");
|
||||||
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
|
fprintf(stderr, " <value> => fixed value (in hexadecimal for -I and -D)\n\n");
|
||||||
fprintf(stderr, "The gap value (in milliseconds) may have decimal places, e.g. '-g 4.73'\n");
|
fprintf(stderr, "The gap value (in milliseconds) may have decimal places, e.g. '-g 4.73'\n");
|
||||||
fprintf(stderr, "When incrementing the CAN data the data length code "
|
fprintf(stderr, "When incrementing the CAN data the data length code minimum is set to 1.\n");
|
||||||
"minimum is set to 1.\n");
|
|
||||||
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
|
fprintf(stderr, "CAN IDs and data content are given and expected in hexadecimal values.\n\n");
|
||||||
fprintf(stderr, "Examples:\n");
|
fprintf(stderr, "Examples:\n");
|
||||||
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v\n", prg);
|
fprintf(stderr, "%s vcan0 -g 4 -I 42A -L 1 -D i -v -v\n", prg);
|
||||||
|
|
@ -142,7 +128,7 @@ void print_usage(char *prg)
|
||||||
fprintf(stderr, "\t(my favourite default :)\n\n");
|
fprintf(stderr, "\t(my favourite default :)\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sigterm(int signo)
|
static void sigterm(int signo)
|
||||||
{
|
{
|
||||||
running = 0;
|
running = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +163,7 @@ int main(int argc, char **argv)
|
||||||
int s; /* socket */
|
int s; /* socket */
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
|
|
||||||
struct sockaddr_can addr;
|
struct sockaddr_can addr = { 0 };
|
||||||
static struct canfd_frame frame;
|
static struct canfd_frame frame;
|
||||||
struct can_frame *ccf = (struct can_frame *)&frame;
|
struct can_frame *ccf = (struct can_frame *)&frame;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
|
|
@ -186,6 +172,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* set seed value for pseudo random numbers */
|
/* set seed value for pseudo random numbers */
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
|
|
@ -195,13 +182,9 @@ int main(int argc, char **argv)
|
||||||
signal(SIGHUP, sigterm);
|
signal(SIGHUP, sigterm);
|
||||||
signal(SIGINT, sigterm);
|
signal(SIGINT, sigterm);
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "ig:ebEfmI:L:D:xp:n:c:vR8h?")) != -1) {
|
while ((opt = getopt(argc, argv, "g:efbER8mI:L:D:p:n:ixc:vh?")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
|
||||||
case 'i':
|
|
||||||
ignore_enobufs = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'g':
|
case 'g':
|
||||||
gap = strtod(optarg, NULL);
|
gap = strtod(optarg, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
@ -224,6 +207,14 @@ int main(int argc, char **argv)
|
||||||
canfd = 1;
|
canfd = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'R':
|
||||||
|
rtr_frame = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '8':
|
||||||
|
len8_dlc = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
mix = 1;
|
mix = 1;
|
||||||
canfd = 1; /* to switch the socket into CAN FD mode */
|
canfd = 1; /* to switch the socket into CAN FD mode */
|
||||||
|
|
@ -263,32 +254,12 @@ int main(int argc, char **argv)
|
||||||
} else {
|
} else {
|
||||||
data_mode = MODE_FIX;
|
data_mode = MODE_FIX;
|
||||||
if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) {
|
if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) {
|
||||||
printf ("wrong fix data definition\n");
|
printf("wrong fix data definition\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
|
||||||
burst_count = strtoul(optarg, NULL, 10);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'v':
|
|
||||||
verbose++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'x':
|
|
||||||
loopback_disable = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'R':
|
|
||||||
rtr_frame = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '8':
|
|
||||||
len8_dlc = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
polltimeout = strtoul(optarg, NULL, 10);
|
polltimeout = strtoul(optarg, NULL, 10);
|
||||||
break;
|
break;
|
||||||
|
|
@ -301,12 +272,27 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
ignore_enobufs = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
loopback_disable = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
burst_count = strtoul(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
print_usage(basename(argv[0]));
|
print_usage(basename(argv[0]));
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,8 +306,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* recognize obviously missing commandline option */
|
/* recognize obviously missing commandline option */
|
||||||
if (id_mode == MODE_FIX && 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,35 +315,36 @@ int main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
|
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
|
||||||
|
if (s < 0) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.can_family = AF_CAN;
|
addr.can_family = AF_CAN;
|
||||||
|
addr.can_ifindex = if_nametoindex(argv[optind]);
|
||||||
strcpy(ifr.ifr_name, argv[optind]);
|
if (!addr.can_ifindex) {
|
||||||
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
perror("if_nametoindex");
|
||||||
perror("SIOCGIFINDEX");
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
addr.can_ifindex = ifr.ifr_ifindex;
|
|
||||||
|
|
||||||
/* disable default receive filter on this RAW socket */
|
/*
|
||||||
/* This is obsolete as we do not read from the socket at all, but for */
|
* disable default receive filter on this RAW socket
|
||||||
/* this reason we can remove the receive list in the Kernel to save a */
|
* This is obsolete as we do not read from the socket at all, but for
|
||||||
/* little (really a very little!) CPU usage. */
|
* this reason we can remove the receive list in the Kernel to save a
|
||||||
|
* little (really a very little!) CPU usage.
|
||||||
|
*/
|
||||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
|
||||||
|
|
||||||
if (loopback_disable) {
|
if (loopback_disable) {
|
||||||
int loopback = 0;
|
const int loopback = 0;
|
||||||
|
|
||||||
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK,
|
||||||
&loopback, sizeof(loopback));
|
&loopback, sizeof(loopback));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canfd) {
|
if (canfd) {
|
||||||
int enable_canfd = 1;
|
const int enable_canfd = 1;
|
||||||
|
|
||||||
/* check if the frame fits into the CAN netdevice */
|
/* check if the frame fits into the CAN netdevice */
|
||||||
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
if (ioctl(s, SIOCGIFMTU, &ifr) < 0) {
|
||||||
|
|
@ -372,7 +358,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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, &enable_canfd, sizeof(enable_canfd))){
|
if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))) {
|
||||||
printf("error when enabling CAN FD support\n");
|
printf("error when enabling CAN FD support\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -409,7 +395,7 @@ int main(int argc, char **argv)
|
||||||
if (count && (--count == 0))
|
if (count && (--count == 0))
|
||||||
running = 0;
|
running = 0;
|
||||||
|
|
||||||
if (canfd){
|
if (canfd) {
|
||||||
mtu = CANFD_MTU;
|
mtu = CANFD_MTU;
|
||||||
maxdlen = CANFD_MAX_DLEN;
|
maxdlen = CANFD_MAX_DLEN;
|
||||||
if (brs)
|
if (brs)
|
||||||
|
|
@ -438,7 +424,6 @@ int main(int argc, char **argv)
|
||||||
frame.can_id |= CAN_RTR_FLAG;
|
frame.can_id |= CAN_RTR_FLAG;
|
||||||
|
|
||||||
if (dlc_mode == MODE_RANDOM) {
|
if (dlc_mode == MODE_RANDOM) {
|
||||||
|
|
||||||
if (canfd)
|
if (canfd)
|
||||||
frame.len = can_fd_dlc2len(random() & 0xF);
|
frame.len = can_fd_dlc2len(random() & 0xF);
|
||||||
else {
|
else {
|
||||||
|
|
@ -460,7 +445,6 @@ int main(int argc, char **argv)
|
||||||
frame.len = 1; /* min dlc value for incr. data */
|
frame.len = 1; /* min dlc value for incr. data */
|
||||||
|
|
||||||
if (data_mode == MODE_RANDOM) {
|
if (data_mode == MODE_RANDOM) {
|
||||||
|
|
||||||
rnd = random();
|
rnd = random();
|
||||||
memcpy(&frame.data[0], &rnd, 4);
|
memcpy(&frame.data[0], &rnd, 4);
|
||||||
rnd = random();
|
rnd = random();
|
||||||
|
|
@ -482,11 +466,10 @@ int main(int argc, char **argv)
|
||||||
memset(&frame.data[frame.len], 0, maxdlen - frame.len);
|
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, maxdlen);
|
fprint_long_canframe(stdout, &frame, "\n", (verbose > 2) ? 1 : 0, maxdlen);
|
||||||
else
|
else
|
||||||
fprint_canframe(stdout, &frame, "\n", 1, maxdlen);
|
fprint_canframe(stdout, &frame, "\n", 1, maxdlen);
|
||||||
}
|
}
|
||||||
|
|
@ -503,8 +486,6 @@ resend:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (polltimeout) {
|
if (polltimeout) {
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* wait for the write socket (with timeout) */
|
/* wait for the write socket (with timeout) */
|
||||||
ret = poll(&fds, 1, polltimeout);
|
ret = poll(&fds, 1, polltimeout);
|
||||||
if (ret == 0 || (ret == -1 && errno != -EINTR)) {
|
if (ret == 0 || (ret == -1 && errno != -EINTR)) {
|
||||||
|
|
@ -512,8 +493,9 @@ resend:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
goto resend;
|
goto resend;
|
||||||
} else
|
} else {
|
||||||
enobufs_count++;
|
enobufs_count++;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (nbytes < mtu) {
|
} else if (nbytes < mtu) {
|
||||||
fprintf(stderr, "write: incomplete CAN frame\n");
|
fprintf(stderr, "write: incomplete CAN frame\n");
|
||||||
|
|
@ -521,7 +503,8 @@ resend:
|
||||||
}
|
}
|
||||||
|
|
||||||
burst_sent_count++;
|
burst_sent_count++;
|
||||||
if (gap && burst_sent_count >= burst_count) /* gap == 0 => performance test :-] */
|
if ((ts.tv_sec || ts.tv_nsec) &&
|
||||||
|
burst_sent_count >= burst_count)
|
||||||
if (nanosleep(&ts, NULL))
|
if (nanosleep(&ts, NULL))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
@ -532,7 +515,6 @@ resend:
|
||||||
frame.can_id++;
|
frame.can_id++;
|
||||||
|
|
||||||
if (dlc_mode == MODE_INCREMENT) {
|
if (dlc_mode == MODE_INCREMENT) {
|
||||||
|
|
||||||
incdlc++;
|
incdlc++;
|
||||||
incdlc %= CAN_MAX_RAW_DLC + 1;
|
incdlc %= CAN_MAX_RAW_DLC + 1;
|
||||||
|
|
||||||
|
|
@ -553,22 +535,21 @@ resend:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_mode == MODE_INCREMENT) {
|
if (data_mode == MODE_INCREMENT) {
|
||||||
|
|
||||||
incdata++;
|
incdata++;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mix) {
|
if (mix) {
|
||||||
i = random();
|
i = random();
|
||||||
extended = i&1;
|
extended = i & 1;
|
||||||
canfd = i&2;
|
canfd = i & 2;
|
||||||
if (canfd) {
|
if (canfd) {
|
||||||
brs = i&4;
|
brs = i & 4;
|
||||||
esi = i&8;
|
esi = i & 8;
|
||||||
}
|
}
|
||||||
rtr_frame = ((i&24) == 24); /* reduce RTR frames to 1/4 */
|
rtr_frame = ((i & 24) == 24); /* reduce RTR frames to 1/4 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue