can-j1939: add jsr program
jsr sends data on <stdin> to j1939, and received j1939 data is put on <stdout>. Signed-off-by: Kurt Van Dijck <kurt.van.dijck@eia.be> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>pull/63/merge
parent
c50b5a39de
commit
2cd00814a1
|
|
@ -41,6 +41,7 @@ GNUmakefile.in
|
|||
/isotpsniffer
|
||||
/isotptun
|
||||
/jspy
|
||||
/jsr
|
||||
/log2asc
|
||||
/log2long
|
||||
/slcan_attach
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ bin_PROGRAMS = \
|
|||
isotpsniffer \
|
||||
isotptun \
|
||||
jspy \
|
||||
jsr \
|
||||
log2asc \
|
||||
log2long \
|
||||
slcan_attach \
|
||||
|
|
@ -64,6 +65,7 @@ bin_PROGRAMS = \
|
|||
slcanpty
|
||||
|
||||
jspy_LDADD = libj1939.la
|
||||
jsr_LDADD = libj1939.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -55,7 +55,7 @@ CPPFLAGS += -Iinclude \
|
|||
PROGRAMS_ISOTP = isotpdump isotprecv isotpsend isotpsniffer isotptun isotpserver isotpperf
|
||||
PROGRAMS_CANGW = cangw
|
||||
PROGRAMS_SLCAN = slcan_attach slcand
|
||||
PROGRAMS_J1939 = jspy
|
||||
PROGRAMS_J1939 = jspy jsr
|
||||
PROGRAMS = can-calc-bit-timing candump cansniffer cansend canplayer cangen canbusload\
|
||||
log2long log2asc asc2log\
|
||||
canlogserver bcmserver\
|
||||
|
|
@ -87,6 +87,7 @@ log2long.o: lib.h
|
|||
log2asc.o: lib.h
|
||||
asc2log.o: lib.h
|
||||
jspy.o: libj1939.h
|
||||
jsr.o: libj1939.h
|
||||
canframelen.o: canframelen.h
|
||||
|
||||
cansend: cansend.o lib.o
|
||||
|
|
@ -100,3 +101,4 @@ asc2log: asc2log.o lib.o
|
|||
canbusload: canbusload.o canframelen.o
|
||||
|
||||
jspy: jspy.o libj1939.o
|
||||
jsr: jsr.o libj1939.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2011 EIA Electronics
|
||||
*
|
||||
* Authors:
|
||||
* Kurt Van Dijck <kurt.van.dijck@eia.be>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <error.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "libj1939.h"
|
||||
|
||||
/*
|
||||
* getopt
|
||||
*/
|
||||
static const char help_msg[] =
|
||||
"jsr: An SAE J1939 send/recv utility" "\n"
|
||||
"Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
|
||||
"\n"
|
||||
" -v, --verbose Increase verbosity" "\n"
|
||||
" -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
|
||||
" -S, --serialize Strictly serialize outgoing packets" "\n"
|
||||
" -s, --size Packet size, default autodetected" "\n"
|
||||
"\n"
|
||||
" SOURCE [IFACE:][NAME|SA][,PGN]" "\n"
|
||||
" DEST [NAME|SA]" "\n"
|
||||
;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
static struct option long_opts[] = {
|
||||
{ "help", no_argument, NULL, '?', },
|
||||
{ "verbose", no_argument, NULL, 'v', },
|
||||
|
||||
{ "priority", required_argument, NULL, 'p', },
|
||||
{ "size", required_argument, NULL, 's', },
|
||||
{ "serialize", no_argument, NULL, 'S', },
|
||||
{ },
|
||||
};
|
||||
#else
|
||||
#define getopt_long(argc, argv, optstring, longopts, longindex) \
|
||||
getopt((argc), (argv), (optstring))
|
||||
#endif
|
||||
static const char optstring[] = "vp:s:S?";
|
||||
|
||||
/*
|
||||
* static variables: configurations
|
||||
*/
|
||||
static struct {
|
||||
int verbose;
|
||||
int sendflags; /* flags for sendto() */
|
||||
int pkt_len;
|
||||
int priority;
|
||||
int defined;
|
||||
#define DEF_SRC 1
|
||||
#define DEF_DST 2
|
||||
#define DEF_PRIO 4
|
||||
struct sockaddr_can src, dst;
|
||||
} s = {
|
||||
.priority = 6,
|
||||
.src.can_addr.j1939 = {
|
||||
.name = J1939_NO_NAME,
|
||||
.addr = J1939_NO_ADDR,
|
||||
.pgn = J1939_NO_PGN,
|
||||
},
|
||||
.dst.can_addr.j1939 = {
|
||||
.name = J1939_NO_NAME,
|
||||
.addr = J1939_NO_ADDR,
|
||||
.pgn = J1939_NO_PGN,
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
int ret, sock, opt;
|
||||
unsigned int len;
|
||||
struct pollfd pfd[2];
|
||||
uint8_t *buf;
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
program_invocation_name = program_invocation_short_name;
|
||||
#endif
|
||||
/* argument parsing */
|
||||
while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
|
||||
switch (opt) {
|
||||
case 'v':
|
||||
++s.verbose;
|
||||
break;
|
||||
case 's':
|
||||
s.pkt_len = strtoul(optarg, 0, 0);
|
||||
if (!s.pkt_len)
|
||||
error(1, EINVAL, "packet size of %s", optarg);
|
||||
break;
|
||||
case 'p':
|
||||
s.priority = strtoul(optarg, 0, 0);
|
||||
s.defined |= DEF_PRIO;
|
||||
break;
|
||||
case 'S':
|
||||
s.sendflags |= MSG_SYN;
|
||||
break;
|
||||
default:
|
||||
fputs(help_msg, stderr);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (argv[optind]) {
|
||||
optarg = argv[optind++];
|
||||
ret = libj1939_str2addr(optarg, 0, &s.src);
|
||||
if (ret < 0)
|
||||
error(1, 0, "bad address spec [%s]", optarg);
|
||||
s.defined |= DEF_SRC;
|
||||
}
|
||||
if (argv[optind]) {
|
||||
optarg = argv[optind++];
|
||||
ret = libj1939_str2addr(optarg, 0, &s.dst);
|
||||
if (ret < 0)
|
||||
error(1, 0, "bad address spec [%s]", optarg);
|
||||
s.defined |= DEF_DST;
|
||||
}
|
||||
|
||||
if (!s.pkt_len) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(STDIN_FILENO, &st) < 0)
|
||||
error(1, errno, "stat stdin, could not determine buffer size");
|
||||
s.pkt_len = st.st_size ?: 1024;
|
||||
}
|
||||
|
||||
/* prepare */
|
||||
buf = malloc(s.pkt_len);
|
||||
if (!buf)
|
||||
error(1, errno, "malloc %u", s.pkt_len);
|
||||
|
||||
sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
|
||||
if (sock < 0)
|
||||
error(1, errno, "socket(can, dgram, j1939)");
|
||||
|
||||
if (s.defined & DEF_PRIO) {
|
||||
ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &s.priority, sizeof(s.priority));
|
||||
if (ret < 0)
|
||||
error(1, errno, "setsockopt priority");
|
||||
}
|
||||
if (s.defined & DEF_SRC) {
|
||||
s.src.can_family = AF_CAN;
|
||||
ret = bind(sock, (void *)&s.src, sizeof(s.src));
|
||||
if (ret < 0)
|
||||
error(1, errno, "bind(%s), %i", libj1939_addr2str(&s.src), -errno);
|
||||
}
|
||||
|
||||
if (s.defined & DEF_DST) {
|
||||
s.dst.can_family = AF_CAN;
|
||||
ret = connect(sock, (void *)&s.dst, sizeof(s.dst));
|
||||
if (ret < 0)
|
||||
error(1, errno, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno);
|
||||
}
|
||||
|
||||
pfd[0].fd = STDIN_FILENO;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = sock;
|
||||
pfd[1].events = POLLIN;
|
||||
|
||||
/* run */
|
||||
while (1) {
|
||||
ret = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), -1);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
error(1, errno, "poll()");
|
||||
}
|
||||
if (pfd[0].revents) {
|
||||
ret = read(pfd[0].fd, buf, s.pkt_len);
|
||||
if (ret < 0)
|
||||
error(1, errno, "read(stdin)");
|
||||
if (!ret)
|
||||
break;
|
||||
len = ret;
|
||||
do {
|
||||
ret = send(pfd[1].fd, buf, len, s.sendflags);
|
||||
if (ret < 0)
|
||||
error(errno != ENOBUFS, errno, "write(%s)",
|
||||
libj1939_addr2str(&s.src));
|
||||
} while (ret < 0);
|
||||
}
|
||||
if (pfd[1].revents) {
|
||||
ret = read(pfd[1].fd, buf, s.pkt_len);
|
||||
if (ret < 0) {
|
||||
ret = errno;
|
||||
error(0, errno, "read(%s)", libj1939_addr2str(&s.dst));
|
||||
switch (ret) {
|
||||
case EHOSTDOWN:
|
||||
break;
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
write(STDOUT_FILENO, buf, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue