Oliver,

Yet another interesting general purpose tool: jdate
It sends out the date/time PGN.

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
 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
 
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
 
 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"
+       " -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 */
+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;
+
+       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;
+       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);
+               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:
+                       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

Reply via email to