#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <getopt.h>
#include <boilerplate/ancillaries.h>
#include <alchemy/task.h>
#include <alchemy/timer.h>
#include <rtdm/can.h>
extern int optind, opterr, optopt;
static void print_usage(char *prg)
{
fprintf(stderr,
"Usage: %s <can-interface> [Options] <can-msg>\n"
"<can-msg> can consist of up to 8 bytes given as a space separated list\n"
"Options:\n"
" -i, --identifier=ID CAN Identifier (default = 1)\n"
" -r --rtr send remote request\n"
" -e --extended send extended frame\n"
" -l --loop=COUNT send message COUNT times\n"
" -c, --count message count in data[0-3]\n"
" -d, --delay=MS delay in ms (default = 1ms)\n"
" -s, --send use send instead of sendto\n"
" -t, --timeout=MS timeout in ms\n"
" -L, --loopback=0|1 switch local loopback off or on\n"
" -v, --verbose be verbose\n"
" -p, --print=MODULO print every MODULO message\n"
" -h, --help this help\n",
prg);
}
RT_TASK rt_task_desc;
static int s=-1, dlc=0, rtr=0, extended=0, verbose=0, loops=1;
static SRTIME delay=1000000;
static int count=0, print=1, use_send=0, loopback=-1;
static void cleanup(void)
{
int ret;
if (verbose)
printf("Cleaning up...\n");
usleep(100000);
if (s >= 0) {
ret = close(s);
s = -1;
if (ret) {
fprintf(stderr, "close: %s\n", strerror(errno));
}
exit(EXIT_SUCCESS);
}
}
static void cleanup_and_exit(int sig)
{
if (verbose)
printf("Signal %d received\n", sig);
cleanup();
exit(0);
}
static void rt_task(void)
{
int i, j, ret;
for (i = 0; i < loops; i++) {
if (count)
memcpy(&frame.data[0], &i, sizeof(i));
if (use_send)
else
ret = sendto(s, (
void *)&frame,
sizeof(
can_frame_t), 0,
(struct sockaddr *)&to_addr, sizeof(to_addr));
if (ret < 0) {
switch (errno) {
case ETIMEDOUT:
if (verbose)
printf("send(to): timed out\n");
break;
case EBADF:
if (verbose)
printf("send(to): aborted because socket was closed\n");
break;
default:
fprintf(stderr, "send: %s\n", strerror(errno));
break;
}
i = loops;
break;
}
if (verbose && (i % print) == 0) {
else
printf(" [%d]", frame.can_dlc);
for (j = 0; j < frame.can_dlc; j++) {
printf(" %02x", frame.data[j]);
}
printf("\n");
}
}
}
int main(int argc, char **argv)
{
int i, opt, ret;
char name[32];
struct option long_options[] = {
{ "help", no_argument, 0, 'h' },
{ "identifier", required_argument, 0, 'i'},
{ "rtr", no_argument, 0, 'r'},
{ "extended", no_argument, 0, 'e'},
{ "verbose", no_argument, 0, 'v'},
{ "count", no_argument, 0, 'c'},
{ "print", required_argument, 0, 'p'},
{ "loop", required_argument, 0, 'l'},
{ "delay", required_argument, 0, 'd'},
{ "send", no_argument, 0, 's'},
{ "timeout", required_argument, 0, 't'},
{ "loopback", required_argument, 0, 'L'},
{ 0, 0, 0, 0},
};
signal(SIGTERM, cleanup_and_exit);
signal(SIGINT, cleanup_and_exit);
frame.can_id = 1;
while ((opt = getopt_long(argc, argv, "hvi:l:red:t:cp:sL:",
long_options, NULL)) != -1) {
switch (opt) {
case 'h':
print_usage(argv[0]);
exit(0);
case 'p':
print = strtoul(optarg, NULL, 0);
case 'v':
verbose = 1;
break;
case 'c':
count = 1;
break;
case 'l':
loops = strtoul(optarg, NULL, 0);
break;
case 'i':
frame.can_id = strtoul(optarg, NULL, 0);
break;
case 'r':
rtr = 1;
break;
case 'e':
extended = 1;
break;
case 'd':
delay = strtoul(optarg, NULL, 0) * 1000000LL;
break;
case 's':
use_send = 1;
break;
case 't':
timeout = strtoul(optarg, NULL, 0) * 1000000LL;
break;
case 'L':
loopback = strtoul(optarg, NULL, 0);
break;
default:
fprintf(stderr, "Unknown option %c\n", opt);
break;
}
}
if (optind == argc) {
print_usage(argv[0]);
exit(0);
}
if (argv[optind] == NULL) {
fprintf(stderr, "No Interface supplied\n");
exit(-1);
}
if (verbose)
printf("interface %s\n", argv[optind]);
if (ret < 0) {
fprintf(stderr, "socket: %s\n", strerror(errno));
return -1;
}
s = ret;
if (loopback >= 0) {
&loopback, sizeof(loopback));
if (ret < 0) {
fprintf(stderr, "setsockopt: %s\n", strerror(errno));
goto failure;
}
if (verbose)
printf("Using loopback=%d\n", loopback);
}
namecpy(ifr.ifr_name, argv[optind]);
if (verbose)
printf("s=%d, ifr_name=%s\n", s, ifr.ifr_name);
if (ret < 0) {
fprintf(stderr, "ioctl: %s\n", strerror(errno));
goto failure;
}
memset(&to_addr, 0, sizeof(to_addr));
to_addr.can_ifindex = ifr.ifr_ifindex;
if (use_send) {
if (ret < 0) {
fprintf(stderr, "setsockopt: %s\n", strerror(errno));
goto failure;
}
ret = bind(s, (struct sockaddr *)&to_addr, sizeof(to_addr));
if (ret < 0) {
fprintf(stderr, "bind: %s\n", strerror(errno));
goto failure;
}
}
if (count)
frame.can_dlc = sizeof(int);
else {
for (i = optind + 1; i < argc; i++) {
frame.data[dlc] = strtoul(argv[i], NULL, 0);
dlc++;
if( dlc == 8 )
break;
}
frame.can_dlc = dlc;
}
if (rtr)
if (extended)
if (timeout) {
if (verbose)
printf("Timeout: %lld ns\n", (long long)timeout);
if (ret) {
fprintf(stderr, "ioctl SND_TIMEOUT: %s\n", strerror(errno));
goto failure;
}
}
snprintf(name, sizeof(name), "rtcansend-%d", getpid());
if (ret) {
fprintf(stderr, "rt_task_shadow: %s\n", strerror(-ret));
goto failure;
}
rt_task();
cleanup();
return 0;
failure:
cleanup();
return -1;
}