diff options
-rw-r--r-- | sbin/ldattach/ldattach.8 | 18 | ||||
-rw-r--r-- | sbin/ldattach/ldattach.c | 5 | ||||
-rw-r--r-- | share/man/man4/Makefile | 4 | ||||
-rw-r--r-- | share/man/man4/endrun.4 | 82 | ||||
-rw-r--r-- | sys/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/conf/files | 4 | ||||
-rw-r--r-- | sys/kern/tty_conf.c | 17 | ||||
-rw-r--r-- | sys/kern/tty_endrun.c | 532 | ||||
-rw-r--r-- | sys/sys/ttycom.h | 3 |
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_ */ |