summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/ldattach/ldattach.818
-rw-r--r--sbin/ldattach/ldattach.c5
-rw-r--r--share/man/man4/Makefile4
-rw-r--r--share/man/man4/endrun.482
-rw-r--r--sys/conf/GENERIC3
-rw-r--r--sys/conf/files4
-rw-r--r--sys/kern/tty_conf.c17
-rw-r--r--sys/kern/tty_endrun.c532
-rw-r--r--sys/sys/ttycom.h3
9 files changed, 655 insertions, 13 deletions
diff --git a/sbin/ldattach/ldattach.8 b/sbin/ldattach/ldattach.8
index b1ba89c9c3e..aacde1b7d31 100644
--- a/sbin/ldattach/ldattach.8
+++ b/sbin/ldattach/ldattach.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ldattach.8,v 1.12 2008/06/09 22:57:49 jmc Exp $
+.\" $OpenBSD: ldattach.8,v 1.13 2009/05/06 18:21:23 stevesk Exp $
.\"
.\" Copyright (c) 2007, 2008 Marc Balmer <mbalmer@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 9 2008 $
+.Dd $Mdocdate: May 6 2009 $
.Dt LDATTACH 8
.Os
.Sh NAME
@@ -72,15 +72,17 @@ If not specified, the default of 9600 baud is used
(4800 baud for
.Xr nmea 4 ) .
.It Fl t Ar cond
-.Xr nmea 4
-and
+.Xr nmea 4 ,
.Xr msts 4
+and
+.Xr endrun 4
line disciplines only.
Chooses the condition which will cause the current system time to be
immediately copied to the terminal timestamp storage for subsequent use by
-.Xr nmea 4
+.Xr nmea 4 ,
+.Xr msts 4
or
-.Xr msts 4 .
+.Xr endrun 4 .
Only one can be used.
.Pp
.Bl -tag -width DCDXX -offset indent -compact
@@ -103,6 +105,10 @@ character of each block of NMEA sentences.
Specifies the name of the line discipline to be attached.
.Pp
.Bl -tag -width nmeaXX -offset -indet -compact
+.It endrun
+Attach the
+.Xr endrun 4
+line discipline.
.It msts
Attach the
.Xr msts 4
diff --git a/sbin/ldattach/ldattach.c b/sbin/ldattach/ldattach.c
index 69fa88fe105..bf24ca565b4 100644
--- a/sbin/ldattach/ldattach.c
+++ b/sbin/ldattach/ldattach.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldattach.c,v 1.11 2008/06/12 03:52:48 mbalmer Exp $ */
+/* $OpenBSD: ldattach.c,v 1.12 2009/05/06 18:21:23 stevesk Exp $ */
/*
* Copyright (c) 2007, 2008 Marc Balmer <mbalmer@openbsd.org>
@@ -206,6 +206,8 @@ main(int argc, char *argv[])
speed = B4800; /* default is 4800 baud for nmea */
} else if (!strcmp(disc, "msts")) {
ldisc = MSTSDISC;
+ } else if (!strcmp(disc, "endrun")) {
+ ldisc = ENDRUNDISC;
} else {
syslog(LOG_ERR, "unknown line discipline %s", disc);
goto bail_out;
@@ -270,6 +272,7 @@ main(int argc, char *argv[])
/* line discpline specific setup */
switch (ldisc) {
case NMEADISC:
+ case ENDRUNDISC:
if (ioctl(fd, TIOCSTSTAMP, &tstamps) < 0) {
warnx("TIOCSTSTAMP");
goto bail_out;
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 004dfd17da9..1cdcd1235f9 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.480 2009/04/24 21:04:27 mk Exp $
+# $OpenBSD: Makefile,v 1.481 2009/05/06 18:21:23 stevesk Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
@@ -16,7 +16,7 @@ MAN= aac.4 ac97.4 acphy.4 \
ch.4 ciphy.4 ciss.4 clcs.4 clct.4 cmpci.4 cnw.4 \
com.4 crypto.4 cue.4 cy.4 cz.4 dc.4 dcphy.4 ddb.4 de.4 dpt.4 \
drm.4 eap.4 ec.4 eephy.4 ef.4 eg.4 ehci.4 eisa.4 el.4 em.4 \
- emu.4 enc.4 envy.4 ep.4 epic.4 esa.4 \
+ emu.4 enc.4 endrun.4 envy.4 ep.4 epic.4 esa.4 \
eso.4 ess.4 et.4 etphy.4 ex.4 exphy.4 \
faith.4 fd.4 fdc.4 fins.4 fintek.4 fms.4 fpa.4 fxp.4 gdt.4 \
gentbi.4 gem.4 gif.4 \
diff --git a/share/man/man4/endrun.4 b/share/man/man4/endrun.4
new file mode 100644
index 00000000000..ba90ce2badb
--- /dev/null
+++ b/share/man/man4/endrun.4
@@ -0,0 +1,82 @@
+.\" $OpenBSD: endrun.4,v 1.1 2009/05/06 18:21:23 stevesk Exp $
+.\"
+.\" Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
+.\" Copyright (c) 2009 Kevin Steves <stevesk@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: May 6 2009 $
+.Dt ENDRUN 4
+.Os
+.Sh NAME
+.Nm endrun
+.Nd EndRun Technologies native time-of-day message timedelta sensor
+.Sh SYNOPSIS
+.Cd "pseudo-device endrun" Op Ar count
+.Sh DESCRIPTION
+This line discipline interfaces serial EndRun Technologies devices.
+.Pp
+The line discipline is enabled by the following sequence:
+.Bd -literal -offset indent
+#include <sys/ttycom.h>
+int ldisc = ENDRUNDISC, fildes; ...
+ioctl(fildes, TIOCSETD, &ldisc);
+.Ed
+.Pp
+The byte stream is unaltered by the line discipline which
+maintains a timedelta sensor using the EndRun data.
+The timedelta sensor will appear as endrun* in the list of sensors and the delta
+(in nanoseconds) between the received time information and the local time can
+be accessed through the
+.Xr sysctl 8
+interface.
+.Sh SENSOR STATES
+The quality of the timedelta is reported as the sensor status:
+.Bl -tag -width "CRITICALXX" -offset indent
+.It OK
+The time information is valid.
+The timedelta is safe to use for applications like
+.Xr ntpd 8 .
+.It WARN
+The attached receiver has been indicating a warning condition
+for at least the last ten minutes.
+The timedelta should be used with care.
+.It CRITICAL
+tty timestamping has been turned on but there is no PPS signal present or the
+receiver indicated a warning condition for at least the last twenty minutes.
+Check your hardware.
+.El
+.Pp
+The status of a second sensor is used to report the status of the
+device itself using the Time Figure Of Merit (TFOM) character:
+.Bl -tag -width "CRITICALXX" -offset indent
+.It OK
+The clock is synchronized.
+TFOM is 6-9.
+.It WARN
+The clock is synchronized and the time error is greater
+than 10ms or the clock is in the unsynchronized state.
+TFOM is 9.
+.It CRITICAL
+The TFOM is invalid.
+.El
+.Sh SEE ALSO
+.Xr tty 4 ,
+.Xr ldattach 8 ,
+.Xr ntpd 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+interface first appeared in
+.Ox 4.6 .
diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC
index e71a38cff30..a4d904ec0c3 100644
--- a/sys/conf/GENERIC
+++ b/sys/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.143 2008/11/02 01:05:25 pedro Exp $
+# $OpenBSD: GENERIC,v 1.144 2009/05/06 18:21:23 stevesk Exp $
#
# Machine-independent option; used by all architectures for their
# GENERIC kernel
@@ -78,6 +78,7 @@ pseudo-device enc 1 # option IPSEC needs the encapsulation interface
pseudo-device pty 16 # initial number of pseudo-terminals
pseudo-device nmea 1 # NMEA 0183 line discipline
pseudo-device msts 1 # MSTS line discipline
+pseudo-device endrun 1 # EndRun line discipline
pseudo-device vnd 4 # paging to files
pseudo-device ccd 4 # concatenated disk devices
pseudo-device ksyms 1 # kernel symbols device
diff --git a/sys/conf/files b/sys/conf/files
index 7fc38d114ca..38d4e2014c2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.454 2009/01/29 15:12:28 pyr Exp $
+# $OpenBSD: files,v 1.455 2009/05/06 18:21:23 stevesk Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -468,6 +468,7 @@ file dev/ramdisk.c rd needs-flag
pseudo-device pty: tty
pseudo-device nmea: tty
pseudo-device msts: tty
+pseudo-device endrun: tty
pseudo-device loop: ifnet
pseudo-device sl: ifnet
@@ -709,6 +710,7 @@ file kern/tty_conf.c
file kern/tty_pty.c pty needs-count
file kern/tty_nmea.c nmea needs-flag
file kern/tty_msts.c msts needs-flag
+file kern/tty_endrun.c endrun needs-flag
file kern/tty_subr.c
file kern/tty_tty.c
file kern/uipc_domain.c
diff --git a/sys/kern/tty_conf.c b/sys/kern/tty_conf.c
index 783fa7bdcb4..6ef5c80fd1b 100644
--- a/sys/kern/tty_conf.c
+++ b/sys/kern/tty_conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty_conf.c,v 1.12 2008/01/05 17:33:28 mbalmer Exp $ */
+/* $OpenBSD: tty_conf.c,v 1.13 2009/05/06 18:21:23 stevesk Exp $ */
/* $NetBSD: tty_conf.c,v 1.18 1996/05/19 17:17:55 jonathan Exp $ */
/*-
@@ -98,6 +98,13 @@ int mstsclose(struct tty *, int);
int mstsinput(int, struct tty *);
#endif
+#include "endrun.h"
+#if NENDRUN > 0
+int endrunopen(dev_t, struct tty *);
+int endrunclose(struct tty *, int);
+int endruninput(int, struct tty *);
+#endif
+
struct linesw linesw[] =
{
{ ttyopen, ttylclose, ttread, ttwrite, nullioctl,
@@ -157,6 +164,14 @@ struct linesw linesw[] =
{ ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
ttyerrinput, ttyerrstart, nullmodem },
#endif
+
+#if NENDRUN > 0
+ { endrunopen, endrunclose, ttread, ttwrite, nullioctl,
+ endruninput, ttstart, ttymodem }, /* 9- ENDRUNDISC */
+#else
+ { ttynodisc, ttyerrclose, ttyerrio, ttyerrio, nullioctl,
+ ttyerrinput, ttyerrstart, nullmodem },
+#endif
};
int nlinesw = sizeof (linesw) / sizeof (linesw[0]);
diff --git a/sys/kern/tty_endrun.c b/sys/kern/tty_endrun.c
new file mode 100644
index 00000000000..202b56b4cf2
--- /dev/null
+++ b/sys/kern/tty_endrun.c
@@ -0,0 +1,532 @@
+/* $OpenBSD: tty_endrun.c,v 1.1 2009/05/06 18:21:23 stevesk Exp $ */
+
+/*
+ * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
+ * Copyright (c) 2009 Kevin Steves <stevesk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A tty line discipline to decode the EndRun Technologies native
+ * time-of-day message.
+ * http://www.endruntechnologies.com/
+ */
+
+/*
+ * EndRun Format:
+ *
+ * T YYYY DDD HH:MM:SS zZZ m<CR><LF>
+ *
+ * T is the Time Figure of Merit (TFOM) character (described below).
+ * This is the on-time character, transmitted during the first
+ * millisecond of each second.
+ *
+ * YYYY is the year
+ * DDD is the day-of-year
+ * : is the colon character (0x3A)
+ * HH is the hour of the day
+ * MM is the minute of the hour
+ * SS is the second of the minute
+ * z is the sign of the offset to UTC, + implies time is ahead of UTC.
+ * ZZ is the magnitude of the offset to UTC in units of half-hours.
+ * Non-zero only when the Timemode is Local.
+ * m is the Timemode character and is one of:
+ * G = GPS
+ * L = Local
+ * U = UTC
+ * <CR> is the ASCII carriage return character (0x0D)
+ * <LF> is the ASCII line feed character (0x0A)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/sensors.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/time.h>
+
+#ifdef ENDRUN_DEBUG
+#define DPRINTFN(n, x) do { if (endrundebug > (n)) printf x; } while (0)
+int endrundebug = 0;
+#else
+#define DPRINTFN(n, x)
+#endif
+#define DPRINTF(x) DPRINTFN(0, x)
+
+int endrunopen(dev_t, struct tty *);
+int endrunclose(struct tty *, int);
+int endruninput(int, struct tty *);
+void endrunattach(int);
+
+#define ENDRUNLEN 27 /* strlen("6 2009 018 20:41:17 +00 U\r\n") */
+#define NUMFLDS 6
+#ifdef ENDRUN_DEBUG
+#define TRUSTTIME 30
+#else
+#define TRUSTTIME (10 * 60) /* 10 minutes */
+#endif
+
+int endrun_count, endrun_nxid;
+
+struct endrun {
+ char cbuf[ENDRUNLEN]; /* receive buffer */
+ struct ksensor time; /* the timedelta sensor */
+ struct ksensor signal; /* signal status */
+ struct ksensordev timedev;
+ struct timespec ts; /* current timestamp */
+ struct timespec lts; /* timestamp of last TFOM */
+ struct timeout endrun_tout; /* invalidate sensor */
+ int64_t gap; /* gap between two sentences */
+ int64_t last; /* last time rcvd */
+#define SYNC_SCAN 1 /* scanning for '\n' */
+#define SYNC_EOL 2 /* '\n' seen, next char TFOM */
+ int sync;
+ int pos; /* position in rcv buffer */
+ int no_pps; /* no PPS although requested */
+#ifdef ENDRUN_DEBUG
+ char tfom;
+#endif
+};
+
+/* EndRun decoding */
+void endrun_scan(struct endrun *, struct tty *);
+void endrun_decode(struct endrun *, struct tty *, char *fld[], int fldcnt);
+
+/* date and time conversion */
+int endrun_atoi(char *s, int len);
+int endrun_date_to_nano(char *s1, char *s2, int64_t *nano);
+int endrun_time_to_nano(char *s, int64_t *nano);
+int endrun_offset_to_nano(char *s, int64_t *nano);
+
+/* degrade the timedelta sensor */
+void endrun_timeout(void *);
+
+void
+endrunattach(int dummy)
+{
+}
+
+int
+endrunopen(dev_t dev, struct tty *tp)
+{
+ struct proc *p = curproc;
+ struct endrun *np;
+ int error;
+
+ DPRINTF(("endrunopen\n"));
+ if (tp->t_line == ENDRUNDISC)
+ return ENODEV;
+ if ((error = suser(p, 0)) != 0)
+ return error;
+ np = malloc(sizeof(struct endrun), M_DEVBUF, M_WAITOK|M_ZERO);
+ snprintf(np->timedev.xname, sizeof(np->timedev.xname), "endrun%d",
+ endrun_nxid++);
+ endrun_count++;
+ np->time.status = SENSOR_S_UNKNOWN;
+ np->time.type = SENSOR_TIMEDELTA;
+#ifndef ENDRUN_DEBUG
+ np->time.flags = SENSOR_FINVALID;
+#endif
+ sensor_attach(&np->timedev, &np->time);
+
+ np->signal.type = SENSOR_PERCENT;
+ np->signal.status = SENSOR_S_UNKNOWN;
+ np->signal.value = 100000LL;
+ strlcpy(np->signal.desc, "Signal", sizeof(np->signal.desc));
+ sensor_attach(&np->timedev, &np->signal);
+
+ np->sync = SYNC_SCAN;
+#ifdef ENDRUN_DEBUG
+ np->tfom = '0';
+#endif
+ tp->t_sc = (caddr_t)np;
+
+ error = linesw[TTYDISC].l_open(dev, tp);
+ if (error) {
+ free(np, M_DEVBUF);
+ tp->t_sc = NULL;
+ } else {
+ sensordev_install(&np->timedev);
+ timeout_set(&np->endrun_tout, endrun_timeout, np);
+ }
+
+ return error;
+}
+
+int
+endrunclose(struct tty *tp, int flags)
+{
+ struct endrun *np = (struct endrun *)tp->t_sc;
+
+ DPRINTF(("endrunclose\n"));
+ tp->t_line = TTYDISC; /* switch back to termios */
+ timeout_del(&np->endrun_tout);
+ sensordev_deinstall(&np->timedev);
+ free(np, M_DEVBUF);
+ tp->t_sc = NULL;
+ endrun_count--;
+ if (endrun_count == 0)
+ endrun_nxid = 0;
+ return linesw[TTYDISC].l_close(tp, flags);
+}
+
+/* collect EndRun sentence from tty */
+int
+endruninput(int c, struct tty *tp)
+{
+ struct endrun *np = (struct endrun *)tp->t_sc;
+ struct timespec ts;
+ int64_t gap;
+ long tmin, tmax;
+
+ if (np->sync == SYNC_EOL) {
+ nanotime(&ts);
+ np->pos = 0;
+ np->sync = SYNC_SCAN;
+ np->cbuf[np->pos++] = c; /* TFOM char */
+
+ gap = (ts.tv_sec * 1000000000LL + ts.tv_nsec) -
+ (np->lts.tv_sec * 1000000000LL + np->lts.tv_nsec);
+
+ np->lts.tv_sec = ts.tv_sec;
+ np->lts.tv_nsec = ts.tv_nsec;
+
+ if (gap <= np->gap)
+ goto nogap;
+
+ np->ts.tv_sec = ts.tv_sec;
+ np->ts.tv_nsec = ts.tv_nsec;
+ np->gap = gap;
+
+ /*
+ * If a tty timestamp is available, make sure its value is
+ * reasonable by comparing against the timestamp just taken.
+ * If they differ by more than 2 seconds, assume no PPS signal
+ * is present, note the fact, and keep using the timestamp
+ * value. When this happens, the sensor state is set to
+ * CRITICAL later when the EndRun sentence is decoded.
+ */
+ if (tp->t_flags & (TS_TSTAMPDCDSET | TS_TSTAMPDCDCLR |
+ TS_TSTAMPCTSSET | TS_TSTAMPCTSCLR)) {
+ tmax = lmax(np->ts.tv_sec, tp->t_tv.tv_sec);
+ tmin = lmin(np->ts.tv_sec, tp->t_tv.tv_sec);
+ if (tmax - tmin > 1)
+ np->no_pps = 1;
+ else {
+ np->ts.tv_sec = tp->t_tv.tv_sec;
+ np->ts.tv_nsec = tp->t_tv.tv_usec *
+ 1000L;
+ np->no_pps = 0;
+ }
+ }
+ } else if (c == '\n') {
+ if (np->pos == ENDRUNLEN - 1) {
+ /* don't copy '\n' into cbuf */
+ np->cbuf[np->pos] = '\0';
+ endrun_scan(np, tp);
+ }
+ np->sync = SYNC_EOL;
+ } else {
+ if (np->pos < ENDRUNLEN - 1)
+ np->cbuf[np->pos++] = c;
+ }
+
+nogap:
+ /* pass data to termios */
+ return linesw[TTYDISC].l_rint(c, tp);
+}
+
+/* Scan the EndRun sentence just received */
+void
+endrun_scan(struct endrun *np, struct tty *tp)
+{
+ int fldcnt = 0, n;
+ char *fld[NUMFLDS], *cs;
+
+ DPRINTFN(1, ("%s\n", np->cbuf));
+ /* split into fields */
+ fld[fldcnt++] = &np->cbuf[0];
+ for (cs = NULL, n = 0; n < np->pos && cs == NULL; n++) {
+ switch (np->cbuf[n]) {
+ case '\r':
+ np->cbuf[n] = '\0';
+ cs = &np->cbuf[n + 1];
+ break;
+ case ' ':
+ if (fldcnt < NUMFLDS) {
+ np->cbuf[n] = '\0';
+ fld[fldcnt++] = &np->cbuf[n + 1];
+ } else {
+ DPRINTF(("endrun: nr of fields in sentence "
+ "exceeds expected: %d\n", NUMFLDS));
+ return;
+ }
+ break;
+ }
+ }
+ endrun_decode(np, tp, fld, fldcnt);
+}
+
+/* Decode the time string */
+void
+endrun_decode(struct endrun *np, struct tty *tp, char *fld[], int fldcnt)
+{
+ int64_t date_nano, time_nano, offset_nano, endrun_now;
+ char tfom;
+
+ if (fldcnt != NUMFLDS) {
+ DPRINTF(("endrun: field count mismatch, %d\n", fldcnt));
+ return;
+ }
+ if (endrun_time_to_nano(fld[3], &time_nano) == -1) {
+ DPRINTF(("endrun: illegal time, %s\n", fld[3]));
+ return;
+ }
+ if (endrun_date_to_nano(fld[1], fld[2], &date_nano) == -1) {
+ DPRINTF(("endrun: illegal date, %s %s\n", fld[1], fld[2]));
+ return;
+ }
+ offset_nano = 0;
+ /* only parse offset when timemode is local */
+ if (fld[5][0] == 'L' &&
+ endrun_offset_to_nano(fld[4], &offset_nano) == -1) {
+ DPRINTF(("endrun: illegal offset, %s\n", fld[4]));
+ return;
+ }
+
+ endrun_now = date_nano + time_nano + offset_nano;
+ if (endrun_now <= np->last) {
+ DPRINTF(("endrun: time not monotonically increasing "
+ "last %lld now %lld\n",
+ (long long)np->last, (long long)endrun_now));
+ return;
+ }
+ np->last = endrun_now;
+ np->gap = 0LL;
+#ifdef ENDRUN_DEBUG
+ if (np->time.status == SENSOR_S_UNKNOWN) {
+ np->time.status = SENSOR_S_OK;
+ timeout_add_sec(&np->endrun_tout, TRUSTTIME);
+ }
+#endif
+
+ np->time.value = np->ts.tv_sec * 1000000000LL +
+ np->ts.tv_nsec - endrun_now;
+ np->time.tv.tv_sec = np->ts.tv_sec;
+ np->time.tv.tv_usec = np->ts.tv_nsec / 1000L;
+ if (np->time.status == SENSOR_S_UNKNOWN) {
+ np->time.status = SENSOR_S_OK;
+ np->time.flags &= ~SENSOR_FINVALID;
+ strlcpy(np->time.desc, "EndRun", sizeof(np->time.desc));
+ }
+ /*
+ * Only update the timeout if the clock reports the time as valid.
+ *
+ * Time Figure Of Merit (TFOM) values:
+ *
+ * 6 - time error is < 100 us
+ * 7 - time error is < 1 ms
+ * 8 - time error is < 10 ms
+ * 9 - time error is > 10 ms,
+ * unsynchronized state if never locked to CDMA
+ */
+
+ switch (tfom = fld[0][0]) {
+ case '6':
+ case '7':
+ case '8':
+ np->time.status = SENSOR_S_OK;
+ np->signal.status = SENSOR_S_OK;
+ timeout_add_sec(&np->endrun_tout, TRUSTTIME);
+ break;
+ case '9':
+ np->signal.status = SENSOR_S_WARN;
+ break;
+ default:
+ DPRINTF(("endrun: invalid TFOM: '%c'\n", tfom));
+ np->signal.status = SENSOR_S_CRIT;
+ break;
+ }
+
+#ifdef ENDRUN_DEBUG
+ if (np->tfom != tfom) {
+ DPRINTF(("endrun: TFOM changed from %c to %c\n",
+ np->tfom, tfom));
+ np->tfom = tfom;
+ }
+#endif
+
+ /*
+ * If tty timestamping is requested, but no PPS signal is present, set
+ * the sensor state to CRITICAL.
+ */
+ if (np->no_pps)
+ np->time.status = SENSOR_S_CRIT;
+}
+
+int
+endrun_atoi(char *s, int len)
+{
+ int n;
+ char *p;
+
+ /* make sure the input contains only numbers */
+ for (n = 0, p = s; n < len && *p && *p >= '0' && *p <= '9'; n++, p++)
+ ;
+ if (n != len || *p != '\0')
+ return -1;
+
+ for (n = 0; *s; s++)
+ n = n * 10 + *s - '0';
+
+ return n;
+}
+
+/*
+ * Convert date fields from EndRun to nanoseconds since the epoch.
+ * The year string must be of the form YYYY .
+ * The day of year string must be of the form DDD .
+ * Return 0 on success, -1 if illegal characters are encountered.
+ */
+int
+endrun_date_to_nano(char *y, char *doy, int64_t *nano)
+{
+ struct clock_ymdhms clock;
+ time_t secs;
+ int n, i;
+ int year_days = 365;
+ int month_days[] = {
+ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+#define FEBRUARY 2
+
+#define LEAPYEAR(x) \
+ ((x) % 4 == 0 && \
+ (x) % 100 != 0) || \
+ (x) % 400 == 0
+
+ if ((n = endrun_atoi(y, 4)) == -1)
+ return -1;
+ clock.dt_year = n;
+
+ if (LEAPYEAR(n)) {
+ month_days[FEBRUARY]++;
+ year_days++;
+ }
+
+ if ((n = endrun_atoi(doy, 3)) == -1 || n == 0 || n > year_days)
+ return -1;
+
+ /* convert day of year to month, day */
+ for (i = 1; n > month_days[i]; i++) {
+ n -= month_days[i];
+ }
+ clock.dt_mon = i;
+ clock.dt_day = n;
+
+ DPRINTFN(1, ("mm/dd %d/%d\n", i, n));
+
+ clock.dt_hour = clock.dt_min = clock.dt_sec = 0;
+
+ secs = clock_ymdhms_to_secs(&clock);
+ *nano = secs * 1000000000LL;
+ return 0;
+}
+
+/*
+ * Convert time field from EndRun to nanoseconds since midnight.
+ * The string must be of the form HH:MM:SS .
+ * Return 0 on success, -1 if illegal characters are encountered.
+ */
+int
+endrun_time_to_nano(char *s, int64_t *nano)
+{
+ struct clock_ymdhms clock;
+ time_t secs;
+ int n;
+
+ if (s[2] != ':' || s[5] != ':')
+ return -1;
+
+ s[2] = '\0';
+ s[5] = '\0';
+
+ if ((n = endrun_atoi(&s[0], 2)) == -1 || n > 23)
+ return -1;
+ clock.dt_hour = n;
+ if ((n = endrun_atoi(&s[3], 2)) == -1 || n > 59)
+ return -1;
+ clock.dt_min = n;
+ if ((n = endrun_atoi(&s[6], 2)) == -1 || n > 60)
+ return -1;
+ clock.dt_sec = n;
+
+ DPRINTFN(1, ("hh:mm:ss %d:%d:%d\n", (int)clock.dt_hour,
+ (int)clock.dt_min,
+ (int)clock.dt_sec));
+ secs = clock.dt_hour * 3600
+ + clock.dt_min * 60
+ + clock.dt_sec;
+
+ DPRINTFN(1, ("secs %lu\n", (unsigned long)secs));
+
+ *nano = secs * 1000000000LL;
+ return 0;
+}
+
+int
+endrun_offset_to_nano(char *s, int64_t *nano)
+{
+ time_t secs;
+ int n;
+
+ if (!(s[0] == '+' || s[0] == '-'))
+ return -1;
+
+ if ((n = endrun_atoi(&s[1], 2)) == -1)
+ return -1;
+ secs = n * 30 * 60;
+
+ *nano = secs * 1000000000LL;
+ if (s[0] == '+')
+ *nano = -*nano;
+
+ DPRINTFN(1, ("offset secs %lu nanosecs %lld\n",
+ (unsigned long)secs, (long long)*nano));
+
+ return 0;
+}
+
+/*
+ * Degrade the sensor state if we received no EndRun string for more than
+ * TRUSTTIME seconds.
+ */
+void
+endrun_timeout(void *xnp)
+{
+ struct endrun *np = xnp;
+
+ if (np->time.status == SENSOR_S_OK) {
+ np->time.status = SENSOR_S_WARN;
+ /*
+ * further degrade in TRUSTTIME seconds if no new valid EndRun
+ * strings are received.
+ */
+ timeout_add_sec(&np->endrun_tout, TRUSTTIME);
+ } else
+ np->time.status = SENSOR_S_CRIT;
+}
diff --git a/sys/sys/ttycom.h b/sys/sys/ttycom.h
index 2ff8be949fc..524e3bf6dc1 100644
--- a/sys/sys/ttycom.h
+++ b/sys/sys/ttycom.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ttycom.h,v 1.10 2008/05/08 01:17:54 fgsch Exp $ */
+/* $OpenBSD: ttycom.h,v 1.11 2009/05/06 18:21:23 stevesk Exp $ */
/* $NetBSD: ttycom.h,v 1.4 1996/05/19 17:17:53 jonathan Exp $ */
/*-
@@ -144,5 +144,6 @@ struct tstamps {
#define STRIPDISC 6 /* metricom wireless IP discipline */
#define NMEADISC 7 /* NMEA0183 discipline */
#define MSTSDISC 8 /* Meinberg time string discipline */
+#define ENDRUNDISC 9 /* EndRun time format discipline */
#endif /* !_SYS_TTYCOM_H_ */