On 05/11/2011 11:04 PM, Kurt Van Dijck wrote: > Oliver, > > Yet another interesting general purpose tool: jdate > It sends out the date/time PGN.
Can you add a date/time receiver to this tool, too? Some nitpicking inline: cheers, Marc > Kurt > PS: I know you can't test immediately :-) > --- > Signed-off-by: Kurt Van Dijck <[email protected]> > --- > Index: can-utils/Makefile > =================================================================== > --- can-utils/Makefile (revision 1257) > +++ can-utils/Makefile (working copy) > @@ -56,7 +56,7 @@ > PROGRAMS_ISOTP = isotpdump isotprecv isotpsend isotpsniffer isotptun > isotpserver > PROGRAMS_CANGW = cangw > PROGRAMS_SLCAN = slcan_attach slcand > -PROGRAMS_J1939 = jacd jspy jsr > +PROGRAMS_J1939 = jacd jspy jsr jdate keep/make the list sorted > PROGRAMS = can-calc-bit-timing candump cansniffer cansend canplayer cangen > canbusload\ > log2long log2asc asc2log\ > canlogserver bcmserver\ > @@ -107,4 +107,5 @@ > > jspy: libj1939.a > jsr: libj1939.a > +jdate: libj1939.a dito > > Index: can-utils/GNUmakefile.am > =================================================================== > --- can-utils/GNUmakefile.am (revision 1257) > +++ can-utils/GNUmakefile.am (working copy) > @@ -56,11 +56,13 @@ > bin_PROGRAMS += \ > jacd \ > jsr \ > - jspy > + jspy \ > + jdate dito > > jacd_LDADD = libj1939.la > jsr_LDADD = libj1939.la > jspy_LDADD = libj1939.la > +jdate_LDADD = libj1939.la > > noinst_LTLIBRARIES += libj1939.la > > Index: can-utils/jdate.c > =================================================================== > --- can-utils/jdate.c (revision 0) > +++ can-utils/jdate.c (revision 0) > @@ -0,0 +1,279 @@ > +/* > + * Copyright (c) 2011 EIA Electronics > + * > + * Authors: > + * Kurt Van Dijck <[email protected]> > + * > + * 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 <signal.h> > +#include <time.h> > +#include <inttypes.h> > +#include <errno.h> > +#include <string.h> > +#include <stdlib.h> > +#include <stdio.h> > + > +#include <unistd.h> > +#include <getopt.h> > +#include <error.h> > +#include <sys/time.h> > +#include <sys/socket.h> > +#include <linux/can.h> > +#include <linux/can/j1939.h> > +#include "libj1939.h" > + > +static const char help_msg[] = > + "jdate: Send the datetime pgn, each second or on request" "\n" > + "Usage: jdate SOURCE" "\n" > + " -v, --verbose Show info" "\n" > + " -l, --listen Answer to request PGN's only" "\n" ^ 's make no sense here > + " -i, --iso11783 iso-11783 format" "\n" > + "\n" > + "Example:" "\n" > + "jdate --iso can1:20" "\n" > + "\n" > + "Specifications" "\n" > + " - SAE J1939-71 pgn65254" "\n" > + " - ISO 11783-7 Annex B.1" "\n" > + "\n" > + "Notes" "\n" > + "Time/Date Adjust is not yet supported" "\n" > + ; > + > +#ifdef _GNU_SOURCE > +static struct option long_opts[] = { > + { "help", no_argument, NULL, '?', }, > + { "listen", no_argument, NULL, 'l', }, > + { "verbose", no_argument, NULL, 'v', }, > + { "iso11783", no_argument, NULL, 'i', }, > + { }, > +}; > +#else > +#define getopt_long(argc, argv, optstring, longopts, longindex) \ > + getopt((argc), (argv), (optstring)) > +#endif > +static const char optstring[] = "liv?"; > + > +/* global variables */ > +static struct { > + const char *source; > + int periodic; > + int verbose; > + int iso; > + int sig_term; > + int sig_alrm; > +} s = { > + .source = "can0:", > + .periodic = 1, > +}; > + > +/* j1939 socket */ > +static const struct j1939_filter filt[] = { > + { > + .pgn = 0x0ea00, > + .pgn_mask = 0x3ff00, > + }, > +}; > + > +static int open_socket(const char *source) > +{ > + int ret, sock; > + struct sockaddr_can saddr; > + > + ret = libj1939_str2addr(source, 0, &saddr); > + if (ret < 0) > + error(1, 0, "source spec '%s'", source); > + if (saddr.can_addr.j1939.pgn != J1939_NO_PGN) > + error(1, 0, "no pgn allowed in '%s'", source); > + saddr.can_addr.j1939.pgn = 0xfee6; > + > + sock = ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939); > + if (ret < 0) > + error(1, errno, "socket(j1939)"); > + > + ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_FILTER, > + &filt, sizeof(filt)); > + if (ret < 0) > + error(1, errno, "setsockopt filter"); > + > + ret = bind(sock, (void *)&saddr, sizeof(saddr)); > + if (ret < 0) > + error(1, errno, "bind()"); > + return sock; > +} > + > +/* signa handling */ ^l > +static void sighandler(int sig, siginfo_t *info, void *vp) > +{ > + switch (sig) { > + case SIGINT: > + case SIGTERM: > + s.sig_term = 1; > + break; > + case SIGALRM: > + s.sig_alrm = 1; > + break; > + } > +} > + > +static void install_signal(int sig) > +{ > + int ret; > + struct sigaction sigact = { > + .sa_sigaction = sighandler, > + .sa_flags = SA_SIGINFO, > + }; > + > + sigfillset(&sigact.sa_mask); > + ret = sigaction(sig, &sigact, NULL); > + if (ret < 0) > + error(1, errno, "sigaction for signal %i", sig); > +} > + > +static void schedule_repeating_itimer(int msec) > +{ > + int ret; > + struct itimerval val = {}; > + > + val.it_value.tv_sec = msec / 1000; > + val.it_value.tv_usec = (msec % 1000) * 1000; > + val.it_interval = val.it_value; C99 initializer? > + > + s.sig_alrm = 0; > + do { > + ret = setitimer(ITIMER_REAL, &val, NULL); > + } while ((ret < 0) && (errno == EINTR)); > + if (ret < 0) > + error(1, errno, "setitimer %i msec", msec); > +} > + > +static void fill_datetime(uint8_t dat[8]) > +{ > + struct timeval tv; > + struct timezone tz; > + struct tm tm; > + > + if (gettimeofday(&tv, &tz) < 0) > + error(1, errno, "gettimeofday"); > + > + tm = *gmtime(&tv.tv_sec); > + dat[0] = tm.tm_sec *4; ^ > + dat[1] = tm.tm_min; > + dat[2] = tm.tm_hour; > + dat[3] = tm.tm_mon +1 ^ ; > + dat[4] = tm.tm_mday *4; ^ please add a whitespace, each :) > + dat[5] = tm.tm_year - 85; > + if (s.iso) { > + dat[6] = 0; > + dat[7] = (-tz.tz_minuteswest / 60) + 24; > + } else { > + dat[6] = (-tz.tz_minuteswest % 60) + 125; > + dat[7] = (-tz.tz_minuteswest / 60) + 125; > + } > +} > + > +static int ratelimit_errno(int _errno) > +{ > + static int saved_errno; > + int ret; > + > + ret = _errno != saved_errno; > + saved_errno = _errno; > + return ret; > +} > + > +/* main */ > +int main(int argc, char *argv[]) > +{ > + int ret, sock, pgn, opt; > + uint8_t dat[9]; > + struct sockaddr_can daddr; > + > +#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 'l': > + s.periodic = 0; > + break; > + case 'i': > + s.iso = 1; > + break; > + case 'v': > + ++s.verbose; > + break; > + default: > + fputs(help_msg, stderr); > + exit(1); > + break; > + } > + if (argv[optind]) > + s.source = argv[optind++]; > + /* args done */ > + > + ret = sock = open_socket(s.source); > + > + install_signal(SIGTERM); > + install_signal(SIGINT); > + install_signal(SIGALRM); > + install_signal(SIGUSR1); > + install_signal(SIGUSR2); > + > + if (s.periodic) > + schedule_repeating_itimer(1000); > + > + while (!s.sig_term) { > + if (s.sig_alrm) { > + /* send datetime */ > + memset(&daddr, 0, sizeof(daddr)); > + > + fill_datetime(dat); > + ret = send(sock, dat, 8, 0); > + if (ret < 0) > + switch (errno) { > + case EINTR: > + continue; > + case ENOBUFS: > + case EHOSTDOWN: > + case EADDRNOTAVAIL: > + if (ratelimit_errno(errno)) > + error(0, errno, "j1939 send"); > + break; > + default: > + error(1, errno, "j1939 send"); > + break; > + } else if (ratelimit_errno(0)) > + error(0, 0, "j1939 send ok"); > + > + s.sig_alrm = 0; > + if (s.verbose && (ret >= 0)) > + error(0, 0, "send"); > + } > + > + ret = recv(sock, dat, sizeof(dat), 0); You send 8 byte but receive 9. Is this a j1939 thing speciality? > + if (ret < 0) { > + if (EINTR == errno) > + continue; > + error(1, errno, "recvfrom()"); > + } > + if (ret < 3) > + continue; > + pgn = dat[0] + (dat[1] << 8) + ((dat[2] & 0x03) << 16); > + > + switch (pgn) { > + case 0x0fee6: Quite unusual, I'd write: if (pgn == 0x0fee6) > + if (s.verbose) > + error(0, 0, "got request"); > + s.sig_alrm = 1; > + break; > + } > + } > + return 0; > +} > + > > Property changes on: can-utils/jdate.c > ___________________________________________________________________ > Name: svn:eol-style > + native > > _______________________________________________ > Socketcan-core mailing list > [email protected] > https://lists.berlios.de/mailman/listinfo/socketcan-core -- Pengutronix e.K. | Marc Kleine-Budde | Industrial Linux Solutions | Phone: +49-231-2826-924 | Vertretung West/Dortmund | Fax: +49-5121-206917-5555 | Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Socketcan-core mailing list [email protected] https://lists.berlios.de/mailman/listinfo/socketcan-core
