From 2cd00814a162989257946cda7fb02272cce8183b Mon Sep 17 00:00:00 2001 From: Kurt Van Dijck Date: Wed, 13 Mar 2013 20:44:57 +0100 Subject: [PATCH] can-j1939: add jsr program jsr sends data on to j1939, and received j1939 data is put on . Signed-off-by: Kurt Van Dijck Signed-off-by: Marc Kleine-Budde --- .gitignore | 1 + GNUmakefile.am | 2 + Makefile | 4 +- jsr.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 jsr.c diff --git a/.gitignore b/.gitignore index c3cfde9..02274a2 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ GNUmakefile.in /isotpsniffer /isotptun /jspy +/jsr /log2asc /log2long /slcan_attach diff --git a/GNUmakefile.am b/GNUmakefile.am index 7aec699..a75dad1 100644 --- a/GNUmakefile.am +++ b/GNUmakefile.am @@ -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 \ diff --git a/Makefile b/Makefile index 01a59c2..b9a5182 100644 --- a/Makefile +++ b/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 diff --git a/jsr.c b/jsr.c new file mode 100644 index 0000000..0303af0 --- /dev/null +++ b/jsr.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2011 EIA Electronics + * + * Authors: + * Kurt Van Dijck + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} +