aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/xntpd/xntpd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/xntpd')
-rw-r--r--usr.sbin/xntpd/xntpd/Makefile.tmpl52
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_config.c882
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_control.c317
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_filegen.c32
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_intres.c21
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_io.c388
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_leap.c38
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_loopfilter.c1180
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_monitor.c130
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_peer.c68
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_proto.c1239
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_refclock.c1185
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_request.c400
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_restrict.c40
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_timer.c18
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_unixclock.c79
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_util.c149
-rw-r--r--usr.sbin/xntpd/xntpd/ntpd.c22
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_acts.c895
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_as2201.c986
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_atom.c499
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_chu.c777
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_conf.c95
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_datum.c871
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_goes.c1188
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_gpstm.c78
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_heath.c393
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_irig.c569
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_leitch.c64
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_local.c357
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_moto.c2
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_msfees.c135
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_mx4200.c72
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_datum.c593
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_gpstm.c999
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_leitch.c718
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c1575
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_mx4200.c977
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_omega.c999
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_parse.c3617
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_nmea.c391
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_datum.c645
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_gpstm.c998
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_leitch.c709
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_msfees.c1575
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_mx4200.c1342
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_omega.c999
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_old/refclock_parse.c3605
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_omega.c70
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_parse.c344
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_pst.c1893
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_tpro.c501
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_trak.c1083
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_wwvb.c1121
54 files changed, 28257 insertions, 9718 deletions
diff --git a/usr.sbin/xntpd/xntpd/Makefile.tmpl b/usr.sbin/xntpd/xntpd/Makefile.tmpl
index 6a5a2b1f81c3..919d2a0c9174 100644
--- a/usr.sbin/xntpd/xntpd/Makefile.tmpl
+++ b/usr.sbin/xntpd/xntpd/Makefile.tmpl
@@ -1,5 +1,5 @@
#
-# Makefile.tmpl,v 3.1 1993/07/06 01:11:10 jbj Exp
+# Makefile.tmpl
#
PROGRAM= xntpd
#
@@ -29,24 +29,28 @@ TOP=../
SOURCE= ntp_config.c ntp_control.c ntp_io.c ntp_leap.c \
ntp_loopfilter.c ntp_monitor.c ntp_peer.c ntp_proto.c \
ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \
- ntp_unixclock.c ntp_util.c ntpd.c refclock_chu.c \
- refclock_conf.c refclock_local.c refclock_pst.c \
- refclock_wwvb.c refclock_goes.c refclock_mx4200.c \
- refclock_parse.c refclock_as2201.c refclock_omega.c \
- refclock_tpro.c refclock_leitch.c refclock_irig.c \
- refclock_msfees.c refclock_gpstm.c refclock_trak.c \
- ntp_intres.c ntp_filegen.c
+ ntp_unixclock.c ntp_util.c ntp_intres.c ntp_filegen.c ntpd.c \
+ refclock_conf.c refclock_chu.c refclock_local.c \
+ refclock_pst.c refclock_wwvb.c refclock_goes.c \
+ refclock_mx4200.c refclock_parse.c refclock_as2201.c \
+ refclock_omega.c refclock_tpro.c refclock_leitch.c \
+ refclock_irig.c refclock_msfees.c refclock_gpstm.c \
+ refclock_trak.c refclock_datum.c refclock_acts.c \
+ refclock_heath.c, refclock_nmea.c refclock_moto.c \
+ refclock_atom.c
OBJS= ntp_config.o ntp_control.o ntp_io.o ntp_leap.o \
ntp_loopfilter.o ntp_monitor.o ntp_peer.o ntp_proto.o \
ntp_refclock.o ntp_request.o ntp_restrict.o ntp_timer.o \
- ntp_unixclock.o ntp_util.o ntpd.o refclock_chu.o \
- refclock_conf.o refclock_local.o refclock_pst.o \
- refclock_wwvb.o refclock_goes.o refclock_mx4200.o \
- refclock_parse.o refclock_as2201.o refclock_omega.o \
- refclock_tpro.o refclock_leitch.o refclock_irig.o \
- refclock_msfees.o refclock_gpstm.o refclock_trak.o \
- ntp_intres.o ntp_filegen.o
+ ntp_unixclock.o ntp_util.o ntp_intres.o ntp_filegen.o ntpd.o \
+ refclock_conf.o refclock_chu.o refclock_local.o \
+ refclock_pst.o refclock_wwvb.o refclock_goes.o \
+ refclock_mx4200.o refclock_parse.o refclock_as2201.o \
+ refclock_omega.o refclock_tpro.o refclock_leitch.o \
+ refclock_irig.o refclock_msfees.o refclock_gpstm.o \
+ refclock_trak.o refclock_datum.o refclock_acts.o \
+ refclock_heath.o refclock_nmea.o refclock_moto.o \
+ refclock_atom.o
all: $(PROGRAM)
@@ -144,3 +148,21 @@ refclock_trak.o: refclock_trak.c
refclock_gpstm.o: refclock_gpstm.c
$(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_datum.o: refclock_datum.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_acts.o: refclock_acts.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_heath.o: refclock_heath.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_nmea.o: refclock_nmea.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_moto.o: refclock_moto.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
+
+refclock_atom.o: refclock_atom.c
+ $(CC) $(COPTS) $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) $(INCL) -c $*.c
diff --git a/usr.sbin/xntpd/xntpd/ntp_config.c b/usr.sbin/xntpd/xntpd/ntp_config.c
index 8f356ac8c2e7..385e53623f8e 100644
--- a/usr.sbin/xntpd/xntpd/ntp_config.c
+++ b/usr.sbin/xntpd/xntpd/ntp_config.c
@@ -1,17 +1,12 @@
/*
- * ntp_config.c - read and apply configuration information
+ k ntp_config.c - read and apply configuration information
*/
-#define RESOLVE_INTERNAL /* gdt */
-
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
-
-#ifdef RESOLVE_INTERNAL
-#include <sys/time.h>
-#endif
+#include <sys/time.h>
#include "ntpd.h"
#include "ntp_io.h"
@@ -42,35 +37,33 @@
/*
* We understand the following configuration entries and defaults.
*
- * peer 128.100.1.1 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
- * server 128.100.2.2 [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * peer [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
+ * server [ addr ] [ version 3 ] [ key 0 ] [ minpoll 6 ] [ maxpoll 10 ]
* precision -7
- * broadcast 128.100.224.255 [ version 3 ] [ key 0 ] [ ttl 1 ]
+ * broadcast [ addr ] [ version 3 ] [ key 0 ] [ ttl 1 ]
* broadcastclient
* multicastclient [224.0.1.1]
* broadcastdelay 0.0102
- * authenticate yes|no
- * monitor yes|no
+ * authenticate yes|no XXX depredated
+ * monitor yes|no XXX depredated
* authdelay 0.00842
- * pps [ delay 0.000247 ] [ baud 38400 ]
- * restrict 128.100.100.0 [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery
+ * restrict [ addr ] [ mask 255.255.255.0 ] ignore|noserve|notrust|noquery
* driftfile file_name
* keys file_name
* statsdir /var/NTP/
* filegen peerstats [ file peerstats ] [ type day ] [ link ]
- * resolver /path/progname
* clientlimit [ n ]
* clientperiod [ 3600 ]
* trustedkey [ key ]
* requestkey [ key]
* controlkey [ key ]
- * trap [ address ]
- * fudge [ ... ]
+ * trap [ addr ]
+ * fudge [ addr ] [ stratum ] [ refid ] ...
* pidfile [ ]
- * logfile [ ]
* setvar [ ]
- *
- * And then some. See the manual page.
+ * enable auth|bclient|pll|pps|monitor|stats
+ * disable auth|bclient|pll|pps|monitor|stats
+ * phone ...
*/
/*
@@ -99,13 +92,14 @@
#define CONFIG_STATSDIR 19
#define CONFIG_FILEGEN 20
#define CONFIG_STATISTICS 21
-#define CONFIG_PPS 22
-#define CONFIG_PIDFILE 23
-#define CONFIG_LOGFILE 24
-#define CONFIG_SETVAR 25
-#define CONFIG_CLIENTLIMIT 26
-#define CONFIG_CLIENTPERIOD 27
-#define CONFIG_MULTICASTCLIENT 28
+#define CONFIG_PIDFILE 22
+#define CONFIG_SETVAR 23
+#define CONFIG_CLIENTLIMIT 24
+#define CONFIG_CLIENTPERIOD 25
+#define CONFIG_MULTICASTCLIENT 26
+#define CONFIG_ENABLE 27
+#define CONFIG_DISABLE 28
+#define CONFIG_PHONE 29
#define CONF_MOD_VERSION 1
#define CONF_MOD_KEY 2
@@ -113,9 +107,7 @@
#define CONF_MOD_MAXPOLL 4
#define CONF_MOD_PREFER 5
#define CONF_MOD_TTL 6
-
-#define CONF_PPS_DELAY 1
-#define CONF_PPS_BAUD 2
+#define CONF_MOD_MODE 7
#define CONF_RES_MASK 1
#define CONF_RES_IGNORE 2
@@ -134,8 +126,8 @@
#define CONF_FDG_TIME1 1
#define CONF_FDG_TIME2 2
-#define CONF_FDG_VALUE1 3
-#define CONF_FDG_VALUE2 4
+#define CONF_FDG_STRATUM 3
+#define CONF_FDG_REFID 4
#define CONF_FDG_FLAG1 5
#define CONF_FDG_FLAG2 6
#define CONF_FDG_FLAG3 7
@@ -148,15 +140,6 @@
#define CONF_FGEN_FLAG_ENABLE 5
#define CONF_FGEN_FLAG_DISABLE 6
-#define CONF_BAUD_300 1
-#define CONF_BAUD_600 2
-#define CONF_BAUD_1200 3
-#define CONF_BAUD_2400 4
-#define CONF_BAUD_4800 5
-#define CONF_BAUD_9600 6
-#define CONF_BAUD_19200 7
-#define CONF_BAUD_38400 8
-
/*
* Translation table - keywords to function index
*/
@@ -165,6 +148,9 @@ struct keyword {
int keytype;
};
+/*
+ * Command keywords
+ */
static struct keyword keywords[] = {
{ "peer", CONFIG_PEER },
{ "server", CONFIG_SERVER },
@@ -177,7 +163,6 @@ static struct keyword keywords[] = {
{ "keys", CONFIG_KEYS },
{ "monitor", CONFIG_MONITOR },
{ "authdelay", CONFIG_AUTHDELAY },
- { "pps", CONFIG_PPS },
{ "restrict", CONFIG_RESTRICT },
{ "broadcastdelay", CONFIG_BDELAY },
{ "trustedkey", CONFIG_TRUSTEDKEY },
@@ -185,20 +170,21 @@ static struct keyword keywords[] = {
{ "controlkey", CONFIG_CONTROLKEY },
{ "trap", CONFIG_TRAP },
{ "fudge", CONFIG_FUDGE },
- { "resolver", CONFIG_RESOLVER },
{ "statsdir", CONFIG_STATSDIR },
{ "filegen", CONFIG_FILEGEN },
{ "statistics", CONFIG_STATISTICS },
{ "pidfile", CONFIG_PIDFILE },
- { "logfile", CONFIG_LOGFILE },
{ "setvar", CONFIG_SETVAR },
{ "clientlimit", CONFIG_CLIENTLIMIT },
{ "clientperiod", CONFIG_CLIENTPERIOD },
+ { "enable", CONFIG_ENABLE },
+ { "disable", CONFIG_DISABLE },
+ { "phone", CONFIG_PHONE },
{ "", CONFIG_UNKNOWN }
};
/*
- * Modifier keywords
+ * "peer", "server", "broadcast" modifier keywords
*/
static struct keyword mod_keywords[] = {
{ "version", CONF_MOD_VERSION },
@@ -206,21 +192,13 @@ static struct keyword mod_keywords[] = {
{ "minpoll", CONF_MOD_MINPOLL },
{ "maxpoll", CONF_MOD_MAXPOLL },
{ "prefer", CONF_MOD_PREFER },
- { "ttl", CONF_MOD_TTL },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * PPS modifier keywords
- */
-static struct keyword pps_keywords[] = {
- { "delay", CONF_PPS_DELAY },
- { "baud", CONF_PPS_BAUD },
+ { "mode", CONF_MOD_MODE }, /* reference clocks */
+ { "ttl", CONF_MOD_TTL }, /* NTP peers */
{ "", CONFIG_UNKNOWN }
};
/*
- * Special restrict keywords
+ * "restrict" modifier keywords
*/
static struct keyword res_keywords[] = {
{ "mask", CONF_RES_MASK },
@@ -231,29 +209,14 @@ static struct keyword res_keywords[] = {
{ "nomodify", CONF_RES_NOMODIFY },
{ "nopeer", CONF_RES_NOPEER },
{ "notrap", CONF_RES_NOTRAP },
- { "lowpriotrap", CONF_RES_LPTRAP },
+ { "lowpriotrap", CONF_RES_LPTRAP },
{ "ntpport", CONF_RES_NTPPORT },
{ "limited", CONF_RES_LIMITED },
{ "", CONFIG_UNKNOWN }
};
/*
- * Baud rate keywords
- */
-static struct keyword baud_keywords[] = {
- { "300", CONF_BAUD_300 },
- { "600", CONF_BAUD_600 },
- { "1200", CONF_BAUD_1200 },
- { "2400", CONF_BAUD_2400 },
- { "4800", CONF_BAUD_4800 },
- { "9600", CONF_BAUD_9600 },
- { "19200", CONF_BAUD_19200 },
- { "38400", CONF_BAUD_38400 },
- { "", CONFIG_UNKNOWN }
-};
-
-/*
- * Keywords for the trap command
+ * "trap" modifier keywords
*/
static struct keyword trap_keywords[] = {
{ "port", CONF_TRAP_PORT },
@@ -263,13 +226,13 @@ static struct keyword trap_keywords[] = {
/*
- * Keywords for the fudge command
+ * "fudge" modifier keywords
*/
static struct keyword fudge_keywords[] = {
{ "time1", CONF_FDG_TIME1 },
{ "time2", CONF_FDG_TIME2 },
- { "value1", CONF_FDG_VALUE1 },
- { "value2", CONF_FDG_VALUE2 },
+ { "stratum", CONF_FDG_STRATUM },
+ { "refid", CONF_FDG_REFID },
{ "flag1", CONF_FDG_FLAG1 },
{ "flag2", CONF_FDG_FLAG2 },
{ "flag3", CONF_FDG_FLAG3 },
@@ -279,7 +242,7 @@ static struct keyword fudge_keywords[] = {
/*
- * Keywords for the filegen command
+ * "filegen" modifier keywords
*/
static struct keyword filegen_keywords[] = {
{ "file", CONF_FGEN_FILE },
@@ -291,6 +254,9 @@ static struct keyword filegen_keywords[] = {
{ "", CONFIG_UNKNOWN }
};
+/*
+ * "type" modifier keywords
+ */
static struct keyword fgen_types[] = {
{ "none", FILEGEN_NONE },
{ "pid", FILEGEN_PID },
@@ -302,12 +268,25 @@ static struct keyword fgen_types[] = {
{ "", CONFIG_UNKNOWN}
};
+/*
+ * "enable", "disable" modifier keywords
+ */
+static struct keyword flags_keywords[] = {
+ { "auth", PROTO_AUTHENTICATE },
+ { "bclient", PROTO_BROADCLIENT },
+ { "pll", PROTO_PLL },
+ { "pps", PROTO_PPS },
+ { "monitor", PROTO_MONITOR },
+ { "stats", PROTO_FILEGEN },
+ { "", CONFIG_UNKNOWN }
+};
/*
* Limits on things
*/
#define MAXTOKENS 20 /* 20 tokens on line */
#define MAXLINE 1024 /* maximum length of line */
+#define MAXPHONE 5 /* maximum number of phone strings */
#define MAXFILENAME 128 /* maximum length of a file name (alloca()?) */
@@ -333,20 +312,21 @@ static char res_file[20]; /* enough for /tmp/xntpXXXXXX\0 */
#ifdef DEBUG
extern int debug;
#endif
-extern char *FindConfig();
- char *progname;
-static char *xntp_options = "abc:de:f:k:l:mp:r:s:t:v:V:";
-
-static int gettokens P((FILE *, char *, char **, int *));
-static int matchkey P((char *, struct keyword *));
-static int getnetnum P((char *, struct sockaddr_in *, int));
-static void save_resolve P((char *, int, int, int, int, int, int, U_LONG));
-static void do_resolve P((char *, U_LONG, char *));
-#ifdef RESOLVE_INTERNAL
-static void do_resolve_internal P((void));
-#endif /* RESOLVE_INTERNAL */
-static void abort_resolve P((void));
-static RETSIGTYPE catchchild P((int));
+extern char *FindConfig();
+ char *progname;
+ char sys_phone[MAXPHONE][MAXDIAL]; /* ACTS phone numbers */
+static char *xntp_options = "abc:dD:e:f:k:l:mp:r:s:t:v:V:";
+
+/*
+ * Function prototypes
+ */
+static int gettokens P((FILE *, char *, char **, int *));
+static int matchkey P((char *, struct keyword *));
+static int getnetnum P((char *, struct sockaddr_in *, int));
+static void save_resolve P((char *, int, int, int, int, int, int, u_long));
+static void do_resolve_internal P((void));
+static void abort_resolve P((void));
+static RETSIGTYPE catchchild P((int));
/*
* getstartup - search through the options looking for a debugging flag
@@ -360,6 +340,7 @@ getstartup(argc, argv)
int errflg;
int c;
extern int ntp_optind;
+ extern char *ntp_optarg;
debug = 0; /* no debugging by default */
@@ -385,6 +366,10 @@ getstartup(argc, argv)
case 'd':
++debug;
break;
+ case 'D':
+ debug = strtol(ntp_optarg, 0, 0);
+ printf("Debug1: %s -> %x = %d\n", ntp_optarg, debug, debug);
+ break;
case '?':
++errflg;
break;
@@ -428,7 +413,7 @@ getconfig(argc, argv)
int minpoll;
int maxpoll;
int ttl;
- U_LONG peerkey;
+ u_long peerkey;
int peerflags;
int hmode;
struct sockaddr_in peeraddr;
@@ -441,17 +426,12 @@ getconfig(argc, argv)
struct interface *localaddr;
char *config_file;
struct refclockstat clock;
- int have_resolver;
-#ifdef RESOLVE_INTERNAL
- int resolve_internal;
-#endif
- char resolver_name[MAXFILENAME];
int have_keyfile;
char keyfile[MAXFILENAME];
extern int ntp_optind;
extern char *ntp_optarg;
extern char *Version;
- extern U_LONG info_auth_keyid;
+ extern u_long info_auth_keyid;
FILEGEN *filegen;
/*
@@ -464,7 +444,8 @@ getconfig(argc, argv)
config_file = CONFIG_FILE;
progname = argv[0];
res_fp = NULL;
- have_resolver = have_keyfile = 0;
+ have_keyfile = 0;
+ memset((char *)sys_phone, 0, sizeof(sys_phone));
/*
* install a non default variable with this daemon version
@@ -472,21 +453,17 @@ getconfig(argc, argv)
(void) sprintf(line, "daemon_version=\"%s\"", Version);
set_sys_var(line, strlen(line)+1, RO);
-#ifdef RESOLVE_INTERNAL
- resolve_internal = 1;
-#endif
-
/*
* Decode argument list
*/
while ((c = ntp_getopt(argc, argv, xntp_options)) != EOF) {
switch (c) {
case 'a':
- proto_config(PROTO_AUTHENTICATE, (LONG)1);
+ proto_config(PROTO_AUTHENTICATE, 1);
break;
case 'b':
- proto_config(PROTO_BROADCLIENT, (LONG)1);
+ proto_config(PROTO_BROADCLIENT, 1);
break;
case 'c':
@@ -500,6 +477,12 @@ getconfig(argc, argv)
errflg++;
#endif /* DEBUG */
break;
+ case 'D':
+#ifdef DEBUG
+ debug = strtol(ntp_optarg, 0, 0);
+ printf("Debug2: %s -> %x = %d\n", ntp_optarg, debug, debug);
+#endif /* DEBUG */
+ break;
case 'e':
do {
@@ -529,7 +512,7 @@ getconfig(argc, argv)
getauthkeys(ntp_optarg);
if ((int)strlen(ntp_optarg) >= MAXFILENAME) {
syslog(LOG_ERR,
- "key file name too LONG (>%d, sigh), no name resolution possible",
+ "key file name too long (>%d, sigh), no name resolution possible",
MAXFILENAME);
} else {
have_keyfile = 1;
@@ -538,7 +521,7 @@ getconfig(argc, argv)
break;
case 'm':
- proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP));
break;
case 'p':
@@ -569,22 +552,23 @@ getconfig(argc, argv)
case 't':
do {
- int tkey;
+ u_long tkey;
- tkey = atoi(ntp_optarg);
+ tkey = atol(ntp_optarg);
if (tkey <= 0 || tkey > NTP_MAXKEY) {
syslog(LOG_ERR,
"command line trusted key %s is unlikely",
ntp_optarg);
} else {
- authtrust(tkey, (LONG)1);
+ authtrust(tkey, 1);
}
} while (0);
break;
case 'v':
case 'V':
- set_sys_var(ntp_optarg, strlen(ntp_optarg)+1, RW | ((c == 'V') ? DEF : 0));
+ set_sys_var(ntp_optarg, strlen(ntp_optarg)+1,
+ RW | ((c == 'V') ? DEF : 0));
break;
default:
@@ -622,8 +606,8 @@ getconfig(argc, argv)
if (ntokens < 2) {
syslog(LOG_ERR,
- "No address for %s, line ignored",
- tokens[0]);
+ "No address for %s, line ignored",
+ tokens[0]);
break;
}
@@ -638,24 +622,24 @@ getconfig(argc, argv)
#endif
ISBADADR(&peeraddr)) {
syslog(LOG_ERR,
- "attempt to configure invalid address %s",
- ntoa(&peeraddr));
+ "attempt to configure invalid address %s",
+ ntoa(&peeraddr));
break;
}
}
peerversion = NTP_VERSION;
minpoll = NTP_MINDPOLL;
- maxpoll = NTP_MAXPOLL;
+ maxpoll = NTP_MAXDPOLL;
peerkey = 0;
peerflags = 0;
- ttl = 1;
+ ttl = 0;
for (i = 2; i < ntokens; i++)
switch (matchkey(tokens[i], mod_keywords)) {
case CONF_MOD_VERSION:
if (i >= ntokens-1) {
syslog(LOG_ERR,
- "peer/server version requires an argument");
+ "peer/server version requires an argument");
errflg = 1;
break;
}
@@ -663,26 +647,20 @@ getconfig(argc, argv)
if ((u_char)peerversion > NTP_VERSION
|| (u_char)peerversion < NTP_OLDVERSION) {
syslog(LOG_ERR,
- "inappropriate version number %s, line ignored",
- tokens[i]);
+ "inappropriate version number %s, line ignored",
+ tokens[i]);
errflg = 1;
}
break;
case CONF_MOD_KEY:
- /*
- * XXX
- * This is bad because atoi
- * returns 0 on errors. Do
- * something later.
- */
if (i >= ntokens-1) {
syslog(LOG_ERR,
- "key: argument required");
+ "key: argument required");
errflg = 1;
break;
}
- peerkey = (U_LONG)atoi(tokens[++i]);
+ peerkey = atol(tokens[++i]);
peerflags |= FLAG_AUTHENABLE;
break;
@@ -725,6 +703,16 @@ getconfig(argc, argv)
ttl = atoi(tokens[++i]);
break;
+ case CONF_MOD_MODE:
+ if (i >= ntokens-1) {
+ syslog(LOG_ERR,
+ "mode: argument required");
+ errflg = 1;
+ break;
+ }
+ ttl = atoi(tokens[++i]);
+ break;
+
case CONFIG_UNKNOWN:
errflg = 1;
break;
@@ -753,10 +741,10 @@ getconfig(argc, argv)
i = atoi(tokens[1]);
if (i >= 0 || i < -25)
syslog(LOG_ERR,
- "unlikely precision %s, line ignored",
- tokens[1]);
+ "unlikely precision %s, line ignored",
+ tokens[1]);
else
- proto_config(PROTO_PRECISION, (LONG)i);
+ proto_config(PROTO_PRECISION, i);
}
break;
@@ -774,54 +762,28 @@ getconfig(argc, argv)
stats_config(STATS_PID_FILE, (char *)0);
break;
- case CONFIG_LOGFILE: {
-#ifdef SYSLOG_FILE
- extern int syslogit;
-
- syslogit = 0;
- if (ntokens >= 2) {
- FILE *new_file;
- new_file = fopen(tokens[1], "a");
- if (new_file != NULL) {
- if (syslog_file != NULL)
- (void)fclose(syslog_file);
- syslog_file = new_file;
- }
- else
- syslog(LOG_ERR,
- "Cannot open log file %s",
- tokens[1]);
- }
- else
- syslog(LOG_ERR, "logfile needs one argument");
-
-#else
- syslog(LOG_ERR, "logging to logfile not compiled into xntpd - logfile \"%s\" ignored", (ntokens == 2) ? tokens[1] : "");
-#endif
- } break;
-
case CONFIG_BROADCASTCLIENT:
- proto_config(PROTO_BROADCLIENT, (U_LONG)1);
+ proto_config(PROTO_BROADCLIENT, 1);
break;
case CONFIG_MULTICASTCLIENT:
if (ntokens > 1) {
for (i = 1; i < ntokens; i++) {
- if (getnetnum(tokens[i], &peeraddr, 1));
+ if (getnetnum(tokens[i], &peeraddr, 1))
proto_config(PROTO_MULTICAST_ADD,
peeraddr.sin_addr.s_addr);
}
} else
- proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ proto_config(PROTO_MULTICAST_ADD, htonl(INADDR_NTP));
break;
case CONFIG_AUTHENTICATE:
errflg = 0;
if (ntokens >= 2) {
if (STREQ(tokens[1], "yes"))
- proto_config(PROTO_AUTHENTICATE, (LONG)1);
+ proto_config(PROTO_AUTHENTICATE, 1);
else if (STREQ(tokens[1], "no"))
- proto_config(PROTO_AUTHENTICATE, (LONG)0);
+ proto_config(PROTO_AUTHENTICATE, 0);
else
errflg++;
} else {
@@ -830,7 +792,7 @@ getconfig(argc, argv)
if (errflg)
syslog(LOG_ERR,
- "should be `authenticate yes|no'");
+ "should be `authenticate yes|no'");
break;
case CONFIG_KEYS:
@@ -838,8 +800,8 @@ getconfig(argc, argv)
getauthkeys(tokens[1]);
if ((int)strlen(tokens[1]) >= MAXFILENAME) {
syslog(LOG_ERR,
- "key file name too LONG (>%d, sigh), no name resolution possible",
- MAXFILENAME);
+ "key file name too long (>%d, sigh), no name resolution possible",
+ MAXFILENAME);
} else {
have_keyfile = 1;
(void)strcpy(keyfile, tokens[1]);
@@ -862,7 +824,7 @@ getconfig(argc, argv)
if (errflg)
syslog(LOG_ERR,
- "should be `monitor yes|no'");
+ "should be `monitor yes|no'");
break;
case CONFIG_AUTHDELAY:
@@ -871,74 +833,25 @@ getconfig(argc, argv)
if (!atolfp(tokens[1], &tmp)) {
syslog(LOG_ERR,
- "authdelay value %s undecodable",
- tokens[1]);
+ "authdelay value %s undecodable",
+ tokens[1]);
} else if (tmp.l_ui != 0) {
syslog(LOG_ERR,
- "authdelay value %s is unlikely",
- tokens[1]);
+ "authdelay value %s is unlikely",
+ tokens[1]);
} else {
proto_config(PROTO_AUTHDELAY, tmp.l_f);
}
}
break;
- case CONFIG_PPS:
- for (i = 1 ; i < ntokens ; i++) {
- switch(matchkey(tokens[i],pps_keywords)) {
- case CONF_PPS_DELAY:
- if (i >= ntokens-1) {
- syslog(LOG_ERR,
- "pps delay requires an argument");
- errflg = 1;
- break;
- }
- {
- l_fp tmp;
-
- if (!atolfp(tokens[++i],&tmp)) {
- syslog(LOG_ERR,
- "pps delay value %s undecodable",
- tokens[i]);
- } else {
- loop_config(LOOP_PPSDELAY, &tmp, 0);
- }
- }
- break;
- case CONF_PPS_BAUD:
- if (i >= ntokens-1) {
- syslog(LOG_ERR,
- "pps baud requires an argument");
- errflg = 1;
- break;
- }
- {
- int tmp;
-
- if (matchkey(tokens[++i],baud_keywords)) {
- tmp = atoi(tokens[i]);
- if (tmp < 19200) {
- syslog(LOG_WARNING,
- "pps baud %d unlikely\n", tmp);
- }
- loop_config(LOOP_PPSBAUD, NULL, tmp);
- }
- }
- break;
- case CONFIG_UNKNOWN:
- errflg = 1;
- break;
- }
- }
- break;
-
case CONFIG_RESTRICT:
if (ntokens < 2) {
syslog(LOG_ERR, "restrict requires an address");
break;
}
if (STREQ(tokens[1], "default"))
- peeraddr.sin_addr.s_addr = INADDR_ANY;
+ peeraddr.sin_addr.s_addr = htonl(INADDR_ANY);
else if (!getnetnum(tokens[1], &peeraddr, 1))
break;
@@ -954,7 +867,7 @@ getconfig(argc, argv)
case CONF_RES_MASK:
if (i >= ntokens-1) {
syslog(LOG_ERR,
- "mask keyword needs argument");
+ "mask keyword needs argument");
errflg++;
break;
}
@@ -1008,11 +921,11 @@ getconfig(argc, argv)
break;
}
}
- if (SRCADR(&peeraddr) == INADDR_ANY)
+ if (SRCADR(&peeraddr) == htonl(INADDR_ANY))
maskaddr.sin_addr.s_addr = 0;
if (!errflg)
restrict(RESTRICT_FLAGS, &peeraddr, &maskaddr,
- (int)peerkey, peerversion);
+ (int)peerkey, peerversion);
break;
case CONFIG_BDELAY:
@@ -1021,12 +934,12 @@ getconfig(argc, argv)
if (!atolfp(tokens[1], &tmp)) {
syslog(LOG_ERR,
- "broadcastdelay value %s undecodable",
- tokens[1]);
+ "broadcastdelay value %s undecodable",
+ tokens[1]);
} else if (tmp.l_ui != 0) {
syslog(LOG_ERR,
- "broadcastdelay value %s is unlikely",
- tokens[1]);
+ "broadcastdelay value %s is unlikely",
+ tokens[1]);
} else {
proto_config(PROTO_BROADDELAY, tmp.l_f);
}
@@ -1035,13 +948,13 @@ getconfig(argc, argv)
case CONFIG_TRUSTEDKEY:
for (i = 1; i < ntokens; i++) {
- U_LONG tkey;
+ u_long tkey;
- tkey = (U_LONG) atoi(tokens[i]);
+ tkey = atol(tokens[i]);
if (tkey == 0) {
syslog(LOG_ERR,
- "trusted key %s unlikely",
- tokens[i]);
+ "trusted key %s unlikely",
+ tokens[i]);
} else {
authtrust(tkey, 1);
}
@@ -1050,21 +963,21 @@ getconfig(argc, argv)
case CONFIG_REQUESTKEY:
if (ntokens >= 2) {
- U_LONG rkey;
+ u_long rkey;
if (!atouint(tokens[1], &rkey)) {
syslog(LOG_ERR,
- "%s is undecodeable as request key",
- tokens[1]);
+ "%s is undecodeable as request key",
+ tokens[1]);
} else if (rkey == 0) {
syslog(LOG_ERR,
- "%s makes a poor request keyid",
- tokens[1]);
+ "%s makes a poor request keyid",
+ tokens[1]);
} else {
#ifdef DEBUG
if (debug > 3)
printf(
- "set info_auth_key to %lu\n", rkey);
+ "set info_auth_key to %lu\n", rkey);
#endif
info_auth_keyid = rkey;
}
@@ -1073,14 +986,14 @@ getconfig(argc, argv)
case CONFIG_CONTROLKEY:
if (ntokens >= 2) {
- U_LONG ckey;
- extern U_LONG ctl_auth_keyid;
+ u_long ckey;
+ extern u_long ctl_auth_keyid;
- ckey = (U_LONG)atoi(tokens[1]);
+ ckey = atol(tokens[1]);
if (ckey == 0) {
syslog(LOG_ERR,
- "%s makes a poor control keyid",
- tokens[1]);
+ "%s makes a poor control keyid",
+ tokens[1]);
} else {
ctl_auth_keyid = ckey;
}
@@ -1090,7 +1003,7 @@ getconfig(argc, argv)
case CONFIG_TRAP:
if (ntokens < 2) {
syslog(LOG_ERR,
- "no address for trap command, line ignored");
+ "no address for trap command, line ignored");
break;
}
if (!getnetnum(tokens[1], &peeraddr, 1))
@@ -1107,7 +1020,7 @@ getconfig(argc, argv)
case CONF_TRAP_PORT:
if (i >= ntokens-1) {
syslog(LOG_ERR,
- "trap port requires an argument");
+ "trap port requires an argument");
errflg = 1;
break;
}
@@ -1115,7 +1028,7 @@ getconfig(argc, argv)
if (peerversion <= 0
|| peerversion > 32767) {
syslog(LOG_ERR,
- "invalid port number %s, trap ignored",
+ "invalid port number %s, trap ignored",
tokens[i]);
errflg = 1;
}
@@ -1124,13 +1037,13 @@ getconfig(argc, argv)
case CONF_TRAP_INTERFACE:
if (i >= ntokens-1) {
syslog(LOG_ERR,
- "trap interface requires an argument");
+ "trap interface requires an argument");
errflg = 1;
break;
}
if (!getnetnum(tokens[++i],
- &maskaddr, 1)) {
+ &maskaddr, 1)) {
errflg = 1;
break;
}
@@ -1138,8 +1051,8 @@ getconfig(argc, argv)
localaddr = findinterface(&maskaddr);
if (localaddr == NULL) {
syslog(LOG_ERR,
- "can't find interface with address %s",
- ntoa(&maskaddr));
+ "can't find interface with address %s",
+ ntoa(&maskaddr));
errflg = 1;
}
break;
@@ -1159,17 +1072,17 @@ getconfig(argc, argv)
if (localaddr == NULL)
localaddr = any_interface;
if (!ctlsettrap(&peeraddr, localaddr, 0,
- NTP_VERSION))
+ NTP_VERSION))
syslog(LOG_ERR,
- "can't set trap for %s, no resources",
- ntoa(&peeraddr));
+ "can't set trap for %s, no resources",
+ ntoa(&peeraddr));
}
break;
case CONFIG_FUDGE:
if (ntokens < 2) {
syslog(LOG_ERR,
- "no address for fudge command, line ignored");
+ "no address for fudge command, line ignored");
break;
}
if (!getnetnum(tokens[1], &peeraddr, 1))
@@ -1177,8 +1090,8 @@ getconfig(argc, argv)
if (!ISREFCLOCKADR(&peeraddr)) {
syslog(LOG_ERR,
- "%s is inappropriate address for the fudge command, line ignored",
- ntoa(&peeraddr));
+ "%s is inappropriate address for the fudge command, line ignored",
+ ntoa(&peeraddr));
break;
}
@@ -1186,13 +1099,13 @@ getconfig(argc, argv)
errflg = 0;
for (i = 2; i < ntokens-1; i++) {
switch (c = matchkey(tokens[i],
- fudge_keywords)) {
+ fudge_keywords)) {
case CONF_FDG_TIME1:
if (!atolfp(tokens[++i],
- &clock.fudgetime1)) {
+ &clock.fudgetime1)) {
syslog(LOG_ERR,
- "fudge %s time1 value in error",
- ntoa(&peeraddr));
+ "fudge %s time1 value in error",
+ ntoa(&peeraddr));
errflg = i;
break;
}
@@ -1201,40 +1114,34 @@ getconfig(argc, argv)
case CONF_FDG_TIME2:
if (!atolfp(tokens[++i],
- &clock.fudgetime2)) {
+ &clock.fudgetime2)) {
syslog(LOG_ERR,
- "fudge %s time2 value in error",
- ntoa(&peeraddr));
+ "fudge %s time2 value in error",
+ ntoa(&peeraddr));
errflg = i;
break;
}
clock.haveflags |= CLK_HAVETIME2;
break;
- case CONF_FDG_VALUE1:
+ case CONF_FDG_STRATUM:
if (!atoint(tokens[++i],
- &clock.fudgeval1)) {
+ (long *)&clock.fudgeval1)) {
syslog(LOG_ERR,
- "fudge %s value1 value in error",
- ntoa(&peeraddr));
+ "fudge %s stratum value in error",
+ ntoa(&peeraddr));
errflg = i;
break;
}
clock.haveflags |= CLK_HAVEVAL1;
break;
- case CONF_FDG_VALUE2:
- if (!atoint(tokens[++i],
- &clock.fudgeval2)) {
- syslog(LOG_ERR,
- "fudge %s value2 value in error",
- ntoa(&peeraddr));
- errflg = i;
- break;
- }
+ case CONF_FDG_REFID:
+ strncpy((char *)&clock.fudgeval2,
+ tokens[++i], 4);
clock.haveflags |= CLK_HAVEVAL2;
break;
-
+
case CONF_FDG_FLAG1:
case CONF_FDG_FLAG2:
case CONF_FDG_FLAG3:
@@ -1242,8 +1149,8 @@ getconfig(argc, argv)
if (!atouint(tokens[++i], &peerkey)
|| peerkey > 1) {
syslog(LOG_ERR,
- "fudge %s flag value in error",
- ntoa(&peeraddr));
+ "fudge %s flag value in error",
+ ntoa(&peeraddr));
errflg = i;
break;
}
@@ -1285,27 +1192,11 @@ getconfig(argc, argv)
*/
if (!errflg) {
refclock_control(&peeraddr, &clock,
- (struct refclockstat *)0);
+ (struct refclockstat *)0);
}
#endif
break;
- case CONFIG_RESOLVER:
- if (ntokens >= 2) {
- if (strlen(tokens[1]) >= (size_t)MAXFILENAME) {
- syslog(LOG_ERR,
- "resolver path name too LONG (>%d, sigh), no name resolution possible",
- MAXFILENAME);
- break;
- }
- strcpy(resolver_name, tokens[1]);
- have_resolver = 1;
-#ifdef RESOLVE_INTERNAL
- resolve_internal = 0;
-#endif
- }
- break;
-
case CONFIG_STATSDIR:
if (ntokens >= 2) {
stats_config(STATS_STATSDIR,tokens[1]);
@@ -1318,14 +1209,14 @@ getconfig(argc, argv)
if (filegen == NULL) {
syslog(LOG_ERR,
- "no statistics named %s available",
- tokens[i]);
+ "no statistics named %s available",
+ tokens[i]);
continue;
}
#ifdef DEBUG
if (debug > 3)
printf("enabling filegen for %s statistics \"%s%s\"\n",
- tokens[i], filegen->prefix, filegen->basename);
+ tokens[i], filegen->prefix, filegen->basename);
#endif
filegen->flag |= FGEN_FLAG_ENABLED;
}
@@ -1334,15 +1225,15 @@ getconfig(argc, argv)
case CONFIG_FILEGEN:
if (ntokens < 2) {
syslog(LOG_ERR,
- "no id for filegen command, line ignored");
+ "no id for filegen command, line ignored");
break;
}
filegen = filegen_get(tokens[1]);
if (filegen == NULL) {
syslog(LOG_ERR,
- "unknown filegen \"%s\" ignored",
- tokens[1]);
+ "unknown filegen \"%s\" ignored",
+ tokens[1]);
break;
}
/*
@@ -1360,8 +1251,8 @@ getconfig(argc, argv)
case CONF_FGEN_FILE:
if (i >= ntokens - 1) {
syslog(LOG_ERR,
- "filegen %s file requires argument",
- tokens[1]);
+ "filegen %s file requires argument",
+ tokens[1]);
errflg = i;
break;
}
@@ -1370,16 +1261,16 @@ getconfig(argc, argv)
case CONF_FGEN_TYPE:
if (i >= ntokens -1) {
syslog(LOG_ERR,
- "filegen %s type requires argument",
- tokens[1]);
+ "filegen %s type requires argument",
+ tokens[1]);
errflg = i;
break;
}
peerkey = matchkey(tokens[++i], fgen_types);
if (peerkey == CONFIG_UNKNOWN) {
syslog(LOG_ERR,
- "filegen %s unknown type \"%s\"",
- tokens[1], tokens[i]);
+ "filegen %s unknown type \"%s\"",
+ tokens[1], tokens[i]);
errflg = i;
break;
}
@@ -1409,70 +1300,98 @@ getconfig(argc, argv)
break;
case CONFIG_SETVAR:
- if (ntokens < 2)
- {
- syslog(LOG_ERR,
- "no value for setvar command - line ignored");
- }
- else
- {
- set_sys_var(tokens[1], strlen(tokens[1])+1, RW |
- ((((ntokens > 2) && !strcmp(tokens[2], "default"))) ? DEF : 0));
- }
+ if (ntokens < 2) {
+ syslog(LOG_ERR,
+ "no value for setvar command - line ignored");
+ } else {
+ set_sys_var(tokens[1], strlen(tokens[1])+1, RW |
+ ((((ntokens > 2) && !strcmp(tokens[2],
+ "default"))) ? DEF : 0));
+ }
break;
case CONFIG_CLIENTLIMIT:
- if (ntokens < 2)
- {
- syslog(LOG_ERR,
- "no value for clientlimit command - line ignored");
- }
- else
- {
- U_LONG i;
- if (!atouint(tokens[1], &i) || !i)
- {
+ if (ntokens < 2) {
syslog(LOG_ERR,
- "illegal value for clientlimit command - line ignored");
- }
- else
- {
- extern U_LONG client_limit;
- char bp[80];
-
- sprintf(bp, "client_limit=%d", i);
- set_sys_var(bp, strlen(bp)+1, RO);
-
- client_limit = i;
- }
- }
+ "no value for clientlimit command - line ignored");
+ } else {
+ u_long i;
+ if (!atouint(tokens[1], &i) || !i) {
+ syslog(LOG_ERR,
+ "illegal value for clientlimit command - line ignored");
+ } else {
+ extern u_long client_limit;
+ char bp[80];
+
+#ifdef DEBUG
+ if (debug)
+ sprintf(bp, "client_limit=%lu", i);
+#endif
+ set_sys_var(bp, strlen(bp)+1, RO);
+ client_limit = i;
+ }
+ }
break;
case CONFIG_CLIENTPERIOD:
- if (ntokens < 2)
- {
- syslog(LOG_ERR,
- "no value for clientperiod command - line ignored");
- }
- else
- {
- U_LONG i;
- if (!atouint(tokens[1], &i) || i < 64)
- {
+ if (ntokens < 2) {
syslog(LOG_ERR,
- "illegal value for clientperiod command - line ignored");
- }
- else
- {
- extern U_LONG client_limit_period;
- char bp[80];
-
- sprintf(bp, "client_limit_period=%d", i);
- set_sys_var(bp, strlen(bp)+1, RO);
-
- client_limit_period = i;
- }
- }
+ "no value for clientperiod command - line ignored");
+ } else {
+ u_long i;
+
+ if (!atouint(tokens[1], &i) || i < 64) {
+ syslog(LOG_ERR,
+ "illegal value for clientperiod command - line ignored");
+ } else {
+ extern u_long client_limit_period;
+ char bp[80];
+
+ sprintf(bp, "client_limit_period=%ld", i);
+ set_sys_var(bp, strlen(bp)+1, RO);
+ client_limit_period = i;
+ }
+ }
+ break;
+
+ case CONFIG_ENABLE:
+ for (i = 1; i < ntokens; i++) {
+ int flag;
+
+ flag = matchkey(tokens[i], flags_keywords);
+ if (flag == CONFIG_UNKNOWN) {
+ syslog(LOG_ERR,
+ "enable unknown flag %s",
+ tokens[i]);
+ errflg = 1;
+ break;
+ }
+ proto_config(flag, 1L);
+ }
+ break;
+
+ case CONFIG_DISABLE:
+ for (i = 1; i < ntokens; i++) {
+ int flag;
+
+ flag = matchkey(tokens[i], flags_keywords);
+ if (flag == CONFIG_UNKNOWN) {
+ syslog(LOG_ERR,
+ "disable unknown flag %s",
+ tokens[i]);
+ errflg = 1;
+ break;
+ }
+ proto_config(flag, 0L);
+ }
+ break;
+
+ case CONFIG_PHONE:
+ for (i = 1; i < ntokens && i < MAXPHONE; i++) {
+ (void)strncpy(sys_phone[i - 1],
+ tokens[i], MAXDIAL);
+ }
+ sys_phone[i - 1][0] = '\0';
break;
}
}
@@ -1482,38 +1401,7 @@ getconfig(argc, argv)
/*
* Need name resolution
*/
- errflg = 0;
-#ifdef RESOLVE_INTERNAL
- if ( resolve_internal )
- do_resolve_internal();
- else
- {
-#endif
-
- if (info_auth_keyid == 0) {
- syslog(LOG_ERR,
- "no request key defined, peer name resolution not possible");
- errflg++;
- }
- if (!have_resolver) {
- syslog(LOG_ERR,
- "no resolver defined, peer name resolution not possible");
- errflg++;
- }
- if (!have_keyfile) {
- syslog(LOG_ERR,
- "no key file specified, peer name resolution not possible");
- errflg++;
- }
-
- if (!errflg)
-
- do_resolve(resolver_name, info_auth_keyid, keyfile);
- else
- abort_resolve();
-#ifdef RESOLVE_INTERNAL
- }
-#endif
+ do_resolve_internal();
}
}
@@ -1622,7 +1510,7 @@ getnetnum(num, addr, complain)
register int i;
register int temp;
char buf[80]; /* will core dump on really stupid stuff */
- U_LONG netnum;
+ u_long netnum;
/* XXX ELIMINATE replace with decodenetnum */
cp = num;
@@ -1648,7 +1536,7 @@ getnetnum(num, addr, complain)
netnum += temp;
#ifdef DEBUG
if (debug > 3)
- printf("getnetnum %s step %d buf %s temp %d netnum %d\n",
+ printf("getnetnum %s step %d buf %s temp %d netnum %lu\n",
num, i, buf, temp, netnum);
#endif
}
@@ -1676,7 +1564,7 @@ getnetnum(num, addr, complain)
addr->sin_addr.s_addr = htonl(netnum);
#ifdef DEBUG
if (debug > 1)
- printf("getnetnum given %s, got %s (%x)\n",
+ printf("getnetnum given %s, got %s (%lx)\n",
num, ntoa(addr), netnum);
#endif
return 1;
@@ -1711,7 +1599,7 @@ save_resolve(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
int maxpoll;
int flags;
int ttl;
- U_LONG keyid;
+ u_long keyid;
{
if (res_fp == NULL) {
(void) strcpy(res_file, RES_TEMPFILE);
@@ -1754,186 +1642,76 @@ abort_resolve()
}
+#define KEY_TYPE_ASCII 3
+
/*
- * do_resolve - start up the resolver program
+ * do_resolve_internal - start up the resolver function (not program)
*/
static void
-do_resolve(program, auth_keyid, keyfile)
- char *program;
- U_LONG auth_keyid;
- char *keyfile;
+do_resolve_internal()
{
- register LONG i;
- register char **ap;
- /* 1 progname + 5 -d's + 1 -r + keyid + keyfile + tempfile + 1 */
- char *argv[15];
- char numbuf[15];
- /*
- * Clean environment so the resolver is consistant
- */
- static char *resenv[] = {
- "HOME=/",
- "SHELL=/bin/sh",
- "TERM=dumb",
- "USER=root",
- NULL
- };
+ int i;
+
+ extern u_long req_keyid; /* request keyid */
+ extern char *req_file; /* name of the file with config info */
+ extern u_long info_auth_keyid;
if (res_fp == NULL) {
/* belch */
- syslog(LOG_ERR, "internal error in do_resolve: res_fp == NULL");
+ syslog(LOG_ERR,
+ "internal error in do_resolve_internal: res_fp == NULL");
exit(1);
}
+
+ /* we are done with this now */
(void) fclose(res_fp);
res_fp = NULL;
- ap = argv;
- *ap++ = program;
-
- /*
- * xntpres [-d ...] -r key# keyfile tempfile
- */
-#ifdef DEBUG
- i = debug;
- if (i > 5)
- i = 5;
- while (i-- > 0)
- *ap++ = "-d";
-#endif
- *ap++ = "-r";
-
- (void) sprintf(numbuf, "%lu", auth_keyid);
- *ap++ = numbuf;
- *ap++ = keyfile;
- *ap++ = res_file;
- *ap = NULL;
+ /* find a keyid */
+ if (info_auth_keyid == 0)
+ req_keyid = 65535;
+ else
+ req_keyid = info_auth_keyid;
+
+ /* if doesn't exist, make up one at random */
+ if (!authhavekey(req_keyid)) {
+ char rankey[9];
+ struct timeval now;
+
+ /* generate random key */
+ GETTIMEOFDAY(&now, (struct timezone *)0);
+ srand(now.tv_sec * now.tv_usec);
+ for (i = 0; i < 8; i++)
+ rankey[i] = (rand() % 255) + 1;
+ rankey[8] = 0;
+ authusekey(req_keyid, KEY_TYPE_ASCII, rankey);
+ }
+ /* save keyid so we will accept config requests with it */
+ info_auth_keyid = req_keyid;
+ req_file = res_file; /* set up pointer to res file */
(void) signal_no_reset(SIGCHLD, catchchild);
i = fork();
if (i == 0) {
/*
- * In child here, close up all descriptors and
- * exec the resolver program. Close the syslog()
- * facility gracefully in case we must reopen it.
+ * this used to close everything
+ * I don't think this is necessary
*/
- (void) signal(SIGCHLD, SIG_DFL);
- closelog();
-#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD)
- i = sysconf(_SC_OPEN_MAX);
-#else
- i = getdtablesize();
-#endif
-#ifdef DEBUG
- while (i-- > 2)
-#else
- while (i-- > 0)
-#endif
- (void) close(i);
- (void) execve(program, argv, resenv);
+ (void) signal_no_reset(SIGCHLD, SIG_DFL);
+ ntp_intres();
/*
- * If we got here, the exec screwed up. Open the log file
- * and print something so we don't die without complaint
+ * If we got here, the intres code screwed up.
+ * Print something so we don't die without complaint
*/
-#ifndef LOG_DAEMON
- openlog("xntpd", LOG_PID);
-#else
-#ifndef LOG_NTP
-#define LOG_NTP LOG_DAEMON
-#endif
- openlog("xntpd", LOG_PID | LOG_NDELAY, LOG_NTP);
-#endif /* LOG_DAEMON */
- syslog(LOG_ERR, "exec of resolver %s failed!", program);
+ syslog(LOG_ERR, "call to ntp_intres lost");
abort_resolve();
exit(1);
}
-
if (i == -1) {
- syslog(LOG_ERR, "fork() failed, can't start %s", program);
+ syslog(LOG_ERR, "fork() failed, can't start ntp_intres");
(void) signal_no_reset(SIGCHLD, SIG_DFL);
abort_resolve();
}
}
-
-
-#ifdef RESOLVE_INTERNAL
-
-#define KEY_TYPE_ASCII 3
-
-/*
- * do_resolve_internal - start up the resolver function (not program)
- */
-static void
-do_resolve_internal()
-{
- int i;
-
- extern U_LONG req_keyid; /* request keyid */
- extern char *req_file; /* name of the file with configuration info */
- extern U_LONG info_auth_keyid;
-
- if (res_fp == NULL) {
- /* belch */
- syslog(LOG_ERR, "internal error in do_resolve_internal: res_fp == NULL");
- exit(1);
- }
-
- /* we are done with this now */
- (void) fclose(res_fp);
- res_fp = NULL;
-
- /* find a keyid */
- if (info_auth_keyid == 0)
- req_keyid = 65535;
- else
- req_keyid = info_auth_keyid;
-
- /* if doesn't exist, make up one at random */
- if ( ! authhavekey(req_keyid) )
- {
- char rankey[9];
- struct timeval now;
-
- /* generate random key */
- GETTIMEOFDAY(&now, (struct timezone *)0);
- srand(now.tv_sec * now.tv_usec);
-
- for ( i = 0; i < 8; i++ )
- rankey[i] = (rand() % 255) + 1;
- rankey[8] = 0;
-
- authusekey(req_keyid, KEY_TYPE_ASCII, rankey);
- }
-
- /* save keyid so we will accept config requests with it */
- info_auth_keyid = req_keyid;
-
- req_file = res_file; /* set up pointer to res file */
-
- (void) signal_no_reset(SIGCHLD, catchchild);
-
- i = fork();
- if (i == 0) {
- /* this used to close everything
- * I don't think this is necessary */
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
-
- ntp_intres();
-
- /*
- * If we got here, the intres code screwed up.
- * Print something so we don't die without complaint
- */
- syslog(LOG_ERR, "call to ntp_intres lost");
- abort_resolve();
- exit(1);
- }
-
- if (i == -1) {
- syslog(LOG_ERR, "fork() failed, can't start ntp_intres");
- (void) signal_no_reset(SIGCHLD, SIG_DFL);
- abort_resolve();
- }
-}
-#endif
diff --git a/usr.sbin/xntpd/xntpd/ntp_control.c b/usr.sbin/xntpd/xntpd/ntp_control.c
index ef9c37a6751d..0f1dc2b4d494 100644
--- a/usr.sbin/xntpd/xntpd/ntp_control.c
+++ b/usr.sbin/xntpd/xntpd/ntp_control.c
@@ -3,11 +3,12 @@
*/
#include <stdio.h>
#include <ctype.h>
-#include <signal.h>
#include <sys/types.h>
+#include <signal.h>
#include <sys/time.h>
#include "ntpd.h"
+#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
#include "ntp_stdlib.h"
@@ -41,18 +42,13 @@ static void ctl_flushpkt P((int));
static void ctl_putdata P((char *, int, int));
static void ctl_putstr P((char *, char *, int));
static void ctl_putlfp P((char *, l_fp *));
-
-#ifdef UNUSED
-static void ctl_putulfp P((char *, l_fp *));
-#endif /* UNUSED */
-
static void ctl_putfp P((char *, s_fp));
static void ctl_putufp P((char *, u_fp));
-static void ctl_putuint P((char *, U_LONG));
-static void ctl_puthex P((char *, U_LONG));
-static void ctl_putint P((char *, LONG));
+static void ctl_putuint P((char *, u_long));
+static void ctl_puthex P((char *, u_long));
+static void ctl_putint P((char *, long));
static void ctl_putts P((char *, l_fp *));
-static void ctl_putadr P((char *, U_LONG));
+static void ctl_putadr P((char *, u_long));
static void ctl_putid P((char *, char *));
static void ctl_putarray P((char *, s_fp *, int));
static void ctl_putsys P((int));
@@ -61,7 +57,7 @@ static void ctl_putpeer P((int, struct peer *));
static void ctl_putclock P((int, struct refclockstat *, int));
#endif /* REFCLOCK */
static struct ctl_var *ctl_getitem P((struct ctl_var *, char **));
-static unsigned long count_var P((struct ctl_var *));
+static u_long count_var P((struct ctl_var *));
static void control_unspec P((struct recvbuf *, int));
static void read_status P((struct recvbuf *, int));
static void read_variables P((struct recvbuf *, int));
@@ -101,7 +97,7 @@ static struct ctl_var sys_var[] = {
{ CS_PEERID, RO, "peer" }, /* 9 */
{ CS_OFFSET, RO, "phase" }, /* 10 */
{ CS_DRIFT, RO, "freq" }, /* 11 */
- { CS_COMPLIANCE, RO, "compliance" }, /* 12 */
+ { CS_COMPLIANCE, RO, "error" }, /* 12 */
{ CS_CLOCK, RO, "clock" }, /* 13 */
{ CS_LEAPIND, RW, "leapindicator" }, /* 14 */
{ CS_LEAPWARNING, RW, "leapwarning" }, /* 15 */
@@ -231,8 +227,8 @@ static struct ctl_var clock_var[] = {
{ CC_BADDATA, RO, "baddata" }, /* 6 */
{ CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */
{ CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */
- { CC_FUDGEVAL1, RO, "fudgeval1" }, /* 9 */
- { CC_FUDGEVAL2, RO, "fudgeval2" }, /* 10 */
+ { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */
+ { CC_FUDGEVAL2, RO, "refid" }, /* 10 */
{ CC_FLAGS, RO, "flags" }, /* 11 */
{ CC_DEVICE, RO, "device" }, /* 12 */
{ CC_VARLIST, RO, "clock_var_list" },/* 13 */
@@ -304,30 +300,36 @@ static struct utsname utsname;
* set peer->sstclktype to something different than CTL_SST_TS_UNSPEC.
*/
static u_char clocktypes[] = {
- CTL_SST_TS_NTP, /* REFCLK_NONE */
- CTL_SST_TS_UNSPEC, /* REFCLK_LOCALCLOCK */
- CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK */
- CTL_SST_TS_HF, /* REFCLK_WWV_PST */
- CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM */
- CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME */
- CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK */
- CTL_SST_TS_HF, /* REFCLK_CHU */
+ CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
+ CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */
+ CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
+ CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
+ CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME (5) */
+ CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */
+ CTL_SST_TS_HF, /* REFCLK_CHU (7) */
CTL_SST_TS_LF, /* REFCLOCK_PARSE - default value - driver supplies actual value in peer->sstclktype */
- CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM_HP */
- CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 */
- CTL_SST_TS_LF, /* REFCLK_OMEGA_TRUETIME */
- CTL_SST_TS_UNSPEC, /* Future expansion */
- CTL_SST_TS_UNSPEC, /* Future expansion */
- CTL_SST_TS_UNSPEC, /* Future expansion */
- CTL_SST_TS_UNSPEC /* Future expansion */
+ CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
+ CTL_SST_TS_LF, /* REFCLK_OMEGA_TRUETIME (11) */
+ CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
+ CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
+ CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */
+ CTL_SST_TS_UHF, /* REFCLK_GPSTM_TRUETIME (15) */
+ CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
+ CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACT (18) */
+ CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_MOTO (21) */
+ CTL_SST_TS_ATOM /* REFCLK_ATOM_PPS (22) */
};
-
/*
* Keyid used for authenticating write requests.
*/
-U_LONG ctl_auth_keyid;
+u_long ctl_auth_keyid;
/*
* We keep track of the last error reported by the system internally
@@ -339,21 +341,21 @@ static u_char ctl_sys_num_events;
/*
* Statistic counters to keep track of requests and responses.
*/
-U_LONG ctltimereset; /* time stats reset */
-U_LONG numctlreq; /* number of requests we've received */
-U_LONG numctlbadpkts; /* number of bad control packets */
-U_LONG numctlresponses; /* number of resp packets sent with data */
-U_LONG numctlfrags; /* number of fragments sent */
-U_LONG numctlerrors; /* number of error responses sent */
-U_LONG numctltooshort; /* number of too short input packets */
-U_LONG numctlinputresp; /* number of responses on input */
-U_LONG numctlinputfrag; /* number of fragments on input */
-U_LONG numctlinputerr; /* number of input pkts with err bit set */
-U_LONG numctlbadoffset; /* number of input pkts with nonzero offset */
-U_LONG numctlbadversion; /* number of input pkts with unknown version */
-U_LONG numctldatatooshort; /* data too short for count */
-U_LONG numctlbadop; /* bad op code found in packet */
-U_LONG numasyncmsgs; /* number of async messages we've sent */
+u_long ctltimereset; /* time stats reset */
+u_long numctlreq; /* number of requests we've received */
+u_long numctlbadpkts; /* number of bad control packets */
+u_long numctlresponses; /* number of resp packets sent with data */
+u_long numctlfrags; /* number of fragments sent */
+u_long numctlerrors; /* number of error responses sent */
+u_long numctltooshort; /* number of too short input packets */
+u_long numctlinputresp; /* number of responses on input */
+u_long numctlinputfrag; /* number of fragments on input */
+u_long numctlinputerr; /* number of input pkts with err bit set */
+u_long numctlbadoffset; /* number of input pkts with nonzero offset */
+u_long numctlbadversion; /* number of input pkts with unknown version */
+u_long numctldatatooshort; /* data too short for count */
+u_long numctlbadop; /* bad op code found in packet */
+u_long numasyncmsgs; /* number of async messages we've sent */
/*
* Imported from the I/O module
@@ -368,7 +370,7 @@ extern int debug;
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
+extern u_long current_time;
extern struct peer *assoc_hash[];
extern int pps_control; /* flag for 1-pps signal present */
@@ -380,7 +382,7 @@ extern u_char sys_stratum;
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
-extern U_LONG sys_refid;
+extern u_long sys_refid;
extern l_fp sys_reftime;
extern l_fp sys_refskew;
extern u_char sys_poll;
@@ -390,7 +392,7 @@ extern struct peer *sys_peer;
*/
extern l_fp last_offset;
extern s_fp drift_comp;
-extern int time_constant;
+extern u_fp sys_maxd;
extern int pll_control;
/*
* Imported from the leap module
@@ -419,7 +421,7 @@ static struct interface *lcl_inter;
static u_char res_authenticate;
static u_char res_authokay;
-static U_LONG res_keyid;
+static u_long res_keyid;
#define MAXDATALINELEN (72)
@@ -480,14 +482,14 @@ ctl_error(errcode)
if (res_authenticate) {
int maclen;
- *(U_LONG *)((u_char *)&rpkt + CTL_HEADER_LEN)
+ *(u_long *)((u_char *)&rpkt + CTL_HEADER_LEN)
= htonl(res_keyid);
maclen =
authencrypt(res_keyid, (U_LONG *)&rpkt, CTL_HEADER_LEN);
- sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
CTL_HEADER_LEN + maclen);
} else {
- sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
CTL_HEADER_LEN);
}
numctlerrors++;
@@ -596,17 +598,17 @@ process_control(rbufp, restrict)
properlen = (properlen + 7) & ~7;
- if ((rbufp->recv_length & (sizeof(U_LONG)-1)) == 0
+ if ((rbufp->recv_length & (sizeof(u_long)-1)) == 0
&& (maclen = (rbufp->recv_length - properlen)) >= MIN_MAC_LEN
&& maclen <= MAX_MAC_LEN) {
res_authenticate = 1;
- res_keyid = ntohl(*(U_LONG *)((u_char *)pkt + properlen));
+ res_keyid = ntohl(*(u_long *)((u_char *)pkt + properlen));
#ifdef DEBUG
if (debug >= 3)
printf(
- "recv_len %d, properlen %d, wants auth with keyid %d, MAC length=%d\n",
+ "recv_len %d, properlen %d, wants auth with keyid %ld, MAC length=%d\n",
rbufp->recv_length, properlen, res_keyid, maclen);
#endif
if (!authhavekey(res_keyid)) {
@@ -728,15 +730,18 @@ ctlsysstatus()
register u_char clock;
clock = CTL_SST_TS_UNSPEC;
- if (sys_peer != 0)
- if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC)
+ if (sys_peer != 0) {
+ if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
clock = sys_peer->sstclktype;
- else {
+ if (pps_control)
+ clock |= CTL_SST_TS_PPS;
+ } else {
if (sys_peer->refclktype < sizeof(clocktypes))
clock = clocktypes[sys_peer->refclktype];
if (pps_control)
clock |= CTL_SST_TS_PPS;
}
+ }
return (u_short)CTL_SYS_STATUS(sys_leap, clock,
ctl_sys_num_events, ctl_sys_last_event);
}
@@ -788,6 +793,7 @@ ctl_flushpkt(more)
rpkt.sequence = htons(ctl_trap[i].tr_sequence);
sendpkt(&ctl_trap[i].tr_addr,
ctl_trap[i].tr_localaddr,
+ -4,
(struct pkt *)&rpkt, sendlen);
if (!more)
ctl_trap[i].tr_sequence++;
@@ -808,14 +814,14 @@ ctl_flushpkt(more)
*datapt++ = '\0';
totlen++;
}
- *(U_LONG *)datapt = htonl(res_keyid);
+ *(u_long *)datapt = htonl(res_keyid);
maclen =
authencrypt(res_keyid, (U_LONG *)&rpkt, totlen);
- sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, -5, (struct pkt *)&rpkt,
totlen + maclen);
} else {
- sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, -6, (struct pkt *)&rpkt,
sendlen);
}
if (more)
@@ -935,33 +941,6 @@ ctl_putlfp(tag, ts)
}
-#ifdef UNUSED
-/*
- * ctl_putlfp - write a tagged, unsigned l_fp into the response
- */
-static void
-ctl_putulfp(tag, ts)
- char *tag;
- l_fp *ts;
-{
- register char *cp, *cq;
- char buffer[200];
-
- cp = buffer;
- cq = tag;
- while (*cq != '\0')
- *cp++ = *cq++;
-
- *cp++ = '=';
- cq = ulfptoms(ts, 3);
- while (*cq != '\0')
- *cp++ = *cq++;
-
- ctl_putdata(buffer, cp - buffer, 0);
-}
-#endif /* UNUSED */
-
-
/*
* ctl_putfp - write a tagged s_fp number into the response
*/
@@ -1018,7 +997,7 @@ ctl_putufp(tag, ufp)
static void
ctl_putuint(tag, uval)
char *tag;
- U_LONG uval;
+ u_long uval;
{
register char *cp, *cq;
char buffer[200];
@@ -1029,7 +1008,7 @@ ctl_putuint(tag, uval)
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%u", uval);
+ (void) sprintf(cp, "%lu", uval);
while (*cp != '\0')
cp++;
@@ -1043,7 +1022,7 @@ ctl_putuint(tag, uval)
static void
ctl_puthex(tag, uval)
char *tag;
- U_LONG uval;
+ u_long uval;
{
register char *cp, *cq;
char buffer[200];
@@ -1068,7 +1047,7 @@ ctl_puthex(tag, uval)
static void
ctl_putint(tag, ival)
char *tag;
- LONG ival;
+ long ival;
{
register char *cp, *cq;
char buffer[200];
@@ -1079,7 +1058,7 @@ ctl_putint(tag, ival)
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%d", ival);
+ (void) sprintf(cp, "%ld", ival);
while (*cp != '\0')
cp++;
@@ -1119,7 +1098,7 @@ ctl_putts(tag, ts)
static void
ctl_putadr(tag, addr)
char *tag;
- U_LONG addr;
+ u_long addr;
{
register char *cp, *cq;
char buffer[200];
@@ -1225,13 +1204,13 @@ ctl_putsys(varid)
switch (varid) {
case CS_LEAP:
- ctl_putuint(sys_var[CS_LEAP].text, (U_LONG)sys_leap);
+ ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
break;
case CS_STRATUM:
- ctl_putuint(sys_var[CS_STRATUM].text, (U_LONG)sys_stratum);
+ ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
break;
case CS_PRECISION:
- ctl_putint(sys_var[CS_PRECISION].text, (LONG)sys_precision);
+ ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
break;
case CS_ROOTDELAY:
ctl_putfp(sys_var[CS_ROOTDELAY].text, sys_rootdelay);
@@ -1241,23 +1220,23 @@ ctl_putsys(varid)
sys_rootdispersion);
break;
case CS_REFID:
- if (sys_stratum <= 1)
- ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid);
- else
+ if (sys_stratum > 1)
ctl_putadr(sys_var[CS_REFID].text, sys_refid);
+ else
+ ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid);
break;
case CS_REFTIME:
ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
break;
case CS_POLL:
- ctl_putuint(sys_var[CS_POLL].text, (U_LONG)sys_poll);
+ ctl_putuint(sys_var[CS_POLL].text, sys_poll);
break;
case CS_PEERID:
if (sys_peer == NULL)
- ctl_putuint(sys_var[CS_PEERID].text, (U_LONG)0);
+ ctl_putuint(sys_var[CS_PEERID].text, 0);
else
ctl_putuint(sys_var[CS_PEERID].text,
- (U_LONG)sys_peer->associd);
+ sys_peer->associd);
break;
case CS_OFFSET:
ctl_putlfp(sys_var[CS_OFFSET].text, &last_offset);
@@ -1266,17 +1245,17 @@ ctl_putsys(varid)
ctl_putfp(sys_var[CS_DRIFT].text, drift_comp);
break;
case CS_COMPLIANCE:
- ctl_putuint(sys_var[CS_COMPLIANCE].text, (U_LONG)time_constant);
+ ctl_putufp(sys_var[CS_COMPLIANCE].text, sys_maxd);
break;
case CS_CLOCK:
get_systime(&tmp);
ctl_putts(sys_var[CS_CLOCK].text, &tmp);
break;
case CS_LEAPIND:
- ctl_putuint(sys_var[CS_LEAPIND].text, (U_LONG)leap_indicator);
+ ctl_putuint(sys_var[CS_LEAPIND].text, leap_indicator);
break;
case CS_LEAPWARNING:
- ctl_putuint(sys_var[CS_LEAPWARNING].text, (U_LONG)leap_warning);
+ ctl_putuint(sys_var[CS_LEAPWARNING].text, leap_warning);
break;
case CS_PROCESSOR:
#ifndef HAVE_UNAME
@@ -1297,7 +1276,7 @@ ctl_putsys(varid)
#endif /* HAVE_UNAME */
break;
case CS_KEYID:
- ctl_putuint(sys_var[CS_KEYID].text, (U_LONG)0);
+ ctl_putuint(sys_var[CS_KEYID].text, 0);
break;
case CS_REFSKEW:
ctl_putlfp(sys_var[CS_REFSKEW].text, &sys_refskew);
@@ -1378,15 +1357,15 @@ ctl_putpeer(varid, peer)
switch (varid) {
case CP_CONFIG:
ctl_putuint(peer_var[CP_CONFIG].text,
- (U_LONG)((peer->flags & FLAG_CONFIG) != 0));
+ ((peer->flags & FLAG_CONFIG) != 0));
break;
case CP_AUTHENABLE:
ctl_putuint(peer_var[CP_AUTHENABLE].text,
- (U_LONG)((peer->flags & FLAG_AUTHENABLE) != 0));
+ ((peer->flags & FLAG_AUTHENABLE) != 0));
break;
case CP_AUTHENTIC:
ctl_putuint(peer_var[CP_AUTHENTIC].text,
- (U_LONG)((peer->flags & FLAG_AUTHENTIC) != 0));
+ ((peer->flags & FLAG_AUTHENTIC) != 0));
break;
case CP_SRCADR:
ctl_putadr(peer_var[CP_SRCADR].text,
@@ -1394,33 +1373,40 @@ ctl_putpeer(varid, peer)
break;
case CP_SRCPORT:
ctl_putuint(peer_var[CP_SRCPORT].text,
- (U_LONG)ntohs(peer->srcadr.sin_port));
+ ntohs(peer->srcadr.sin_port));
break;
case CP_DSTADR:
ctl_putadr(peer_var[CP_DSTADR].text,
- peer->dstadr->sin.sin_addr.s_addr);
+ peer->processed ?
+ peer->cast_flags & MDF_BCAST ?
+ peer->dstadr->bcast.sin_addr.s_addr:
+ peer->cast_flags ?
+ peer->dstadr->sin.sin_addr.s_addr ?
+ peer->dstadr->sin.sin_addr.s_addr:
+ peer->dstadr->bcast.sin_addr.s_addr:
+ 8 : 12);
break;
case CP_DSTPORT:
ctl_putuint(peer_var[CP_DSTPORT].text,
- (U_LONG)ntohs(peer->dstadr->sin.sin_port));
+ ntohs(peer->dstadr->sin.sin_port));
break;
case CP_LEAP:
- ctl_putuint(peer_var[CP_LEAP].text, (U_LONG)peer->leap);
+ ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
break;
case CP_HMODE:
- ctl_putuint(peer_var[CP_HMODE].text, (U_LONG)peer->hmode);
+ ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
break;
case CP_STRATUM:
- ctl_putuint(peer_var[CP_STRATUM].text, (U_LONG)peer->stratum);
+ ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
break;
case CP_PPOLL:
- ctl_putuint(peer_var[CP_PPOLL].text, (U_LONG)peer->ppoll);
+ ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
break;
case CP_HPOLL:
- ctl_putuint(peer_var[CP_HPOLL].text, (U_LONG)peer->hpoll);
+ ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
break;
case CP_PRECISION:
- ctl_putint(peer_var[CP_PRECISION].text, (LONG)peer->precision);
+ ctl_putint(peer_var[CP_PRECISION].text, peer->precision);
break;
case CP_ROOTDELAY:
ctl_putfp(peer_var[CP_ROOTDELAY].text, peer->rootdelay);
@@ -1431,7 +1417,12 @@ ctl_putpeer(varid, peer)
break;
case CP_REFID:
if (peer->stratum > 1)
- ctl_putadr(peer_var[CP_REFID].text, peer->refid);
+ if (peer->flags & FLAG_REFCLOCK)
+ ctl_putadr(peer_var[CP_REFID].text,
+ peer->srcadr.sin_addr.s_addr);
+ else
+ ctl_putadr(peer_var[CP_REFID].text,
+ peer->refid);
else
ctl_putid(peer_var[CP_REFID].text,
(char *)&peer->refid);
@@ -1449,13 +1440,13 @@ ctl_putpeer(varid, peer)
ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
break;
case CP_REACH:
- ctl_puthex(peer_var[CP_REACH].text, (U_LONG)peer->reach);
+ ctl_puthex(peer_var[CP_REACH].text, peer->reach);
break;
case CP_FLASH:
- ctl_puthex(peer_var[CP_FLASH].text, (U_LONG)peer->flash);
+ ctl_puthex(peer_var[CP_FLASH].text, peer->flash);
break;
case CP_VALID:
- ctl_putuint(peer_var[CP_VALID].text, (U_LONG)peer->valid);
+ ctl_putuint(peer_var[CP_VALID].text, peer->valid);
break;
case CP_TIMER:
ctl_putuint(peer_var[CP_TIMER].text,
@@ -1486,7 +1477,7 @@ ctl_putpeer(varid, peer)
(s_fp *)peer->filter_error, (int)peer->filter_nextpt);
break;
case CP_PMODE:
- ctl_putuint(peer_var[CP_PMODE].text, (U_LONG)peer->pmode);
+ ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
break;
case CP_RECEIVED:
ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
@@ -1552,8 +1543,7 @@ ctl_putclock(varid, clock, mustput)
case CC_TYPE:
if (mustput || clock->clockdesc == NULL
|| *(clock->clockdesc) == '\0') {
- ctl_putuint(clock_var[CC_TYPE].text,
- (U_LONG)clock->type);
+ ctl_putuint(clock_var[CC_TYPE].text, clock->type);
}
break;
case CC_TIMECODE:
@@ -1561,7 +1551,7 @@ ctl_putclock(varid, clock, mustput)
(int)clock->lencode);
break;
case CC_POLL:
- ctl_putuint(clock_var[CC_POLL].text, (U_LONG)clock->polls);
+ ctl_putuint(clock_var[CC_POLL].text, clock->polls);
break;
case CC_NOREPLY:
ctl_putuint(clock_var[CC_NOREPLY].text, clock->noresponse);
@@ -1589,14 +1579,17 @@ ctl_putclock(varid, clock, mustput)
break;
case CC_FUDGEVAL2:
if (mustput || (clock->haveflags & CLK_HAVEVAL2))
- ctl_putint(clock_var[CC_FUDGEVAL2].text,
- clock->fudgeval2);
+ if (clock->fudgeval1 > 1)
+ ctl_putadr(clock_var[CC_FUDGEVAL2].text,
+ clock->fudgeval2);
+ else
+ ctl_putid(clock_var[CC_FUDGEVAL2].text,
+ (char *)&clock->fudgeval2);
break;
case CC_FLAGS:
if (mustput || (clock->haveflags &
(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)))
- ctl_putuint(clock_var[CC_FLAGS].text,
- (U_LONG)clock->flags);
+ ctl_putuint(clock_var[CC_FLAGS].text, clock->flags);
break;
case CC_DEVICE:
if (clock->clockdesc == NULL || *(clock->clockdesc) == '\0') {
@@ -1966,8 +1959,8 @@ write_variables(rbufp, restrict)
register struct ctl_var *v;
register int ext_var;
char *valuep;
- LONG val;
- u_char leapind, leapwarn;
+ long val;
+ int leapind, leapwarn;
/*
* If he's trying to write into a peer tell him no way
@@ -1985,8 +1978,8 @@ write_variables(rbufp, restrict)
/*
* Set flags to not-in-sync so we can tell when we get something.
*/
- leapind = (u_char)~0;
- leapwarn = (u_char)~0;
+ leapind = ~0;
+ leapwarn = ~0;
/*
* Look through the variables. Dump out at the first sign of trouble.
@@ -2037,13 +2030,13 @@ write_variables(rbufp, restrict)
switch(v->code) {
case CS_LEAP:
case CS_LEAPIND:
- leapind = (u_char)val;
+ leapind = val;
break;
case CS_LEAPWARNING:
- leapwarn = (u_char)val;
+ leapwarn = val;
break;
default:
- ctl_error(CERR_UNSPEC); /* our fault, really */
+ ctl_error(CERR_UNSPEC); /* our fault, really */
return;
}
}
@@ -2052,7 +2045,7 @@ write_variables(rbufp, restrict)
/*
* If we got anything, do it.
*/
- if (leapind != (u_char)~0 || leapwarn != (u_char)~0) {
+ if (leapind != ~0 || leapwarn != ~0) {
if (!leap_setleap((int)leapind, (int)leapwarn)) {
ctl_error(CERR_PERMISSION);
return;
@@ -2436,18 +2429,32 @@ report_event(err, peer)
if (!(err & PEER_EVENT)) {
if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
ctl_sys_num_events++;
- if (ctl_sys_last_event != (u_char)err)
- syslog(LOG_INFO, "system event %x status %x",
- err, ctlsysstatus());
- ctl_sys_last_event = (u_char)err;
+ if (ctl_sys_last_event != (u_char)err) {
+ syslog(LOG_INFO, "system event %x status %x",
+ err, ctlsysstatus());
+#ifdef DEBUG
+ if (debug)
+ printf("report_event: system event %x status %x\n",
+ err, ctlsysstatus());
+#endif
+ ctl_sys_last_event = (u_char)err;
+ }
} else if (peer != 0) {
peer->last_event = (u_char)(err & ~PEER_EVENT);
if (peer->num_events < CTL_PEER_MAXEVENTS)
- peer->num_events++;
+ peer->num_events++;
syslog(LOG_INFO, "peer %s event %x status %x",
ntoa(&peer->srcadr), err, ctlpeerstatus(peer));
+#ifdef DEBUG
+ if (debug)
+ printf("peer %s event %x status %x\n",
+ ntoa(&peer->srcadr), err, ctlpeerstatus(peer));
+#endif
} else {
syslog(LOG_ERR, "report_event: err %x, no peer", err);
+#ifdef DEBUG
+ printf("report_event: err %x, no peer\n", err);
+#endif
return;
}
@@ -2489,10 +2496,8 @@ report_event(err, peer)
clock.kv_list = (struct ctl_var *)0;
refclock_control(&peer->srcadr,
- (struct refclockstat *)0,
- &clock);
- ctl_puthex("refclockstatus",
- (U_LONG)ctlclkstatus(&clock));
+ (struct refclockstat *)0, &clock);
+ ctl_puthex("refclockstatus", ctlclkstatus(&clock));
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
@@ -2528,7 +2533,7 @@ report_event(err, peer)
&clock);
ctl_puthex("refclockstatus",
- (U_LONG)ctlclkstatus(&clock));
+ ctlclkstatus(&clock));
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
@@ -2572,11 +2577,11 @@ ctl_clr_stats()
numasyncmsgs = 0;
}
-static unsigned long
+static u_long
count_var(k)
struct ctl_var *k;
{
- register unsigned long c;
+ register u_long c;
c = 0;
while (k && !(k++->flags & EOV))
@@ -2588,10 +2593,10 @@ count_var(k)
char *
add_var(kv, size, def)
struct ctl_var **kv;
- unsigned long size;
+ u_long size;
int def;
{
- register unsigned long c;
+ register u_long c;
register struct ctl_var *k;
c = count_var(*kv);
@@ -2617,7 +2622,7 @@ void
set_var(kv, data, size, def)
struct ctl_var **kv;
char *data;
- unsigned long size;
+ u_long size;
int def;
{
register struct ctl_var *k;
@@ -2665,7 +2670,7 @@ set_var(kv, data, size, def)
void
set_sys_var(data, size, def)
char *data;
- unsigned long size;
+ u_long size;
int def;
{
set_var(&ext_sys_var, data, size, def);
diff --git a/usr.sbin/xntpd/xntpd/ntp_filegen.c b/usr.sbin/xntpd/xntpd/ntp_filegen.c
index 55cf1aebab13..4c23bed44f06 100644
--- a/usr.sbin/xntpd/xntpd/ntp_filegen.c
+++ b/usr.sbin/xntpd/xntpd/ntp_filegen.c
@@ -25,7 +25,7 @@
#include "ntp_stdlib.h"
/*
- * NTP is intended to run LONG periods of time without restart.
+ * NTP is intended to run long periods of time without restart.
* Thus log and statistic files generated by NTP will grow large.
*
* this set of routines provides a central interface
@@ -43,7 +43,7 @@ extern int errno;
/*
* imported from timer
*/
-extern U_LONG current_time;
+extern u_long current_time;
/*
* redefine this if your system dislikes filename suffixes like
@@ -60,7 +60,7 @@ extern U_LONG current_time;
extern int debug;
#endif
-static void filegen_open P((FILEGEN *, U_LONG));
+static void filegen_open P((FILEGEN *, u_long));
static int valid_fileref P((char *, char *));
#ifdef UNUSED
static FILEGEN *filegen_unregister P((char *));
@@ -74,7 +74,7 @@ static FILEGEN *filegen_unregister P((char *));
static void
filegen_open(gen, newid)
FILEGEN *gen;
- U_LONG newid;
+ u_long newid;
{
char *filename;
char *basename;
@@ -100,7 +100,7 @@ filegen_open(gen, newid)
case FILEGEN_PID:
filename = emalloc(len + 1 + 1 + 10);
- sprintf(filename,"%s%c#%d", basename, SUFFIX_SEP, newid);
+ sprintf(filename,"%s%c#%ld", basename, SUFFIX_SEP, newid);
break;
case FILEGEN_DAY:
@@ -142,7 +142,7 @@ filegen_open(gen, newid)
case FILEGEN_AGE:
filename = emalloc(len + 1 + 2 + 10);
- sprintf(filename, "%s%ca%08d", basename, SUFFIX_SEP, newid);
+ sprintf(filename, "%s%ca%08ld", basename, SUFFIX_SEP, newid);
break;
}
@@ -156,7 +156,7 @@ filegen_open(gen, newid)
/*
* try to resolve name collisions
*/
- static U_LONG conflicts = 0;
+ static u_long conflicts = 0;
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG)
@@ -170,7 +170,8 @@ filegen_open(gen, newid)
*/
char *savename = emalloc(len + 1 + 1 + 10 + 10);
sprintf(savename, "%s%c%dC%lu",
- basename, SUFFIX_SEP, getpid(), conflicts++);
+ basename, SUFFIX_SEP, getpid(),
+ (u_long)conflicts++);
if (rename(basename, savename) != 0)
syslog(LOG_ERR," couldn't save %s: %m", basename);
free(savename);
@@ -207,7 +208,7 @@ filegen_open(gen, newid)
#ifdef DEBUG
if (debug > 3)
printf("opening filegen (type=%d/id=%lu) \"%s\"\n",
- gen->type, newid, filename);
+ gen->type, (u_long)newid, filename);
#endif
if (fp == NULL) {
@@ -265,9 +266,9 @@ filegen_open(gen, newid)
void
filegen_setup(gen,now)
FILEGEN *gen;
- U_LONG now;
+ u_long now;
{
- U_LONG new_gen = ~0;
+ u_long new_gen = ~0;
struct calendar cal;
if (!(gen->flag & FGEN_FLAG_ENABLED)) {
@@ -450,9 +451,10 @@ filegen_get(name)
while(f) {
if (f->name == name || strcmp(name, f->name) == 0) {
-#ifdef DEBUG
+#ifdef XXX /* this gives the Alpha compiler fits */
if (debug > 3)
- printf("filegen_get(\"%s\") = %x\n", name, (u_int)f->filegen);
+ printf("filegen_get(\"%s\") = %x\n", name,
+ (u_int)f->filegen);
#endif
return f->filegen;
}
@@ -472,13 +474,13 @@ filegen_register(name, filegen)
{
struct filegen_entry **f = &filegen_registry;
-#ifdef DEBUG
+#ifdef XXX /* this gives the Alpha compiler fits */
if (debug > 3)
printf("filegen_register(\"%s\",%x)\n", name, (u_int)filegen);
#endif
while (*f) {
if ((*f)->name == name || strcmp(name, (*f)->name) == 0) {
-#ifdef DEBUG
+#ifdef XXX /* this gives the Alpha compiler fits */
if (debug > 4) {
printf("replacing filegen %x\n", (u_int)(*f)->filegen);
}
diff --git a/usr.sbin/xntpd/xntpd/ntp_intres.c b/usr.sbin/xntpd/xntpd/ntp_intres.c
index 5ff4af4d8242..c05354b6837d 100644
--- a/usr.sbin/xntpd/xntpd/ntp_intres.c
+++ b/usr.sbin/xntpd/xntpd/ntp_intres.c
@@ -1,4 +1,4 @@
-/* ntp_intres.c,v 3.1 1993/07/06 01:11:16 jbj Exp
+/*
* ripped off from ../xnptres/xntpres.c by Greg Troxel 4/2/92
* routine callable from xntpd, rather than separate program
* also, key info passed in via a global, so no key file needed.
@@ -118,7 +118,7 @@ static int sockfd = -1;
/* stuff to be filled in by caller */
-U_LONG req_keyid; /* request keyid */
+u_long req_keyid; /* request keyid */
char *req_file; /* name of the file with configuration info */
/* end stuff to be filled in */
@@ -130,7 +130,7 @@ extern int errno;
static RETSIGTYPE bong P((int));
static void checkparent P((void));
static void removeentry P((struct conf_entry *));
-static void addentry P((char *, int, int, int, int, int, int, U_LONG));
+static void addentry P((char *, int, int, int, int, int, int, u_long));
static int findhostaddr P((struct conf_entry *));
static void openntp P((void));
static int request P((struct conf_peer *));
@@ -147,9 +147,10 @@ ntp_intres()
{
FILE *in;
+#ifdef DEBUG
if ( debug )
- syslog(LOG_INFO, "ntp_intres running");
-
+ syslog(LOG_INFO, "ntp_intres running");
+#endif
/* check out auth stuff */
if (!authhavekey(req_keyid)) {
@@ -171,7 +172,7 @@ ntp_intres()
readconf(in, req_file);
(void) fclose(in);
- if ( ! debug )
+ if (!debug )
(void) unlink(req_file);
/*
@@ -289,7 +290,7 @@ addentry(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
int maxpoll;
int flags;
int ttl;
- U_LONG keyid;
+ u_long keyid;
{
register char *cp;
register struct conf_entry *ce;
@@ -308,7 +309,7 @@ addentry(name, mode, version, minpoll, maxpoll, flags, ttl, keyid)
ce->ce_maxpoll = (u_char)maxpoll;
ce->ce_flags = (u_char)flags;
ce->ce_ttl = (u_char)ttl;
- ce->ce_keyid = htonl(keyid);
+ ce->ce_keyid = keyid;
ce->ce_next = NULL;
if (confentries == NULL) {
@@ -466,7 +467,7 @@ request(conf)
auth1crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
gettstamp(&ts);
- M_ADDUF(ts.l_ui, ts.l_uf, SKEWTIME);
+ L_ADDUF(&ts, SKEWTIME);
HTONL_FP(&ts, &reqpkt.tstamp);
n = auth2crypt(req_keyid, (U_LONG *)&reqpkt, REQ_LEN_NOMAC);
@@ -683,7 +684,7 @@ readconf(fp, name)
{
register int i;
char *token[NUMTOK];
- U_LONG intval[NUMTOK];
+ u_long intval[NUMTOK];
int flags;
char buf[MAXLINESIZE];
char *bp;
diff --git a/usr.sbin/xntpd/xntpd/ntp_io.c b/usr.sbin/xntpd/xntpd/ntp_io.c
index 551df510dc37..dcb68efd9089 100644
--- a/usr.sbin/xntpd/xntpd/ntp_io.c
+++ b/usr.sbin/xntpd/xntpd/ntp_io.c
@@ -1,4 +1,4 @@
-/* ntp_io.c,v 3.1 1993/07/06 01:11:17 jbj Exp
+/*
* xntp_io.c - input/output routines for xntpd. The socket-opening code
* was shamelessly stolen from ntpd.
*/
@@ -7,12 +7,13 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/param.h>
-#include <sys/ioctl.h>
#include <sys/time.h>
-
-#ifdef MCAST
-#include "ntp_in.h"
-#endif /* MCAST */
+#ifndef __bsdi__
+#include <netinet/in.h>
+#endif
+#if defined(__bsdi__) || defined(SYS_NETBSD) || defined(SYS_FREEBSD) || defined(SYS_AIX)
+#include <sys/ioctl.h>
+#endif
#include "ntpd.h"
#include "ntp_select.h"
@@ -21,6 +22,10 @@
#include "ntp_if.h"
#include "ntp_stdlib.h"
+#if defined(MCAST) && !defined(IP_ADD_MEMBERSHIP)
+#undef MCAST
+#endif
+
#if defined(BSD)&&!defined(sun)&&!defined(SYS_SINIXM)
#if BSD >= 199006
#define HAVE_VARIABLE_IFR_LENGTH
@@ -61,7 +66,7 @@
#define BLOCKIO() ((void) block_sigio())
#define UNBLOCKIO() ((void) unblock_sigio())
#else
-#define BLOCKIO()
+#define BLOCKIO()
#define UNBLOCKIO()
#endif
@@ -76,15 +81,15 @@
/*
* Memory allocation
*/
-U_LONG full_recvbufs; /* number of recvbufs on fulllist */
-U_LONG free_recvbufs; /* number of recvbufs on freelist */
+u_long full_recvbufs; /* number of recvbufs on fulllist */
+u_long free_recvbufs; /* number of recvbufs on freelist */
static struct recvbuf *freelist; /* free buffers */
static struct recvbuf *fulllist; /* lifo buffers with data */
static struct recvbuf *beginlist; /* fifo buffers with data */
-U_LONG total_recvbufs; /* total recvbufs currently in use */
-U_LONG lowater_additions; /* number of times we have added memory */
+u_long total_recvbufs; /* total recvbufs currently in use */
+u_long lowater_additions; /* number of times we have added memory */
static struct recvbuf initial_bufs[RECV_INIT]; /* initial allocation */
@@ -92,15 +97,15 @@ static struct recvbuf initial_bufs[RECV_INIT]; /* initial allocation */
/*
* Other statistics of possible interest
*/
-U_LONG packets_dropped; /* total number of packets dropped on reception */
-U_LONG packets_ignored; /* packets received on wild card interface */
-U_LONG packets_received; /* total number of packets received */
-U_LONG packets_sent; /* total number of packets sent */
-U_LONG packets_notsent; /* total number of packets which couldn't be sent */
+u_long packets_dropped; /* total number of packets dropped on reception */
+u_long packets_ignored; /* packets received on wild card interface */
+u_long packets_received; /* total number of packets received */
+u_long packets_sent; /* total number of packets sent */
+u_long packets_notsent; /* total number of packets which couldn't be sent */
-U_LONG handler_calls; /* number of calls to interrupt handler */
-U_LONG handler_pkts; /* number of pkts received by handler */
-U_LONG io_timereset; /* time counters were reset */
+u_long handler_calls; /* number of calls to interrupt handler */
+u_long handler_pkts; /* number of pkts received by handler */
+u_long io_timereset; /* time counters were reset */
/*
* Interface stuff
@@ -128,16 +133,16 @@ int maxactivefd;
/*
* Imported from ntp_timer.c
*/
-extern U_LONG current_time;
+extern u_long current_time;
extern int errno;
extern int debug;
-static int create_sockets P((unsigned int));
+static int create_sockets P((u_int));
static int open_socket P((struct sockaddr_in *, int));
static void close_socket P((int));
#ifdef HAVE_SIGNALED_IO
-static int init_clock_sig P(());
+static int init_clock_sig P(());
static void init_socket_sig P((int));
static void set_signal P(());
static RETSIGTYPE sigio_handler P((int));
@@ -202,7 +207,7 @@ init_io()
*/
static int
create_sockets(port)
- unsigned int port;
+ u_int port;
{
#ifdef STREAMS_TLI
struct strioctl ioc;
@@ -223,7 +228,7 @@ create_sockets(port)
*/
inter_list[0].sin.sin_family = AF_INET;
inter_list[0].sin.sin_port = port;
- inter_list[0].sin.sin_addr.s_addr = INADDR_ANY;
+ inter_list[0].sin.sin_addr.s_addr = htonl(INADDR_ANY);
(void) strncpy(inter_list[0].name, "wildcard",
sizeof(inter_list[0].name));
inter_list[0].mask.sin_addr.s_addr = htonl(~0);
@@ -231,9 +236,6 @@ create_sockets(port)
inter_list[0].sent = 0;
inter_list[0].notsent = 0;
inter_list[0].flags = INT_BROADCAST;
-#ifdef MCAST
- inter_list[0].flags |= INT_MULTICAST;
-#endif /* MCAST */
#ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
if ((vs = open("/dev/ip", O_RDONLY)) < 0) {
@@ -246,7 +248,7 @@ create_sockets(port)
i = 1;
- ifc.ifc_len = sizeof(buf);
+ ifc.ifc_len = sizeof(buf);
#ifdef STREAMS_TLI
ioc.ic_cmd = SIOCGIFCONF;
ioc.ic_timout = 0;
@@ -382,13 +384,13 @@ create_sockets(port)
}
inter_list[i].mask = *(struct sockaddr_in *)&ifreq.ifr_addr;
- /*
+ /*
* look for an already existing source interface address. If
- * the machine has multiple point to point interfaces, then
+ * the machine has multiple point to point interfaces, then
* the local address may appear more than once.
- */
+ */
for (j=0; j < i; j++)
- if (inter_list[j].sin.sin_addr.s_addr ==
+ if (inter_list[j].sin.sin_addr.s_addr ==
inter_list[i].sin.sin_addr.s_addr) {
break;
}
@@ -406,6 +408,15 @@ create_sockets(port)
inter_list[i].flags & INT_BROADCAST);
}
+#if defined(MCAST) && !defined(sun) && !defined(SYS_BSDI) && !defined(SYS_DECOSF1) && !defined(SYS_44BSD)
+ /*
+ * enable possible multicast reception on the broadcast socket
+ */
+ inter_list[0].bcast.sin_addr.s_addr = htonl(INADDR_ANY);
+ inter_list[0].bcast.sin_family = AF_INET;
+ inter_list[0].bcast.sin_port = port;
+#endif /* MCAST */
+
/*
* Blacklist all bound interface addresses
*/
@@ -419,7 +430,7 @@ create_sockets(port)
if (debug > 2) {
printf("create_sockets: ninterfaces=%d\n", ninterfaces);
for (i = 0; i < ninterfaces; i++) {
- printf("interface %d: fd=%d, bfd=%d, name=%.8s, flags=0x%x\n",
+ printf("interface %d: fd=%d, bfd=%d, name=%.8s, flags=0x%x\n",
i,
inter_list[i].fd,
inter_list[i].bfd,
@@ -454,7 +465,7 @@ io_setbclient()
if (inter_list[i].flags & INT_BCASTOPEN)
continue;
#ifdef SOLARIS
- inter_list[i].bcast.sin_addr.s_addr = INADDR_ANY;
+ inter_list[i].bcast.sin_addr.s_addr = htonl(INADDR_ANY);
#endif
#ifndef SYS_DOMAINOS
inter_list[i].bfd = open_socket(&inter_list[i].bcast, 0);
@@ -464,30 +475,85 @@ io_setbclient()
}
-#ifdef MCAST
/*
* io_multicast_add() - add multicast group address
*/
void
io_multicast_add(addr)
- U_LONG addr;
+ u_long addr;
{
- int fd = inter_list[0].fd;
+#ifdef MCAST
struct ip_mreq mreq;
-
- if (!IN_CLASSD(addr))
+ int i = ninterfaces; /* Use the next interface */
+ u_long haddr = ntohl(addr);
+ struct in_addr iaddr;
+ int s;
+ struct sockaddr_in *sinp;
+
+ iaddr.s_addr = addr;
+
+ if (!IN_CLASSD(haddr))
+ { syslog(LOG_ERR,
+ "cannot add multicast address %s as it is not class D",
+ inet_ntoa(iaddr));
return;
+ }
+
+ for (i=0; i<ninterfaces; i++) {
+ /* Already have this address */
+ if (inter_list[i].sin.sin_addr.s_addr == addr) return;
+ /* found a free slot */
+ if (inter_list[i].sin.sin_addr.s_addr == 0 &&
+ inter_list[i].fd <= 0 && inter_list[i].bfd <= 0 &&
+ inter_list[i].flags == 0) break;
+ }
+ sinp = &(inter_list[i].sin);
+
+ memset((char *)&mreq, 0, sizeof(mreq));
+ memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
+ sinp->sin_family = AF_INET;
+ sinp->sin_addr = iaddr;
+ sinp->sin_port = htons(123);
+
+ s = open_socket(sinp, 0);
+ /* Try opening a socket for the specified class D address */
+ /* This works under SunOS 4.x, but not OSF1 .. :-( */
+ if (s < 0) {
+ memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
+ i = 0;
+ /* HACK ! -- stuff in an address */
+ inter_list[i].bcast.sin_addr.s_addr = addr;
+ syslog(LOG_ERR, "...multicast address %s using wildcard socket",
+ inet_ntoa(iaddr));
+ }
+ else {
+ inter_list[i].fd = s;
+ inter_list[i].bfd = -1;
+ (void) strncpy(inter_list[i].name, "multicast",
+ sizeof(inter_list[i].name));
+ inter_list[i].mask.sin_addr.s_addr = htonl(~0);
+ }
+
/*
* enable reception of multicast packets
*/
- mreq.imr_multiaddr.s_addr = addr;
- mreq.imr_interface.s_addr = INADDR_ANY;
- if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ mreq.imr_multiaddr = iaddr;
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&mreq, sizeof(mreq)) == -1)
- syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP fails: %m");
-}
+ syslog(LOG_ERR,
+ "setsockopt IP_ADD_MEMBERSHIP fails: %m for %x / %x (%s)",
+ mreq.imr_multiaddr, mreq.imr_interface.s_addr,
+ inet_ntoa(iaddr));
+ inter_list[i].flags |= INT_MULTICAST;
+ if (i >= ninterfaces) ninterfaces = i+1;
+#else /* MCAST */
+ struct in_addr iaddr;
+ iaddr.s_addr = addr;
+ syslog(LOG_ERR, "cannot add multicast address %s as no MCAST support",
+ inet_ntoa(iaddr));
#endif /* MCAST */
-
+}
/*
* io_unsetbclient - close the broadcast client sockets
@@ -506,38 +572,66 @@ io_unsetbclient()
}
-#ifdef MCAST
/*
* io_multicast_del() - delete multicast group address
*/
void
io_multicast_del(addr)
- U_LONG addr;
+ u_long addr;
{
- int fd = inter_list[0].fd;
+#ifdef MCAST
+ int i;
struct ip_mreq mreq;
+ struct sockaddr_in sinaddr;
- if (!IN_CLASSD(addr))
+ if (!IN_CLASSD(addr)) {
+ sinaddr.sin_addr.s_addr = addr;
+ syslog(LOG_ERR,
+ "invalid multicast address %s", ntoa(&sinaddr));
return;
+ }
+
/*
- * disable reception of multicast packets
+ * Disable reception of multicast packets
*/
mreq.imr_multiaddr.s_addr = addr;
- mreq.imr_interface.s_addr = INADDR_ANY;
- if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
- (char *)&mreq, sizeof(mreq)) == -1)
- syslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m");
-}
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ for (i = 0; i < ninterfaces; i++) {
+ if (!(inter_list[i].flags & INT_MULTICAST))
+ continue;
+ if (!(inter_list[i].fd < 0))
+ continue;
+ if (addr != inter_list[i].sin.sin_addr.s_addr)
+ continue;
+ if (i != 0) {
+ /* we have an explicit fd, so we can slose it */
+ close_socket(inter_list[i].fd);
+ memset((char *)&inter_list[i], 0, sizeof inter_list[0]);
+ inter_list[i].fd = -1;
+ inter_list[i].bfd = -1;
+ } else {
+ /* We are sharing "any address" port :-( Don't close it! */
+ if (setsockopt(inter_list[i].fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
+ (char *)&mreq, sizeof(mreq)) == -1)
+ syslog(LOG_ERR, "setsockopt IP_DROP_MEMBERSHIP fails: %m");
+ /* This is **WRONG** -- there may be others ! */
+ /* There should be a count of users ... */
+ inter_list[i].flags &= ~INT_MULTICAST;
+ }
+ }
+#else /* MCAST */
+ syslog(LOG_ERR, "this function requires multicast kernel");
#endif /* MCAST */
+}
/*
* open_socket - open a socket, returning the file descriptor
*/
static int
-open_socket(addr, bcast)
+open_socket(addr, flags)
struct sockaddr_in *addr;
- int bcast;
+ int flags;
{
int fd;
int on = 1, off = 0;
@@ -549,10 +643,6 @@ open_socket(addr, bcast)
/*NOTREACHED*/
}
- if (fd > maxactivefd)
- maxactivefd = fd;
- FD_SET(fd, &activefds);
-
/* set SO_REUSEADDR since we will be binding the same port
number on each interface */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
@@ -566,15 +656,32 @@ open_socket(addr, bcast)
if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
char buff[160];
sprintf(buff,
- "bind() fd %d, family %d, port %d, addr %08x, bcast=%d fails: %%m",
- fd,
- addr->sin_family,
- addr->sin_port,
- addr->sin_addr.s_addr,
- bcast);
+ "bind() fd %d, family %d, port %d, addr %08lx, in_classd=%d flags=%d fails: %%m",
+ fd, addr->sin_family, (int)ntohs(addr->sin_port),
+ (u_long)ntohl(addr->sin_addr.s_addr),
+ IN_CLASSD(ntohl(addr->sin_addr.s_addr)), flags);
syslog(LOG_ERR, buff);
+ close(fd);
+
+ /*
+ * soft fail if opening a class D address
+ */
+ if (IN_CLASSD(ntohl(addr->sin_addr.s_addr)))
+ return -1;
exit(1);
}
+#ifdef DEBUG
+ if (debug)
+ printf("bind() fd %d, family %d, port %d, addr %08lx, flags=%d\n",
+ fd,
+ addr->sin_family,
+ (int)ntohs(addr->sin_port),
+ (u_long)ntohl(addr->sin_addr.s_addr),
+ flags);
+#endif
+ if (fd > maxactivefd)
+ maxactivefd = fd;
+ FD_SET(fd, &activefds);
#ifdef HAVE_SIGNALED_IO
init_socket_sig(fd);
@@ -613,23 +720,9 @@ Need non blocking I/O
syslog(LOG_ERR, "setsockopt SO_REUSEADDR off fails: %m");
}
-#ifdef MCAST
- /* for the moment we use the bcast option to set multicast ttl */
-
- if (bcast) {
- unsigned char mttl = 127;
-
- /* set the multicast ttl for outgoing packets */
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
- &mttl, sizeof(mttl)) == -1) {
- syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m");
- }
- }
-#endif /* MCAST */
-
#ifdef SO_BROADCAST
/* if this interface can support broadcast, set SO_BROADCAST */
- if (bcast) {
+ if (flags & INT_BROADCAST) {
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
(char *)&on, sizeof(on))) {
syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m");
@@ -679,7 +772,7 @@ findbcastinter(addr)
{
#ifdef SIOCGIFCONF
register int i;
- register U_LONG netnum;
+ register u_long netnum;
netnum = NSRCADR(addr);
for (i = 1; i < ninterfaces; i++) {
@@ -709,7 +802,7 @@ getrecvbufs()
#ifdef DEBUG
if (debug > 4)
- printf("getrecvbufs: %d handler interrupts, %d frames\n",
+ printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
handler_calls, handler_pkts);
#endif
@@ -726,7 +819,7 @@ getrecvbufs()
*/
#ifdef DEBUG
if (debug > 4)
- printf("getrecvbufs returning %d buffers\n", full_recvbufs);
+ printf("getrecvbufs returning %ld buffers\n", full_recvbufs);
#endif
rb = beginlist;
fulllist = 0;
@@ -787,9 +880,10 @@ freerecvbuf(rb)
* destination is logged.
*/
void
-sendpkt(dest, inter, pkt, len)
+sendpkt(dest, inter, ttl, pkt, len)
struct sockaddr_in *dest;
struct interface *inter;
+ int ttl;
struct pkt *pkt;
int len;
{
@@ -802,6 +896,7 @@ sendpkt(dest, inter, pkt, len)
u_short port;
struct in_addr addr;
};
+
#ifndef ERRORCACHESIZE
#define ERRORCACHESIZE 8
#endif
@@ -813,10 +908,26 @@ sendpkt(dest, inter, pkt, len)
#ifdef DEBUG
if (debug)
- printf("sendpkt(fd=%d %s, %s, %d)\n", inter->fd, ntoa(dest),
- ntoa(&inter->sin), len);
+ printf("%ssendpkt(fd=%d %s, %s, ttl=%d, %d)\n",
+ (ttl >= 0) ? "\tMCAST\t*****" : "",
+ inter->fd, ntoa(dest),
+ ntoa(&inter->sin), ttl, len);
#endif
+#ifdef MCAST
+ /* for the moment we use the bcast option to set multicast ttl */
+ if (ttl >= 0 && ttl != inter->last_ttl) {
+ u_char mttl = ttl;
+
+ /* set the multicast ttl for outgoing packets */
+ if (setsockopt(inter->fd, IPPROTO_IP, IP_MULTICAST_TTL,
+ &mttl, sizeof(mttl)) == -1) {
+ syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL fails: %m");
+ }
+ else inter->last_ttl = ttl;
+ }
+#endif /* MCAST */
+
for (slot = ERRORCACHESIZE; --slot >= 0; )
if (badaddrs[slot].port == dest->sin_port &&
badaddrs[slot].addr.s_addr == dest->sin_addr.s_addr)
@@ -924,7 +1035,7 @@ again:
read(fd, (char *)&rb->recv_space, i);
if (rb->recv_length == -1) {
- syslog(LOG_ERR, "clock read: %m");
+ syslog(LOG_ERR, "clock read fd %d: %m", fd);
rb->next = freelist;
freelist = rb;
free_recvbufs++;
@@ -937,6 +1048,7 @@ again:
*/
rb->recv_srcclock = rp->srcclock;
rb->dstadr = 0;
+ rb->fd = fd;
rb->recv_time = ts;
rb->receiver = rp->clock_recv;
@@ -969,43 +1081,45 @@ again:
break;
fd = inter_list[i].bfd;
}
+ if (fd < 0) continue;
if (FD_ISSET(fd, &fds)) {
n--;
/*
* Get a buffer and read the frame. If we
* haven't got a buffer, or this is received
- * on the wild card socket, just dump the packet.
+ * on the wild card socket, just dump the
+ * packet.
*/
-
- if (!(free_recvbufs && i == 0 &&
+ if (!(free_recvbufs && i == 0 &&
inter_list[i].flags & INT_MULTICAST)) {
-
#ifdef UDP_WILDCARD_DELIVERY
-/*
- * these guys manage to put properly addressed packets into the wildcard queue
- */
+ /*
+ * these guys manage to put properly addressed
+ * packets into the wildcard queue
+ */
if (free_recvbufs == 0) {
#else
- if (i == 0 || free_recvbufs == 0) {
+ if (i == 0 || free_recvbufs == 0) {
#endif
- char buf[RX_BUFF_SIZE];
-
-#ifndef UDP_WILDCARD_DELIVERY
- (void) read(fd, buf, sizeof buf);
-#else
- fromlen = 0;
- (void) recvfrom(fd, buf, sizeof(buf), 0,
- (struct sockaddr *)0,
- &fromlen);
+ char buf[RX_BUFF_SIZE];
+ struct sockaddr from;
+ fromlen = sizeof from;
+ (void) recvfrom(fd, buf,
+ sizeof(buf), 0,
+ &from, &fromlen);
+#ifdef DEBUG
+ if (debug)
+ printf("ignore/drop on %d(%lu) fd=%d from %s\n",
+ i, free_recvbufs, fd,
+ inet_ntoa(((struct sockaddr_in *) &from)->sin_addr));
#endif
-
- if (i == 0)
- packets_ignored++;
- else
- packets_dropped++;
- continue;
- }
+ if (i == 0)
+ packets_ignored++;
+ else
+ packets_dropped++;
+ continue;
+ }
}
rb = freelist;
@@ -1024,14 +1138,17 @@ again:
freelist = rb;
free_recvbufs++;
#ifdef DEBUG
- if (debug)
- printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd);
+ if (debug)
+ printf("input_handler: fd=%d dropped (bad recvfrom)\n", fd);
#endif
continue;
}
#ifdef DEBUG
- if (debug)
- printf("input_handler: fd=%d length %d\n", fd, rb->recv_length);
+ if (debug)
+ printf("input_handler: fd=%d length %d from %08lx %s\n",
+ fd, rb->recv_length,
+ (u_long)ntohl(rb->recv_srcadr.sin_addr.s_addr) &
+ 0x00000000ffffffff, inet_ntoa(rb->recv_srcadr.sin_addr));
#endif
/*
@@ -1039,6 +1156,7 @@ again:
* put it on the full list and do bookkeeping.
*/
rb->dstadr = &inter_list[i];
+ rb->fd = fd;
rb->recv_time = ts;
rb->receiver = receive;
@@ -1074,7 +1192,7 @@ findinterface(addr)
struct sockaddr_in *addr;
{
register int i;
- register U_LONG saddr;
+ register u_long saddr;
/*
* Just match the address portion.
@@ -1107,7 +1225,7 @@ io_clr_stats()
#ifdef REFCLOCK
-/*
+/*
* This is a hack so that I don't have to fool with these ioctls in the
* pps driver ... we are already non-blocking and turn on SIGIO thru
* another mechanisim
@@ -1243,7 +1361,7 @@ io_closeclock(rio)
* Spical cases first!
*/
#if defined(SYS_HPUX)
-#define CLOCK_DONE
+#define CLOCK_DONE
static int
init_clock_sig(rio)
struct refclockio *rio;
@@ -1273,12 +1391,12 @@ init_clock_sig(rio)
}
return 0;
}
-#endif /* SYS_HPUX */
+#endif /* SYS_HPUX */
#if defined(SYS_AIX)&&!defined(_BSD)
/*
* SYSV compatibility mode under AIX.
*/
-#define CLOCK_DONE
+#define CLOCK_DONE
static int
init_clock_sig(rio)
struct refclockio *rio;
@@ -1302,7 +1420,7 @@ init_clock_sig(rio)
return 0;
}
#endif /* AIX && !BSD */
-#ifndef CLOCK_DONE
+#ifndef CLOCK_DONE
static int
init_clock_sig(rio)
struct refclockio *rio;
@@ -1328,7 +1446,7 @@ static init_clock_sig(rio)
if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) {
syslog(LOG_ERR,
"ioctl(I_SETSIG, S_INPUT) fails for clock I/O: %m");
- return 1;
+ return 1;
}
return 0;
}
@@ -1342,7 +1460,7 @@ static init_clock_sig(rio)
* Special cases first!
*/
#if defined(SYS_HPUX) || defined(SYS_LINUX)
-#define SOCKET_DONE
+#define SOCKET_DONE
static void
init_socket_sig(fd)
int fd;
@@ -1380,7 +1498,7 @@ init_socket_sig(fd)
/*
* SYSV compatibility mod under AIX
*/
-#define SOCKET_DONE
+#define SOCKET_DONE
static void
init_socket_sig(fd)
int fd;
@@ -1408,9 +1526,9 @@ init_socket_sig(fd)
#endif /* AIX && !BSD */
#if defined(UDP_BACKWARDS_SETOWN)
/*
- * SunOS 3.5 and Ultirx 2.0
+ * SunOS 3.5 and Ultirx 2.0
*/
-#define SOCKET_DONE
+#define SOCKET_DONE
static void
init_socket_sig(fd)
int fd;
@@ -1635,8 +1753,8 @@ block_io_and_alarm()
{
int mask;
- mask = sigmask(SIGIO)|sigmask(SIGALRM);
- (void)sigblock(mask);
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ (void)sigblock(mask);
}
void
@@ -1659,7 +1777,7 @@ unblock_io_and_alarm()
{
int mask, omask;
- mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
omask = sigblock(0);
omask &= ~mask;
(void)sigsetmask(omask);
@@ -1668,9 +1786,9 @@ unblock_io_and_alarm()
void
unblock_sigio()
{
- int mask, omask;
-
- mask = sigmask(SIGIO);
+ int mask, omask;
+
+ mask = sigmask(SIGIO);
omask = sigblock(0);
omask &= ~mask;
(void)sigsetmask(omask);
@@ -1681,7 +1799,7 @@ wait_for_signal()
{
int mask, omask;
- mask = sigmask(SIGIO)|sigmask(SIGALRM);
+ mask = sigmask(SIGIO)|sigmask(SIGALRM);
omask = sigblock(0);
omask &= ~mask;
sigpause(omask);
diff --git a/usr.sbin/xntpd/xntpd/ntp_leap.c b/usr.sbin/xntpd/xntpd/ntp_leap.c
index aadbb09dc346..6473362cf652 100644
--- a/usr.sbin/xntpd/xntpd/ntp_leap.c
+++ b/usr.sbin/xntpd/xntpd/ntp_leap.c
@@ -1,4 +1,4 @@
-/* ntp_leap.c,v 3.1 1993/07/06 01:11:18 jbj Exp
+/*
* ntp_leap - maintain leap bits and take action when a leap occurs
*/
#include <stdio.h>
@@ -41,7 +41,7 @@ u_char leap_mask; /* set on day before a potential leap */
* Timer. The timer code imports this so it can call us prior to
* calling out any pending transmits.
*/
-U_LONG leap_timer;
+u_long leap_timer;
/*
* We don't want to do anything drastic if the leap function is handled
@@ -67,18 +67,18 @@ u_char leapbits;
/*
* Imported from the timer module.
*/
-extern U_LONG current_time;
+extern u_long current_time;
/*
* Some statistics counters
*/
-U_LONG leap_processcalls; /* calls to leap_process */
-U_LONG leap_notclose; /* leap found to be a LONG time from now */
-U_LONG leap_monthofleap; /* in the month of a leap */
-U_LONG leap_dayofleap; /* This is the day of the leap */
-U_LONG leap_hoursfromleap; /* only 2 hours from leap */
-U_LONG leap_happened; /* leap process saw the leap */
+u_long leap_processcalls; /* calls to leap_process */
+u_long leap_notclose; /* leap found to be a long time from now */
+u_long leap_monthofleap; /* in the month of a leap */
+u_long leap_dayofleap; /* This is the day of the leap */
+u_long leap_hoursfromleap; /* only 2 hours from leap */
+u_long leap_happened; /* leap process saw the leap */
/*
* Imported from the main module
@@ -86,7 +86,7 @@ U_LONG leap_happened; /* leap process saw the leap */
extern int debug;
-static void setnexttimeout P((U_LONG));
+static void setnexttimeout P((u_long));
/*
* init_leap - initialize the leap module's data.
@@ -114,18 +114,18 @@ init_leap()
void
leap_process()
{
- U_LONG leapnext;
- U_LONG leaplast;
+ u_long leapnext;
+ u_long leaplast;
l_fp ts;
u_char bits;
extern u_char sys_leap;
leap_processcalls++;
get_systime(&ts);
- calleapwhen(ts.l_ui, &leaplast, &leapnext);
+ calleapwhen((u_long)ts.l_ui, &leaplast, &leapnext);
/*
- * Figure out what to do based on how LONG to the next leap.
+ * Figure out what to do based on how long to the next leap.
*/
if (leapnext > OKAYTOSETWARNING) {
if (leaplast < ONEMINUTE) {
@@ -189,7 +189,7 @@ leap_process()
* recomputed.
*/
if ((leapnext - DAYBEFORE) >= DAYBEFORE)
- setnexttimeout((U_LONG)DAYBEFORE);
+ setnexttimeout((u_long)DAYBEFORE);
else
setnexttimeout(leapnext - DAYBEFORE);
return;
@@ -223,7 +223,7 @@ leap_process()
*/
static void
setnexttimeout(secs)
- U_LONG secs;
+ u_long secs;
{
/*
* We try to aim the time out at between 1 and 1+(1<<EVENT_TIMEOUT)
@@ -243,13 +243,13 @@ leap_setleap(indicator, warning)
int indicator;
int warning;
{
- U_LONG leapnext;
- U_LONG leaplast;
+ u_long leapnext;
+ u_long leaplast;
l_fp ts;
int i;
get_systime(&ts);
- calleapwhen(ts.l_ui, &leaplast, &leapnext);
+ calleapwhen((u_long)ts.l_ui, &leaplast, &leapnext);
i = 0;
if (warning != ~0)
diff --git a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
index 61332b9b6384..168ef3289a6e 100644
--- a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
+++ b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
@@ -1,7 +1,6 @@
/*
* ntp_loopfilter.c - implements the NTP loop filter algorithm
*/
-
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
@@ -10,41 +9,10 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
-
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-#include <sys/stat.h>
-#include "ntp_refclock.h"
-#endif /* PPS || PPSCLK || PPSPPS */
-
-#if defined(PPSCLK) || defined(PPSPPS)
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#ifdef HAVE_TERMIOS
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#if defined(PPSCLK)
-#include <sys/clkdefs.h>
-#endif /* PPSCLK */
-#endif /* STREAM */
-
-#endif /* PPSCLK || PPSPPS */
-
-#if defined(PPSPPS)
-#include <sys/ppsclock.h>
-#endif /* PPSPPS */
-
#include "ntp_stdlib.h"
#ifdef KERNEL_PLL
-#include <sys/timex.h>
+#include "sys/timex.h"
#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
#endif /* KERNEL_PLL */
@@ -59,122 +27,83 @@
* seconds. When adjustments are capped inside this range (see
* CLOCK_MAX_{I,F}) both the clock_adjust and the compliance
* registers should be fine. (When the compliance is above 16, it
- * will at most accumulate 2**CLOCK_MULT times the maximum offset,
+ * will at most accumulate 2 ** CLOCK_MULT times the maximum offset,
* which means it fits in a s_fp.)
*
* The skew compensation is a special case. In version 2, it was
- * kept in ms/4s (i.e., CLOCK_FREQ was 10). In version 3 (Section 5)
- * it seems to be 2**-16ms/4s in a s_fp for a maximum of +-125ppm
+ * kept in ms / 4s (i.e., CLOCK_FREQ was 10). In version 3 (Section 5)
+ * it seems to be 2 ** -16ms / 4s in a s_fp for a maximum of +-125ppm
* (stated maximum 100ppm). Since this seems about to change to a
- * larger range, it will be kept in units of 2**-20 (CLOCK_DSCALE)
+ * larger range, it will be kept in units of 2 ** -20 (CLOCK_DSCALE)
* in an s_fp (mainly because that's nearly the same as parts per
* million). Note that this is ``seconds per second'', whereas a
* clock adjustment is a 32-bit fraction of a second to be applied
- * every 2**CLOCK_ADJ seconds; to find it, shift the drift right by
- * (CLOCK_DSCALE-16-CLOCK_ADJ). When updating the drift, on the other
- * hand, the CLOCK_FREQ factor from the spec assumes the value to be
- * in ``seconds per 4 seconds''; to get our units, CLOCK_ADJ must be
+ * every 2 ** CLOCK_ADJ seconds; to find it, shift the drift right by
+ * (CLOCK_DSCALE - 16 - CLOCK_ADJ). When updating the drift, on the
+ * other hand, the CLOCK_FREQ factor from the spec assumes the value to
+ * be in ``seconds per 4 seconds''; to get our units, CLOCK_ADJ must be
* added to the shift.
+ *
+ * Kernel PLL/PPS state machine
+ *
+ * The following state machine is used when the kernel PLL modifications
+ * described in the README.kernel file are present. The initial
+ * configuration routine loop_config() sets up the initial frequency
+ * estimate and tests if the kernel modifications are present. If so and
+ * the PLL mode bit 1 (STA_PLL) of the mode word in the drift file
+ * (ntp.drift) is set, pll_control is set true and the kernel pll is
+ * enabled. If the kernel modifications are present and the PLL mode bit
+ * 2 (STA_PPSFREQ) is set, the kernel PPS frequency discipline is
+ * enabled.
+ *
+ * Each update to a prefer peer sets pps_update true if it survives the
+ * intersection algorithm and its time is within range. The PPS time
+ * discipline is enabled (STA_PPSTIME bit set in the status word) when
+ * pps_update is true and the PPS frequency discipline is enabled. If
+ * the PPS time discipline is enabled and the kernel reports a PPS
+ * signal is present, the pps_control variable is set to the current
+ * time. If the current time is later than pps_control by PPS_MAXAGE
+ * (120 s), this variable is set to zero.
+ *
+ * The pll_enable switch can be set both at configuration time and at
+ * run time using xntpdc. If true, the kernel modifications are active
+ * as described above; if false, the kernel is bypassed entirely (except
+ * for the PPS frequency update, if enabled) and the daemon PLL used
+ * instead.
*/
-
-/*
- * Macro to compute log2(). We don't want to to this very often, but
- * needs what must.
- */
-#define LOG2(r, t) \
- do { \
- LONG x = t; \
- r = 0; \
- while(x >> 1) \
- r++; \
- }
-
#define RSH_DRIFT_TO_FRAC (CLOCK_DSCALE - 16)
#define RSH_DRIFT_TO_ADJ (RSH_DRIFT_TO_FRAC - CLOCK_ADJ)
#define RSH_FRAC_TO_FREQ (CLOCK_FREQ + CLOCK_ADJ - RSH_DRIFT_TO_FRAC)
-#define PPS_MAXAGE 120 /* pps signal timeout (s) */
-#define PPS_MAXUPDATE 600 /* pps update timeout (s) */
+#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */
/*
* Program variables
*/
- l_fp last_offset; /* last adjustment done */
-static LONG clock_adjust; /* clock adjust (fraction only) */
-
- s_fp drift_comp; /* drift compensation register */
-static s_fp max_comp; /* drift limit imposed by max host clock slew */
-
- int time_constant; /* log2 of time constant (0 .. 4) */
-static U_LONG tcadj_time; /* last time-constant adjust time */
-
- U_LONG watchdog_timer; /* watchdog timer, in seconds */
-static int first_adjustment; /* 1 if waiting for first adjustment */
-static int tc_counter; /* time-constant hold counter */
-
-static l_fp pps_offset; /* filtered pps offset */
-static u_fp pps_dispersion; /* pps dispersion */
-static U_LONG pps_time; /* last pps sample time */
-
- int pps_control; /* true if working pps signal */
+ l_fp last_offset; /* last clock offset */
+ u_long last_time; /* time of last clock update (s) */
+ u_fp clock_stability; /* clock stability (ppm) */
+ s_fp clock_frequency; /* clock frequency error (ppm) */
+ s_fp drift_comp; /* pll frequency (ppm) */
+static long clock_adjust; /* clock adjust (fraction only) */
+static s_fp max_comp; /* max frequency offset (ppm) */
+ int tc_counter; /* poll-adjust counter */
+ int pll_status; /* status bits for kernel pll */
int pll_control; /* true if working kernel pll */
-static l_fp pps_delay; /* pps tuning offset */
- U_LONG pps_update; /* last pps update time */
+ int pll_enable; /* true if pll enabled */
+ u_long pps_control; /* last pps sample time */
+ int pps_update; /* pps update valid */
int fdpps = -1; /* pps file descriptor */
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-/*
- * This module has support for a 1-pps signal to fine-tune the local
- * clock. The signal is optional; when present and operating within
- * given tolerances in frequency and jitter, it is used to discipline
- * the local clock. In order for this to work, the local clock must be
- * set to within +-500 ms by another means, such as a radio clock or
- * NTP itself. The 1-pps signal is connected via a serial port and
- * gadget box consisting of a one-shot and EIA level-converter. When
- * operated at 38.4 kbps with a SPARCstation IPC, this arrangement has a
- * worst-case jitter less than 26 us. The pps delay configuration
- * declaration can be used to compensate for miscellaneous uart and
- * os delays. Allow about 247 us for uart delays at 38400 bps and
- * -1 ms for SunOS streams nonsense.
- */
-
-/*
- * A really messy way to map an integer baud rate to the system baud rate.
- * There should be a better way.
- */
-#define SYS_BAUD(i) \
- ( i == 38400 ? B38400 : \
- ( i == 19200 ? B19200 : \
- ( i == 9600 ? B9600 : \
- ( i == 4800 ? B4800 : \
- ( i == 2400 ? B2400 : \
- ( i == 1200 ? B1200 : \
- ( i == 600 ? B600 : \
- ( i == 300 ? B300 : 0 ))))))))
-
-#define PPS_BAUD B38400 /* default serial port speed */
-timecode */
-#define PPS_DEV "/dev/pps" /* pps port */
-#define PPS_FAC 3 /* pps shift (log2 trimmed samples) */
-#define PPS_TRIM 6 /* samples trimmed from median filter */
-#define NPPS ((1 << PPS_FAC) + 2 * PPS_TRIM) /* pps filter size */
-#define PPS_XCPT "\377" /* intercept character */
-
-#if defined(PPSCLK)
-static struct refclockio io; /* given to the I/O handler */
-static int pps_baud; /* baud rate of PPS line */
-#endif /* PPSCLK */
-static U_LONG nsamples; /* number of pps samples collected */
-static LONG samples[NPPS]; /* median filter for pps samples */
-
-#endif /* PPS || PPSCLK || PPSPPS */
-
/*
* Imported from the ntp_proto module
*/
-extern u_char sys_stratum;
-extern s_fp sys_rootdelay;
-extern u_fp sys_rootdispersion;
-extern s_char sys_precision;
+extern s_fp sys_rootdelay; /* root delay */
+extern u_fp sys_rootdispersion; /* root dispersion */
+extern struct peer *sys_peer; /* system peer pointer */
+extern u_char sys_poll; /* log2 of system poll interval */
+extern u_char sys_leap; /* system leap bits */
+extern l_fp sys_refskew; /* accumulated skew since last update */
+extern u_fp sys_maxd; /* max dispersion of survivor list */
/*
* Imported from ntp_io.c
@@ -189,31 +118,13 @@ extern int debug; /* global debug flag */
/*
* Imported from timer module
*/
-extern U_LONG current_time; /* like it says, in seconds */
-
-/*
- * sys_poll and sys_refskew are set here
- */
-extern u_char sys_poll; /* log2 of system poll interval */
-extern u_char sys_leap; /* system leap bits */
-extern l_fp sys_refskew; /* accumulated skew since last update */
-extern u_fp sys_maxd; /* max dispersion of survivor list */
+extern u_long current_time; /* like it says, in seconds */
/*
* Imported from leap module
*/
extern u_char leapbits; /* sanitized leap bits */
-/*
- * Function prototypes
- */
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-int pps_sample P((l_fp *));
-#if defined(PPSCLK)
-static void pps_receive P((struct recvbuf *));
-#endif /* PPSCLK */
-#endif /* PPS || PPSCLK || PPSPPS */
-
#if defined(KERNEL_PLL)
#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
MOD_STATUS | MOD_TIMECONST)
@@ -221,7 +132,6 @@ extern int sigvec P((int, struct sigvec *, struct sigvec *));
extern int syscall P((int, void *, ...));
void pll_trap P((void));
-static int pll_status; /* status bits for kernel pll */
static struct sigvec sigsys; /* current sigvec status */
static struct sigvec newsigsys; /* new sigvec status */
#endif /* KERNEL_PLL */
@@ -232,299 +142,164 @@ static struct sigvec newsigsys; /* new sigvec status */
void
init_loopfilter()
{
- extern U_LONG tsf_maxslew;
- U_LONG tsf_limit;
-#if defined(PPSCLK)
- int fd232;
-#endif /* PPSCLK */
- clock_adjust = 0;
- drift_comp = 0;
- time_constant = 0;
- tcadj_time = 0;
- watchdog_timer = 0;
- tc_counter = 0;
- last_offset.l_i = 0;
- last_offset.l_f = 0;
- first_adjustment = 1;
+ extern u_long tsf_maxslew;
+ u_long tsf_limit;
-/*
- * Limit for drift_comp, minimum of two values. The first is to avoid
- * signed overflow, the second to keep within 75% of the maximum
- * adjustment possible in adj_systime().
- */
+ /*
+ * Limit for drift_comp, minimum of two values. The first is to
+ * avoid signed overflow, the second to keep within 75% of the
+ * maximum adjustment possible in adj_systime().
+ */
max_comp = 0x7fff0000;
tsf_limit = ((tsf_maxslew >> 1) + (tsf_maxslew >> 2));
if ((max_comp >> RSH_DRIFT_TO_ADJ) > tsf_limit)
max_comp = tsf_limit << RSH_DRIFT_TO_ADJ;
- pps_control = 0;
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-#if defined(PPSCLK)
- pps_baud = PPS_BAUD;
-#endif /* PPSCLK */
- pps_delay.l_i = 0;
- pps_delay.l_f = 0;
- pps_time = pps_update = 0;
- nsamples = 0;
-#if defined(PPSCLK)
-
- /*
- * Open pps serial port. We don't care if the serial port comes
- * up; if not, we just use the timecode. Therefore, if anything
- * goes wrong, just reclaim the resources and continue.
- */
- fd232 = open(PPS_DEV, O_RDONLY);
- if (fd232 == -1) {
- syslog(LOG_ERR, "loopfilter: open of %s: %m", PPS_DEV);
- return;
- }
-
-#if !defined(HPUXGADGET) /* dedicated to Ken Stone */
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- */
- PPSCLK SUPPORT NOT AVAILABLE IN TERMIO INTERFACE
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The PPSCLK option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the tty_clk streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "loopfilter: tcgetattr(%s): %m", PPS_DEV);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = PPS_BAUD|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "loopfilter: tcsetattr(%s): %m", PPS_DEV);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "loopfilter: tcflush(%s): %m", PPS_DEV);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#if defined(STREAM)
- while (ioctl(fd232, I_POP, 0 ) >= 0) ;
- if (ioctl(fd232, I_PUSH, "clk") < 0) {
- syslog(LOG_ERR,
- "loopfilter: ioctl(%s, I_PUSH, clk): %m", PPS_DEV);
- goto screwed;
- }
- if (ioctl(fd232, CLK_SETSTR, PPS_XCPT) < 0) {
- syslog(LOG_ERR,
- "loopfilter: ioctl(%s, CLK_SETSTR, PPS_XCPT): %m", PPS_DEV);
- goto screwed;
- }
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The PPSCLK option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the tty_clk line discipline and 4.3bsd or later.
- */
- { struct sgttyb ttyb;
- int ldisc = CLKLDISC;
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "loopfilter: ioctl(%s, TIOCGETP): %m", PPS_DEV);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = PPS_BAUD;
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "loopfilter: ioctl(%s, TIOCSETP): %m", PPS_DEV);
- goto screwed;
- }
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "loopfilter: ioctl(%s, TIOCSETD): %m", PPS_DEV);
- goto screwed;
- }
- }
-#endif /* HAVE_BSD_TTYS */
-#endif /* HPUXGADGET */
- fdpps = fd232;
-
/*
- * Insert in device list.
+ * Reset clockworks
*/
- io.clock_recv = pps_receive;
- io.srcclock = (caddr_t)NULL;
- io.datalen = 0;
- io.fd = fdpps;
-#if defined(HPUXGADGET)
- if (!io_addclock_simple(&io))
-#else
- if (!io_addclock(&io))
-#endif /* HPUXGADGET */
- goto screwed;
- return;
+ drift_comp = 0;
+ clock_adjust = 0;
+ tc_counter = 0;
+ sys_poll = NTP_MINPOLL;
- /*
- * Something broke. Reclaim resources.
- */
-screwed:
- (void)close(fdpps);
- return;
-#endif /* PPSCLK */
-#endif /* PPS || PPSCLK || PPSPPS */
+ L_CLR(&last_offset);
+ last_time = 0;
+ clock_frequency = 0;
+ clock_stability = 0;
+ pps_update = pps_control = 0;
}
/*
* local_clock - the NTP logical clock loop filter. Returns 1 if the
- * clock was stepped, 0 if it was slewed and -1 if it is
- * hopeless.
+ * clock was stepped, 0 if it was slewed and -1 if it is hopeless.
*/
int
local_clock(fp_offset, peer)
l_fp *fp_offset; /* best offset estimate */
struct peer *peer; /* from peer - for messages */
{
- register LONG offset;
- register U_LONG tmp_ui;
- register U_LONG tmp_uf;
- register LONG tmp;
- int isneg;
+ long offset;
+ long tmp;
+ int return_code;
+ l_fp ftmp;
+ s_fp stmp;
+ u_fp smax;
+ long allan;
+ long interval;
#if defined(KERNEL_PLL)
struct timex ntv;
#endif /* KERNEL_PLL */
+ /*
+ * Initialize estimated measurement error and Allan variance
+ * intercept point. The measurement error is assumed the sum of
+ * the peer dispersion plus select dispersion, which seems
+ * reasonable. The Allan variance intercept point is assumed
+ * at MAXSEC for reference clocks and twice that for peer
+ * clocks, which seems cowardly.
+ */
+ if (peer->refclktype)
+ allan = CLOCK_MAXSEC;
+ else
+ allan = CLOCK_MAXSEC << 1;
+
+ if (!last_time)
+ last_time = current_time;
+ interval = (long)(current_time - last_time);
+ clock_adjust = 0;
+ offset = fp_offset->l_f;
+ smax = peer->dispersion + peer->selectdisp;
+ return_code = 0;
+
#ifdef DEBUG
if (debug > 1)
- printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 6),
- ntoa(&peer->srcadr));
+ printf(
+ "local_clock: offset %s peer %s watch %ld)\n",
+ lfptoa(fp_offset, 6), ntoa(&peer->srcadr),
+ interval);
#endif
/*
- * Take the absolute value of the offset
- */
- tmp_ui = fp_offset->l_ui;
- tmp_uf = fp_offset->l_uf;
- if (M_ISNEG(tmp_ui, tmp_uf)) {
- M_NEG(tmp_ui, tmp_uf);
- isneg = 1;
- } else
- isneg = 0;
-
- /*
* If the clock is way off, don't tempt fate by correcting it.
*/
- if (tmp_ui >= CLOCK_WAYTOOBIG) {
+ ftmp = *fp_offset;
+ if (L_ISNEG(&ftmp))
+ L_NEG(&ftmp);
+ if (ftmp.l_ui >= CLOCK_WAYTOOBIG) {
syslog(LOG_ERR,
- "Clock appears to be %u seconds %s, something may be wrong",
- tmp_ui, isneg>0?"fast":"slow");
+ "time error %s is way too large (set clock manually)",
+ lfptoa(fp_offset, 6));
#ifndef BIGTIMESTEP
return (-1);
#endif /* BIGTIMESTEP */
- }
/*
- * Save this offset for later perusal
+ * If the magnitude of the offset is greater than CLOCK.MAX
+ * (128 ms), reset the time and frequency. We are quite
+ * aggresive here, since the intrinsic clock oscillator
+ * frequency error can be quite large, sometimes over +-300 ppm.
+ * With something this large and a noisy peer, the casual time
+ * updates wander right through the acceptable range, causing
+ * this section to trigger.
*/
- last_offset = *fp_offset;
+ } else if (ftmp.l_ui > CLOCK_MAX_I || (ftmp.l_ui == CLOCK_MAX_I
+ && ftmp.l_uf >= CLOCK_MAX_F)) {
+ tc_counter = 0;
+ sys_poll = peer->minpoll;
- /*
- * If the magnitude of the offset is greater than CLOCK.MAX,
- * step the time and reset the registers.
- */
- if (tmp_ui > CLOCK_MAX_I || (tmp_ui == CLOCK_MAX_I
- && (U_LONG)tmp_uf >= (U_LONG)CLOCK_MAX_F)) {
- if (watchdog_timer < CLOCK_MINSTEP) {
- /* Mustn't step yet, pretend we adjusted. */
- syslog(LOG_INFO,
- "clock correction %s too large (ignored)\n",
- lfptoa(fp_offset, 6));
- return (0);
- }
- syslog(LOG_NOTICE, "clock reset (%s) %s\n",
+ /*
+ * Either we are not in synchronization, or we have gone
+ * CLOCK_MINSTEP (900 s) since the last acceptable
+ * update. We step the clock and leave the frequency
+ * alone. Since the clock filter has been reset, the
+ * dispersions will be high upon recovery and the quick-
+ * march code below will trigger to keep the clock in
+ * bounds.
+ */
+ if (sys_leap == LEAP_NOTINSYNC || interval >
+ CLOCK_MINSTEP) {
+ step_systime(fp_offset);
+ syslog(LOG_NOTICE,
+
+ "time reset (%s) %s s",
#ifdef SLEWALWAYS
- "slew",
+ "slew",
#else
- "step",
+ "step",
#endif
- lfptoa(fp_offset, 6));
- step_systime(fp_offset);
- clock_adjust = 0;
- watchdog_timer = 0;
- first_adjustment = 1;
- pps_update = 0;
- return (1);
- }
+ lfptoa(fp_offset, 6));
+ return_code = 1;
+
+ /*
+ * The local clock is out of range, but we haven't
+ * allowed enough time for the peer (usually a radio
+ * clock) to recover after a leap second. Pretend we wuz
+ * never here.
+ */
+ } else
+ return (return_code);
/*
- * Here we've got an offset small enough to slew. Note that
- * since the offset is small we don't have to carry the damned
- * high order longword in our calculations.
- *
- * The time constant and sample interval are approximated with
- * shifts, as in Section 5 of the v3 spec. The spec procedure
- * looks strange, as an interval of 64 to 127 seconds seems to
- * cause multiplication with 128 (and so on). This code lowers
- * the multiplier by one bit.
- *
- * The time constant update goes after adjust and skew updates,
- * as in appendix G.
- */
- /*
- * If pps samples are valid, update offset, root delay and
- * root dispersion. Also, set the system stratum to 1, even if
- * the source of approximate time runs at a higher stratum. This
- * may be a dramatic surprise to high-stratum clients, since all
- * of a sudden this server looks like a stratum-1 clock.
- */
- if (pps_control) {
- last_offset = pps_offset;
- sys_maxd = pps_dispersion;
- sys_stratum = 1;
- sys_rootdelay = 0;
- offset = LFPTOFP(&pps_offset);
- if (offset < 0)
- offset = -offset;
- sys_rootdispersion = offset + pps_dispersion;
- }
- offset = last_offset.l_f;
-
- /*
- * The pll_control is active when the phase-lock code is
+ * This code segment works when the clock-adjustment code is
* implemented in the kernel, which at present is only in the
- * (modified) SunOS 4.1.x, Ultrix 4.3 and OSF/1 kernels. In the
+ * (modified) SunOS 4.1, Ultrix 4.3 and OSF/1 kernels. In the
* case of the DECstation 5000/240 and Alpha AXP, additional
- * kernal modifications provide a true microsecond clock. We
- * know the scaling of the frequency variable (s_fp) is the
- * same as the kernel variable (1 << SHIFT_USEC = 16).
- *
- * For kernels with the PPS discipline, the current offset and
- * dispersion are set from kernel variables to maintain
- * beauteous displays, but don't do much of anything.
- *
- * In the case of stock kernels the phase-lock loop is
- * implemented the hard way and the clock_adjust and drift_comp
- * computed as required.
- */
- if (pll_control) {
+ * kernel modifications provide a true microsecond clock. We
+ * know the scaling of the frequency variable (s_fp) is the same
+ * as the kernel variable (1 << SHIFT_USEC = 16).
+ */
#if defined(KERNEL_PLL)
+ } else if (pll_control && pll_enable) {
+ l_fp pps_offset;
+ u_fp pps_dispersion;
+
+ /*
+ * We initialize the structure for the ntp_adjtime()
+ * system call. We have to convert everything to
+ * microseconds first. Afterwards, remember the
+ * frequency offset for the drift file.
+ */
memset((char *)&ntv, 0, sizeof ntv);
ntv.modes = MOD_BITS;
if (offset >= 0) {
@@ -533,210 +308,310 @@ local_clock(fp_offset, peer)
TSFTOTVU(-offset, ntv.offset);
ntv.offset = -ntv.offset;
}
- TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2, ntv.maxerror);
+ TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2,
+ ntv.maxerror);
TSFTOTVU(sys_rootdispersion, ntv.esterror);
- ntv.status = pll_status;
- if (pps_update)
+ ntv.status = pll_status & (STA_PLL | STA_PPSFREQ);
+ if (pps_update && pll_status & STA_PPSFREQ)
ntv.status |= STA_PPSTIME;
if (sys_leap & LEAP_ADDSECOND &&
- sys_leap & LEAP_DELSECOND)
+ sys_leap & LEAP_DELSECOND)
ntv.status |= STA_UNSYNC;
else if (sys_leap & LEAP_ADDSECOND)
ntv.status |= STA_INS;
else if (sys_leap & LEAP_DELSECOND)
ntv.status |= STA_DEL;
- ntv.constant = time_constant;
+ ntv.constant = min(peer->ppoll, sys_poll) - NTP_MINPOLL;
(void)ntp_adjtime(&ntv);
drift_comp = ntv.freq;
- if (ntv.status & STA_PPSTIME && ntv.status & STA_PPSSIGNAL
- && ntv.shift) {
- if (ntv.offset >= 0) {
+ pll_status = ntv.status;
+
+ /*
+ * If the kernel pps discipline is working, monitor its
+ * performance.
+ */
+ if (pll_status & STA_PPSTIME && pll_status &
+ STA_PPSSIGNAL && ntv.shift) {
+ if (ntv.offset >= 0)
TVUTOTSF(ntv.offset, offset);
- } else {
+ else {
TVUTOTSF(-ntv.offset, offset);
offset = -offset;
}
- pps_offset.l_i = pps_offset.l_f = 0;
- M_ADDF(pps_offset.l_i, pps_offset.l_f, offset);
+ L_CLR(&pps_offset);
+ L_ADDF(&pps_offset, offset);
TVUTOTSF(ntv.jitter, tmp);
pps_dispersion = (tmp >> 16) & 0xffff;
- pps_time = current_time;
+ if (!pps_control)
+ syslog(LOG_INFO,
+ "kernel pps sync enabled");
+ pps_control = current_time;
record_peer_stats(&loopback_interface->sin,
- ctlsysstatus(), &pps_offset, 0, pps_dispersion);
- } else
- pps_time = 0;
-#endif /* KERNEL_PLL */
- } else {
- if (offset < 0) {
- clock_adjust = -((-offset) >> time_constant);
- } else {
- clock_adjust = offset >> time_constant;
+ ctlsysstatus(), fp_offset, 0,
+ pps_dispersion);
}
+#endif /* KERNEL_PLL */
- /*
- * Calculate the new frequency error. The factor given
- * in the spec gives the adjustment per 2**CLOCK_ADJ
- * seconds, but we want it as a (scaled) pure ratio, so
- * we include that factor now and remove it later.
- */
- if (first_adjustment) {
- first_adjustment = 0;
- } else {
+ /*
+ * If the dispersion exceeds 128 ms, we need to quick-march it
+ * to nominal zero offset and wait for the next update. This is
+ * necessary when the intrinsic frequency error is large and the
+ * clock has drifted during the interval the clock filter was
+ * stabilizing. Note that, if unsynchronized, the dispersion is
+ * always greater than 128 ms, so we don't need a check for
+ * that.
+ */
+ } else if (smax > CLOCK_MAX_FP) {
+ clock_adjust = offset;
+
+ /*
+ * If the dispersion has increased substantially over the
+ * previous value, we have a spike which probably should be
+ * suppressed. A factor of eight has been found reasonable by
+ * simulation.
+ */
+ } else if (smax > sys_maxd << 3) {
+ return (0);
+
+ /*
+ * If the interval between corrections is less than the Allan
+ * variance intercept point, we use a phase-lock loop to compute
+ * new values of time and frequency. The bandwidth is controlled
+ * by the time constant, which is adjusted in response to the
+ * phase error and dispersion. Note the frequency is not changed
+ * if the local clock driver is in control.
+ */
+ } else if (interval < allan) {
+ int time_constant = min(peer->ppoll, sys_poll) -
+ NTP_MINPOLL;
+ int ltmp = interval;
+
+ if (offset < 0)
+ clock_adjust = -(-offset >> time_constant);
+ else
+ clock_adjust = offset >> time_constant;
+ if (interval && !(peer->refclktype ==
+ REFCLK_LOCALCLOCK)) {
tmp = peer->maxpoll;
- tmp_uf = watchdog_timer;
- if (tmp_uf == 0)
- tmp_uf = 1;
- while (tmp_uf < (1 << peer->maxpoll)) {
+ while (ltmp < (1 << peer->maxpoll)) {
tmp--;
- tmp_uf <<= 1;
+ ltmp <<= 1;
}
-
- /*
- * We apply the frequency scaling at the same
- * time as the sample interval; this ensures a
- * safe right-shift. (as long as it keeps below
- * 31 bits, which current parameters should
- * ensure.
- */
- tmp = (RSH_FRAC_TO_FREQ - tmp) +
- time_constant + time_constant;
+ tmp = (RSH_FRAC_TO_FREQ - tmp) + time_constant +
+ time_constant;
if (offset < 0)
- tmp = -((-offset) >> tmp);
+ tmp = -(-offset >> tmp);
else
tmp = offset >> tmp;
drift_comp += tmp;
- if (drift_comp > max_comp)
- drift_comp = max_comp;
- else if (drift_comp < -max_comp)
- drift_comp = -max_comp;
}
+
+ /*
+ * If the interval between corrections is greater than the Allan
+ * variance intercept point, we use a hybrid frequency-lock loop
+ * to compute new values of phase and frequency. The following
+ * code is based on ideas suggested by Judah Levine of NIST and
+ * used in his "lockclock" implementation of ACTS. The magic
+ * factor of 4 in the left shift is to convert from s_fp to ppm.
+ */
+ } else {
+ clock_adjust = offset;
+ stmp = (offset / interval) << 4;
+ if (stmp < 0)
+ drift_comp -= -stmp >> CLOCK_G;
+ else
+ drift_comp += stmp >> CLOCK_G;
}
- watchdog_timer = 0;
/*
- * Determine when to adjust the time constant and poll interval.
+ * As a sanity check, we clamp the frequency not to exceed the
+ * slew rate of the stock Unix adjtime() system call. Finally,
+ * do a little housekeeping.
*/
- if (pps_control)
- time_constant = 0;
- else if (current_time - tcadj_time >= (1 << sys_poll) && !pps_control) {
- tcadj_time = current_time;
- tmp = offset;
- if (tmp < 0)
- tmp = -tmp;
- tmp = tmp >> (16 + CLOCK_WEIGHTTC - time_constant);
- if (tmp > sys_maxd) {
- tc_counter = 0;
- time_constant--;
+ if (drift_comp > max_comp)
+ drift_comp = max_comp;
+ else if (drift_comp < -max_comp)
+ drift_comp = -max_comp;
+ if (interval > (1 << (peer->minpoll - 1))) {
+
+ /*
+ * Determine when to adjust the poll interval. We do
+ * this regardless of what source controls the loop,
+ * since we might flap back and forth between sources.
+ */
+ stmp = LFPTOFP(fp_offset);
+ if (stmp < 0)
+ stmp = -stmp;
+ if (stmp > smax) {
+ tc_counter -= (int)sys_poll << 1;
+ if (tc_counter < -CLOCK_LIMIT) {
+ tc_counter = -CLOCK_LIMIT;
+ if (sys_poll > peer->minpoll) {
+ sys_poll--;
+ tc_counter = 0;
+ }
+ }
} else {
- tc_counter++;
- if (tc_counter > CLOCK_HOLDTC) {
- tc_counter = 0;
- time_constant++;
+ tc_counter += (int)sys_poll;
+ if (tc_counter > CLOCK_LIMIT) {
+ tc_counter = CLOCK_LIMIT;
+ if (sys_poll < peer->maxpoll) {
+ sys_poll++;
+ tc_counter = 0;
+ }
}
}
- if (time_constant < (int)(peer->minpoll - NTP_MINPOLL))
- time_constant = peer->minpoll - NTP_MINPOLL;
- if (time_constant > (int)(peer->maxpoll - NTP_MINPOLL))
- time_constant = peer->maxpoll - NTP_MINPOLL;
+
+ /*
+ * Calculate the frequency offset and frequency
+ * stability. These are useful for performance
+ * monitoring, but do not affect the loop variables. The
+ * results are scaled as a s_fp in ppm, because we know
+ * more than we should.
+ */
+ ftmp = *fp_offset;
+ L_SUB(&ftmp, &last_offset);
+ clock_frequency = (LFPTOFP(&ftmp) / interval) << 20;
+ if (clock_frequency < -max_comp)
+ clock_frequency = -max_comp;
+ else if (clock_frequency > max_comp)
+ clock_frequency = max_comp;
+ stmp = clock_frequency;
+ if (stmp < 0)
+ stmp = -stmp;
+ stmp -= clock_stability;
+ if (stmp < 0)
+ clock_stability -= -stmp >> NTP_MAXD;
+ else
+ clock_stability += stmp >> NTP_MAXD;
}
- sys_poll = (u_char)(NTP_MINPOLL + time_constant);
+ last_offset = *fp_offset;
+ last_time = current_time;
#ifdef DEBUG
if (debug > 1)
- printf("adj %s, drft %s, tau %3i\n",
- mfptoa((clock_adjust<0?-1:0), clock_adjust, 6),
- fptoa(drift_comp, 6), time_constant);
+ printf(
+ "local_clock: phase %s freq %s err %s allan %ld poll %d\n",
+ mfptoa((clock_adjust < 0 ? -1 : 0), clock_adjust,
+ 6), fptoa(drift_comp, 3), fptoa(smax, 6), allan,
+ sys_poll);
#endif /* DEBUG */
- (void) record_loop_stats(&last_offset, &drift_comp, time_constant);
+ (void) record_loop_stats(fp_offset, drift_comp, sys_poll);
/*
* Whew. I've had enough.
*/
- return (0);
+ return (return_code);
}
/*
- * adj_host_clock - Called every 2**CLOCK_ADJ seconds to update host clock
+ * adj_host_clock - Called every 1 << CLOCK_ADJ seconds to update host
+ * clock
*/
void
adj_host_clock()
{
- register LONG adjustment;
-#if defined(PPSPPS)
- struct ppsclockev ev;
- l_fp ts;
-#endif /* PPSPPS */
-
- watchdog_timer += (1 << CLOCK_ADJ);
- if (watchdog_timer >= NTP_MAXAGE) {
- first_adjustment = 1; /* don't use next offset for freq */
- }
- if (sys_refskew.l_i >= NTP_MAXSKEW)
- sys_refskew.l_f = 0; /* clamp it */
- else
- L_ADDUF(&sys_refskew, NTP_SKEWINC);
+ register long adjustment;
+ l_fp offset;
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-#if defined(PPSPPS)
/*
- * Note that nothing ugly happens even if the CIOGETEV ioctl is
- * not configured. Correct for signal delays (!) for ultimate
- * finick.
+ * Update the dispersion since the last update. Don't allow
+ * frequency measurements over periods longer than NTP_MAXAGE
+ * (86400 s = one day).
*/
- if (fdpps != -1 && ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
- static int last_serial = 0; /* avoid stale events */
-
- if (last_serial != ev.serial) {
- TVUTOTSF(ev.tv.tv_usec, ts.l_uf);
- ts.l_ui = 0; /* seconds don't matter here */
- L_SUB(&ts, &pps_delay);
- ts.l_uf = ~ts.l_uf; /* map [0.5..1[ into [-0.5..0[ */
- ts.l_ui = (ts.l_f < 0) ? ~0 : 0; /* sign extension */
- (void)pps_sample(&ts);
- last_serial = ev.serial;
- }
- }
-#endif /* PPSPPS */
-#endif /* PPS || PPSCLK || PPSPPS */
- if (pps_time && current_time - pps_time > PPS_MAXAGE)
- pps_time = 0;
- if (pps_update && current_time - pps_update > PPS_MAXUPDATE)
- pps_update = 0;
- if (pps_time && pps_update) {
- if (!pps_control)
- syslog(LOG_INFO, "PPS synch");
- pps_control = 1;
- } else {
+ if (current_time - last_time > NTP_MAXAGE)
+ last_time = 0;
+ L_ADDUF(&sys_refskew, NTP_SKEWINC);
+
+ /*
+ * Declare PPS kernel unsync if the pps signal has been heard
+ * during the last few minutes.
+ */
+ if (pps_control && current_time - pps_control > PPS_MAXAGE) {
if (pps_control)
- syslog(LOG_INFO, "PPS synch lost");
+ syslog(LOG_INFO, "kernel pps sync disabled");
pps_control = 0;
}
/*
- * Resist the following code if the phase-lock loop has been
- * implemented in the kernel.
+ * If the phase-lock loop is not implemented in the kernel, we
+ * do it the hard way using incremental adjustments and the
+ * adjtime() system call.
*/
- if (pll_control)
+ if (pll_control && pll_enable)
return;
adjustment = clock_adjust;
if (adjustment < 0)
- adjustment = -((-adjustment) >> CLOCK_PHASE);
+ adjustment = -(-adjustment >> CLOCK_PHASE);
else
adjustment >>= CLOCK_PHASE;
clock_adjust -= adjustment;
if (drift_comp < 0)
- adjustment -= ((-drift_comp) >> RSH_DRIFT_TO_ADJ);
+ adjustment -= -drift_comp >> RSH_DRIFT_TO_ADJ;
else
adjustment += drift_comp >> RSH_DRIFT_TO_ADJ;
- { l_fp offset;
- offset.l_i = 0;
- offset.l_f = adjustment;
- adj_systime(&offset);
+ /*
+ * Intricate wrinkle. If the local clock driver is in use and
+ * selected for synchronization, somebody else may be tinker the
+ * adjtime() syscall. In this case we have to avoid calling
+ * adjtime(), since that may truncate the other guy's requests.
+ * That means the local clock fudge time and frequency
+ * adjustments don't work in that case. Caveat empty.
+ */
+ if (sys_peer) {
+ if (sys_peer->refclktype == REFCLK_LOCALCLOCK &&
+ sys_peer->flags & FLAG_PREFER)
+ return;
}
+ L_CLR(&offset);
+ L_ADDF(&offset, adjustment);
+ adj_systime(&offset);
+}
+
+
+/*
+ * adj_frequency - adjust local clock frequency
+ */
+void
+adj_frequency(freq)
+ s_fp freq; /* frequency (ppm) */
+{
+#if defined(KERNEL_PLL)
+ struct timex ntv;
+#endif /* KERNEL_PLL */
+
+ /*
+ * This routine adjusts the frequency offset. It is used by the
+ * local clock driver to adjust frequency when no external
+ * discipline source is available and by the acts driver when
+ * the interval between updates is greater than 1 <<
+ * NTP_MAXPOLL. Note that the maximum offset is limited by
+ * max_comp when the daemon pll is used, but the maximum may be
+ * different when the kernel pll is used.
+ */
+ drift_comp += freq;
+ if (drift_comp > max_comp)
+ drift_comp = max_comp;
+ else if (drift_comp < -max_comp)
+ drift_comp = -max_comp;
+#if defined(KERNEL_PLL)
+ /*
+ * If the phase-lock code is implemented in the kernel, set the
+ * kernel frequency as well, but be sure to set drift_comp to
+ * the actual frequency.
+ */
+ if (!(pll_control && pll_enable))
+ return;
+ memset((char *)&ntv, 0, sizeof ntv);
+ ntv.modes = MOD_FREQUENCY;
+ ntv.freq = freq + drift_comp;
+ (void)ntp_adjtime(&ntv);
+ drift_comp = ntv.freq;
+#endif /* KERNEL_PLL */
}
@@ -749,106 +624,76 @@ loop_config(item, lfp_value, int_value)
l_fp *lfp_value;
int int_value;
{
- s_fp tmp;
#if defined(KERNEL_PLL)
struct timex ntv;
#endif /* KERNEL_PLL */
+#ifdef DEBUG
+ if (debug) {
+ printf("loop_config %d %s %x\n", item,
+ lfptoa(lfp_value, 3), int_value);
+ }
+#endif
switch (item) {
- case LOOP_DRIFTCOMP:
- tmp = LFPTOFP(lfp_value);
- if (tmp >= max_comp || tmp <= -max_comp) {
- syslog(LOG_ERR,
- "loop_config: frequency offset %s in ntp.conf file is too large",
- fptoa(tmp, 5));
- } else {
- drift_comp = tmp;
+
+ case LOOP_DRIFTCOMP:
+ drift_comp = LFPTOFP(lfp_value);
+ if (drift_comp > max_comp)
+ drift_comp = max_comp;
+ if (drift_comp < -max_comp)
+ drift_comp = -max_comp;
#if defined(KERNEL_PLL)
- /*
- * If the phase-lock code is implemented in the
- * kernel, give the time_constant and saved
- * frequency offset to the kernel. If not, no
- * harm is done.
- */
+ /*
+ * If the phase-lock code is implemented in the kernel,
+ * give the time_constant and saved frequency offset to
+ * the kernel. If not, no harm is done. We do this
+ * whether or not the use of the kernel mods is
+ * requested, in order to clear out the trash from
+ * possible prior customers.
+ */
+ memset((char *)&ntv, 0, sizeof ntv);
+ pll_status = int_value & (STA_PLL | STA_PPSFREQ);
+ if (pll_status & STA_PLL)
pll_control = 1;
- pll_status = STA_PLL | STA_PPSFREQ;
- ntv.modes = MOD_BITS | MOD_FREQUENCY;
- ntv.offset = 0;
+ else
+ pll_control = 0;
+ ntv.modes = MOD_BITS | MOD_FREQUENCY;
+ if (pll_status) {
ntv.freq = drift_comp;
ntv.maxerror = NTP_MAXDISPERSE;
ntv.esterror = NTP_MAXDISPERSE;
ntv.status = pll_status | STA_UNSYNC;
- ntv.constant = time_constant;
- newsigsys.sv_handler = pll_trap;
- newsigsys.sv_mask = 0;
- newsigsys.sv_flags = 0;
- if ((sigvec(SIGSYS, &newsigsys, &sigsys)))
- syslog(LOG_ERR,
- "sigvec() fails to save SIGSYS trap: %m\n");
- (void)ntp_adjtime(&ntv);
- if ((sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)))
- syslog(LOG_ERR,
- "sigvec() fails to restore SIGSYS trap: %m\n");
- if (pll_control)
- syslog(LOG_NOTICE,
- "using kernel phase-lock loop %04x",
- ntv.status);
- else
- syslog(LOG_NOTICE,
- "using xntpd phase-lock loop");
-#endif /* KERNEL_PLL */
-
+ ntv.constant = sys_poll - NTP_MINPOLL;
}
+ newsigsys.sv_handler = pll_trap;
+ newsigsys.sv_mask = 0;
+ newsigsys.sv_flags = 0;
+ if ((sigvec(SIGSYS, &newsigsys, &sigsys)))
+ syslog(LOG_ERR,
+ "sigvec() fails to save SIGSYS trap: %m");
+ (void)ntp_adjtime(&ntv);
+ if ((sigvec(SIGSYS, &sigsys,
+ (struct sigvec *)NULL)))
+ syslog(LOG_ERR,
+ "sigvec() fails to restore SIGSYS trap: %m");
+ if (pll_control)
+ syslog(LOG_NOTICE,
+ "using kernel phase-lock loop %04x",
+ ntv.status);
+ else
+ syslog(LOG_NOTICE,
+ "using xntpd phase-lock loop");
+#endif /* KERNEL_PLL */
break;
-
- case LOOP_PPSDELAY:
- pps_delay = *lfp_value;
- break;
-
-#if defined(PPSCLK)
- case LOOP_PPSBAUD:
-#if defined(HAVE_TERMIOS)
- /*
- * System V TERMIOS serial line parameters
- * (termios interface)
- */
- { struct termios ttyb, *ttyp;
- if (fdpps == -1)
- return;
-
- ttyp = &ttyb;
- if (tcgetattr(fdpps, ttyp) < 0)
- return;
- ttyp->c_cflag = CS8|CLOCAL|CREAD | int_value;
- if (tcsetattr(fdpps, TCSANOW, ttyp) < 0)
- return;
- }
-#endif /* HAVE_TERMIOS */
-#if defined(HAVE_BSD_TTYS)
-
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- */
- { struct sgttyb ttyb;
-
- if (fdpps == -1 || ioctl(fdpps, TIOCGETP, &ttyb) < 0)
- return;
- ttyb.sg_ispeed = ttyb.sg_ospeed = SYS_BAUD(int_value);
- if (ioctl(fdpps, TIOCSETP, &ttyb) < 0)
- return;
- }
-#endif /* HAVE_BSD_TTYS */
- pps_baud = int_value;
- break;
-#endif /* PPSCLK */
- default:
+ default:
/* sigh */
break;
}
}
+
#if defined(KERNEL_PLL)
/*
* _trap - trap processor for undefined syscalls
@@ -865,128 +710,3 @@ pll_trap()
}
#endif /* KERNEL_PLL */
-#if defined(PPSCLK)
-/*
- * pps_receive - compute and store 1-pps signal offset
- *
- * This routine is called once per second when the 1-pps signal is
- * present. It calculates the offset of the local clock relative to the
- * 1-pps signal and saves in a circular buffer for later use. If the
- * clock line discipline is active, its timestamp is used; otherwise,
- * the buffer timestamp is used.
- */
-static void
-pps_receive(rbufp)
- struct recvbuf *rbufp;
-{
- u_char *dpt; /* buffer pointer */
- l_fp ts; /* l_fp temps */
- int dpend; /* buffer length */
-
- /*
- * Set up pointers, check the buffer length, discard intercept
- * character and convert unix timeval to timestamp format.
- */
- dpt = (u_char *)&rbufp->recv_space;
- dpend = rbufp->recv_length;
-#if !defined(HPUXGADGET)
- dpt++;
- dpend--;
-#endif /* HPUXGADGET */
- if (dpend != sizeof(struct timeval) || !buftvtots((char *)dpt, &ts))
- ts = rbufp->recv_time;
-
- /*
- * Correct for uart and os delay and process sample offset.
- */
- L_SUB(&ts, &pps_delay);
- L_NEG(&ts);
- (void)pps_sample(&ts);
-}
-#endif /* PPSCLK */
-
-#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
-/*
- * pps_sample - process pps sample offset
- */
-int pps_sample(tsr)
- l_fp *tsr;
-{
- int i, j; /* temp ints */
- LONG sort[NPPS]; /* temp array for sorting */
- l_fp lftemp, ts; /* l_fp temps */
- u_fp utemp; /* u_fp temp */
- LONG ltemp; /* long temp */
-
- /*
- * Note the seconds offset is already in the low-order timestamp
- * doubleword, so all we have to do is sign-extend and invert
- * it. The resulting offset is believed only if within
- * CLOCK_MAX.
- */
- ts = *tsr;
- lftemp.l_i = lftemp.l_f = 0;
- M_ADDF(lftemp.l_i, lftemp.l_f, ts.l_f);
- if (ts.l_f <= -CLOCK_MAX_F || ts.l_f >= CLOCK_MAX_F) {
- pps_time = 0;
- return (-1);
- }
-
- /*
- * Save the sample in a circular buffer for later processing.
- */
- nsamples++;
- i = ((int)(nsamples)) % NPPS;
- samples[i] = lftemp.l_f;
- if (i != NPPS-1)
- return (0);
-
- /*
- * When the buffer fills up, construct an array of sorted
- * samples.
- */
- pps_time = current_time;
- for (i = 0; i < NPPS; i++) {
- sort[i] = samples[i];
- for (j = 0; j < i; j++) {
- if (sort[j] > sort[i]) {
- ltemp = sort[j];
- sort[j] = sort[i];
- sort[i] = ltemp;
- }
- }
- }
-
- /*
- * Compute offset as the average of all samples in the filter
- * less PPS_TRIM samples trimmed from the beginning and end,
- * dispersion as the difference between max and min of samples
- * retained. The system stratum, root delay and root dispersion
- * are also set here.
- */
- pps_offset.l_i = pps_offset.l_f = 0;
- for (i = PPS_TRIM; i < NPPS - PPS_TRIM; i++)
- M_ADDF(pps_offset.l_i, pps_offset.l_f, sort[i]);
- if (L_ISNEG(&pps_offset)) {
- L_NEG(&pps_offset);
- for (i = 0; i < PPS_FAC; i++)
- L_RSHIFT(&pps_offset);
- L_NEG(&pps_offset);
- } else {
- for (i = 0; i < PPS_FAC; i++)
- L_RSHIFT(&pps_offset);
- }
- lftemp.l_i = 0;
- lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM];
- pps_dispersion = LFPTOFP(&lftemp);
-#ifdef DEBUG
- if (debug)
- printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6),
- lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5));
-#endif /* DEBUG */
- record_peer_stats(&loopback_interface->sin, ctlsysstatus(),
- &pps_offset, 0, pps_dispersion);
- return (0);
-}
-#endif /* PPS || PPSCLK || PPSPPS */
-
diff --git a/usr.sbin/xntpd/xntpd/ntp_monitor.c b/usr.sbin/xntpd/xntpd/ntp_monitor.c
index e2d2eb51adac..55bd5d542b90 100644
--- a/usr.sbin/xntpd/xntpd/ntp_monitor.c
+++ b/usr.sbin/xntpd/xntpd/ntp_monitor.c
@@ -1,6 +1,7 @@
-/* ntp_monitor.c,v 3.1 1993/07/06 01:11:21 jbj Exp
+/*
* ntp_monitor.c - monitor who is using the xntpd server
*/
+#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
@@ -33,6 +34,8 @@
* hit the memory limit. Then we free memory by grabbing entries off
* the tail for the MRU list, unlinking from the hash table, and
* reinitializing.
+ *
+ * trimmed back memory consumption ... jdg 8/94
*/
/*
@@ -40,9 +43,15 @@
* with the illicit knowlege that we can only return somewhat less
* than 8K bytes in a mode 7 response packet, and that each structure
* will require about 20 bytes of space in the response.
+ *
+ * ... I don't believe the above is true anymore ... jdg
*/
-#define MAXMONMEM 400 /* we allocate up to 400 structures */
+#ifndef MAXMONMEM
+#define MAXMONMEM 600 /* we allocate up to 400 structures */
+#endif
+#ifndef MONMEMINC
#define MONMEMINC 40 /* allocate them 40 at a time */
+#endif
/*
* Hashing stuff
@@ -55,17 +64,15 @@
* Pointers to the hash table, the MRU list and the count table. Memory
* for the hash and count tables is only allocated if monitoring is turned on.
*/
-static struct mon_data *mon_hash; /* Pointer to array of hash buckets */
-static int *mon_hash_count; /* Point to hash count stats keeper */
+static struct mon_data *mon_hash[MON_HASH_SIZE]; /* array of list ptrs */
struct mon_data mon_mru_list;
struct mon_data mon_fifo_list;
/*
* List of free structures structures, and counters of free and total
* structures. The free structures are linked with the hash_next field.
*/
-static struct mon_data *mon_free;
+static struct mon_data *mon_free; /* the free list or null if none */
-static int mon_free_mem; /* number of structures on free list */
static int mon_total_mem; /* total number of structures allocated */
static int mon_mem_increments; /* number of times we've called malloc() */
@@ -79,9 +86,10 @@ static int mon_have_memory;
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
+extern u_long current_time;
static void mon_getmoremem P((void));
+static void remove_from_hash P((struct mon_data *));
/*
* init_mon - initialize monitoring global data
@@ -96,12 +104,10 @@ init_mon()
mon_enabled = MON_OFF;
mon_have_memory = 0;
- mon_free_mem = 0;
mon_total_mem = 0;
mon_mem_increments = 0;
- mon_free = 0;
- mon_hash = 0;
- mon_hash_count = 0;
+ mon_free = NULL;
+ memset((char *)&mon_hash[0], 0, sizeof mon_hash);
memset((char *)&mon_mru_list, 0, sizeof mon_mru_list);
memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list);
}
@@ -114,8 +120,6 @@ void
mon_start(mode)
int mode;
{
- register struct mon_data *md;
- register int i;
if (mon_enabled != MON_OFF) {
mon_enabled |= mode;
@@ -125,26 +129,13 @@ mon_start(mode)
return; /* Ooops.. */
if (!mon_have_memory) {
- mon_hash = (struct mon_data *)
- emalloc(MON_HASH_SIZE * sizeof(struct mon_data));
- memset((char *)mon_hash, 0,
- MON_HASH_SIZE*sizeof(struct mon_data));
- mon_hash_count = (int *)emalloc(MON_HASH_SIZE * sizeof(int));
- mon_free_mem = 0;
mon_total_mem = 0;
mon_mem_increments = 0;
- mon_free = 0;
+ mon_free = NULL;
mon_getmoremem();
mon_have_memory = 1;
}
- md = mon_hash;
- for (i = 0; i < MON_HASH_SIZE; i++, md++) {
- md->hash_next = md;
- md->hash_prev = md;
- *(mon_hash_count + i) = 0;
- }
-
mon_mru_list.mru_next = &mon_mru_list;
mon_mru_list.mru_prev = &mon_mru_list;
@@ -162,7 +153,7 @@ void
mon_stop(mode)
int mode;
{
- register struct mon_data *md;
+ register struct mon_data *md, *md_next;
register int i;
if (mon_enabled == MON_OFF)
@@ -177,15 +168,14 @@ mon_stop(mode)
/*
* Put everything back on the free list
*/
- md = mon_hash;
- for (i = 0; i < MON_HASH_SIZE; i++, md++) {
- if (md->hash_next != md) {
- md->hash_prev->hash_next = mon_free;
- mon_free = md->hash_next;
- mon_free_mem += *(mon_hash_count + i);
- md->hash_next = md;
- md->hash_prev = md;
- *(mon_hash_count + i) = 0;
+ for (i = 0; i < MON_HASH_SIZE; i++) {
+ md = mon_hash[i]; /* get next list */
+ mon_hash[i] = NULL; /* zero the list head */
+ while (md != NULL) {
+ md_next = md->hash_next;
+ md->hash_next = mon_free;
+ mon_free = md;
+ md = md_next;
}
}
@@ -206,10 +196,9 @@ monitor(rbufp)
{
register struct pkt *pkt;
register struct mon_data *md;
- register U_LONG netnum;
+ register u_long netnum;
register int hash;
register int mode;
- register struct mon_data *mdhash;
if (mon_enabled == MON_OFF)
return;
@@ -219,9 +208,11 @@ monitor(rbufp)
hash = MON_HASH(netnum);
mode = PKT_MODE(pkt->li_vn_mode);
- md = (mon_hash + hash)->hash_next;
- while (md != (mon_hash + hash)) {
- if (md->rmtadr == netnum && md->mode == (u_char)mode) {
+ md = mon_hash[hash];
+ while (md != NULL) {
+ if (md->rmtadr == netnum &&
+ /* ?? md->interface == rbufp->dstadr && ?? */
+ md->mode == (u_char)mode) {
md->lasttime = current_time;
md->count++;
md->version = PKT_VERSION(pkt->li_vn_mode);
@@ -248,16 +239,16 @@ monitor(rbufp)
* guy. Get him some memory, either from the free list
* or from the tail of the MRU list.
*/
- if (mon_free_mem == 0 && mon_total_mem >= MAXMONMEM) {
+ if (mon_free == NULL && mon_total_mem >= MAXMONMEM) {
/*
* Get it from MRU list
*/
md = mon_mru_list.mru_prev;
md->mru_prev->mru_next = &mon_mru_list;
mon_mru_list.mru_prev = md->mru_prev;
- md->hash_next->hash_prev = md->hash_prev;
- md->hash_prev->hash_next = md->hash_next;
- *(mon_hash_count + MON_HASH(md->rmtadr)) -= 1;
+
+ remove_from_hash(md);
+
/*
* Get it from FIFO list
*/
@@ -265,11 +256,10 @@ monitor(rbufp)
md->fifo_next->fifo_prev = md->fifo_prev;
} else {
- if (mon_free_mem == 0)
- mon_getmoremem();
+ if (mon_free == NULL) /* if free list empty */
+ mon_getmoremem(); /* then get more */
md = mon_free;
mon_free = md->hash_next;
- mon_free_mem--;
}
/*
@@ -282,18 +272,19 @@ monitor(rbufp)
md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
md->mode = (u_char) mode;
md->version = PKT_VERSION(pkt->li_vn_mode);
+ md->interface = rbufp->dstadr;
+ md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) &&
+ rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd ==
+ md->interface->bfd ? MDF_BCAST : MDF_UCAST;
/*
- * Shuffle him into the hash table, inserting him at the
- * end. Also put him on top of the MRU list
+ * Drop him into front of the hash table.
+ * Also put him on top of the MRU list
* and at bottom of FIFO list
*/
- mdhash = mon_hash + MON_HASH(netnum);
- md->hash_next = mdhash;
- md->hash_prev = mdhash->hash_prev;
- mdhash->hash_prev->hash_next = md;
- mdhash->hash_prev = md;
- *(mon_hash_count + MON_HASH(netnum)) += 1;
+
+ md->hash_next = mon_hash[hash];
+ mon_hash[hash] = md;
md->mru_next = mon_mru_list.mru_next;
md->mru_prev = &mon_mru_list;
@@ -315,7 +306,7 @@ mon_getmoremem()
{
register struct mon_data *md;
register int i;
- struct mon_data *freedata;
+ struct mon_data *freedata; /* 'old' free list (null) */
md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data));
freedata = mon_free;
@@ -331,7 +322,28 @@ mon_getmoremem()
*/
md->hash_next = freedata;
- mon_free_mem += MONMEMINC;
mon_total_mem += MONMEMINC;
mon_mem_increments++;
}
+
+static void
+remove_from_hash(md)
+struct mon_data *md;
+{ register int hash;
+ register struct mon_data *md_prev;
+
+ hash = MON_HASH(md->rmtadr);
+ if (mon_hash[hash] == md) {
+ mon_hash[hash] = md->hash_next;
+ } else {
+ md_prev = mon_hash[hash];
+ while (md_prev->hash_next != md) {
+ md_prev = md_prev->hash_next;
+ if (md_prev == NULL) {
+ /* logic error */
+ return;
+ }
+ }
+ md_prev->hash_next = md->hash_next;
+ }
+}
diff --git a/usr.sbin/xntpd/xntpd/ntp_peer.c b/usr.sbin/xntpd/xntpd/ntp_peer.c
index 9d8ec35dee78..389cc2c75671 100644
--- a/usr.sbin/xntpd/xntpd/ntp_peer.c
+++ b/usr.sbin/xntpd/xntpd/ntp_peer.c
@@ -1,4 +1,4 @@
-/* ntp_peer.c,v 3.1 1993/07/06 01:11:22 jbj Exp
+/*
* ntp_peer.c - management of data maintained for peer associations
*/
#include <stdio.h>
@@ -49,11 +49,11 @@ u_short current_association_ID;
/*
* Miscellaneous statistic counters which may be queried.
*/
-U_LONG peer_timereset; /* time stat counters were zeroed */
-U_LONG findpeer_calls; /* number of calls to findpeer */
-U_LONG assocpeer_calls; /* number of calls to findpeerbyassoc */
-U_LONG peer_allocations; /* number of allocations from the free list */
-U_LONG peer_demobilizations; /* number of structs freed to free list */
+u_long peer_timereset; /* time stat counters were zeroed */
+u_long findpeer_calls; /* number of calls to findpeer */
+u_long assocpeer_calls; /* number of calls to findpeerbyassoc */
+u_long peer_allocations; /* number of allocations from the free list */
+u_long peer_demobilizations; /* number of structs freed to free list */
int total_peer_structs; /* number of peer structs in circulation */
/*
@@ -64,7 +64,7 @@ extern struct interface *any_interface;
/*
* Timer queue and current time. Imported from the timer module.
*/
-extern U_LONG current_time;
+extern u_long current_time;
extern struct event timerqueue[];
/*
@@ -77,7 +77,7 @@ static struct peer init_peer_alloc[INIT_PEER_ALLOC];
* we try to get their poll update timers initialized to different values
* to prevent us from sending big clumps of data all at once.
*/
-U_LONG init_peer_starttime;
+u_long init_peer_starttime;
extern int initializing;
extern int debug;
@@ -192,12 +192,14 @@ findexistingpeer(addr, start_peer)
* findpeer - find and return a peer in the hash table.
*/
struct peer *
-findpeer(srcadr, dstadr)
+findpeer(srcadr, dstadr, fd)
struct sockaddr_in *srcadr;
struct interface *dstadr;
+ int fd;
{
register struct peer *any_inter_peer;
register struct peer *peer;
+ register struct peer *best = (struct peer *) 0;
int hash;
findpeer_calls++;
@@ -207,9 +209,16 @@ findpeer(srcadr, dstadr)
for (peer = peer_hash[hash]; peer != 0; peer = peer->next) {
if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr)
&& NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
- if (peer->dstadr == dstadr)
- return peer; /* got it! */
+ if (peer->dstadr == dstadr) {
+ int rfd = (peer->cast_flags & MDF_BCAST) ?
+ dstadr->bfd : dstadr->fd;
+
+ if (rfd == fd)
+ return peer; /* got it! */
+ best = peer;
+ }
if (peer->dstadr == any_interface) {
+
/*
* We shouldn't have more than one
* instance of the peer in the table,
@@ -223,9 +232,22 @@ findpeer(srcadr, dstadr)
"two instances of default interface for %s in hash table",
ntoa(srcadr));
}
+
+ /*
+ * Multicast hacks to determine peer when a
+ * packet arrives and there exists an assoc.
+ * with src in client/server mode
+ */
+ if (((dstadr == any_interface) || (peer->cast_flags &
+ MDF_MCAST)) && peer->flags & FLAG_MCAST2)
+ return peer;
}
}
+ if(best) {
+ return best;
+ }
+
/*
* If we didn't find the specific peer but found a wild card,
* modify the interface and return him.
@@ -349,13 +371,13 @@ peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, flags, ttl, key)
int maxpoll;
int flags;
int ttl;
- U_LONG key;
+ u_long key;
{
register struct peer *peer;
#ifdef DEBUG
if (debug)
- printf("peer_config: addr %s mode %d version %d minpoll %d maxpoll %d flags %d ttl %d key %u\n",
+ printf("peer_config: addr %s mode %d version %d minpoll %d maxpoll %d flags %d ttl %d key %lu\n",
ntoa(srcadr), hmode, version, minpoll, maxpoll, flags,
ttl, key);
#endif
@@ -387,8 +409,10 @@ peer_config(srcadr, dstadr, hmode, version, minpoll, maxpoll, flags, ttl, key)
peer->maxpoll = (u_char)maxpoll;
peer->hpoll = peer->minpoll;
peer->ppoll = peer->minpoll;
- peer->flags = ((u_char)(flags|FLAG_CONFIG))
- |(peer->flags & (FLAG_REFCLOCK|FLAG_DEFBDELAY));
+ peer->flags = ((u_char)(flags | FLAG_CONFIG)) |
+ (peer->flags & FLAG_REFCLOCK);
+ peer->cast_flags = (hmode == MODE_BROADCAST) ?
+ IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) ? MDF_MCAST : MDF_BCAST : MDF_UCAST;
peer->ttl = (u_char)ttl;
peer->keyid = key;
return peer;
@@ -418,7 +442,7 @@ newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, ttl, key)
int minpoll;
int maxpoll;
int ttl;
- U_LONG key;
+ u_long key;
{
register struct peer *peer;
register int i;
@@ -427,8 +451,8 @@ newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, ttl, key)
* Some dirt here. Some of the initialization requires
* knowlege of our system state.
*/
- extern U_LONG sys_bdelay;
- extern LONG sys_clock;
+ extern s_fp sys_bdelay;
+ extern long sys_clock;
if (peer_free_count == 0)
getmorepeermem();
@@ -453,6 +477,11 @@ newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, ttl, key)
peer->dstadr = findbcastinter(srcadr);
else
peer->dstadr = any_interface;
+ peer->cast_flags = (hmode == MODE_BROADCAST) ?
+ (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) ? MDF_MCAST : MDF_BCAST :
+ (hmode == MODE_BCLIENT || hmode == MODE_MCLIENT) ?
+ (peer->dstadr->flags & INT_MULTICAST) ? MDF_MCAST : MDF_BCAST :
+ MDF_UCAST;
peer->hmode = (u_char)hmode;
peer->version = (u_char)version;
peer->minpoll = (u_char)minpoll;
@@ -462,7 +491,6 @@ newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, ttl, key)
peer->ttl = ttl;
peer->keyid = key;
peer->estbdelay = sys_bdelay;
- peer->flags |= FLAG_DEFBDELAY;
peer->leap = LEAP_NOTINSYNC;
peer->precision = DEFPRECISION;
peer->dispersion = NTP_MAXDISPERSE;
@@ -616,8 +644,6 @@ peer_reset(peer)
peer->processed = 0;
peer->badauth = 0;
peer->bogusorg = 0;
- peer->bogusrec = 0;
- peer->bogusdelay = 0;
peer->oldpkt = 0;
peer->seldisptoolarge = 0;
peer->selbroken = 0;
diff --git a/usr.sbin/xntpd/xntpd/ntp_proto.c b/usr.sbin/xntpd/xntpd/ntp_proto.c
index a3f744eae881..7889d9315e47 100644
--- a/usr.sbin/xntpd/xntpd/ntp_proto.c
+++ b/usr.sbin/xntpd/xntpd/ntp_proto.c
@@ -1,4 +1,4 @@
-/* ntp_proto.c,v 3.1 1993/07/06 01:11:23 jbj Exp
+/*
* ntp_proto.c - NTP version 3 protocol machinery
*/
#include <stdio.h>
@@ -10,50 +10,51 @@
#include "ntp_unixtime.h"
/*
- * System variables are declared here. See Section 3.2 of
- * the specification.
+ * System variables are declared here. See Section 3.2 of the
+ * specification.
*/
u_char sys_leap; /* system leap indicator */
u_char sys_stratum; /* stratum of system */
s_char sys_precision; /* local clock precision */
s_fp sys_rootdelay; /* distance to current sync source */
u_fp sys_rootdispersion; /* dispersion of system clock */
-U_LONG sys_refid; /* reference source for local clock */
+u_long sys_refid; /* reference source for local clock */
l_fp sys_offset; /* combined offset from clock_select */
u_fp sys_maxd; /* dispersion of selected peer */
l_fp sys_reftime; /* time we were last updated */
l_fp sys_refskew; /* accumulated skew since last update */
-struct peer *sys_peer; /* our current peer */
-u_char sys_poll; /* log2 of desired system poll interval */
-extern LONG sys_clock; /* second part of current time - now in systime.c */
-LONG sys_lastselect; /* sys_clock at last synch-dist update */
+struct peer *sys_peer; /* our current peer */
+u_char sys_poll; /* log2 of system poll interval */
+extern long sys_clock; /* second part of current time */
+long sys_lastselect; /* sys_clock at last synch update */
/*
- * Non-specified system state variables.
+ * Nonspecified system state variables.
*/
int sys_bclient; /* we set our time to broadcasts */
-U_LONG sys_bdelay; /* default delay to use for broadcasting */
+s_fp sys_bdelay; /* broadcast client default delay */
int sys_authenticate; /* authenticate time used for syncing */
-
-U_LONG sys_authdelay; /* ts fraction, time it takes for encrypt() */
+u_char consensus_leap; /* mitigated leap bits */
+u_long sys_authdelay; /* encryption time (l_fp fraction) */
+u_char leap_consensus; /* consensus of survivor leap bits */
/*
* Statistics counters
*/
-U_LONG sys_stattime; /* time when we started recording */
-U_LONG sys_badstratum; /* packets with invalid incoming stratum */
-U_LONG sys_oldversionpkt; /* old version packets received */
-U_LONG sys_newversionpkt; /* new version packets received */
-U_LONG sys_unknownversion; /* don't know version packets */
-U_LONG sys_badlength; /* packets with bad length */
-U_LONG sys_processed; /* packets processed */
-U_LONG sys_badauth; /* packets dropped because of authorization */
-U_LONG sys_limitrejected; /* pkts rejected due toclient count per net */
+u_long sys_stattime; /* time when we started recording */
+u_long sys_badstratum; /* packets with invalid stratum */
+u_long sys_oldversionpkt; /* old version packets received */
+u_long sys_newversionpkt; /* new version packets received */
+u_long sys_unknownversion; /* don't know version packets */
+u_long sys_badlength; /* packets with bad length */
+u_long sys_processed; /* packets processed */
+u_long sys_badauth; /* packets dropped because of auth */
+u_long sys_limitrejected; /* pkts rejected due toclient count per net */
/*
* Imported from ntp_timer.c
*/
-extern U_LONG current_time;
+extern u_long current_time;
extern struct event timerqueue[];
/*
@@ -64,11 +65,16 @@ extern struct interface *any_interface;
/*
* Imported from ntp_loopfilter.c
*/
-extern int pps_control;
-extern U_LONG pps_update;
+extern int pll_enable;
+extern int pps_update;
+
+/*
+ * Imported from ntp_util.c
+ */
+extern int stats_control;
/*
- * The peer hash table. Imported from ntp_peer.c
+ * The peer hash table. Imported from ntp_peer.c
*/
extern struct peer *peer_hash[];
extern int peer_hash_count[];
@@ -81,18 +87,40 @@ extern int debug;
static void clear_all P((void));
/*
- * transmit - Transmit Procedure. See Section 3.4.1 of the specification.
+ * transmit - Transmit Procedure. See Section 3.4.1 of the
+ * specification.
*/
void
transmit(peer)
register struct peer *peer;
{
struct pkt xpkt; /* packet to send */
- U_LONG peer_timer;
+ u_long peer_timer;
+ u_fp precision;
+ int bool;
- if ((peer->hmode != MODE_BROADCAST && peer->hmode != MODE_BCLIENT) ||
- (peer->hmode == MODE_BROADCAST && sys_leap != LEAP_NOTINSYNC)) {
- U_LONG xkeyid;
+ /*
+ * We need to be very careful about honking uncivilized time. If
+ * not operating in broadcast mode, honk in all except broadcast
+ * client mode. If operating in broadcast mode and synchronized
+ * to a real source, honk except when the peer is the local-
+ * clock driver and the prefer flag is not set. In other words,
+ * in broadcast mode we never honk unless known to be
+ * synchronized to real time.
+ */
+ bool = 0;
+ if (peer->hmode != MODE_BROADCAST) {
+ if (peer->hmode != MODE_BCLIENT)
+ bool = 1;
+ } else if (sys_peer != 0 && sys_leap != LEAP_NOTINSYNC) {
+ if (!(sys_peer->refclktype == REFCLK_LOCALCLOCK &&
+ !(sys_peer->flags & FLAG_PREFER)))
+ bool = 1;
+ }
+ if (bool) {
+ u_long xkeyid;
+ int find_rtt = (peer->cast_flags & MDF_MCAST) &&
+ peer->hmode != MODE_BROADCAST;
/*
* Figure out which keyid to include in the packet
@@ -108,38 +136,43 @@ transmit(peer)
/*
* Make up a packet to send.
*/
- xpkt.li_vn_mode
- = PKT_LI_VN_MODE(sys_leap, peer->version, peer->hmode);
+ xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap,
+ peer->version, peer->hmode);
xpkt.stratum = STRATUM_TO_PKT(sys_stratum);
xpkt.ppoll = peer->hpoll;
xpkt.precision = sys_precision;
xpkt.rootdelay = HTONS_FP(sys_rootdelay);
- xpkt.rootdispersion =
- HTONS_FP(sys_rootdispersion +
- (FP_SECOND >> (-(int)sys_precision)) +
- LFPTOFP(&sys_refskew));
+ precision = FP_SECOND >> -(int)sys_precision;
+ if (precision == 0)
+ precision = 1;
+ xpkt.rootdispersion = HTONS_FP(sys_rootdispersion +
+ precision + LFPTOFP(&sys_refskew));
xpkt.refid = sys_refid;
HTONL_FP(&sys_reftime, &xpkt.reftime);
HTONL_FP(&peer->org, &xpkt.org);
HTONL_FP(&peer->rec, &xpkt.rec);
/*
- * Decide whether to authenticate or not. If so, call encrypt()
- * to fill in the rest of the frame. If not, just add in the
- * xmt timestamp and send it quick.
+ * Decide whether to authenticate or not. If so, call
+ * encrypt() to fill in the rest of the frame. If not,
+ * just add in the xmt timestamp and send it quick.
*/
if (peer->flags & FLAG_AUTHENABLE) {
int sendlen;
xpkt.keyid = htonl(xkeyid);
- auth1crypt(xkeyid, (U_LONG *)&xpkt, LEN_PKT_NOMAC);
+ auth1crypt(xkeyid, (U_LONG *)&xpkt,
+ LEN_PKT_NOMAC);
get_systime(&peer->xmt);
L_ADDUF(&peer->xmt, sys_authdelay);
HTONL_FP(&peer->xmt, &xpkt.xmt);
sendlen = auth2crypt(xkeyid, (U_LONG *)&xpkt,
LEN_PKT_NOMAC);
- sendpkt(&(peer->srcadr), peer->dstadr, &xpkt,
- sendlen + LEN_PKT_NOMAC);
+ sendpkt(&peer->srcadr, find_rtt ?
+ any_interface : peer->dstadr,
+ ((peer->cast_flags & MDF_MCAST) && !find_rtt) ?
+ peer->ttl : -7, &xpkt, sendlen +
+ LEN_PKT_NOMAC);
#ifdef DEBUG
if (debug > 1)
printf("transmit auth to %s\n",
@@ -148,15 +181,21 @@ transmit(peer)
peer->sent++;
} else {
/*
- * Get xmt timestamp, then send it without mac field
+ * Get xmt timestamp, then send it without mac
+ * field
*/
+ int find_rtt = (peer->cast_flags & MDF_MCAST) &&
+ peer->dstadr != any_interface;
get_systime(&(peer->xmt));
HTONL_FP(&peer->xmt, &xpkt.xmt);
- sendpkt(&(peer->srcadr), peer->dstadr, &xpkt,
- LEN_PKT_NOMAC);
+ sendpkt(&(peer->srcadr), find_rtt ?
+ any_interface : peer->dstadr,
+ ((peer->cast_flags & MDF_MCAST) && !find_rtt) ?
+ peer->ttl : -8, &xpkt, LEN_PKT_NOMAC);
#ifdef DEBUG
if (debug > 1)
- printf("transmit to %s\n", ntoa(&(peer->srcadr)));
+ printf("transmit to %s\n",
+ ntoa(&(peer->srcadr)));
#endif
peer->sent++;
}
@@ -166,40 +205,49 @@ transmit(peer)
u_char opeer_reach;
/*
* Determine reachability and diddle things if we
- * haven't heard from the host for a while.
+ * haven't heard from the host for a while. If we are
+ * about to become unreachable and are a
+ * broadcast/multicast client, the server has refused to
+ * boogie in client/server mode, so we switch to
+ * MODE_BCLIENT anyway and wait for subsequent
+ * broadcasts.
*/
opeer_reach = peer->reach;
+ if (opeer_reach & 0x80 && peer->flags & FLAG_MCAST2) {
+ peer->hmode = MODE_BCLIENT;
+ }
peer->reach <<= 1;
if (peer->reach == 0) {
if (opeer_reach != 0)
report_event(EVNT_UNREACH, peer);
/*
* Clear this guy out. No need to redo clock
- * selection since by now this guy won't be a player
+ * selection since by now this guy won't be a
+ * player
*/
if (peer->flags & FLAG_CONFIG) {
if (opeer_reach != 0) {
peer_clear(peer);
- peer->timereachable = current_time;
+ peer->timereachable =
+ current_time;
}
- } else {
- unpeer(peer);
- return;
}
/*
- * While we have a chance, if our system peer
- * is zero or his stratum is greater than the
- * last known stratum of this guy, make sure
- * hpoll is clamped to the minimum before
- * resetting the timer.
- * If the peer has been unreachable for a while
- * and we have a system peer who is at least his
- * equal, we may want to ramp his polling interval
- * up to avoid the useless traffic.
+ * While we have a chance, if our system peer is
+ * zero or his stratum is greater than the last
+ * known stratum of this guy, make sure hpoll is
+ * clamped to the minimum before resetting the
+ * timer. If the peer has been unreachable for a
+ * while and we have a system peer who is at
+ * least his equal, we may want to ramp his
+ * polling interval up to avoid the useless
+ * traffic.
*/
- if (sys_peer == 0
- || sys_peer->stratum > peer->stratum) {
+ if (sys_peer == 0) {
+ peer->hpoll = peer->minpoll;
+ peer->unreach = 0;
+ } else if (sys_peer->stratum > peer->stratum) {
peer->hpoll = peer->minpoll;
peer->unreach = 0;
} else {
@@ -223,8 +271,9 @@ transmit(peer)
peer->valid--;
if (peer->hpoll > peer->minpoll)
peer->hpoll--;
- off.l_ui = off.l_uf = 0;
- clock_filter(peer, &off, (s_fp)0, (u_fp)NTP_MAXDISPERSE);
+ L_CLR(&off);
+ clock_filter(peer, &off, (s_fp)0,
+ (u_fp)NTP_MAXDISPERSE);
if (peer->flags & FLAG_SYSPEER)
clock_select();
} else {
@@ -238,24 +287,34 @@ transmit(peer)
}
/*
- * Finally, adjust the hpoll variable for special conditions.
+ * Finally, adjust the hpoll variable for special conditions. If
+ * we are a broadcast/multicast client, we use the server poll
+ * interval if listening for broadcasts and one-eighth this
+ * interval if in client/server mode. The following clamp
+ * prevents madness. If this is the system poll, sys_poll
+ * controls hpoll.
*/
- if (peer->hmode == MODE_BCLIENT)
- peer->hpoll = peer->ppoll;
- else if (peer->flags & FLAG_SYSPEER &&
- peer->hpoll > sys_poll)
- peer->hpoll = max(peer->minpoll, sys_poll);
+ if (peer->flags & FLAG_MCAST2) {
+ if (peer->hmode == MODE_BCLIENT)
+ peer->hpoll = peer->ppoll;
+ else
+ peer->hpoll = peer->ppoll - 3;
+ } else if (peer->flags & FLAG_SYSPEER)
+ peer->hpoll = sys_poll;
+ if (peer->hpoll < peer->minpoll)
+ peer->hpoll = peer->minpoll;
/*
- * Arrange for our next timeout. hpoll will be less than
- * maxpoll for sure.
+ * Arrange for our next timeout. hpoll will be less than maxpoll
+ * for sure.
*/
if (peer->event_timer.next != 0)
/*
* Oops, someone did already.
*/
TIMER_DEQUEUE(&peer->event_timer);
- peer_timer = 1 << (int)max((u_char)min(peer->ppoll, peer->hpoll), peer->minpoll);
+ peer_timer = 1 << (int)max((u_char)min(peer->ppoll,
+ peer->hpoll), peer->minpoll);
peer->event_timer.event_time = current_time + peer_timer;
TIMER_ENQUEUE(timerqueue, &peer->event_timer);
}
@@ -274,7 +333,7 @@ receive(rbufp)
int has_mac;
int trustable;
int is_authentic;
- U_LONG hiskeyid;
+ u_long hiskeyid;
struct peer *peer2;
#ifdef DEBUG
@@ -313,7 +372,7 @@ receive(rbufp)
}
/*
- * Catch private mode packets. Dump it if queries not allowed.
+ * Catch private mode packets. Dump it if queries not allowed.
*/
if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) {
if (restrict & RES_NOQUERY)
@@ -340,16 +399,16 @@ receive(rbufp)
return;
/*
- * See if we only accept limited number of clients
- * from the net this guy is from.
- * Note: the flag is determined dynamically within restrictions()
+ * See if we only accept limited number of clients from the net
+ * this guy is from. Note: the flag is determined dynamically
+ * within restrictions()
*/
if (restrict & RES_LIMITED) {
- extern U_LONG client_limit;
+ extern u_long client_limit;
sys_limitrejected++;
syslog(LOG_NOTICE,
- "rejected mode %d request from %s - per net client limit (%d) exceeded",
+ "rejected mode %d request from %s - per net client limit (%d) exceeded",
PKT_MODE(pkt->li_vn_mode),
ntoa(&rbufp->recv_srcadr), client_limit);
return;
@@ -364,36 +423,34 @@ receive(rbufp)
}
/*
- * Find the peer. This will return a null if this guy
- * isn't in the database.
+ * Find the peer. This will return a null if this guy isn't in
+ * the database.
*/
- peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr);
+ peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd);
/*
* Check the length for validity, drop the packet if it is
- * not as expected.
- *
- * If this is a client mode poll, go no further. Send back
- * his time and drop it.
+ * not as expected. If this is a client mode poll, go no
+ * further. Send back his time and drop it.
*
* The scheme we use for authentication is this. If we are
* running in non-authenticated mode, we accept both frames
* which are authenticated and frames which aren't, but don't
- * authenticate. We do record whether the frame had a mac field
+ * authenticate. We do record whether the frame had a mac field
* or not so we know what to do on output.
*
* If we are running in authenticated mode, we only trust frames
* which have authentication attached, which are validated and
- * which are using one of our trusted keys. We respond to all
- * other pollers without saving any state. If a host we are
+ * which are using one of our trusted keys. We respond to all
+ * other pollers without saving any state. If a host we are
* passively peering with changes his key from a trusted one to
* an untrusted one, we immediately unpeer with him, reselect
* the clock and treat him as an unmemorable client (this is
* a small denial-of-service hole I'll have to think about).
* If a similar event occurs with a configured peer we drop the
- * frame and hope he'll revert to our key again. If we get a
+ * frame and hope he'll revert to our key again. If we get a
* frame which can't be authenticated with the given key, we
- * drop it. Either we disagree on the keys or someone is trying
+ * drop it. Either we disagree on the keys or someone is trying
* some funny stuff.
*/
@@ -405,9 +462,10 @@ receive(rbufp)
has_mac = rbufp->recv_length - LEN_PKT_NOMAC;
hiskeyid = ntohl(pkt->keyid);
#ifdef DEBUG
- if (debug > 3)
- printf("receive: pkt is %d octets, mac %d octets long, keyid %d\n",
- rbufp->recv_length, has_mac, hiskeyid);
+ if (debug > 2)
+ printf(
+ "receive: pkt is %d octets, mac %d octets long, keyid %ld\n",
+ rbufp->recv_length, has_mac, hiskeyid);
#endif
} else if (rbufp->recv_length == LEN_PKT_NOMAC) {
hiskeyid = 0;
@@ -415,15 +473,14 @@ receive(rbufp)
} else {
#ifdef DEBUG
if (debug > 2)
- printf("receive: bad length %d (not > %d or == %d)\n",
- rbufp->recv_length, LEN_PKT_MAC, LEN_PKT_NOMAC);
+ printf("receive: bad length %d %ld\n",
+ rbufp->recv_length, sizeof(struct pkt));
#endif
sys_badlength++;
return;
}
-
/*
* Figure out his mode and validate it.
*/
@@ -432,7 +489,8 @@ receive(rbufp)
if (debug > 2)
printf("receive: his mode %d\n", hismode);
#endif
- if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode == 0) {
+ if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode ==
+ 0) {
/*
* Easy. If it is from the NTP port it is
* a sym act, else client.
@@ -452,34 +510,43 @@ receive(rbufp)
}
}
-
/*
- * If he included a mac field, decrypt it to see if it is authentic.
+ * If he included a mac field, decrypt it to see if it is
+ * authentic.
*/
is_authentic = 0;
if (has_mac) {
if (authhavekey(hiskeyid)) {
- if (authdecrypt(hiskeyid, (U_LONG *)pkt, LEN_PKT_NOMAC)) {
+ if (!authistrusted(hiskeyid)) {
+ sys_badauth++;
+#ifdef DEBUG
+ if (debug > 3)
+ printf("receive: untrusted keyid\n");
+#endif
+ return;
+ }
+ if (authdecrypt(hiskeyid, (U_LONG *)pkt,
+ LEN_PKT_NOMAC)) {
is_authentic = 1;
#ifdef DEBUG
if (debug > 3)
- printf("receive: authdecrypt succeeds\n");
+ printf("receive: authdecrypt succeeds\n");
#endif
} else {
sys_badauth++;
#ifdef DEBUG
if (debug > 3)
- printf("receive: authdecrypt fails\n");
+ printf("receive: authdecrypt fails\n");
#endif
}
}
}
/*
- * If this is someone we don't remember from a previous association,
- * dispatch him now. Either we send something back quick, we
- * ignore him, or we allocate some memory for him and let
- * him continue.
+ * If this is someone we don't remember from a previous
+ * association, dispatch him now. Either we send something back
+ * quick, we ignore him, or we allocate some memory for him and
+ * let him continue.
*/
if (peer == 0) {
int mymode;
@@ -493,15 +560,13 @@ receive(rbufp)
* later. If not, send his time quick.
*/
if (restrict & RES_NOPEER) {
- fast_xmit(rbufp, (int)hismode, is_authentic);
+ fast_xmit(rbufp, (int)hismode,
+ is_authentic);
return;
}
break;
case MODE_PASSIVE:
-#ifdef MCAST
- /* process the packet to determine the rt-delay */
-#endif /* MCAST */
case MODE_SERVER:
/*
* These are obvious errors. Ignore.
@@ -519,11 +584,9 @@ receive(rbufp)
/*
* Sort of a repeat of the above...
*/
-/*
if ((restrict & RES_NOPEER) || !sys_bclient)
return;
-*/
- mymode = MODE_BCLIENT;
+ mymode = MODE_MCLIENT;
break;
}
@@ -531,9 +594,10 @@ receive(rbufp)
* Okay, we're going to keep him around. Allocate him
* some memory.
*/
- peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, mymode,
- PKT_VERSION(pkt->li_vn_mode), NTP_MINDPOLL,
- NTP_MAXPOLL, 0, hiskeyid);
+ peer = newpeer(&rbufp->recv_srcadr,
+ rbufp->dstadr, mymode, PKT_VERSION(pkt->li_vn_mode),
+ NTP_MINDPOLL, NTP_MAXDPOLL, 0, hiskeyid);
+
if (peer == 0) {
/*
* The only way this can happen is if the
@@ -559,8 +623,10 @@ receive(rbufp)
*/
if (!(peer->flags & FLAG_CONFIG)) {
if (has_mac) {
+ if (!(peer->reach && peer->keyid != hiskeyid)) {
peer->keyid = hiskeyid;
peer->flags |= FLAG_AUTHENABLE;
+ }
} else {
peer->keyid = 0;
peer->flags &= ~FLAG_AUTHENABLE;
@@ -577,8 +643,8 @@ receive(rbufp)
} else {
/*
* If this guy is authenable, and has been authenticated
- * in the past, but just failed the authentic test, report
- * the event.
+ * in the past, but just failed the authentic test,
+ * report the event.
*/
if (peer->flags & FLAG_AUTHENABLE
&& peer->flags & FLAG_AUTHENTIC)
@@ -595,38 +661,33 @@ receive(rbufp)
trustable = 1;
if (sys_authenticate && trustable) {
- if (!(peer->flags & FLAG_CONFIG)
- || (peer->flags & FLAG_AUTHENABLE))
- trustable = 0;
-
- if (has_mac) {
- if (authistrusted(hiskeyid)) {
- if (is_authentic) {
- trustable = 1;
- } else {
- trustable = 0;
- peer->badauth++;
- }
+ if (!(peer->flags & FLAG_CONFIG) ||
+ (peer->flags & FLAG_AUTHENABLE)) {
+ if (has_mac && is_authentic)
+ trustable = 1;
+ else
+ trustable = 0;
}
- }
}
/*
- * Dispose of the packet based on our respective modes. We
+ * Dispose of the packet based on our respective modes. We
* don't drive this with a table, though we probably could.
*/
switch (peer->hmode) {
case MODE_ACTIVE:
case MODE_CLIENT:
/*
- * Active mode associations are configured. If the data
- * isn't trustable, ignore it and hope this guy brightens
- * up. Else accept any data we get and process it.
+ * Active mode associations are configured. If the data
+ * isn't trustable, ignore it and hope this guy
+ * brightens up. Else accept any data we get and process
+ * it.
*/
switch (hismode) {
case MODE_ACTIVE:
case MODE_PASSIVE:
case MODE_SERVER:
+ case MODE_BROADCAST:
process_packet(peer, pkt, &(rbufp->recv_time),
has_mac, trustable);
break;
@@ -635,25 +696,20 @@ receive(rbufp)
if (peer->hmode == MODE_ACTIVE)
fast_xmit(rbufp, hismode, is_authentic);
return;
-
- case MODE_BROADCAST:
- /*
- * No good for us, we want real time.
- */
- break;
}
break;
case MODE_PASSIVE:
/*
* Passive mode associations are (in the current
- * implementation) always dynamic. If we get an
- * invalid header, break the connection. I hate
- * doing this since it seems like a waste. Oh, well.
+ * implementation) always dynamic. If we get an invalid
+ * header, break the connection. I hate doing this since
+ * it seems like a waste. Oh, well.
*/
switch (hismode) {
case MODE_ACTIVE:
- if (process_packet(peer, pkt, &(rbufp->recv_time),
+ if (process_packet(peer, pkt,
+ &(rbufp->recv_time),
has_mac, trustable) == 0) {
unpeer(peer);
clock_select();
@@ -680,34 +736,35 @@ receive(rbufp)
case MODE_BCLIENT:
/*
- * Broadcast client pseudo-mode. We accept both server
- * and broadcast data. Passive mode data is an error.
+ * Broadcast client pseudo-mode. We accept both server
+ * and broadcast data. Passive mode data is an error.
*/
switch (hismode) {
case MODE_ACTIVE:
/*
- * This guy wants to give us real time when we've
- * been existing on lousy broadcasts! Create a
- * passive mode association and do it that way,
- * but keep the old one in case the packet turns
- * out to be bad.
+ * This guy wants to give us real time when
+ * we've been existing on lousy broadcasts!
+ * Create a passive mode association and do it
+ * that way, but keep the old one in case the
+ * packet turns out to be bad.
*/
peer2 = newpeer(&rbufp->recv_srcadr,
rbufp->dstadr, MODE_PASSIVE,
PKT_VERSION(pkt->li_vn_mode),
NTP_MINDPOLL, NTP_MAXPOLL, 0, hiskeyid);
- if (process_packet(peer2, pkt, &rbufp->recv_time,
- has_mac, trustable) == 0) {
+ if (process_packet(peer2, pkt,
+ &rbufp->recv_time, has_mac, trustable) == 0) {
/*
- * Strange situation. We've been receiving
- * broadcasts from him which we liked, but
- * we don't like his active mode stuff.
- * Keep his old peer structure and send
- * him some time quickly, we'll figure it
- * out later.
+ * Strange situation. We've been
+ * receiving broadcasts from him which
+ * we liked, but we don't like his
+ * active mode stuff. Keep his old peer
+ * structure and send him some time
+ * quickly, we'll figure it out later.
*/
unpeer(peer2);
- fast_xmit(rbufp, (int)hismode, is_authentic);
+ fast_xmit(rbufp, (int)hismode,
+ is_authentic);
} else
/*
* Drop the old association
@@ -728,15 +785,40 @@ receive(rbufp)
*/
break;
}
+ break;
+
+ case MODE_MCLIENT:
+ /*
+ * This mode is temporary and does not appear outside
+ * this routine. It lasts only from the time the
+ * broadcast/multicast is recognized until the
+ * association is instantiated. Note that we start up in
+ * client/server mode to initially synchronize the
+ * clock.
+ */
+ switch (hismode) {
+ case MODE_BROADCAST:
+ peer->flags |= FLAG_MCAST1 | FLAG_MCAST2;
+ peer->hmode = MODE_CLIENT;
+ process_packet(peer, pkt, &rbufp->recv_time,
+ has_mac, trustable);
+ break;
+
+ case MODE_SERVER:
+ case MODE_PASSIVE:
+ case MODE_ACTIVE:
+ case MODE_CLIENT:
+ break;
+ }
}
}
/*
- * process_packet - Packet Procedure, a la Section 3.4.3 of the specification.
- * Or almost, at least. If we're in here we have a reasonable
- * expectation that we will be having a long term relationship
- * with this host.
+ * process_packet - Packet Procedure, a la Section 3.4.3 of the
+ * specification. Or almost, at least. If we're in here we have a
+ * reasonable expectation that we will be having a long term
+ * relationship with this host.
*/
int
process_packet(peer, pkt, recv_ts, has_mac, trustable)
@@ -746,12 +828,13 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
int has_mac;
int trustable; /* used as "valid header" */
{
- U_LONG t23_ui = 0, t23_uf = 0;
- U_LONG t10_ui, t10_uf;
+ l_fp t10, t23;
s_fp di, ei, p_dist, p_disp;
l_fp ci, p_rec, p_xmt, p_org;
int randomize;
u_char ostratum, oreach;
+ U_LONG temp;
+ u_fp precision;
sys_processed++;
peer->processed++;
@@ -780,49 +863,44 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
peer->bogusorg++;
peer->flash |= TEST2; /* bogus packet */
}
- if ((p_rec.l_ui == 0 && p_rec.l_uf == 0) ||
- (p_org.l_ui == 0 && p_org.l_uf == 0))
+ if (L_ISZERO(&p_rec) || L_ISZERO(&p_org))
peer->flash |= TEST3; /* unsynchronized */
} else {
- if (p_org.l_ui == 0 && p_org.l_uf == 0)
+ if (L_ISZERO(&p_org))
peer->flash |= TEST3; /* unsynchronized */
}
peer->org = p_xmt; /* reuse byte-swapped pkt->xmt */
peer->ppoll = pkt->ppoll;
/*
- * Call poll_update(). This will either start us, if the
+ * Call poll_update(). This will either start us, if the
* association is new, or drop the polling interval if the
* association is existing and ppoll has been reduced.
*/
poll_update(peer, peer->hpoll, randomize);
+
/*
* Test for valid header (tests 5 through 8)
*/
if (trustable == 0) /* test 5 */
peer->flash |= TEST5; /* authentication failed */
+ temp = ntohl(pkt->reftime.l_ui);
if (PKT_LEAP(pkt->li_vn_mode) == LEAP_NOTINSYNC || /* test 6 */
- p_xmt.l_ui < ntohl(pkt->reftime.l_ui) ||
- p_xmt.l_ui >= (ntohl(pkt->reftime.l_ui) + NTP_MAXAGE)) {
- peer->seltooold++; /* test 6 */
+ p_xmt.l_ui < temp || p_xmt.l_ui >= temp + NTP_MAXAGE)
peer->flash |= TEST6; /* peer clock unsynchronized */
- }
if (!(peer->flags & FLAG_CONFIG) && /* test 7 */
(PKT_TO_STRATUM(pkt->stratum) >= NTP_MAXSTRATUM ||
PKT_TO_STRATUM(pkt->stratum) > sys_stratum))
peer->flash |= TEST7; /* peer stratum out of bounds */
if (p_dist >= NTP_MAXDISPERSE /* test 8 */
|| p_dist <= (-NTP_MAXDISPERSE)
- || p_disp >= NTP_MAXDISPERSE) {
- peer->disttoolarge++;
+ || p_disp >= NTP_MAXDISPERSE)
peer->flash |= TEST8; /* delay/dispersion too big */
- }
/*
* If the packet header is invalid (tests 5 through 8), exit
*/
-
if (peer->flash & (TEST5 | TEST6 | TEST7 | TEST8)) {
#ifdef DEBUG
@@ -864,65 +942,78 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
peer->reach |= 1;
/*
- * If running in a normal polled association, calculate the round
- * trip delay (di) and the clock offset (ci). We use the equations
- * (reordered from those in the spec):
+ * If running in a client/server association, calculate the
+ * clock offset c, roundtrip delay d and dispersion e. We use
+ * the equations (reordered from those in the spec). Note that,
+ * in a broadcast association, org has been set to the time of
+ * last reception. Note the computation of dispersion includes
+ * the system precision plus that due to the frequency error
+ * since the originate time.
*
- * d = (t2 - t3) - (t1 - t0)
* c = ((t2 - t3) + (t1 - t0)) / 2
+ * d = (t2 - t3) - (t1 - t0)
+ * e = (org - rec) (seconds only)
+ */
+ t10 = p_xmt; /* compute t1 - t0 */
+ L_SUB(&t10, &peer->rec);
+ t23 = p_rec; /* compute t2 - t3 */
+ L_SUB(&t23, &p_org);
+ ci = t10;
+ precision = FP_SECOND >> -(int)sys_precision;
+ if (precision == 0)
+ precision = 1;
+ ei = precision + peer->rec.l_ui - p_org.l_ui;
+
+ /*
+ * If running in a broacast association, the clock offset is (t1
+ * - t0) corrected by the one-way delay, but we can't measure
+ * that directly; therefore, we start up in client/server mode,
+ * calculate the clock offset, using the engineered refinement
+ * algorithms, while also receiving broadcasts. When a broadcast
+ * is received in client/server mode, we calculate a correction
+ * factor to use after switching back to broadcast mode. We know
+ * NTP_SKEWFACTOR == 16, which accounts for the simplified ei
+ * calculation.
*
- * If running as a broadcast client, these change. di becomes
- * equal to two times our broadcast delay, while the offset
- * becomes equal to:
- *
- * c = (t1 - t0) + estbdelay
- */
- t10_ui = p_xmt.l_ui; /* pkt->xmt == t1 */
- t10_uf = p_xmt.l_uf;
- M_SUB(t10_ui, t10_uf, peer->rec.l_ui, peer->rec.l_uf); /*peer->rec==t0*/
-
- if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) {
- t23_ui = p_rec.l_ui; /* pkt->rec == t2 */
- t23_uf = p_rec.l_uf;
- M_SUB(t23_ui, t23_uf, p_org.l_ui, p_org.l_uf); /*pkt->org==t3*/
- }
+ * If FLAG_MCAST2 is set, we are a broadcast/multicast client.
+ * If FLAG_MCAST1 is set, we haven't calculated the propagation
+ * delay. If hmode is MODE_CLIENT, we haven't set the local
+ * clock in client/server mode. Initially, we come up
+ * MODE_CLIENT. When the clock is first updated and FLAG_MCAST2
+ * is set, we switch from MODE_CLIENT to MODE_BCLIENT.
+ */
+ if (peer->pmode == MODE_BROADCAST) {
+ if (peer->flags & FLAG_MCAST1) {
+ if (peer->hmode == MODE_BCLIENT)
+ peer->flags &= ~FLAG_MCAST1;
+ L_SUB(&ci, &peer->offset);
+ L_NEG(&ci);
+ peer->estbdelay = LFPTOFP(&ci);
+ return (1);
- /* now have (t2 - t3) and (t0 - t1). Calculate (ci), (di) and (ei) */
- ci.l_ui = t10_ui;
- ci.l_uf = t10_uf;
- ei = (FP_SECOND >> (-(int)sys_precision));
+ }
+ FPTOLFP(peer->estbdelay, &t10);
+ L_ADD(&ci, &t10);
+ di = peer->delay;
- /*
- * If broadcast mode, time of last reception has been fiddled
- * to p_org, rather than originate timestamp. We use this to
- * augment dispersion and previously calcuated estbdelay as
- * the delay. We know NTP_SKEWFACTOR == 16, which accounts for
- * the simplified ei calculation.
- */
- if (PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST) {
- M_ADDUF(ci.l_ui, ci.l_uf, peer->estbdelay >> 1);
- di = MFPTOFP(0, peer->estbdelay);
- ei += peer->rec.l_ui - p_org.l_ui;
} else {
- M_ADD(ci.l_ui, ci.l_uf, t23_ui, t23_uf);
- M_RSHIFT(ci.l_i, ci.l_uf);
- M_SUB(t23_ui, t23_uf, t10_ui, t10_uf);
- di = MFPTOFP(t23_ui, t23_uf);
- ei += peer->rec.l_ui - p_org.l_ui;
+ L_ADD(&ci, &t23);
+ L_RSHIFT(&ci);
+ L_SUB(&t23, &t10);
+ di = LFPTOFP(&t23);
}
+
#ifdef DEBUG
if (debug > 3)
printf("offset: %s, delay %s, error %s\n",
- lfptoa(&ci, 9), fptoa(di, 4), fptoa(ei, 4));
+ lfptoa(&ci, 6), fptoa(di, 5), fptoa(ei, 5));
#endif
if (di >= NTP_MAXDISPERSE || di <= (-NTP_MAXDISPERSE)
- || ei >= NTP_MAXDISPERSE) { /* test 4 */
- peer->bogusdelay++;
+ || ei >= NTP_MAXDISPERSE) /* test 4 */
peer->flash |= TEST4; /* delay/dispersion too big */
- }
/*
- * If the packet data is invalid (tests 1 through 4), exit
+ * If the packet data is invalid (tests 1 through 4), exit.
*/
if (peer->flash) {
@@ -942,28 +1033,25 @@ process_packet(peer, pkt, recv_ts, has_mac, trustable)
}
/*
- * This one is valid. Mark it so, give it to clock_filter(),
+ * This one is valid. Mark it so, give it to clock_filter().
*/
clock_filter(peer, &ci, di, (u_fp)ei);
/*
- * If this guy was previously unreachable, report him
- * reachable.
+ * If this guy was previously unreachable, report him reachable.
* Note we do this here so that the peer values we return are
* the updated ones.
*/
- if (oreach == 0) {
+ if (oreach == 0)
report_event(EVNT_REACH, peer);
-#ifdef DEBUG
- if (debug)
- printf("proto: peer reach %d\n", peer->minpoll);
-#endif /* DEBUG */
- }
/*
- * Now update the clock.
+ * Now update the clock. If we have found a system peer and this
+ * is a broadcast/multicast client, switch to listen mode.
*/
clock_update(peer);
+ if (sys_peer && peer->flags & FLAG_MCAST2)
+ peer->hmode = MODE_BCLIENT;
return(1);
}
@@ -985,103 +1073,67 @@ clock_update(peer)
printf("clock_update(%s)\n", ntoa(&peer->srcadr));
#endif
- record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), &peer->offset,
- peer->delay, peer->dispersion);
+ record_peer_stats(&peer->srcadr, ctlpeerstatus(peer),
+ &peer->offset, peer->delay, peer->dispersion);
/*
- * Call the clock selection algorithm to see
- * if this update causes the peer to change.
+ * Call the clock selection algorithm to see if this update
+ * causes the peer to change. If this is not the system peer,
+ * quit now.
*/
clock_select();
-
- /*
- * Quit if this peer isn't the system peer. Other peers
- * used in the combined offset are not allowed to set
- * system variables or update the clock.
- */
if (peer != sys_peer)
return;
/*
- * Quit if the sys_peer is too far away.
- */
- if (peer->synch >= NTP_MAXDISTANCE)
- return;
-
- /*
- * Update the system state
+ * Update the system state. This updates the system stratum,
+ * leap bits, root delay, root dispersion, reference ID and
+ * reference time. We also update select dispersion and max
+ * frequency error.
*/
oleap = sys_leap;
ostratum = sys_stratum;
- /*
- * get leap value (usually the peer leap unless overridden by local configuration)
- */
- sys_leap = leap_actual(peer->leap & leap_mask);
- /*
- * N.B. peer->stratum was guaranteed to be less than
- * NTP_MAXSTRATUM by the receive procedure.
- * We assume peer->update == sys_clock because
- * clock_filter was called right before this function.
- * If the pps signal is in control, the system variables are
- * set in the ntp_loopfilter.c module.
- */
- if (!pps_control) {
- sys_stratum = peer->stratum + 1;
- d = peer->delay;
- if (d < 0)
- d = -d;
- sys_rootdelay = peer->rootdelay + d;
- sys_maxd = peer->dispersion + peer->selectdisp;
- d = peer->soffset;
- if (d < 0)
- d = -d;
- d += sys_maxd;
- if (!peer->flags & FLAG_REFCLOCK && d < NTP_MINDISPERSE)
- d = NTP_MINDISPERSE;
- sys_rootdispersion = peer->rootdispersion + d;
- }
-
- /*
- * Hack for reference clocks. Sigh. This is the
- * only real silly part, though, so the analogy isn't
- * bad.
- */
- if (peer->flags & FLAG_REFCLOCK && peer->stratum == STRATUM_REFCLOCK)
- sys_refid = peer->refid;
- else {
- if (pps_control)
- memmove((char *)&sys_refid, PPSREFID, 4);
- else
- sys_refid = peer->srcadr.sin_addr.s_addr;
- }
+ sys_stratum = peer->stratum + 1;
+ if (sys_stratum == 1)
+ sys_refid = peer->refid;
+ else
+ sys_refid = peer->srcadr.sin_addr.s_addr;
+ sys_reftime = peer->rec;
+ d = peer->delay;
+ if (d < 0)
+ d = -d;
+ sys_rootdelay = peer->rootdelay + d;
+ d = peer->soffset;
+ if (d < 0)
+ d = -d;
+ d += peer->dispersion + peer->selectdisp;
+ if (!peer->flags & FLAG_REFCLOCK && d < NTP_MINDISPERSE)
+ d = NTP_MINDISPERSE;
+ sys_rootdispersion = peer->rootdispersion + d;
/*
- * Report changes. Note that we never sync to
- * an unsynchronized host.
+ * Reset/adjust the system clock. Watch for timewarps here.
*/
- if (oleap == LEAP_NOTINSYNC)
- report_event(EVNT_SYNCCHG, (struct peer *)0);
- else if (ostratum != sys_stratum)
- report_event(EVNT_PEERSTCHG, (struct peer *)0);
-
- sys_reftime = peer->rec;
- sys_refskew.l_i = 0; sys_refskew.l_f = NTP_SKEWINC;
-
switch (local_clock(&sys_offset, peer)) {
case -1:
+
/*
- * Clock is too screwed up. Just exit for now.
+ * Clock is too screwed up. Just exit for now.
*/
report_event(EVNT_SYSFAULT, (struct peer *)0);
exit(1);
/*NOTREACHED*/
case 0:
+
/*
* Clock was slewed. Continue on normally.
*/
+ sys_leap = leap_consensus & leap_mask;
+ L_CLR(&sys_refskew);
break;
case 1:
+
/*
* Clock was stepped. Clear filter registers
* of all peers.
@@ -1093,20 +1145,17 @@ clock_update(peer)
report_event(EVNT_CLOCKRESET, (struct peer *)0);
break;
}
- if (sys_stratum > 1)
- sys_refid = peer->srcadr.sin_addr.s_addr;
- else {
- if (peer->flags & FLAG_REFCLOCK)
- sys_refid = peer->refid;
- else
- memmove((char *)&sys_refid, PPSREFID, 4);
- }
+ sys_maxd = peer->dispersion + peer->selectdisp;
+ if (oleap != sys_leap)
+ report_event(EVNT_SYNCCHG, (struct peer *)0);
+ if (ostratum != sys_stratum)
+ report_event(EVNT_PEERSTCHG, (struct peer *)0);
}
-
/*
- * poll_update - update peer poll interval. See Section 3.4.8 of the spec.
+ * poll_update - update peer poll interval. See Section 3.4.8 of the
+ * spec.
*/
void
poll_update(peer, new_hpoll, randomize)
@@ -1115,7 +1164,7 @@ poll_update(peer, new_hpoll, randomize)
int randomize;
{
register struct event *evp;
- register U_LONG new_timer;
+ register u_long new_timer;
u_char newpoll, oldpoll;
#ifdef DEBUG
@@ -1127,7 +1176,8 @@ poll_update(peer, new_hpoll, randomize)
* Catch reference clocks here. The polling interval for a
* reference clock is fixed and needn't be maintained by us.
*/
- if (peer->flags & FLAG_REFCLOCK || peer->hmode == MODE_BROADCAST)
+ if (peer->flags & FLAG_REFCLOCK || peer->hmode ==
+ MODE_BROADCAST)
return;
/*
@@ -1163,9 +1213,10 @@ poll_update(peer, new_hpoll, randomize)
}
/* hpoll <= maxpoll for sure */
- newpoll = max((u_char)min(peer->ppoll, peer->hpoll), peer->minpoll);
- if (randomize == POLL_MAKERANDOM ||
- (randomize == POLL_RANDOMCHANGE && newpoll != oldpoll))
+ newpoll = max((u_char)min(peer->ppoll, peer->hpoll),
+ peer->minpoll);
+ if (randomize == POLL_MAKERANDOM || (randomize ==
+ POLL_RANDOMCHANGE && newpoll != oldpoll))
new_timer = (1 << (newpoll - 1))
+ ranp2(newpoll - 1) + current_time;
else
@@ -1190,24 +1241,14 @@ clear_all()
for (i = 0; i < HASH_SIZE; i++)
for (peer = peer_hash[i]; peer != 0; peer = peer->next) {
- /*
- * We used to drop all unconfigured pollers here.
- * The problem with doing this is that if your best
- * time source is unconfigured (there are reasons
- * for doing this) and you drop him, he may not
- * get around to polling you for a long time. Hang
- * on to everyone, dropping their polling intervals
- * to the minimum.
- */
peer_clear(peer);
}
/*
- * Clear sys_peer. We'll sync to one later.
+ * Clear sys_peer. We'll sync to one later.
*/
sys_peer = 0;
sys_stratum = STRATUM_UNSPEC;
-
}
@@ -1260,10 +1301,10 @@ clock_filter(peer, sample_offset, sample_delay, sample_error)
s_fp sample_delay;
u_fp sample_error;
{
- register int i;
+ register int i, j, k, n;
register u_char *ord;
- register s_fp sample_distance, sample_soffset, skew;
s_fp distance[NTP_SHIFT];
+ long skew, skewmax;
#ifdef DEBUG
if (debug)
@@ -1273,92 +1314,87 @@ clock_filter(peer, sample_offset, sample_delay, sample_error)
#endif
/*
- * Update sample errors and calculate distances.
- * We know NTP_SKEWFACTOR == 16
+ * Update sample errors and calculate distances. Also initialize
+ * sort index vector. We know NTP_SKEWFACTOR == 16
*/
skew = sys_clock - peer->update;
peer->update = sys_clock;
- for (i = 0; i < NTP_SHIFT; i++) {
- distance[i] = peer->filter_error[i];
- if (peer->filter_error[i] < NTP_MAXDISPERSE) {
- peer->filter_error[i] += skew;
- distance[i] += (peer->filter_delay[i] >> 1);
- }
- }
-
- /*
- * We keep a sort by distance of the current contents of the
- * shift registers. We update this by (1) removing the
- * register we are going to be replacing from the sort, and
- * (2) reinserting it based on the new distance value.
- */
ord = peer->filter_order;
- sample_distance = sample_error + (sample_delay >> 1);
- sample_soffset = LFPTOFP(sample_offset);
-
- for (i = 0; i < NTP_SHIFT-1; i++) /* find old value */
- if (ord[i] == peer->filter_nextpt)
- break;
- for ( ; i < NTP_SHIFT-1; i++) /* i is current, move everything up */
- ord[i] = ord[i+1];
- /* Here, last slot in ord[] is empty */
-
- if (sample_error >= NTP_MAXDISPERSE)
- /*
- * Last slot for this guy.
- */
- i = NTP_SHIFT-1;
- else {
- register int j;
- register u_fp *errorp;
-
- errorp = peer->filter_error;
- /*
- * Find where he goes in, then shift everyone else down
- */
- for (i = 0; i < NTP_SHIFT-1; i++)
- if (errorp[ord[i]] >= NTP_MAXDISPERSE
- || sample_distance <= distance[ord[i]])
- break;
-
- for (j = NTP_SHIFT-1; j > i; j--)
- ord[j] = ord[j-1];
+ j = peer->filter_nextpt;
+ for (i = 0; i < NTP_SHIFT; i++) {
+ peer->filter_error[j] += (u_fp)skew;
+ if (peer->filter_error[j] > NTP_MAXDISPERSE)
+ peer->filter_error[j] = NTP_MAXDISPERSE;
+ distance[i] = peer->filter_error[j] +
+ (peer->filter_delay[j] >> 1);
+ ord[i] = j;
+ if (--j < 0)
+ j += NTP_SHIFT;
}
- ord[i] = peer->filter_nextpt;
/*
- * Got everything in order. Insert sample in current register
- * and increment nextpt.
+ * Insert the new sample at the beginning of the register.
*/
peer->filter_delay[peer->filter_nextpt] = sample_delay;
peer->filter_offset[peer->filter_nextpt] = *sample_offset;
- peer->filter_soffset[peer->filter_nextpt] = sample_soffset;
+ peer->filter_soffset[peer->filter_nextpt] =
+ LFPTOFP(sample_offset);
peer->filter_error[peer->filter_nextpt] = sample_error;
- distance[peer->filter_nextpt] = sample_distance;
+ distance[0] = sample_error + (sample_delay >> 1);
+
+ /*
+ * Sort the samples in the register by distance. The winning
+ * sample will be in ord[0]. Sort the samples only if the
+ * samples are not too old and the delay is meaningful.
+ */
+ skewmax = 0;
+ for (n = 0; n < NTP_SHIFT && sample_delay; n++) {
+ for (j = 0; j < n && skewmax <
+ CLOCK_MAXSEC; j++) {
+ if (distance[j] > distance[n]) {
+ s_fp ftmp;
+
+ ftmp = distance[n];
+ k = ord[n];
+ distance[n] = distance[j];
+ ord[n] = ord[j];
+ distance[j] = ftmp;
+ ord[j] = k;
+ }
+ }
+ skewmax += (1 << peer->hpoll);
+ }
peer->filter_nextpt++;
if (peer->filter_nextpt >= NTP_SHIFT)
peer->filter_nextpt = 0;
/*
- * Now compute the dispersion, and assign values to delay and
- * offset. If there are no samples in the register, delay and
- * offset are not touched and dispersion is set to the maximum.
+ * We compute the dispersion as per the spec. Note that, to make
+ * things simple, both the l_fp and s_fp offsets are retained
+ * and that the s_fp could be nonsense if the l_fp is greater
+ * than about 32000 s. However, the sanity checks in
+ * ntp_loopfilter() require the l_fp offset to be less than 1000
+ * s anyway, so not to worry.
*/
if (peer->filter_error[ord[0]] >= NTP_MAXDISPERSE) {
peer->dispersion = NTP_MAXDISPERSE;
} else {
- register s_fp d;
+ s_fp d;
+ u_fp y;
peer->delay = peer->filter_delay[ord[0]];
peer->offset = peer->filter_offset[ord[0]];
peer->soffset = LFPTOFP(&peer->offset);
peer->dispersion = peer->filter_error[ord[0]];
- for (i = 1; i < NTP_SHIFT; i++) {
- if (peer->filter_error[ord[i]] >= NTP_MAXDISPERSE)
+
+ y = 0;
+ for (i = NTP_SHIFT - 1; i > 0; i--) {
+ if (peer->filter_error[ord[i]] >=
+ NTP_MAXDISPERSE)
d = NTP_MAXDISPERSE;
else {
- d = peer->filter_soffset[ord[i]]
- - peer->filter_soffset[ord[0]];
+ d = peer->filter_soffset[ord[i]] -
+ peer->filter_soffset[ord[0]];
if (d < 0)
d = -d;
if (d > NTP_MAXDISPERSE)
@@ -1367,24 +1403,22 @@ clock_filter(peer, sample_offset, sample_delay, sample_error)
/*
* XXX This *knows* NTP_FILTER is 1/2
*/
- peer->dispersion += (u_fp)(d) >> i;
+ y = ((u_fp)d + y) >> 1;
}
+ peer->dispersion += y;
+
/*
* Calculate synchronization distance backdated to
- * sys_lastselect (clock_select will fix it).
- * We know NTP_SKEWFACTOR == 16
+ * sys_lastselect (clock_select will fix it). We know
+ * NTP_SKEWFACTOR == 16.
*/
d = peer->delay;
if (d < 0)
d = -d;
d += peer->rootdelay;
- peer->synch = (d>>1)
- + peer->rootdispersion + peer->dispersion
- - (sys_clock - sys_lastselect);
+ peer->synch = (d >> 1) + peer->rootdispersion +
+ peer->dispersion - (sys_clock - sys_lastselect);
}
- /*
- * We're done
- */
}
@@ -1401,11 +1435,16 @@ clock_select()
register int j;
register int n;
register int allow, found, k;
- /* XXX correct? */
- s_fp low = 0x7ffffff;
- s_fp high = 0x00000000;
+ s_fp low = 0x7fffffff;
+ s_fp high = -0x7ffffff;
u_fp synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK];
struct peer *osys_peer;
+ struct peer *typeacts = 0;
+ struct peer *typelocal = 0;
+ struct peer *typepps = 0;
+ struct peer *typeprefer = 0;
+ struct peer *typesystem = 0;
+
static int list_alloc = 0;
static struct endpoint *endpoint;
static int *index;
@@ -1417,6 +1456,11 @@ clock_select()
printf("clock_select()\n");
#endif
+ /*
+ * Initizialize. If a prefer peer does not survive this thing,
+ * the pps_update switch will remain zero.
+ */
+ pps_update = 0;
nlist = 0;
for (n = 0; n < HASH_SIZE; n++)
nlist += peer_hash_count[n];
@@ -1459,22 +1503,24 @@ clock_select()
peer->flags &= ~FLAG_SYSPEER;
/*
- * Update synch distance (NTP_SKEWFACTOR == 16)
+ * Update synch distance (NTP_SKEWFACTOR == 16).
+ * Note synch distance check instead of spec
+ * dispersion check. Naughty.
*/
peer->synch += (sys_clock - sys_lastselect);
if (peer->reach == 0)
continue; /* unreachable */
- if (peer->stratum > 1 &&
- peer->refid == peer->dstadr->sin.sin_addr.s_addr)
+ if (peer->stratum > 1 && peer->refid ==
+ peer->dstadr->sin.sin_addr.s_addr)
continue; /* sync loop */
if (peer->stratum >= NTP_MAXSTRATUM ||
peer->stratum > sys_stratum)
continue; /* bad stratum */
- if (peer->dispersion >= NTP_MAXDISPERSE) {
+ if (peer->dispersion >= NTP_MAXDISTANCE) {
peer->seldisptoolarge++;
- continue; /* too noisy or broken */
+ continue; /* too noisy or broken */
}
if (peer->org.l_ui < peer->reftime.l_ui) {
peer->selbroken++;
@@ -1482,15 +1528,34 @@ clock_select()
}
/*
- * This one seems sane.
+ * Don't allow the local-clock or acts drivers
+ * in the kitchen at this point, unless the
+ * prefer peer. Do that later, but only if
+ * nobody else is around.
+ */
+ if (peer->refclktype == REFCLK_LOCALCLOCK) {
+ typelocal = peer;
+ if (!(peer->flags & FLAG_PREFER))
+ continue; /* no local clock */
+ }
+ if (peer->refclktype == REFCLK_NIST_ACTS) {
+ typeacts = peer;
+ if (!(peer->flags & FLAG_PREFER))
+ continue; /* no acts */
+ }
+
+ /*
+ * If we get this far, we assume the peer is
+ * acceptable.
*/
peer->was_sane = 1;
peer_list[nlist++] = peer;
/*
- * Insert each interval endpoint on the sorted list.
+ * Insert each interval endpoint on the sorted
+ * list.
*/
- e = peer->soffset + peer->synch; /* Upper end */
+ e = peer->soffset + peer->synch; /* Upper end */
for (i = nl3 - 1; i >= 0; i--) {
if (e >= endpoint[index[i]].val)
break;
@@ -1533,7 +1598,7 @@ clock_select()
i = 0;
j = nl3 - 1;
- allow = nlist; /* falsetickers assumed */
+ allow = nlist; /* falsetickers assumed */
found = 0;
while (allow > 0) {
allow--;
@@ -1556,14 +1621,30 @@ clock_select()
low = endpoint[index[i++]].val;
high = endpoint[index[j--]].val;
}
+
+ /*
+ * If no survivors remain at this point, check if the acts or
+ * local clock drivers have been found. If so, nominate one of
+ * them as the only survivor. Otherwise, give up and declare us
+ * unsynchronized.
+ */
if ((allow << 1) >= nlist) {
- if (debug)
- printf("clock_select: no intersection\n");
- if (sys_peer != 0)
- report_event(EVNT_PEERSTCHG, (struct peer *)0);
- sys_peer = 0;
- sys_stratum = STRATUM_UNSPEC;
- return;
+ if (typeacts != 0) {
+ typeacts->was_sane = 1;
+ peer_list[0] = typeacts;
+ nlist = 1;
+ } else if (typelocal != 0) {
+ typelocal->was_sane = 1;
+ peer_list[0] = typelocal;
+ nlist = 1;
+ } else {
+ if (sys_peer != 0)
+ report_event(EVNT_PEERSTCHG,
+ (struct peer *)0);
+ sys_peer = 0;
+ sys_stratum = STRATUM_UNSPEC;
+ return;
+ }
}
#ifdef DEBUG
@@ -1574,18 +1655,19 @@ clock_select()
/*
* Clustering algorithm. Process intersection list to discard
- * outlyers. First, construct candidate list in cluster order.
- * Cluster order is determined by the sum of peer
- * synchronization distance plus scaled stratum.
+ * outlyers. Construct candidate list in cluster order
+ * determined by the sum of peer synchronization distance plus
+ * scaled stratum. We must find at least one peer.
*/
-
j = 0;
for (i = 0; i < nlist; i++) {
peer = peer_list[i];
- if (peer->soffset < low || high < peer->soffset)
+ if (nlist > 1 && (peer->soffset < low || high <
+ peer->soffset))
continue;
peer->correct = 1;
- d = peer->synch + ((U_LONG)peer->stratum << NTP_DISPFACTOR);
+ d = peer->synch + ((u_long)peer->stratum <<
+ NTP_DISPFACTOR);
if (j >= NTP_MAXCLOCK) {
if (d >= synch[j - 1])
continue;
@@ -1603,6 +1685,7 @@ clock_select()
j++;
}
nlist = j;
+
#ifdef DEBUG
if (debug > 2)
for (i = 0; i < nlist; i++)
@@ -1612,9 +1695,11 @@ clock_select()
#endif
/*
- * Now, prune outlyers by root dispersion.
+ * Now, prune outlyers by root dispersion. Continue as long as
+ * there are more than NTP_MINCLOCK survivors and the minimum
+ * select dispersion is greater than the maximum peer
+ * dispersion. Stop if we are about to discard a preferred peer.
*/
-
for (i = 0; i < nlist; i++) {
peer = peer_list[i];
peer->candidate = i + 1;
@@ -1628,7 +1713,7 @@ clock_select()
for (k = i = nlist - 1; i >= 0; i--) {
u_fp sdisp = 0;
- for (j = nlist - 1; j >= 0; j--) {
+ for (j = nlist - 1; j > 0; j--) {
d = peer_list[i]->soffset
- peer_list[j]->soffset;
if (d < 0)
@@ -1665,43 +1750,96 @@ clock_select()
#endif
/*
- * What remains is a list of less than NTP_MINCLOCK peers.
- * First record their order, then choose a peer. If the
- * head of the list has a lower stratum than sys_peer
- * choose him right off. If not, see if sys_peer is in
- * the list. If so, keep him. If not, take the top of
- * the list anyway. Also, clamp the polling intervals.
- */
- osys_peer = sys_peer;
+ * What remains is a list of not greater than NTP_MINCLOCK
+ * peers. We want only a peer at the lowest stratum to become
+ * the system peer, although all survivors are eligible for the
+ * combining algorithm. First record their order, diddle the
+ * flags and clamp the poll intervals. Then, consider the peers
+ * at the lowest stratum. Of these, OR the leap bits on the
+ * assumption that, if some of them honk nonzero bits, they must
+ * know what they are doing. Also, check for prefer and pps
+ * peers. If a prefer peer is found within CLOCK_MAX, update the
+ * pps switch. Of the other peers not at the lowest stratum,
+ * check if the system peer is among them and, if found, zap
+ * him. We note that the head of the list is at the lowest
+ * stratum and that unsynchronized peers cannot survive this
+ * far.
+ */
+ leap_consensus = 0;
for (i = nlist - 1; i >= 0; i--) {
- if (peer_list[i]->flags & FLAG_PREFER)
- sys_peer = peer_list[i];
peer_list[i]->select = i + 1;
peer_list[i]->flags |= FLAG_SYSPEER;
poll_update(peer_list[i], peer_list[i]->hpoll,
POLL_RANDOMCHANGE);
- }
- if (sys_peer == 0 || sys_peer->stratum > peer_list[0]->stratum) {
- sys_peer = peer_list[0];
- } else {
- for (i = 1; i < nlist; i++)
+ if (peer_list[i]->stratum == peer_list[0]->stratum) {
+ leap_consensus |= peer_list[i]->leap;
+ if (peer_list[i]->refclktype == REFCLK_ATOM_PPS)
+ typepps = peer_list[i];
if (peer_list[i] == sys_peer)
- break;
- if (i >= nlist)
- sys_peer = peer_list[0];
+ typesystem = peer_list[i];
+ if (peer_list[i]->flags & FLAG_PREFER) {
+ typeprefer = peer_list[i];
+ if (typeprefer->soffset >= -CLOCK_MAX_FP &&
+ typeprefer->soffset < CLOCK_MAX_FP)
+ pps_update = 1;
+ }
+ } else {
+ if (peer_list[i] == sys_peer)
+ sys_peer = 0;
+ }
}
/*
- * If we got a new system peer from all of this, report the event.
+ * Mitigation rules of the game. There are several types of
+ * peers that make a difference here: (1) prefer local peers
+ * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer acts
+ * peers (type REFCLK_NIST_ATOM with FLAG_PREFER), (2) pps peers
+ * (type REFCLK_ATOM_PPS), (3) remaining prefer peers (flag
+ * FLAG_PREFER), (4) the existing system peer, if any, (5) the
+ * head of the survivor list. Note that only one peer can be
+ * declared prefer. The order of preference is in the order
+ * stated. Note that all of these must be at the lowest stratum,
+ * i.e., the stratum of the head of the survivor list.
*/
- if (osys_peer != sys_peer)
- report_event(EVNT_PEERSTCHG, (struct peer *)0);
+ osys_peer = sys_peer;
+ if (typeprefer && (typeprefer == typelocal || typeprefer ==
+ typeacts || !typepps)) {
+ sys_peer = typeprefer;
+ sys_peer->selectdisp = 0;
+ sys_offset = sys_peer->offset;
+#ifdef DEBUG
+ if (debug)
+ printf("select: prefer offset %s\n",
+ lfptoa(&sys_offset, 6));
+#endif
+ } else if (typepps) {
+ sys_peer = typepps;
+ sys_peer->selectdisp = 0;
+ sys_offset = sys_peer->offset;
+#ifdef DEBUG
+ if (debug)
+ printf("select: pps offset %s\n",
+ lfptoa(&sys_offset, 6));
+#endif
+ } else {
+ if (!typesystem)
+ sys_peer = peer_list[0];
+ clock_combine(peer_list, nlist);
+#ifdef DEBUG
+ if (debug)
+ printf("select: combine offset %s\n",
+ lfptoa(&sys_offset, 6));
+#endif
+ }
/*
- * Combine the offsets of the survivors to form a weighted
- * offset.
+ * If we got a new system peer from all of this, report the
+ * event and clamp the system poll interval.
*/
- clock_combine(peer_list, nlist);
+ if (osys_peer != sys_peer) {
+ sys_poll = sys_peer->minpoll;
+ report_event(EVNT_PEERSTCHG, (struct peer *)0);
+ }
}
/*
@@ -1722,21 +1860,12 @@ clock_combine(peers, npeers)
l_fp diff;
/*
- * Sort peers by cluster distance as in the outlyer algorithm. If
- * the preferred peer is found, use its offset only.
+ * Sort the offsets by synch distance.
*/
k = 0;
for (i = 0; i < npeers; i++) {
- if (peers[i]->stratum > sys_peer->stratum) continue;
- if (peers[i]->flags & FLAG_PREFER) {
- sys_offset = peers[i]->offset;
- pps_update = current_time;
-#ifdef DEBUG
- printf("combine: prefer offset %s\n",
- lfptoa(&sys_offset, 6));
-#endif
- return;
- }
+ if (peers[i]->stratum > sys_peer->stratum)
+ continue;
d = peers[i]->synch;
for (j = k; j > 0; j--) {
if (synch[j - 1] <= d)
@@ -1748,6 +1877,7 @@ clock_combine(peers, npeers)
coffset[j] = peers[i]->offset;
k++;
}
+
/*
* Succesively combine the two offsets with the highest
* distance and enter the result into the sorted list.
@@ -1774,6 +1904,7 @@ clock_combine(peers, npeers)
* we just drop the distant offset.
*/
continue;
+
/*
* The offsets are combined by shifting their
* difference the appropriate number of times and
@@ -1823,21 +1954,14 @@ clock_combine(peers, npeers)
synch[j] = d;
coffset[j] = diff;
}
+
/*
* The result is put where clock_update() can find it.
*/
sys_offset = coffset[0];
-
-#ifdef DEBUG
- if (debug) {
- printf("combine: offset %s\n", lfptoa(&sys_offset, 6));
- }
-#endif
-
}
-
/*
* fast_xmit - fast path send for stateless (non-)associations
*/
@@ -1853,6 +1977,7 @@ fast_xmit(rbufp, rmode, authentic)
u_short xkey = 0;
int docrypt = 0;
l_fp xmt_ts;
+ u_fp precision;
#ifdef DEBUG
if (debug > 1)
@@ -1880,9 +2005,11 @@ fast_xmit(rbufp, rmode, authentic)
xpkt.ppoll = max(NTP_MINPOLL, rpkt->ppoll);
xpkt.precision = sys_precision;
xpkt.rootdelay = HTONS_FP(sys_rootdelay);
+ precision = FP_SECOND >> -(int)sys_precision;
+ if (precision == 0)
+ precision = 1;
xpkt.rootdispersion = HTONS_FP(sys_rootdispersion +
- (FP_SECOND >> (-(int)sys_precision)) +
- LFPTOFP(&sys_refskew));
+ precision + LFPTOFP(&sys_refskew));
xpkt.refid = sys_refid;
HTONL_FP(&sys_reftime, &xpkt.reftime);
xpkt.org = rpkt->xmt;
@@ -1900,7 +2027,7 @@ fast_xmit(rbufp, rmode, authentic)
L_ADDUF(&xmt_ts, sys_authdelay);
HTONL_FP(&xmt_ts, &xpkt.xmt);
maclen = auth2crypt(xkey, (U_LONG *)&xpkt, LEN_PKT_NOMAC);
- sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt,
+ sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -9, &xpkt,
LEN_PKT_NOMAC + maclen);
} else {
/*
@@ -1908,50 +2035,32 @@ fast_xmit(rbufp, rmode, authentic)
*/
get_systime(&xmt_ts);
HTONL_FP(&xmt_ts, &xpkt.xmt);
- sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, &xpkt,
+ sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -10, &xpkt,
LEN_PKT_NOMAC);
}
}
-/* Find the precision of the system clock by watching how the current time
- * changes as we read it repeatedly.
- *
- * struct timeval is only good to 1us, which may cause problems as machines
- * get faster, but until then the logic goes:
- *
- * If a machine has precision (i.e. accurate timing info) > 1us, then it will
- * probably use the "unused" low order bits as a counter (to force time to be
- * a strictly increaing variable), incrementing it each time any process
- * requests the time [[ or maybe time will stand still ? ]].
- *
- * SO: the logic goes:
- *
- * IF the difference from the last time is "small" (< MINSTEP)
- * THEN this machine is "counting" with the low order bits
- * ELIF this is not the first time round the loop
- * THEN this machine *WAS* counting, and has now stepped
- * ELSE this machine has precision < time to read clock
- *
- * SO: if it exits on the first loop, assume "full accuracy" (1us)
- * otherwise, take the log2(observered difference, rounded UP)
- *
- * MINLOOPS > 1 ensures that even if there is a STEP between the initial call
- * and the first loop, it doesn't stop too early.
- * Making it even greater allows MINSTEP to be reduced, assuming that the
- * chance of MINSTEP-1 other processes getting in and calling gettimeofday
- * between this processes's calls.
- * Reducing MINSTEP may be necessary as this sets an upper bound for the time
- * to actually call gettimeofday.
+/*
+ * Find the precision of this particular machine
*/
+#define DUSECS 1000000 /* us in a s */
+#define HUSECS (1 << 20) /* approx DUSECS for shifting etc */
+#define MINSTEP 5 /* minimum clock increment (ys) */
+#define MAXSTEP 20000 /* maximum clock increment (us) */
+#define MINLOOPS 5 /* minimum number of step samples */
-#define DUSECS 1000000 /* us's as returned by gettime */
-#define HUSECS (1024*1024) /* Hex us's -- used when shifting etc */
-#define MINSTEP 5 /* some systems increment uS on each call */
- /* Don't use "1" as some *other* process may read too*/
- /*We assume no system actually *ANSWERS* in this time*/
-#define MAXLOOPS DUSECS /* if no STEP in a complete second, then FAST machine*/
-#define MINLOOPS 2 /* ensure at least this many loops */
-
+/*
+ * This routine calculates the differences between successive calls to
+ * gettimeofday(). If a difference is less than zero, the us field
+ * has rolled over to the next second, so we add a second in us. If
+ * the difference is greater than zero and less than MINSTEP, the
+ * clock has been advanced by a small amount to avoid standing still.
+ * If the clock has advanced by a greater amount, then a timer interrupt
+ * has occurred and this amount represents the precision of the clock.
+ * In order to guard against spurious values, which could occur if we
+ * happen to hit a fat interrupt, we do this for MINLOOPS times and
+ * keep the minimum value obtained.
+ */
int default_get_precision()
{
struct timeval tp;
@@ -1960,26 +2069,32 @@ int default_get_precision()
int i;
long diff;
long val;
- int minsteps = 2; /* need at least this many steps */
+ long usec;
+ usec = 0;
+ val = MAXSTEP;
GETTIMEOFDAY(&tp, &tzp);
last = tp.tv_usec;
- for (i = - --minsteps; i< MAXLOOPS; i++) {
- gettimeofday(&tp, &tzp);
+ for (i = 0; i < MINLOOPS && usec < HUSECS;) {
+ GETTIMEOFDAY(&tp, &tzp);
diff = tp.tv_usec - last;
- if (diff < 0) diff += DUSECS;
- if (diff > MINSTEP) if (minsteps-- <= 0) break;
last = tp.tv_usec;
+ if (diff < 0)
+ diff += DUSECS;
+ usec += diff;
+ if (diff > MINSTEP) {
+ i++;
+ if (diff < val)
+ val = diff;
+ }
}
-
- syslog(LOG_INFO, "precision calculation given %dus after %d loop%s",
- diff, i, (i==1) ? "" : "s");
-
- diff = (diff*3) / 2; /* round it up 1.5 is approx sqrt(2) */
- if (i >= MAXLOOPS) diff = 1; /* No STEP, so FAST machine */
- if (i == 0) diff = 1; /* time to read clock >= precision */
- for (i=0, val=HUSECS; val>0; i--, val >>= 1) if (diff >= val) return i;
- return DEFAULT_SYS_PRECISION /* Something's BUST, so lie ! */;
+ syslog(LOG_INFO, "precision = %d usec", val);
+ if (usec >= HUSECS)
+ val = MINSTEP; /* val <= MINSTEP; fast machine */
+ diff = HUSECS;
+ for (i = 0; diff > val; i--)
+ diff >>= 1;
+ return (i);
}
/*
@@ -1991,8 +2106,8 @@ init_proto()
l_fp dummy;
/*
- * Fill in the sys_* stuff. Default is don't listen
- * to broadcasting, don't authenticate.
+ * Fill in the sys_* stuff. Default is don't listen to
+ * broadcasting, don't authenticate.
*/
sys_leap = LEAP_NOTINSYNC;
sys_stratum = STRATUM_UNSPEC;
@@ -2000,7 +2115,7 @@ init_proto()
sys_rootdelay = 0;
sys_rootdispersion = 0;
sys_refid = 0;
- sys_reftime.l_ui = sys_reftime.l_uf = 0;
+ L_CLR(&sys_reftime);
sys_refskew.l_i = NTP_MAXSKEW; sys_refskew.l_f = 0;
sys_peer = 0;
sys_poll = NTP_MINPOLL;
@@ -2009,8 +2124,8 @@ init_proto()
sys_bclient = 0;
sys_bdelay = DEFBROADDELAY;
-
sys_authenticate = 0;
+ sys_authdelay = DEFAUTHDELAY;
sys_stattime = 0;
sys_badstratum = 0;
@@ -2021,7 +2136,11 @@ init_proto()
sys_processed = 0;
sys_badauth = 0;
- syslog(LOG_NOTICE, "default precision is initialized to 2**%d", sys_precision);
+ /*
+ * Default these to enable
+ */
+ pll_enable = 1;
+ stats_control = 1;
}
@@ -2031,12 +2150,36 @@ init_proto()
void
proto_config(item, value)
int item;
- U_LONG value;
+ u_long value;
{
/*
* Figure out what he wants to change, then do it
*/
switch (item) {
+ case PROTO_PLL:
+ /*
+ * Turn on/off pll clock correction
+ */
+ pll_enable = (int)value;
+ break;
+
+ case PROTO_MONITOR:
+ /*
+ * Turn on/off monitoring
+ */
+ if (value)
+ mon_start(MON_ON);
+ else
+ mon_stop(MON_ON);
+ break;
+
+ case PROTO_FILEGEN:
+ /*
+ * Turn on/off statistics
+ */
+ stats_control = (int)value;
+ break;
+
case PROTO_BROADCLIENT:
/*
* Turn on/off facility to listen to broadcasts
@@ -2049,25 +2192,19 @@ proto_config(item, value)
break;
case PROTO_MULTICAST_ADD:
- /*
- * Add multicast group address
- */
- if (!sys_bclient) {
- sys_bclient = 1;
- io_setbclient();
- }
-#ifdef MCAST
+ /*
+ * Add muliticast group address
+ */
+ sys_bclient = 1;
io_multicast_add(value);
-#endif /* MCAST */
break;
case PROTO_MULTICAST_DEL:
/*
* Delete multicast group address
*/
-#ifdef MCAST
+ sys_bclient = 1;
io_multicast_del(value);
-#endif /* MCAST */
break;
case PROTO_PRECISION:
@@ -2079,9 +2216,12 @@ proto_config(item, value)
case PROTO_BROADDELAY:
/*
- * Set default broadcast delay
+ * Set default broadcast delay (s_fp)
*/
- sys_bdelay = ((value) + 0x00000800) & 0xfffff000;
+ if (sys_bdelay < 0)
+ sys_bdelay = -(-value >> 16);
+ else
+ sys_bdelay = value >> 16;
break;
case PROTO_AUTHENTICATE:
@@ -2094,10 +2234,9 @@ proto_config(item, value)
case PROTO_AUTHDELAY:
/*
- * Provide an authentication delay value. Round it to
- * the microsecond. This is crude.
+ * Set authentication delay (l_fp fraction)
*/
- sys_authdelay = ((value) + 0x00000800) & 0xfffff000;
+ sys_authdelay = value;
break;
default:
diff --git a/usr.sbin/xntpd/xntpd/ntp_refclock.c b/usr.sbin/xntpd/xntpd/ntp_refclock.c
index 2cb7cc29d9a4..b0248fb80e12 100644
--- a/usr.sbin/xntpd/xntpd/ntp_refclock.c
+++ b/usr.sbin/xntpd/xntpd/ntp_refclock.c
@@ -1,112 +1,246 @@
-/* ntp_refclock.c,v 3.1 1993/07/06 01:11:25 jbj Exp
+/*
* ntp_refclock - processing support for reference clocks
*/
+#ifdef REFCLOCK
+
#include <stdio.h>
#include <sys/types.h>
#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
-#ifdef REFCLOCK
+#ifdef PPS
+#include <sys/ppsclock.h>
+#endif /* PPS */
+
/*
- * Reference clock support is provided here by maintaining the
- * fiction that the clock is actually a peer. As no packets are
- * exchanged with a reference clock, however, we replace the
- * transmit, receive and packet procedures with separate code
- * to simulate them. Refclock_transmit and refclock_receive
- * maintain the peer variables in a state analogous to an
- * actual peer and pass reference clock data on through the
- * filters. Refclock_peer and refclock_unpeer are called to
- * initialize and terminate reference clock associations.
+ * Reference clock support is provided here by maintaining the fiction
+ * that the clock is actually a peer. As no packets are exchanged with a
+ * reference clock, however, we replace the transmit, receive and packet
+ * procedures with separate code to simulate them. Routines
+ * refclock_transmit() and refclock_receive() maintain the peer
+ * variables in a state analogous to an actual peer and pass reference
+ * clock data on through the filters. Routines refclock_peer() and
+ * refclock_unpeer() are called to initialize and terminate reference
+ * clock associations. A set of utility routines is included to open
+ * serial devices, process sample data, edit input lines to extract
+ * embedded timestamps and to peform various debugging functions.
+ *
+ * The main interface used by these routines is the refclockproc
+ * structure, which contains for most drivers the decimal equivalants of
+ * the year, day, month, hour, second and millisecond/microsecond
+ * decoded from the ASCII timecode. Additional information includes the
+ * receive timestamp, exception report, statistics tallies, etc. In
+ * addition, there may be a driver-specific unit structure used for
+ * local control of the device.
+ *
+ * The support routines are passed a pointer to the peer structure,
+ * which is used for all peer-specific processing and contains a pointer
+ * to the refclockproc structure, which in turn containes a pointer to
+ * the unit structure, if used. In addition, some routines expect an
+ * address in the dotted quad form 127.127.t.u, where t is the clock
+ * type and u the unit. A table typeunit[type][unit] contains the peer
+ * structure pointer for each configured clock type and unit.
+ *
+ * Most drivers support the 1-pps signal provided by some radios and
+ * connected via a level converted described in the gadget directory.
+ * The signal is captured using a separate, dedicated serial port and
+ * the tty_clk line discipline/streams modules described in the kernel
+ * directory. For the highest precision, the signal is captured using
+ * the carrier-detect line of the same serial port using the ppsclock
+ * streams module described in the ppsclock directory.
*/
+#define REFCLOCKMAXDISPERSE (FP_SECOND/4) /* max sample dispersion */
+#define MAXUNIT 4 /* max units */
+#ifndef CLKLDISC
+#define CLKLDISC 10 /* XXX temp tty_clk line discipline */
+#endif
+#ifndef CHULDISC
+#define CHULDISC 10 /* XXX temp tty_chu line discipline */
+#endif
/*
- * The refclock configuration table. Imported from refclock_conf.c
+ * The refclock configuration table. Imported from refclock_conf
*/
-extern struct refclock *refclock_conf[];
-extern u_char num_refclock_conf;
+extern struct refclock *refclock_conf[];
+extern u_char num_refclock_conf;
/*
* Imported from the I/O module
*/
-extern struct interface *any_interface;
-extern struct interface *loopback_interface;
+extern struct interface *any_interface;
+extern struct interface *loopback_interface;
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
-extern struct event timerqueue[];
+extern u_long current_time;
+extern struct event timerqueue[];
/*
- * Imported from the main and peer modules. We use the same
- * algorithm for spacing out timers at configuration time that
- * the peer module does.
+ * Imported from the main and peer modules. We use the same algorithm
+ * for spacing out timers at configuration time that the peer module
+ * does.
*/
-extern U_LONG init_peer_starttime;
-extern int initializing;
-extern int debug;
+extern u_long init_peer_starttime;
+extern int initializing;
+extern int debug;
+
+/*
+ * Type/unit peer index. Used to find the peer structure for control and
+ * debugging. When all clock drivers have been converted to new style,
+ * this dissapears.
+ */
+static struct peer *typeunit[REFCLK_MAX + 1][MAXUNIT];
+
+
+/*
+ * refclock_report - note the occurance of an event
+ *
+ * This routine presently just remembers the report and logs it, but
+ * does nothing heroic for the trap handler. It tries to be a good
+ * citizen and bothers the system log only if things change.
+ */
+void
+refclock_report(peer, code)
+ struct peer *peer;
+ u_char code;
+{
+ struct refclockproc *pp;
+
+ if (!(pp = peer->procptr))
+ return;
+ if (code == CEVNT_BADREPLY)
+ pp->badformat++;
+ if (code == CEVNT_BADTIME)
+ pp->baddata++;
+ if (code == CEVNT_TIMEOUT)
+ pp->noreply++;
+ if (pp->currentstatus != code) {
+ pp->currentstatus = code;
+ if (code == CEVNT_NOMINAL)
+ return;
+ pp->lastevent = code;
+ if (code == CEVNT_FAULT)
+ syslog(LOG_ERR,
+ "clock %s fault %x", ntoa(&peer->srcadr), code);
+ else {
+ syslog(LOG_INFO,
+ "clock %s event %x", ntoa(&peer->srcadr), code);
+ }
+ }
+}
+
+
+/*
+ * init_refclock - initialize the reference clock drivers
+ *
+ * This routine calls each of the drivers in turn to initialize internal
+ * variables, if necessary. Most drivers have nothing to say at this
+ * point.
+ */
+void
+init_refclock()
+{
+ int i, j;
+
+ for (i = 0; i < num_refclock_conf; i++) {
+ if (refclock_conf[i]->clock_init != noentry)
+ (refclock_conf[i]->clock_init)();
+ for (j = 0; j < MAXUNIT; j++)
+ typeunit[i][j] = 0;
+ }
+}
-static void refclock_transmit P((struct peer *));
/*
* refclock_newpeer - initialize and start a reference clock
+ *
+ * This routine allocates and initializes the interface structure which
+ * supports a reference clock in the form of an ordinary NTP peer. A
+ * driver-specific support routine completes the initialization, if
+ * used. Default peer variables which identify the clock and establish
+ * its reference ID and stratum are set here. It returns one if success
+ * and zero if the clock address is invalid or already running,
+ * insufficient resources are available or the driver declares a bum
+ * rap.
*/
int
refclock_newpeer(peer)
- struct peer *peer;
+ struct peer *peer; /* peer structure pointer */
{
+ struct refclockproc *pp;
u_char clktype;
int unit;
/*
- * Sanity...
+ * Check for valid clock address. If already running, shut it * down first.
*/
if (!ISREFCLOCKADR(&peer->srcadr)) {
syslog(LOG_ERR,
- "Internal error: attempting to initialize %s as reference clock",
+ "refclock_newpeer: clock address %s invalid",
ntoa(&peer->srcadr));
- return 0;
+ return (0);
}
-
clktype = REFCLOCKTYPE(&peer->srcadr);
unit = REFCLOCKUNIT(&peer->srcadr);
+ if (clktype >= num_refclock_conf || unit > MAXUNIT ||
+ refclock_conf[clktype]->clock_start == noentry) {
+ syslog(LOG_ERR,
+ "refclock_newpeer: clock type %d invalid\n",
+ clktype);
+ return (0);
+ }
+ refclock_unpeer(peer);
/*
- * If clktype is invalid, return
+ * Allocate and initialize interface structure
*/
- if (clktype >= num_refclock_conf
- || refclock_conf[clktype]->clock_start == noentry) {
- syslog(LOG_ERR,
- "Can't initialize %s, no support for clock type %d\n",
- ntoa(&peer->srcadr), clktype);
- return 0;
- }
+ if (!(pp = (struct refclockproc *)
+ emalloc(sizeof(struct refclockproc))))
+ return (0);
+ memset((char *)pp, 0, sizeof(struct refclockproc));
+ typeunit[clktype][unit] = peer;
+ peer->procptr = pp;
/*
- * Complete initialization of peer structure.
+ * Initialize structures
*/
peer->refclktype = clktype;
peer->refclkunit = unit;
peer->flags |= FLAG_REFCLOCK;
- peer->stratum = STRATUM_REFCLOCK;
- peer->ppoll = peer->minpoll;
- peer->hpoll = peer->minpoll;
peer->event_timer.peer = peer;
peer->event_timer.event_handler = refclock_transmit;
+ pp->type = clktype;
+ pp->timestarted = current_time;
+ peer->stratum = STRATUM_REFCLOCK;
+ peer->refid = peer->srcadr.sin_addr.s_addr;
+ peer->maxpoll = peer->minpoll;
/*
* Do driver dependent initialization
*/
if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
- syslog(LOG_ERR, "Clock dependent initialization of %s failed",
- ntoa(&peer->srcadr));
- return 0;
+ free(pp);
+ return (0);
}
+ peer->hpoll = peer->minpoll;
+ peer->ppoll = peer->maxpoll;
+ if (peer->stratum <= 1)
+ peer->refid = pp->refid;
+ else
+ peer->refid = peer->srcadr.sin_addr.s_addr;
/*
- * Set up the timeout for reachability determination.
+ * Set up the timeout for polling and reachability determination
*/
if (initializing) {
init_peer_starttime += (1 << EVENT_TIMEOUT);
@@ -114,10 +248,11 @@ refclock_newpeer(peer)
init_peer_starttime = (1 << EVENT_TIMEOUT);
peer->event_timer.event_time = init_peer_starttime;
} else {
- peer->event_timer.event_time = current_time + (1 << peer->hpoll);
+ peer->event_timer.event_time = current_time +
+ (1 << peer->hpoll);
}
TIMER_ENQUEUE(timerqueue, &peer->event_timer);
- return 1;
+ return (1);
}
@@ -126,42 +261,50 @@ refclock_newpeer(peer)
*/
void
refclock_unpeer(peer)
- struct peer *peer;
+ struct peer *peer; /* peer structure pointer */
{
- /*
- * Do sanity checks. I know who programmed the calling routine!
- */
- if (peer->refclktype >= num_refclock_conf
- || refclock_conf[peer->refclktype]->clock_shutdown == noentry) {
- syslog(LOG_ERR, "Attempting to shutdown %s: no such clock!",
- ntoa(&peer->srcadr));
- return;
- }
+ u_char clktype;
+ int unit;
/*
- * Tell the driver we're finished.
+ * Wiggle the driver to release its resources, then give back
+ * the interface structure.
*/
- (refclock_conf[peer->refclktype]->clock_shutdown)(peer->refclkunit);
+ if (!peer->procptr)
+ return;
+ clktype = peer->refclktype;
+ unit = peer->refclkunit;
+ if (refclock_conf[clktype]->clock_shutdown != noentry)
+ (refclock_conf[clktype]->clock_shutdown)(unit, peer);
+ free(peer->procptr);
+ peer->procptr = 0;
}
/*
- * refclock_transmit - replacement transmit procedure for reference clocks
+ * refclock_transmit - simulate the transmit procedure
+ *
+ * This routine implements the NTP transmit procedure for a reference
+ * clock. This provides a mechanism to call the driver at the NTP poll
+ * interval, as well as provides a reachability mechanism to detect a
+ * broken radio or other madness.
*/
-static void
+void
refclock_transmit(peer)
- struct peer *peer;
+ struct peer *peer; /* peer structure pointer */
{
- u_char opeer_reach;
- int clktype;
+ struct refclockproc *pp;
+ u_char clktype;
int unit;
+ u_char opeer_reach;
+ pp = peer->procptr;
clktype = peer->refclktype;
unit = peer->refclkunit;
peer->sent++;
/*
- * The transmit procedure is supposed to freeze a time stamp.
+ * The transmit procedure is supposed to freeze a timestamp.
* Get one just for fun, and to tell when we last were here.
*/
get_systime(&peer->xmt);
@@ -173,9 +316,9 @@ refclock_transmit(peer)
peer->reach <<= 1;
if (peer->reach == 0) {
/*
- * Clear this one out. No need to redo
- * selection since this fellow will definitely
- * be suffering from dispersion madness.
+ * Clear this one out. No need to redo selection since
+ * this fellow will definitely be suffering from
+ * dispersion madness.
*/
if (opeer_reach != 0) {
peer_clear(peer);
@@ -187,12 +330,11 @@ refclock_transmit(peer)
* Update reachability and poll variables
*/
} else if ((opeer_reach & 3) == 0) {
-
l_fp off;
if (peer->valid > 0)
peer->valid--;
- off.l_ui = off.l_uf = 0;
+ L_CLR(&off);
clock_filter(peer, &off, 0, NTP_MAXDISPERSE);
if (peer->flags & FLAG_SYSPEER)
clock_select();
@@ -200,11 +342,13 @@ refclock_transmit(peer)
peer->valid++;
/*
- * If he wants to be polled, do it.
+ * If he wants to be polled, do it. New style drivers do not use
+ * the unit argument, since the fudge stuff is in the
+ * refclockproc structure.
*/
if (refclock_conf[clktype]->clock_poll != noentry)
(refclock_conf[clktype]->clock_poll)(unit, peer);
-
+
/*
* Finally, reset the timer
*/
@@ -214,22 +358,150 @@ refclock_transmit(peer)
/*
- * refclock_receive - simulate the receive and packet procedures for clocks
+ * Compare two l_fp's - used with qsort()
+ */
+static int
+refclock_cmpl_fp(p1, p2)
+ register void *p1, *p2; /* l_fp to compare */
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+
+/*
+ * refclock_process - process a pile of samples from the clock
+ *
+ * This routine converts the timecode in the form days, hours, miinutes,
+ * seconds, milliseconds/microseconds to internal timestamp format. It
+ * then calculates the difference from the receive timestamp and
+ * assembles the samples in a shift register. It implements a recursive
+ * median filter to suppress spikes in the data, as well as determine a
+ * rough dispersion estimate. A configuration constant time adjustment
+ * fudgetime1 can be added to the final offset to compensate for various
+ * systematic errors. The routine returns one if success and zero if
+ * failure due to invalid timecode data or very noisy offsets.
+ */
+int
+refclock_process(pp, nstart, nskeep)
+ struct refclockproc *pp; /* peer structure pointer */
+ int nstart; /* stages of median filter */
+ int nskeep; /* stages after outlyer trim */
+{
+ int i, n;
+ l_fp offset, median, lftmp;
+ l_fp off[MAXSTAGE];
+ u_fp disp;
+
+ /*
+ * Compute the timecode timestamp from the days, hours, minutes,
+ * seconds and milliseconds/microseconds of the timecode. Use
+ * clocktime() for the aggregate seconds and the msec/usec for
+ * the fraction, when present. Note that this code relies on the
+ * filesystem time for the years and does not use the years of
+ * the timecode.
+ */
+ pp->nstages = nstart;
+ if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
+ pp->lastrec.l_ui, &pp->yearstart, &pp->lastref.l_ui))
+ return (0);
+ if (pp->usec) {
+ TVUTOTSF(pp->usec, pp->lastref.l_uf);
+ } else {
+ MSUTOTSF(pp->msec, pp->lastref.l_uf);
+ }
+
+ /*
+ * Subtract the receive timestamp from the timecode timestamp
+ * to form the raw offset. Insert in the median filter shift
+ * register.
+ */
+ i = ((int)(pp->coderecv)) % pp->nstages;
+ offset = pp->lastref;
+ L_SUB(&offset, &pp->lastrec);
+ pp->filter[i] = offset;
+ if (pp->coderecv == 0)
+ for (i = 1; i < pp->nstages; i++)
+ pp->filter[i] = pp->filter[0];
+ pp->coderecv++;
+
+ /*
+ * Copy the raw offsets and sort into ascending order
+ */
+ for (i = 0; i < pp->nstages; i++)
+ off[i] = pp->filter[i];
+ qsort((char *)off, pp->nstages, sizeof(l_fp), refclock_cmpl_fp);
+
+ /*
+ * Reject the furthest from the median of nstages samples until
+ * nskeep samples remain.
+ */
+ i = 0;
+ n = pp->nstages;
+ while ((n - i) > nskeep) {
+ lftmp = off[n - 1];
+ median = off[(n + i) / 2];
+ L_SUB(&lftmp, &median);
+ L_SUB(&median, &off[i]);
+ if (L_ISHIS(&median, &lftmp)) {
+ /* reject low end */
+ i++;
+ } else {
+ /* reject high end */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets. Add to this the time since
+ * the last clock update, which represents the dispersion
+ * increase with time. We know that NTP_MAXSKEW is 16. If the
+ * sum is greater than the allowed sample dispersion, bail out.
+ * If the loop is unlocked, return the most recent offset;
+ * otherwise, return the median offset. In either case include
+ * the configured fudgetime1 adjustment.
+ */
+ lftmp = off[n - 1];
+ L_SUB(&lftmp, &off[i]);
+ disp = LFPTOFP(&lftmp) + current_time - pp->lasttime;
+ if (disp > REFCLOCKMAXDISPERSE)
+ return (0);
+ pp->offset = offset;
+ L_ADD(&pp->offset, &pp->fudgetime1);
+ pp->dispersion = disp;
+ return (1);
+}
+
+
+/*
+ * refclock_receive - simulate the receive and packet procedures
+ *
+ * This routine simulates the NTP receive and packet procedures for a
+ * reference clock. This provides a mechanism in which the ordinary NTP
+ * filter, selection and combining algorithms can be used to suppress
+ * misbehaving radios and to mitigate between them when more than one is
+ * available for backup.
*/
void
refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)
- struct peer *peer;
- l_fp *offset;
- s_fp delay;
- u_fp dispersion;
- l_fp *reftime;
- l_fp *rectime;
- int leap;
+ struct peer *peer; /* peer structure pointer */
+ l_fp *offset; /* computed offset (s) */
+ s_fp delay; /* computed delay to peer */
+ u_fp dispersion; /* computed dispersion to peer */
+ l_fp *reftime; /* time at last clock update */
+ l_fp *rectime; /* time at last peer update */
+ int leap; /* synchronization/leap code */
{
int restrict;
int trustable;
- extern u_char leap_indicator;
+ u_fp precision;
+ peer->received++;
#ifdef DEBUG
if (debug)
printf("refclock_receive: %s %s %s %s)\n",
@@ -238,20 +510,12 @@ refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)
#endif
/*
- * The name of this routine is actually a misnomer since
- * we mostly simulate the variable setting of the packet
- * procedure. We do check the flag values, though, and
- * set the trust bits based on this.
+ * The authentication and access-control machinery works, but
+ * its utility may be questionable.
*/
restrict = restrictions(&peer->srcadr);
- if (restrict & (RES_IGNORE|RES_DONTSERVE)) {
- /*
- * Ours is not to reason why...
- */
+ if (restrict & (RES_IGNORE|RES_DONTSERVE))
return;
- }
-
- peer->received++;
peer->processed++;
peer->timereceived = current_time;
if (restrict & RES_DONTTRUST)
@@ -265,155 +529,758 @@ refclock_receive(peer, offset, delay, dispersion, reftime, rectime, leap)
else
peer->flags &= ~FLAG_AUTHENTIC;
}
- if (leap == 0)
- peer->leap = leap_indicator;
- else
- peer->leap = leap;
+ peer->leap = leap;
/*
- * Set the timestamps. rec and org are in local time,
- * while ref is in timecode time.
+ * Set the timestamps. rec and org are in local time, while ref
+ * is in timecode time.
*/
peer->rec = peer->org = *rectime;
peer->reftime = *reftime;
/*
- * If the interface has been set to any_interface, set it
- * to the loop back address if we have one. This is so
- * that peers which are unreachable are easy to see in
- * peer display.
+ * If the interface has been set to any_interface, set it to the
+ * loopback address if we have one. This is so that peers which
+ * are unreachable are easy to see in the peer display.
*/
if (peer->dstadr == any_interface && loopback_interface != 0)
peer->dstadr = loopback_interface;
/*
- * Set peer.pmode based on the hmode. For appearances only.
+ * Set peer.pmode based on the hmode. For appearances only.
*/
switch (peer->hmode) {
+
case MODE_ACTIVE:
peer->pmode = MODE_PASSIVE;
break;
- case MODE_CLIENT:
+
+ default:
peer->pmode = MODE_SERVER;
break;
- default:
- syslog(LOG_ERR, "refclock_receive: internal error, mode = %d",
- peer->hmode);
}
/*
* Abandon ship if the radio came bum. We only got this far
* in order to make pretty billboards, even if bum.
*/
- if (leap == LEAP_NOTINSYNC) return;
+ if (leap == LEAP_NOTINSYNC)
+ return;
/*
* If this guy was previously unreachable, report him
* reachable.
*/
if (peer->reach == 0) report_event(EVNT_REACH, peer);
- peer->reach |= 1;
+ peer->reach |= 1;
/*
- * Give the data to the clock filter and update the clock.
+ * Give the data to the clock filter and update the clock. Note
+ * the clock reading precision initialized by the driver is
+ * added at this point.
*/
- clock_filter(peer, offset, delay, dispersion);
+ precision = FP_SECOND >> -(int)peer->precision;
+ if (precision == 0)
+ precision = 1;
+ refclock_report(peer, CEVNT_NOMINAL);
+ clock_filter(peer, offset, delay, dispersion + precision);
clock_update(peer);
}
/*
- * refclock_control - set and/or return clock values
+ * refclock_gtlin - groom next input line and extract timestamp
+ *
+ * This routine processes the timecode received from the clock and
+ * removes the parity bit and control characters. If a timestamp is
+ * present in the timecode, as produced by the tty_clk line
+ * discipline/streams module, it returns that as the timestamp;
+ * otherwise, it returns the buffer timestamp. The routine return code
+ * is the number of characters in the line.
*/
-void
-refclock_control(srcadr, in, out)
- struct sockaddr_in *srcadr;
- struct refclockstat *in;
- struct refclockstat *out;
+int
+refclock_gtlin(rbufp, lineptr, bmax, tsptr)
+ struct recvbuf *rbufp; /* receive buffer pointer */
+ char *lineptr; /* current line pointer */
+ int bmax; /* remaining characters in line */
+ l_fp *tsptr; /* pointer to timestamp returned */
{
- u_char clktype;
- int unit;
+ char *dpt, *dpend, *dp;
+ int i;
+ l_fp trtmp, tstmp;
+ char c;
+
+ /*
+ * Check for the presence of a timestamp left by the tty_clock
+ * line discipline/streams module and, if present, use that
+ * instead of the buffer timestamp captured by the I/O routines.
+ * We recognize a timestamp by noting its value is earlier than
+ * the buffer timestamp, but not more than one second earlier.
+ */
+ dpt = (char *)&rbufp->recv_space;
+ dpend = dpt + rbufp->recv_length;
+ trtmp = rbufp->recv_time;
+ if (dpend >= dpt + 8) {
+ if (buftvtots(dpend - 8, &tstmp)) {
+ L_SUB(&trtmp, &tstmp);
+ if (trtmp.l_ui == 0) {
+#ifdef DEBUG
+ if (debug) {
+ printf(
+ "refclock_gtlin: fd %d ldisc %s",
+ rbufp->fd,
+ lfptoa(&trtmp, 6));
+ gettstamp(&trtmp);
+ L_SUB(&trtmp, &tstmp);
+ printf(" sigio %s\n",
+ lfptoa(&trtmp, 6));
+ }
+#endif
+ dpend -= 8;
+ trtmp = tstmp;
+ } else
+ trtmp = rbufp->recv_time;
+ }
+ }
+
+ /*
+ * Edit timecode to remove control chars. Don't monkey with the
+ * line buffer if the input buffer contains no ASCII printing
+ * characters.
+ */
+ if (dpend - dpt > bmax - 1)
+ dpend = dpt + bmax - 1;
+ for (dp = lineptr; dpt < dpend; dpt++) {
+ c = *dpt & 0x7f;
+ if (c >= ' ')
+ *dp++ = c;
+ }
+ i = dp - lineptr;
+ if (i > 0)
+ *dp = '\0';
+
+#ifdef DEBUG
+ if (debug)
+ printf("refclock_gtlin: fd %d time %s timecode %d %s\n",
+ rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
+#endif
+ *tsptr = trtmp;
+ return (i);
+}
+
+
+/*
+ * refclock_open - open serial port for reference clock
+ *
+ * This routine opens a serial port for I/O and sets default options. It
+ * returns the file descriptor if success and zero if failure.
+ */
+int
+refclock_open(dev, speed, flags)
+ char *dev; /* device name pointer */
+ int speed; /* serial port speed (code) */
+ int flags; /* line discipline flags */
+{
+ int fd;
+#ifdef HAVE_TERMIOS
+ struct termios ttyb, *ttyp;
+#endif /* HAVE_TERMIOS */
+#ifdef HAVE_SYSV_TTYS
+ struct termio ttyb, *ttyp;
+#endif /* HAVE_SYSV_TTYS */
+#ifdef HAVE_BSD_TTYS
+ struct sgttyb ttyb, *ttyp;
+#endif /* HAVE_BSD_TTYS */
+#ifdef HAVE_MODEM_CONTROL
+ u_long ltemp;
+#endif /* HAVE_MODEM_CONTROL */
+
+ /*
+ * Open serial port and set default options
+ */
+ fd = open(dev, O_RDWR, 0777);
+ if (fd == -1) {
+ syslog(LOG_ERR, "refclock_open: %s: %m", dev);
+ return (0);
+ }
+
+ /*
+ * The following sections initialize the serial line port in
+ * canonical (line-oriented) mode and set the specified line
+ * speed, 8 bits and no parity. The modem control, break, erase
+ * and kill functions are normally disabled. There is a
+ * different section for each terminal interface, as selected at
+ * compile time.
+ */
+ ttyp = &ttyb;
+#ifdef HAVE_TERMIOS
/*
- * Sanity...
+ * POSIX serial line parameters (termios interface)
*/
- if (!ISREFCLOCKADR(srcadr)) {
+ if (tcgetattr(fd, ttyp) < 0) {
syslog(LOG_ERR,
- "Internal error: refclock_control received %s as reference clock",
- ntoa(srcadr));
- return;
+ "refclock_open: fd %d tcgetattr %m", fd);
+ return (0);
}
- clktype = REFCLOCKTYPE(srcadr);
- unit = REFCLOCKUNIT(srcadr);
+ /*
+ * Set canonical mode and local connection; set specified speed,
+ * 8 bits and no parity; map CR to NL; ignore break.
+ */
+ ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = CS8 | CLOCAL | CREAD;
+ (void)cfsetispeed(&ttyb, speed);
+ (void)cfsetospeed(&ttyb, speed);
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+#ifdef HAVE_MODEM_CONTROL
+ /*
+ * If we have modem control, check to see if modem leads are
+ * active; if so, set remote connection. This is necessary for
+ * the kernel pps mods to work.
+ */
+ ltemp = 0;
+ if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
+ syslog(LOG_ERR,
+ "refclock_open: fd %d TIOCMGET %m", fd);
+#if DEBUG
+ if (debug)
+ printf("refclock_open: fd %d modem status %lx\n",
+ fd, ltemp);
+#endif
+ if (ltemp & TIOCM_DSR)
+ ttyp->c_cflag &= ~CLOCAL;
+#endif /* HAVE_MODEM_CONTROL */
+ if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "refclock_open: fd %d tcsetattr %m", fd);
+ return (0);
+ }
+ if (tcflush(fd, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "refclock_open: fd %d tcflush %m", fd);
+ return (0);
+ }
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_SYSV_TTYS
/*
- * If clktype is invalid, return
+ * System V serial line parameters (termio interface)
+ *
*/
- if (clktype >= num_refclock_conf
- || refclock_conf[clktype]->clock_control == noentry) {
+ if (ioctl(fd, TCGETA, ttyp) < 0) {
syslog(LOG_ERR,
- "Internal error: refclock_control finds %s as not supported",
- ntoa(srcadr));
- return;
+ "refclock_open: fd %d TCGETA %m", fd);
+ return (0);
}
/*
- * Give the stuff to the clock.
+ * Set canonical mode and local connection; set specified speed,
+ * 8 bits and no parity; map CR to NL; ignore break.
+ */
+ ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+#ifdef HAVE_MODEM_CONTROL
+ /*
+ * If we have modem control, check to see if modem leads are
+ * active; if so, set remote connection. This is necessary for
+ * the kernel pps mods to work.
*/
- (refclock_conf[clktype]->clock_control)(unit, in, out);
+ ltemp = 0;
+ if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
+ syslog(LOG_ERR,
+ "refclock_open: fd %d TIOCMGET %m", fd);
+#if DEBUG
+ if (debug)
+ printf("refclock_open: fd %d modem status %lx\n",
+ fd, ltemp);
+#endif
+ if (ltemp & TIOCM_DSR)
+ ttyp->c_cflag &= ~CLOCAL;
+#endif /* HAVE_MODEM_CONTROL */
+ if (ioctl(fd, TCSETA, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "refclock_open: fd %d TCSETA %m", fd);
+ return (0);
+ }
+#endif /* HAVE_SYSV_TTYS */
+
+#ifdef HAVE_BSD_TTYS
+
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ */
+ if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
+ syslog(LOG_ERR,
+ "refclock_open: fd %d TIOCGETP %m", fd);
+ return (0);
+ }
+ ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
+ ttyp->sg_flags = EVENP | ODDP | CRMOD;
+ if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
+ syslog(LOG_ERR,
+ "refclock_open: TIOCSETP %m");
+ return (0);
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ if (!refclock_ioctl(fd, flags)) {
+ (void)close(fd);
+ syslog(LOG_ERR, "refclock_open: fd %d ioctl fails",
+ fd);
+ return (0);
+ }
+ return (fd);
}
+/*
+ * refclock_ioctl - set serial port control functions
+ *
+ * This routine attempts to hide the internal, system-specific details
+ * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
+ * (sgtty) interfaces with varying degrees of success. The routine sets
+ * up the tty_clk, chu_clk and ppsclock streams module/line discipline,
+ * if compiled in the daemon and requested in the call. The routine
+ * returns one if success and zero if failure.
+ */
+int
+refclock_ioctl(fd, flags)
+ int fd; /* file descriptor */
+ int flags; /* line discipline flags */
+{
+#ifdef HAVE_TERMIOS
+ struct termios ttyb, *ttyp;
+#endif /* HAVE_TERMIOS */
+#ifdef HAVE_SYSV_TTYS
+ struct termio ttyb, *ttyp;
+#endif /* HAVE_SYSV_TTYS */
+#ifdef HAVE_BSD_TTYS
+ struct sgttyb ttyb, *ttyp;
+#endif /* HAVE_BSD_TTYS */
+
+#ifdef DEBUG
+ if (debug)
+ printf("refclock_ioctl: fd %d flags %x\n",
+ fd, flags);
+#endif
+
+ /*
+ * The following sections select optional features, such as
+ * modem control, line discipline and so forth. Some require
+ * specific operating system support in the form of streams
+ * modules, which can be loaded and unloaded at run time without
+ * rebooting the kernel, or line discipline modules, which must
+ * be compiled in the kernel. The streams modules require System
+ * V STREAMS support, while the line discipline modules require
+ * 4.3bsd or later. The checking frenzy is attenuated here,
+ * since the device is already open.
+ *
+ * Note that both the clk and ppsclock modules are optional; the
+ * dang thing still works, but the accuracy improvement using
+ * them will not be available. The ppsclock module is associated
+ * with a specific, declared line and should be used only once.
+ * If requested, the chu module is mandatory, since the driver
+ * will not work without it.
+ *
+ * Use the LDISC_PPS option ONLY with Sun baseboard ttya or
+ * ttyb. Using it with the SPIF multipexor crashes the kernel.
+ */
+ if (flags == 0)
+ return (1);
+
+#if !(defined(HAVE_TERMIOS) || defined(HAVE_BSD_TTYS))
+ if (flags & (LDISC_CLK | LDISC_CHU | LDISC_PPS | LDISC_ACTS))
+ syslog(LOG_ERR,
+ "refclock_ioctl: unsupported terminal interface");
+ return (0);
+#endif /* HAVE_TERMIOS HAVE_BSD_TTYS */
+
+ ttyp = &ttyb;
+
+#ifdef STREAM
+#ifdef CLK
+
+ /*
+ * The CLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module and System V STREAMS
+ * support.
+ */
+ if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
+ if (ioctl(fd, I_PUSH, "clk") < 0)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional clk streams module unavailable");
+ else {
+ char *str;
+
+ if (flags & LDISC_PPS)
+ str = "\377";
+ else if (flags & LDISC_ACTS)
+ str = "*";
+ else
+ str = "\n";
+ if (ioctl(fd, CLK_SETSTR, str) < 0)
+ syslog(LOG_ERR,
+ "refclock_ioctl: CLK_SETSTR %m");
+ }
+ }
+
+ /*
+ * The ACTS line discipline requires additional line-ending
+ * character '*'.
+ */
+ if (flags & LDISC_ACTS) {
+ (void)tcgetattr(fd, ttyp);
+ ttyp->c_cc[VEOL] = '*';
+ (void)tcsetattr(fd, TCSANOW, ttyp);
+ }
+#else
+ if (flags & LDISC_CLK)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional clk streams module unsupported");
+#endif /* CLK */
+#ifdef CHU
+
+ /*
+ * The CHU option provides timestamping and decoding for the CHU
+ * timecode. It requires the tty_chu streams module and System V
+ * STREAMS support.
+ */
+ if (flags & LDISC_CHU) {
+ (void)tcgetattr(fd, ttyp);
+ ttyp->c_lflag = 0;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ ttyp->c_cc[VMIN] = 1;
+ ttyp->c_cc[VTIME] = 0;
+ (void)tcsetattr(fd, TCSANOW, ttyp);
+ (void)tcflush(fd, TCIOFLUSH);
+ while (ioctl(fd, I_POP, 0) >= 0);
+ if (ioctl(fd, I_PUSH, "chu") < 0) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: required chu streams module unavailable");
+ return (0);
+ }
+ }
+#else
+ if (flags & LDISC_CHU) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: required chu streams module unsupported");
+ return (0);
+ }
+#endif /* CHU */
+#ifdef PPS
+
+ /*
+ * The PPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and System V STREAMS
+ * support.
+ */
+ if (flags & LDISC_PPS) {
+ if (fdpps != -1) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: ppsclock already configured");
+ return (0);
+ }
+ if (ioctl(fd, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional ppsclock streams module unavailable");
+ else
+ fdpps = fd;
+ }
+#else
+ if (flags & LDISC_PPS)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional ppsclock streams module unsupported");
+#endif /* PPS */
+
+#else /* STREAM */
+
+#ifdef HAVE_TERMIOS
+#ifdef CLK
+
+ /*
+ * The CLK option provides timestamping at the driver level. It
+ * requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
+ (void)tcgetattr(fd, ttyp);
+ ttyp->c_lflag = 0;
+ if (flags & LDISC_CLKPPS)
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\377';
+ else if (flags & LDISC_ACTS) {
+ ttyp->c_cc[VERASE] = '*';
+ ttyp->c_cc[VKILL] = '#';
+ } else
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\n';
+ ttyp->c_cc[VMIN] = 1;
+ ttyp->c_cc[VTIME] = 0;
+ ttyp->c_line = CLKLDISC;
+ (void)tcsetattr(fd, TCSANOW, ttyp);
+ (void)tcflush(fd, TCIOFLUSH);
+ }
+#else
+ if (flags & LDISC_CLK)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional clk line discipline unsupported");
+#endif /* CLK */
+#ifdef CHU
+ /*
+ * The CHU option provides timestamping and decoding for the CHU
+ * timecode. It requires the tty_chu line disciplne and 4.3bsd
+ * or later.
+ */
+ if (flags & LDISC_CHU) {
+ (void)tcgetattr(fd, ttyp);
+ ttyp->c_lflag = 0;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\r';
+ ttyp->c_cc[VMIN] = 1;
+ ttyp->c_cc[VTIME] = 0;
+ ttyp->c_line = CHULDISC;
+ (void)tcsetattr(fd, TCSANOW, ttyp) < 0);
+ (void)tcflush(fd, TCIOFLUSH);
+ }
+#else
+ if (flags & LDISC_CHU) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: required chu line discipline unsupported");
+ return (0);
+ }
+#endif /* CHU */
+#endif /* HAVE_TERMIOS */
+
+#ifdef HAVE_BSD_TTYS
+#ifdef CLK
+
+ /*
+ * The CLK option provides timestamping at the driver level. It
+ * requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ if (flags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
+ int ldisc = CLKLDISC;
+
+ (void)ioctl(fd, TIOCGETP, (char *)ttyp);
+ if (flags & LDISC_CLKPPS)
+ ttyp->sg_erase = ttyp->sg_kill = '\377';
+ else if (flags & LDISC_ACTS) {
+ ttyp->sg_erase = '*';
+ ttyp->sg_kill = '#';
+ } else
+ ttyp->sg_erase = ttyp->sg_kill = '\r';
+ ttyp->sg_flags = RAW;
+ (void)ioctl(fd, TIOCSETP, ttyp);
+ if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional clk line discipline unavailable");
+ }
+#else
+ if (flags & LDISC_CLK)
+ syslog(LOG_NOTICE,
+ "refclock_ioctl: optional clk line discipline unsupported");
+
+#endif /* CLK */
+#ifdef CHU
+
+ /*
+ * The CHU option provides timestamping and decoding for the CHU
+ * timecode. It requires the tty_chu line disciplne and 4.3bsd
+ * or later.
+ */
+ if (flags & LDISC_CHU) {
+ int ldisc = CHULDISC;
+
+ (void)ioctl(fd, TIOCGETP, (char *)ttyp);
+ ttyp->sg_erase = ttyp->sg_kill = '\r';
+ ttyp->sg_flags = RAW;
+ (void)ioctl(fd, TIOCSETP, (char *)ttyp);
+ if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: required chu line discipline unavailable");
+ return (0);
+ }
+ }
+#else
+ if (flags & LDISC_CHU) {
+ syslog(LOG_ERR,
+ "refclock_ioctl: required chu line discipline unsupported");
+ return (0);
+ }
+#endif /* CHU */
+#endif /* HAVE_BSD_TTYS */
+
+#endif /* STREAM */
+
+ return (1);
+}
+
/*
- * refclock_buginfo - return debugging info
+ * refclock_control - set and/or return clock values
+ *
+ * This routine is used mainly for debugging. It returns designated
+ * values from the interface structure that can be displayed using
+ * xntpdc and the clockstat command. It can also be used to initialize
+ * configuration variables, such as fudgetimes, fudgevalues, reference
+ * ID and stratum.
*/
void
-refclock_buginfo(srcadr, bug)
+refclock_control(srcadr, in, out)
struct sockaddr_in *srcadr;
- struct refclockbug *bug;
+ struct refclockstat *in;
+ struct refclockstat *out;
{
+ struct peer *peer;
+ struct refclockproc *pp;
u_char clktype;
int unit;
/*
- * Sanity...
+ * Check for valid address and running peer
*/
- if (!ISREFCLOCKADR(srcadr)) {
- syslog(LOG_ERR,
- "Internal error: refclock_buginfo received %s as reference clock",
- ntoa(srcadr));
+ if (!ISREFCLOCKADR(srcadr))
return;
- }
-
clktype = REFCLOCKTYPE(srcadr);
unit = REFCLOCKUNIT(srcadr);
+ if (clktype >= num_refclock_conf || unit > MAXUNIT)
+ return;
+ if (!(peer = typeunit[clktype][unit]))
+ return;
+ pp = peer->procptr;
/*
- * If clktype is invalid or call is unsupported, return
+ * Initialize requested data
*/
- if (clktype >= num_refclock_conf ||
- refclock_conf[clktype]->clock_buginfo == noentry) {
- return;
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ pp->fudgetime1 = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ pp->fudgetime2 = in->fudgetime2;
+ if (in->haveflags & CLK_HAVEVAL1)
+ peer->stratum = in->fudgeval1;
+ if (in->haveflags & CLK_HAVEVAL2)
+ pp->refid = in->fudgeval2;
+ if (peer->stratum <= 1)
+ peer->refid = pp->refid;
+ else
+ peer->refid = peer->srcadr.sin_addr.s_addr;
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ pp->sloppyclockflag &= ~CLK_FLAG1;
+ pp->sloppyclockflag |= in->flags & CLK_FLAG1;
+ }
+ if (in->haveflags & CLK_HAVEFLAG2) {
+ pp->sloppyclockflag &= ~CLK_FLAG2;
+ pp->sloppyclockflag |= in->flags & CLK_FLAG2;
+ }
+ if (in->haveflags & CLK_HAVEFLAG3) {
+ pp->sloppyclockflag &= ~CLK_FLAG3;
+ pp->sloppyclockflag |= in->flags & CLK_FLAG3;
+ }
+ if (in->haveflags & CLK_HAVEFLAG4) {
+ pp->sloppyclockflag &= ~CLK_FLAG4;
+ pp->sloppyclockflag |= in->flags & CLK_FLAG4;
+ }
+ if (in->flags & CLK_FLAG3)
+ (void)refclock_ioctl(pp->io.fd, LDISC_PPS);
+ }
+
+ /*
+ * Readback requested data
+ */
+ if (out != 0) {
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2 | CLK_HAVEFLAG4;
+ out->fudgetime1 = pp->fudgetime1;
+ out->fudgetime2 = pp->fudgetime2;
+ out->fudgeval1 = peer->stratum;
+ out->fudgeval2 = pp->refid;
+ out->flags = pp->sloppyclockflag;
+
+ out->timereset = current_time - pp->timestarted;
+ out->polls = pp->polls;
+ out->noresponse = pp->noreply;
+ out->badformat = pp->badformat;
+ out->baddata = pp->baddata;
+
+ out->lastevent = pp->lastevent;
+ out->currentstatus = pp->currentstatus;
+ out->type = pp->type;
+ out->clockdesc = pp->clockdesc;
+ out->lencode = pp->lencode;
+ out->lastcode = pp->lastcode;
}
/*
- * Give the stuff to the clock.
+ * Give the stuff to the clock
*/
- (refclock_conf[clktype]->clock_buginfo)(unit, bug);
+ if (refclock_conf[clktype]->clock_control != noentry)
+ (refclock_conf[clktype]->clock_control)(unit, in, out);
}
+
/*
- * init_refclock - initialize the reference clock drivers
+ * refclock_buginfo - return debugging info
+ *
+ * This routine is used mainly for debugging. It returns designated
+ * values from the interface structure that can be displayed using
+ * xntpdc and the clkbug command.
*/
void
-init_refclock()
+refclock_buginfo(srcadr, bug)
+ struct sockaddr_in *srcadr; /* clock address */
+ struct refclockbug *bug; /* output structure */
{
- register u_char i;
+ struct peer *peer;
+ struct refclockproc *pp;
+ u_char clktype;
+ int unit;
+ int i;
- for (i = 0; i < num_refclock_conf; i++) {
- if (refclock_conf[i]->clock_init != noentry)
- (refclock_conf[i]->clock_init)();
- }
+ /*
+ * Check for valid address and peer structure
+ */
+ if (!ISREFCLOCKADR(srcadr))
+ return;
+ clktype = REFCLOCKTYPE(srcadr);
+ unit = REFCLOCKUNIT(srcadr);
+ if (clktype >= num_refclock_conf || unit > MAXUNIT)
+ return;
+ if (!(peer = typeunit[clktype][unit]))
+ return;
+ pp = peer->procptr;
+
+ /*
+ * Copy structure values
+ */
+ bug->nvalues = 8;
+ bug->values[0] = pp->year;
+ bug->values[1] = pp->day;
+ bug->values[2] = pp->hour;
+ bug->values[3] = pp->minute;
+ bug->values[4] = pp->second;
+ bug->values[5] = pp->msec;
+ bug->values[6] = pp->yearstart;
+ bug->values[7] = pp->coderecv;
+
+ bug->ntimes = pp->nstages + 3;
+ if (bug->ntimes > NCLKBUGTIMES)
+ bug->ntimes = NCLKBUGTIMES;
+ bug->stimes = 0xfffffffc;
+ bug->times[0] = pp->lastref;
+ bug->times[1] = pp->lastrec;
+ UFPTOLFP(pp->dispersion, &bug->times[2]);
+ for (i = 0; i < bug->ntimes; i++)
+ bug->times[i + 3] = pp->filter[i];
+
+ /*
+ * Give the stuff to the clock
+ */
+ if (refclock_conf[clktype]->clock_buginfo != noentry)
+ (refclock_conf[clktype]->clock_buginfo)(unit, bug);
}
-#endif
+
+#endif /* REFCLOCK */
diff --git a/usr.sbin/xntpd/xntpd/ntp_request.c b/usr.sbin/xntpd/xntpd/ntp_request.c
index a77669875bea..5b3d481df1ed 100644
--- a/usr.sbin/xntpd/xntpd/ntp_request.c
+++ b/usr.sbin/xntpd/xntpd/ntp_request.c
@@ -1,10 +1,9 @@
-/* ntp_request.c,v 3.1 1993/07/06 01:11:26 jbj Exp
+/*
* ntp_request.c - respond to information requests
*/
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
-#include <sys/ioctl.h>
#include <sys/time.h>
#include "ntpd.h"
@@ -17,7 +16,7 @@
#include "ntp_stdlib.h"
#ifdef KERNEL_PLL
-#include <sys/timex.h>
+#include "sys/timex.h"
#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
#endif /* KERNEL_PLL */
@@ -62,7 +61,7 @@ static void do_conf P((struct sockaddr_in *, struct interface *, struct req_pkt
static void do_unconf P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void set_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void clr_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
-static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, U_LONG));
+static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_long));
static void do_monitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_nomonitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void list_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *));
@@ -70,7 +69,8 @@ static void do_resaddflags P((struct sockaddr_in *, struct interface *, struct r
static void do_ressubflags P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_unrestrict P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *, int));
-static void mon_getlist P((struct sockaddr_in *, struct interface *, struct req_pkt *));
+static void mon_getlist_0 P((struct sockaddr_in *, struct interface *, struct req_pkt *));
+static void mon_getlist_1 P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void reset_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void reset_peer P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_key_reread P((struct sockaddr_in *, struct interface *, struct req_pkt *));
@@ -125,23 +125,24 @@ static struct req_proc xntp_codes[] = {
{ REQ_RESADDFLAGS, AUTH, sizeof(struct conf_restrict), do_resaddflags },
{ REQ_RESSUBFLAGS, AUTH, sizeof(struct conf_restrict), do_ressubflags },
{ REQ_UNRESTRICT, AUTH, sizeof(struct conf_restrict), do_unrestrict },
- { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist },
+ { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist_0 },
+ { REQ_MON_GETLIST_1, NOAUTH, 0, mon_getlist_1 },
{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), reset_stats },
{ REQ_RESET_PEER, AUTH, sizeof(struct conf_unpeer), reset_peer },
{ REQ_REREAD_KEYS, AUTH, 0, do_key_reread },
{ REQ_DO_DIRTY_HACK, AUTH, 0, do_dirty_hack },
{ REQ_DONT_DIRTY_HACK, AUTH, 0, dont_dirty_hack },
- { REQ_TRUSTKEY, AUTH, sizeof(U_LONG), trust_key },
- { REQ_UNTRUSTKEY, AUTH, sizeof(U_LONG), untrust_key },
+ { REQ_TRUSTKEY, AUTH, sizeof(u_long), trust_key },
+ { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), untrust_key },
{ REQ_AUTHINFO, NOAUTH, 0, get_auth_info },
{ REQ_TRAPS, NOAUTH, 0, req_get_traps },
{ REQ_ADD_TRAP, AUTH, sizeof(struct conf_trap), req_set_trap },
{ REQ_CLR_TRAP, AUTH, sizeof(struct conf_trap), req_clr_trap },
- { REQ_REQUEST_KEY, AUTH, sizeof(U_LONG), set_request_keyid },
- { REQ_CONTROL_KEY, AUTH, sizeof(U_LONG), set_control_keyid },
+ { REQ_REQUEST_KEY, AUTH, sizeof(u_long), set_request_keyid },
+ { REQ_CONTROL_KEY, AUTH, sizeof(u_long), set_control_keyid },
{ REQ_GET_CTLSTATS, NOAUTH, 0, get_ctl_stats },
{ REQ_GET_LEAPINFO, NOAUTH, 0, get_leap_info },
- { REQ_SET_PRECISION, AUTH, sizeof(LONG), set_precision },
+ { REQ_SET_PRECISION, AUTH, sizeof(long), set_precision },
#ifdef KERNEL_PLL
{ REQ_GET_KERNEL, NOAUTH, 0, get_kernel_info },
#endif /* KERNEL_PLL */
@@ -158,16 +159,16 @@ static struct req_proc xntp_codes[] = {
* Authentication keyid used to authenticate requests. Zero means we
* don't allow writing anything.
*/
-U_LONG info_auth_keyid;
+u_long info_auth_keyid;
/*
* Statistic counters to keep track of requests and responses.
*/
-U_LONG numrequests; /* number of requests we've received */
-U_LONG numresppkts; /* number of resp packets sent with data */
+u_long numrequests; /* number of requests we've received */
+u_long numresppkts; /* number of resp packets sent with data */
-U_LONG errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
+u_long errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
/* by the error code */
#ifdef KERNEL_PLL
@@ -187,18 +188,33 @@ extern int debug;
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
+extern u_long current_time;
/*
* Imported from ntp_loopfilter.c
*/
extern int pll_control;
+extern int pll_enable;
+extern int pps_control;
+
+/*
+ * Imported from ntp_monitor.c
+ */
+extern int mon_enabled;
+
+/*
+ * Imported from ntp_util.c
+ */
+extern int stats_control;
+
+extern struct peer *peer_hash[];
+extern struct peer *sys_peer;
/*
* A hack. To keep the authentication module clear of xntp-ism's, we
* include a time reset variable for its stats here.
*/
-static U_LONG auth_timereset;
+static u_long auth_timereset;
/*
* Response packet used by these routines. Also some state information
@@ -258,7 +274,7 @@ req_ack(srcadr, inter, inpkt, errcode)
/*
* send packet and bump counters
*/
- sendpkt(srcadr, inter, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
+ sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
errorcounter[errcode]++;
}
@@ -322,7 +338,7 @@ more_pkt()
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
- sendpkt(toaddr, frominter, (struct pkt *)&rpkt,
+ sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
RESP_HEADER_SIZE+databytes);
numresppkts++;
@@ -388,7 +404,7 @@ flush_pkt()
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
- sendpkt(toaddr, frominter, (struct pkt *)&rpkt,
+ sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
RESP_HEADER_SIZE+databytes);
numresppkts++;
}
@@ -481,20 +497,18 @@ process_private(rbufp, mod_okay)
* time stamp.
*/
if (proc->needs_auth) {
- register U_LONG tmp_ui;
- register U_LONG tmp_uf;
+ l_fp ftmp;
/*
* If this guy is restricted from doing this, don't let him
* If wrong key was used, or packet doesn't have mac, return.
*/
- if (!INFO_IS_AUTH(inpkt->auth_seq)
- || info_auth_keyid == 0
+ if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
|| ntohl(inpkt->keyid) != info_auth_keyid) {
#ifdef DEBUG
if (debug > 4)
printf(
- "failed auth %d info_auth_keyid %u pkt keyid %u\n",
+ "failed auth %d info_auth_keyid %lu pkt keyid %u\n",
INFO_IS_AUTH(inpkt->auth_seq),
info_auth_keyid, ntohl(inpkt->keyid));
#endif
@@ -504,8 +518,8 @@ process_private(rbufp, mod_okay)
if (rbufp->recv_length > REQ_LEN_MAC) {
#ifdef DEBUG
if (debug > 4)
- printf("failed pkt length pkt %d req %d too long\n",
- rbufp->recv_length, REQ_LEN_MAC);
+ printf("bad pkt length %d\n",
+ rbufp->recv_length);
#endif
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
@@ -523,15 +537,12 @@ process_private(rbufp, mod_okay)
* calculate absolute time difference between xmit time stamp
* and receive time stamp. If too large, too bad.
*/
- tmp_ui = ntohl(inpkt->tstamp.l_ui);
- tmp_uf = ntohl(inpkt->tstamp.l_uf);
- M_SUB(tmp_ui, tmp_uf, rbufp->recv_time.l_ui,
- rbufp->recv_time.l_uf);
- if (M_ISNEG(tmp_ui, tmp_uf))
- M_NEG(tmp_ui, tmp_uf);
+ NTOHL_FP(&inpkt->tstamp, &ftmp);
+ L_SUB(&ftmp, &rbufp->recv_time);
+ if (L_ISNEG(&ftmp))
+ L_NEG(&ftmp);
- if (M_ISHIS(tmp_ui, tmp_uf,
- INFO_TS_MAXSKEW_UI, INFO_TS_MAXSKEW_UF)) {
+ if (ftmp.l_ui >= INFO_TS_MAXSKEW_UI) {
/*
* He's a loser. Tell him.
*/
@@ -588,8 +599,6 @@ peer_list(srcadr, inter, inpkt)
register struct info_peer_list *ip;
register struct peer *pp;
register int i;
- extern struct peer *peer_hash[];
- extern struct peer *sys_peer;
ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_peer_list));
@@ -628,8 +637,6 @@ peer_list_sum(srcadr, inter, inpkt)
register struct info_peer_summary *ips;
register struct peer *pp;
register int i;
- extern struct peer *peer_hash[];
- extern struct peer *sys_peer;
#ifdef DEBUG
if (debug > 2)
@@ -645,10 +652,14 @@ peer_list_sum(srcadr, inter, inpkt)
if (debug > 3)
printf("sum: got one\n");
#endif
- if (pp->dstadr == any_interface)
- ips->dstadr = 0;
- else
- ips->dstadr = pp->dstadr->sin.sin_addr.s_addr;
+ ips->dstadr = (pp->processed) ?
+ pp->cast_flags == MDF_BCAST ?
+ pp->dstadr->bcast.sin_addr.s_addr:
+ pp->cast_flags ?
+ pp->dstadr->sin.sin_addr.s_addr ?
+ pp->dstadr->sin.sin_addr.s_addr:
+ pp->dstadr->bcast.sin_addr.s_addr:
+ 1 : 5;
ips->srcadr = pp->srcadr.sin_addr.s_addr;
ips->srcport = pp->srcadr.sin_port;
ips->stratum = pp->stratum;
@@ -712,7 +723,14 @@ peer_info (srcadr, inter, inpkt)
ipl++;
if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0)
continue;
- ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ ip->dstadr = (pp->processed) ?
+ pp->cast_flags == MDF_BCAST ?
+ pp->dstadr->bcast.sin_addr.s_addr:
+ pp->cast_flags ?
+ pp->dstadr->sin.sin_addr.s_addr ?
+ pp->dstadr->sin.sin_addr.s_addr:
+ pp->dstadr->bcast.sin_addr.s_addr:
+ 2 : 6;
ip->srcadr = NSRCADR(&pp->srcadr);
ip->srcport = NSRCPORT(&pp->srcadr);
ip->flags = 0;
@@ -743,7 +761,7 @@ peer_info (srcadr, inter, inpkt)
ip->reach = pp->reach;
ip->unreach = pp->unreach;
ip->flash = pp->flash;
- ip->estbdelay = htonl(pp->estbdelay);
+ ip->estbdelay = HTONS_FP(pp->estbdelay);
ip->ttl = pp->ttl;
ip->associd = htons(pp->associd);
ip->rootdelay = HTONS_FP(pp->rootdelay);
@@ -803,7 +821,14 @@ peer_stats (srcadr, inter, inpkt)
ipl++;
if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0)
continue;
- ip->dstadr = NSRCADR(&pp->dstadr->sin);
+ ip->dstadr = (pp->processed) ?
+ pp->cast_flags == MDF_BCAST ?
+ pp->dstadr->bcast.sin_addr.s_addr:
+ pp->cast_flags ?
+ pp->dstadr->sin.sin_addr.s_addr ?
+ pp->dstadr->sin.sin_addr.s_addr:
+ pp->dstadr->bcast.sin_addr.s_addr:
+ 3 : 7;
ip->srcadr = NSRCADR(&pp->srcadr);
ip->srcport = NSRCPORT(&pp->srcadr);
ip->flags = 0;
@@ -826,21 +851,13 @@ peer_stats (srcadr, inter, inpkt)
= htonl(pp->event_timer.event_time - current_time);
ip->timereachable = htonl(current_time - pp->timereachable);
ip->sent = htonl(pp->sent);
- ip->received = htonl(pp->received);
ip->processed = htonl(pp->processed);
- ip->badlength = 0;
ip->badauth = htonl(pp->badauth);
ip->bogusorg = htonl(pp->bogusorg);
ip->oldpkt = htonl(pp->oldpkt);
- ip->baddelay = 0;
- ip->seldelay = 0;
ip->seldisp = htonl(pp->seldisptoolarge);
ip->selbroken = htonl(pp->selbroken);
- ip->selold = htonl(pp->seltooold);
ip->candidate = pp->candidate;
- ip->falseticker = 0;
- ip->select = pp->select;
- ip->select_total = 0;
ip = (struct info_peer_stats *)more_pkt();
}
flush_pkt();
@@ -866,14 +883,16 @@ sys_info(srcadr, inter, inpkt)
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
- extern U_LONG sys_refid;
+ extern u_long sys_refid;
extern l_fp sys_reftime;
extern u_char sys_poll;
extern struct peer *sys_peer;
extern int sys_bclient;
- extern U_LONG sys_bdelay;
+ extern s_fp sys_bdelay;
extern int sys_authenticate;
- extern U_LONG sys_authdelay;
+ extern u_long sys_authdelay;
+ extern u_fp clock_stability;
+ extern s_fp clock_frequency;
is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys));
@@ -890,6 +909,8 @@ sys_info(srcadr, inter, inpkt)
is->precision = sys_precision;
is->rootdelay = htonl(sys_rootdelay);
is->rootdispersion = htonl(sys_rootdispersion);
+ is->frequency = htonl(clock_frequency);
+ is->stability = htonl(clock_stability);
is->refid = sys_refid;
HTONL_FP(&sys_reftime, &is->reftime);
@@ -899,9 +920,20 @@ sys_info(srcadr, inter, inpkt)
if (sys_bclient)
is->flags |= INFO_FLAG_BCLIENT;
if (sys_authenticate)
- is->flags |= INFO_FLAG_AUTHENABLE;
- HTONL_UF(sys_bdelay, &is->bdelay);
+ is->flags |= INFO_FLAG_AUTHENTICATE;
+ if (pll_enable)
+ is->flags |= INFO_FLAG_PLL;
+ if (pll_control)
+ is->flags |= INFO_FLAG_PLL_SYNC;
+ if (pps_control)
+ is->flags |= INFO_FLAG_PPS_SYNC;
+ if (mon_enabled != MON_OFF)
+ is->flags |= INFO_FLAG_MONITOR;
+ if (stats_control)
+ is->flags |= INFO_FLAG_FILEGEN;
+ is->bdelay = HTONS_FP(sys_bdelay);
HTONL_UF(sys_authdelay, &is->authdelay);
+
(void) more_pkt();
flush_pkt();
}
@@ -921,15 +953,15 @@ sys_stats(srcadr, inter, inpkt)
/*
* Importations from the protocol module
*/
- extern U_LONG sys_stattime;
- extern U_LONG sys_badstratum;
- extern U_LONG sys_oldversionpkt;
- extern U_LONG sys_newversionpkt;
- extern U_LONG sys_unknownversion;
- extern U_LONG sys_badlength;
- extern U_LONG sys_processed;
- extern U_LONG sys_badauth;
- extern U_LONG sys_limitrejected;
+ extern u_long sys_stattime;
+ extern u_long sys_badstratum;
+ extern u_long sys_oldversionpkt;
+ extern u_long sys_newversionpkt;
+ extern u_long sys_unknownversion;
+ extern u_long sys_badlength;
+ extern u_long sys_processed;
+ extern u_long sys_badauth;
+ extern u_long sys_limitrejected;
ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys_stats));
@@ -966,10 +998,10 @@ mem_stats(srcadr, inter, inpkt)
*/
extern int peer_hash_count[HASH_SIZE];
extern int peer_free_count;
- extern U_LONG peer_timereset;
- extern U_LONG findpeer_calls;
- extern U_LONG peer_allocations;
- extern U_LONG peer_demobilizations;
+ extern u_long peer_timereset;
+ extern u_long findpeer_calls;
+ extern u_long peer_allocations;
+ extern u_long peer_demobilizations;
extern int total_peer_structs;
ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
@@ -1008,18 +1040,18 @@ io_stats(srcadr, inter, inpkt)
/*
* Importations from the io module
*/
- extern U_LONG io_timereset;
- extern U_LONG full_recvbufs;
- extern U_LONG free_recvbufs;
- extern U_LONG total_recvbufs;
- extern U_LONG lowater_additions;
- extern U_LONG packets_dropped;
- extern U_LONG packets_ignored;
- extern U_LONG packets_received;
- extern U_LONG packets_sent;
- extern U_LONG packets_notsent;
- extern U_LONG handler_calls;
- extern U_LONG handler_pkts;
+ extern u_long io_timereset;
+ extern u_long full_recvbufs;
+ extern u_long free_recvbufs;
+ extern u_long total_recvbufs;
+ extern u_long lowater_additions;
+ extern u_long packets_dropped;
+ extern u_long packets_ignored;
+ extern u_long packets_received;
+ extern u_long packets_sent;
+ extern u_long packets_notsent;
+ extern u_long handler_calls;
+ extern u_long handler_pkts;
io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_io_stats));
@@ -1056,10 +1088,10 @@ timer_stats(srcadr, inter, inpkt)
/*
* Importations from the timer module
*/
- extern U_LONG alarm_overflow;
- extern U_LONG timer_timereset;
- extern U_LONG timer_overflows;
- extern U_LONG timer_xmtcalls;
+ extern u_long alarm_overflow;
+ extern u_long timer_timereset;
+ extern u_long timer_overflows;
+ extern u_long timer_xmtcalls;
ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_timer_stats));
@@ -1091,8 +1123,8 @@ loop_info(srcadr, inter, inpkt)
*/
extern l_fp last_offset;
extern s_fp drift_comp;
- extern int time_constant;
- extern U_LONG watchdog_timer;
+ extern int tc_counter;
+ extern u_long last_time;
li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_loop));
@@ -1100,8 +1132,8 @@ loop_info(srcadr, inter, inpkt)
HTONL_FP(&last_offset, &li->last_offset);
FPTOLFP(drift_comp, &tmp);
HTONL_FP(&tmp, &li->drift_comp);
- li->compliance = htonl(time_constant);
- li->watchdog_timer = htonl(watchdog_timer);
+ li->compliance = htonl(tc_counter);
+ li->watchdog_timer = htonl(current_time - last_time);
(void) more_pkt();
flush_pkt();
@@ -1139,7 +1171,7 @@ do_conf(srcadr, inter, inpkt)
&& cp->hmode != MODE_CLIENT
&& cp->hmode != MODE_BROADCAST)
fl = 1;
- if (cp->flags & ~(CONF_FLAG_AUTHENABLE|CONF_FLAG_PREFER))
+ if (cp->flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER))
fl = 1;
cp++;
}
@@ -1265,7 +1297,7 @@ set_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, (U_LONG)1);
+ setclr_flags(srcadr, inter, inpkt, 1);
}
@@ -1278,7 +1310,7 @@ clr_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, (U_LONG)0);
+ setclr_flags(srcadr, inter, inpkt, 0);
}
@@ -1290,9 +1322,9 @@ setclr_flags(srcadr, inter, inpkt, set)
struct sockaddr_in *srcadr;
struct interface *inter;
struct req_pkt *inpkt;
- U_LONG set;
+ u_long set;
{
- register U_LONG flags;
+ register u_long flags;
if (INFO_NITEMS(inpkt->err_nitems) > 1) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
@@ -1301,21 +1333,23 @@ setclr_flags(srcadr, inter, inpkt, set)
flags = ((struct conf_sys_flags *)inpkt->data)->flags;
- if (flags
- & ~(SYS_FLAG_BCLIENT | SYS_FLAG_MCLIENT | SYS_FLAG_AUTHENTICATE)) {
+ if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_AUTHENTICATE |
+ SYS_FLAG_PLL | SYS_FLAG_MONITOR |
+ SYS_FLAG_FILEGEN)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if (flags & SYS_FLAG_BCLIENT)
proto_config(PROTO_BROADCLIENT, set);
- if (flags & SYS_FLAG_MCLIENT)
- if (set)
- proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
- else
- proto_config(PROTO_MULTICAST_DEL, INADDR_NTP);
if (flags & SYS_FLAG_AUTHENTICATE)
proto_config(PROTO_AUTHENTICATE, set);
+ if (flags & SYS_FLAG_PLL)
+ proto_config(PROTO_PLL, set);
+ if (flags & SYS_FLAG_MONITOR)
+ proto_config(PROTO_MONITOR, set);
+ if (flags & SYS_FLAG_FILEGEN)
+ proto_config(PROTO_FILEGEN, set);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1454,7 +1488,7 @@ do_restrict(srcadr, inter, inpkt, op)
bad = 1;
if (cr->flags & ~(RES_ALLFLAGS))
bad = 1;
- if (cr->addr == INADDR_ANY && cr->mask != INADDR_ANY)
+ if (cr->addr == htonl(INADDR_ANY) && cr->mask != htonl(INADDR_ANY))
bad = 1;
cr++;
}
@@ -1490,7 +1524,7 @@ do_restrict(srcadr, inter, inpkt, op)
* mon_getlist - return monitor data
*/
static void
-mon_getlist(srcadr, inter, inpkt)
+mon_getlist_0(srcadr, inter, inpkt)
struct sockaddr_in *srcadr;
struct interface *inter;
struct req_pkt *inpkt;
@@ -1502,7 +1536,7 @@ mon_getlist(srcadr, inter, inpkt)
#ifdef DEBUG
if (debug > 2)
- printf("wants monitor list\n");
+ printf("wants monitor 0 list\n");
#endif
if (!mon_enabled) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
@@ -1530,6 +1564,57 @@ mon_getlist(srcadr, inter, inpkt)
}
/*
+ * mon_getlist - return monitor data
+ */
+static void
+mon_getlist_1(srcadr, inter, inpkt)
+ struct sockaddr_in *srcadr;
+ struct interface *inter;
+ struct req_pkt *inpkt;
+{
+ register struct info_monitor_1 *im;
+ register struct mon_data *md;
+ extern struct mon_data mon_mru_list;
+ extern int mon_enabled;
+
+#ifdef DEBUG
+ if (debug > 2)
+ printf("wants monitor 1 list\n");
+#endif
+ if (!mon_enabled) {
+ req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
+ return;
+ }
+
+ im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt,
+ sizeof(struct info_monitor_1));
+ for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
+ md = md->mru_next) {
+ im->lasttime = htonl(current_time - md->lasttime);
+ im->firsttime = htonl(current_time - md->firsttime);
+ if (md->lastdrop)
+ im->lastdrop = htonl(current_time - md->lastdrop);
+ else
+ im->lastdrop = 0;
+ im->count = htonl(md->count);
+ im->addr = md->rmtadr;
+ im->daddr = md->cast_flags == MDF_BCAST ?
+ md->interface->bcast.sin_addr.s_addr :
+ md->cast_flags ?
+ md->interface->sin.sin_addr.s_addr ?
+ md->interface->sin.sin_addr.s_addr :
+ md->interface->bcast.sin_addr.s_addr :
+ 4;
+ im->flags = md->cast_flags;
+ im->port = md->rmtport;
+ im->mode = md->mode;
+ im->version = md->version;
+ im = (struct info_monitor_1 *)more_pkt();
+ }
+ flush_pkt();
+}
+
+/*
* Module entry points and the flags they correspond with
*/
struct reset_entry {
@@ -1557,7 +1642,7 @@ reset_stats(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- U_LONG flags;
+ u_long flags;
struct reset_entry *rent;
if (INFO_NITEMS(inpkt->err_nitems) > 1) {
@@ -1714,11 +1799,11 @@ do_trustkey(srcadr, inter, inpkt, trust)
struct req_pkt *inpkt;
int trust;
{
- register U_LONG *kp;
+ register u_long *kp;
register int items;
items = INFO_NITEMS(inpkt->err_nitems);
- kp = (U_LONG *)inpkt->data;
+ kp = (u_long *)inpkt->data;
while (items-- > 0) {
authtrust(*kp, trust);
kp++;
@@ -1742,14 +1827,13 @@ get_auth_info(srcadr, inter, inpkt)
/*
* Importations from the authentication module
*/
- extern U_LONG authnumkeys;
- extern U_LONG authnumfreekeys;
- extern U_LONG authkeylookups;
- extern U_LONG authkeynotfound;
- extern U_LONG authencryptions;
- extern U_LONG authdecryptions;
- extern U_LONG authdecryptok;
- extern U_LONG authkeyuncached;
+ extern u_long authnumkeys;
+ extern u_long authnumfreekeys;
+ extern u_long authkeylookups;
+ extern u_long authkeynotfound;
+ extern u_long authencryptions;
+ extern u_long authdecryptions;
+ extern u_long authkeyuncached;
ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_auth));
@@ -1760,7 +1844,6 @@ get_auth_info(srcadr, inter, inpkt)
ia->keynotfound = htonl(authkeynotfound);
ia->encryptions = htonl(authencryptions);
ia->decryptions = htonl(authdecryptions);
- ia->decryptok = htonl(authdecryptok);
ia->keyuncached = htonl(authkeyuncached);
ia->timereset = htonl(current_time - auth_timereset);
@@ -1780,18 +1863,16 @@ reset_auth_stats()
/*
* Importations from the authentication module
*/
- extern U_LONG authkeylookups;
- extern U_LONG authkeynotfound;
- extern U_LONG authencryptions;
- extern U_LONG authdecryptions;
- extern U_LONG authdecryptok;
- extern U_LONG authkeyuncached;
+ extern u_long authkeylookups;
+ extern u_long authkeynotfound;
+ extern u_long authencryptions;
+ extern u_long authdecryptions;
+ extern u_long authkeyuncached;
authkeylookups = 0;
authkeynotfound = 0;
authencryptions = 0;
authdecryptions = 0;
- authdecryptok = 0;
authkeyuncached = 0;
auth_timereset = current_time;
}
@@ -1837,7 +1918,7 @@ req_get_traps(srcadr, inter, inpkt)
it->settime = htonl(current_time - tr->tr_settime);
it->origtime = htonl(current_time - tr->tr_origtime);
it->resets = htonl(tr->tr_resets);
- it->flags = htonl((U_LONG)tr->tr_flags);
+ it->flags = htonl((u_long)tr->tr_flags);
it = (struct info_trap *)more_pkt();
}
}
@@ -1951,7 +2032,7 @@ set_request_keyid(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- U_LONG keyid;
+ u_long keyid;
/*
* Restrict ourselves to one item only.
@@ -1961,7 +2042,7 @@ set_request_keyid(srcadr, inter, inpkt)
return;
}
- keyid = ntohl(*((U_LONG *)(inpkt->data)));
+ keyid = ntohl(*((u_long *)(inpkt->data)));
info_auth_keyid = keyid;
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1977,8 +2058,8 @@ set_control_keyid(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- U_LONG keyid;
- extern U_LONG ctl_auth_keyid;
+ u_long keyid;
+ extern u_long ctl_auth_keyid;
/*
* Restrict ourselves to one item only.
@@ -1988,7 +2069,7 @@ set_control_keyid(srcadr, inter, inpkt)
return;
}
- keyid = ntohl(*((U_LONG *)(inpkt->data)));
+ keyid = ntohl(*((u_long *)(inpkt->data)));
ctl_auth_keyid = keyid;
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2009,21 +2090,21 @@ get_ctl_stats(srcadr, inter, inpkt)
/*
* Importations from the control module
*/
- extern U_LONG ctltimereset;
- extern U_LONG numctlreq;
- extern U_LONG numctlbadpkts;
- extern U_LONG numctlresponses;
- extern U_LONG numctlfrags;
- extern U_LONG numctlerrors;
- extern U_LONG numctltooshort;
- extern U_LONG numctlinputresp;
- extern U_LONG numctlinputfrag;
- extern U_LONG numctlinputerr;
- extern U_LONG numctlbadoffset;
- extern U_LONG numctlbadversion;
- extern U_LONG numctldatatooshort;
- extern U_LONG numctlbadop;
- extern U_LONG numasyncmsgs;
+ extern u_long ctltimereset;
+ extern u_long numctlreq;
+ extern u_long numctlbadpkts;
+ extern u_long numctlresponses;
+ extern u_long numctlfrags;
+ extern u_long numctlerrors;
+ extern u_long numctltooshort;
+ extern u_long numctlinputresp;
+ extern u_long numctlinputfrag;
+ extern u_long numctlinputerr;
+ extern u_long numctlbadoffset;
+ extern u_long numctlbadversion;
+ extern u_long numctldatatooshort;
+ extern u_long numctlbadop;
+ extern u_long numasyncmsgs;
ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_control));
@@ -2072,13 +2153,13 @@ get_leap_info(srcadr, inter, inpkt)
extern u_char leap_indicator;
extern u_char leap_warning;
extern u_char leapbits;
- extern U_LONG leap_timer;
- extern U_LONG leap_processcalls;
- extern U_LONG leap_notclose;
- extern U_LONG leap_monthofleap;
- extern U_LONG leap_dayofleap;
- extern U_LONG leap_hoursfromleap;
- extern U_LONG leap_happened;
+ extern u_long leap_timer;
+ extern u_long leap_processcalls;
+ extern u_long leap_notclose;
+ extern u_long leap_monthofleap;
+ extern u_long leap_dayofleap;
+ extern u_long leap_hoursfromleap;
+ extern u_long leap_happened;
il = (struct info_leap *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_leap));
@@ -2198,7 +2279,7 @@ get_clock_info(srcadr, inter, inpkt)
ic->noresponse = htonl(clock.noresponse);
ic->badformat = htonl(clock.badformat);
ic->baddata = htonl(clock.baddata);
- ic->timestarted = clock.timereset;
+ ic->timestarted = htonl(clock.timereset);
HTONL_FP(&clock.fudgetime1, &ic->fudgetime1);
HTONL_FP(&clock.fudgetime2, &ic->fudgetime2);
ic->fudgeval1 = htonl(clock.fudgeval1);
@@ -2285,9 +2366,9 @@ set_precision(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- register LONG precision;
+ register long precision;
- precision = ntohl(*(LONG *)(inpkt->data));
+ precision = ntohl(*(long *)(inpkt->data));
if (INFO_NITEMS(inpkt->err_nitems) > 1 ||
precision > -1 || precision < -20) {
@@ -2353,10 +2434,9 @@ get_clkbug_info(srcadr, inter, inpkt)
if (i > NUMCBUGTIMES)
i = NUMCBUGTIMES;
ic->ntimes = (u_char)i;
- ic->stimes = htonl((U_LONG)bug.stimes & ((1<<i)-1));
+ ic->stimes = htonl(bug.stimes);
while (--i >= 0) {
- ic->times[i].l_ui = htonl(bug.times[i].l_ui);
- ic->times[i].l_uf = htonl(bug.times[i].l_uf);
+ HTONL_FP(&bug.times[i], &ic->times[i]);
}
ic = (struct info_clkbug *)more_pkt();
diff --git a/usr.sbin/xntpd/xntpd/ntp_restrict.c b/usr.sbin/xntpd/xntpd/ntp_restrict.c
index 43f01f296624..0cc4b7d304b9 100644
--- a/usr.sbin/xntpd/xntpd/ntp_restrict.c
+++ b/usr.sbin/xntpd/xntpd/ntp_restrict.c
@@ -54,10 +54,10 @@ static int restrictcount; /* count of entries in the restriction list */
static struct restrictlist *resfree;
static int numresfree; /* number of structures on free list */
-U_LONG res_calls;
-U_LONG res_found;
-U_LONG res_not_found;
-U_LONG res_timereset;
+u_long res_calls;
+u_long res_found;
+u_long res_not_found;
+u_long res_timereset;
/*
* Parameters of the RES_LIMITED restriction option.
@@ -65,14 +65,14 @@ U_LONG res_timereset;
* client_limit_period is the number of seconds after which an entry
* is no longer considered for client limit determination
*/
-U_LONG client_limit;
-U_LONG client_limit_period;
+u_long client_limit;
+u_long client_limit_period;
/*
* count number of restriction entries referring to RES_LIMITED
* controls activation/deactivation of monitoring
* (with respect ro RES_LIMITED control)
*/
-U_LONG res_limited_refcnt;
+u_long res_limited_refcnt;
/*
* Our initial allocation of list entries.
@@ -82,7 +82,7 @@ static struct restrictlist resinit[INITRESLIST];
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
+extern u_long current_time;
/*
* debug flag
@@ -116,7 +116,7 @@ init_restrict()
* list as our default entry. Everything in here
* should be zero for now.
*/
- resinit[0].addr = INADDR_ANY;
+ resinit[0].addr = htonl(INADDR_ANY);
resinit[0].mask = 0;
restrictlist = &resinit[0];
restrictcount = 1;
@@ -137,9 +137,9 @@ init_restrict()
client_limit_period = 3600;
res_limited_refcnt = 0;
- sprintf(bp, "client_limit=%d", client_limit);
+ sprintf(bp, "client_limit=%ld", client_limit);
set_sys_var(bp, strlen(bp)+1, RO);
- sprintf(bp, "client_limit_period=%d", client_limit_period);
+ sprintf(bp, "client_limit_period=%ld", client_limit_period);
set_sys_var(bp, strlen(bp)+1, RO);
}
@@ -153,7 +153,7 @@ restrictions(srcadr)
{
register struct restrictlist *rl;
register struct restrictlist *match;
- register U_LONG hostaddr;
+ register u_long hostaddr;
register int isntpport;
res_calls++;
@@ -210,7 +210,7 @@ restrictions(srcadr)
#ifdef DEBUG
if (debug > 2)
- printf("limited clients check: %d clients, period %d seconds, net is 0x%X\n",
+ printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n",
client_limit, client_limit_period,
netof(hostaddr));
#endif /*DEBUG*/
@@ -238,7 +238,7 @@ restrictions(srcadr)
> client_limit_period) {
#ifdef DEBUG
if (debug > 5)
- printf("checking: %s: ignore: too old: %d\n",
+ printf("checking: %s: ignore: too old: %ld\n",
numtoa(md->rmtadr),
current_time - md->lasttime);
#endif
@@ -259,7 +259,7 @@ restrictions(srcadr)
netof(hostaddr)) {
#ifdef DEBUG
if (debug > 5)
- printf("checking: %s: different net 0x%X\n",
+ printf("checking: %s: different net 0x%lX\n",
numtoa(md->rmtadr),
netof(md->rmtadr));
#endif
@@ -286,7 +286,7 @@ restrictions(srcadr)
}
#ifdef DEBUG
if (debug > 4)
- printf("this one is rank %d in list, limit is %d: %s\n",
+ printf("this one is rank %d in list, limit is %lu: %s\n",
lcnt, client_limit,
(lcnt <= client_limit) ? "ALLOW" : "REJECT");
#endif
@@ -312,8 +312,8 @@ restrict(op, resaddr, resmask, mflags, flags)
int mflags;
int flags;
{
- register U_LONG addr;
- register U_LONG mask;
+ register u_long addr;
+ register u_long mask;
register struct restrictlist *rl;
register struct restrictlist *rlprev;
int i;
@@ -329,7 +329,7 @@ restrict(op, resaddr, resmask, mflags, flags)
* If this is the default address, point at first on list. Else
* go searching for it.
*/
- if (addr == INADDR_ANY) {
+ if (addr == htonl(INADDR_ANY)) {
rlprev = 0;
rl = restrictlist;
} else {
@@ -433,7 +433,7 @@ restrict(op, resaddr, resmask, mflags, flags)
* interface entry.
*/
if (rl != 0
- && rl->addr != INADDR_ANY
+ && rl->addr != htonl(INADDR_ANY)
&& !(rl->mflags & RESM_INTERFACE)) {
rlprev->next = rl->next;
restrictcount--;
diff --git a/usr.sbin/xntpd/xntpd/ntp_timer.c b/usr.sbin/xntpd/xntpd/ntp_timer.c
index e3ba54cd39bc..99551f74a9f3 100644
--- a/usr.sbin/xntpd/xntpd/ntp_timer.c
+++ b/usr.sbin/xntpd/xntpd/ntp_timer.c
@@ -1,4 +1,4 @@
-/* ntp_timer.c,v 3.1 1993/07/06 01:11:29 jbj Exp
+/*
* ntp_event.c - event timer support routines
*/
#include <stdio.h>
@@ -30,18 +30,18 @@ int alarm_flag;
/*
* adjust and hourly counters
*/
-static U_LONG adjust_timer;
-static U_LONG hourly_timer;
+static u_long adjust_timer;
+static u_long hourly_timer;
/*
* Imported from the leap module. The leap timer.
*/
-extern U_LONG leap_timer;
+extern u_long leap_timer;
/*
* Statistics counter for the interested.
*/
-U_LONG alarm_overflow;
+u_long alarm_overflow;
#define HOUR (60*60)
@@ -50,15 +50,15 @@ U_LONG alarm_overflow;
* increments of 2**EVENT_TIMEOUT seconds. The timer queue is the
* hash into which we sort timer entries.
*/
-U_LONG current_time;
+u_long current_time;
struct event timerqueue[TIMER_NSLOTS];
/*
* Stats. Number of overflows and number of calls to transmit().
*/
-U_LONG timer_timereset;
-U_LONG timer_overflows;
-U_LONG timer_xmtcalls;
+u_long timer_timereset;
+u_long timer_overflows;
+u_long timer_xmtcalls;
static RETSIGTYPE alarming P((int));
diff --git a/usr.sbin/xntpd/xntpd/ntp_unixclock.c b/usr.sbin/xntpd/xntpd/ntp_unixclock.c
index 1950d8c06fb3..6b81429ca626 100644
--- a/usr.sbin/xntpd/xntpd/ntp_unixclock.c
+++ b/usr.sbin/xntpd/xntpd/ntp_unixclock.c
@@ -1,4 +1,4 @@
-/* ntp_unixclock.c,v 3.1 1993/07/06 01:11:30 jbj Exp
+/*
* ntp_unixclock.c - routines for reading and adjusting a 4BSD-style
* system clock
*/
@@ -9,7 +9,7 @@
#include <sys/stat.h>
#include <sys/time.h>
-#if defined(SYS_HPUX) || defined(sgi) || defined(SYS_BSDI)
+#if defined(SYS_HPUX) || defined(sgi) || defined(SYS_BSDI) || defined(SYS_44BSD)
#include <sys/param.h>
#include <utmp.h>
#endif
@@ -20,7 +20,7 @@
#include "ntp_stdlib.h"
#if defined(HAVE_LIBKVM)
-#ifdef SYS_BSDI
+#if defined(SYS_BSDI) || defined(SYS_44BSD)
#include <sys/proc.h>
#endif /* SYS_BSDI */
#include <kvm.h>
@@ -61,19 +61,19 @@ extern int debug;
* We also remember the clock precision we computed from the kernel in
* case someone asks us.
*/
-extern LONG adj_precision; /* adj precision in usec (tickadj) */
-extern LONG tvu_maxslew; /* maximum adjust doable in 1<<CLOCK_ADJ sec (usec) */
+extern long adj_precision; /* adj precision in usec (tickadj) */
+extern long tvu_maxslew; /* maximum adjust doable in 1<<CLOCK_ADJ sec (usec) */
-extern U_LONG tsf_maxslew; /* same as above, as LONG format */
+extern u_long tsf_maxslew; /* same as above, as long format */
extern l_fp sys_clock_offset; /* correction for current system time */
/*
* Import sys_clock (it is updated in get_systime)
*/
-extern LONG sys_clock;
+extern long sys_clock;
-static void clock_parms P((U_LONG *, U_LONG *));
+static void clock_parms P((u_long *, u_long *));
/*
* init_systime - initialize the system clock support code, return
@@ -97,9 +97,9 @@ static void clock_parms P((U_LONG *, U_LONG *));
void
init_systime()
{
- U_LONG tickadj;
- U_LONG tick;
- U_LONG hz;
+ u_long tickadj;
+ u_long tick;
+ u_long hz;
/*
* Obtain the values
@@ -107,7 +107,7 @@ init_systime()
clock_parms(&tickadj, &tick);
#ifdef DEBUG
if (debug)
- printf("kernel vars: tickadj = %d, tick = %d\n", tickadj, tick);
+ printf("kernel vars: tickadj = %ld, tick = %ld\n", tickadj, tick);
#endif
/*
@@ -162,14 +162,14 @@ init_systime()
#ifdef DEBUG
if (debug)
printf(
- "adj_precision = %d, tvu_maxslew = %d, tsf_maxslew = 0.%08x\n",
+ "adj_precision = %ld, tvu_maxslew = %ld, tsf_maxslew = 0.%08lx\n",
adj_precision, tvu_maxslew, tsf_maxslew);
#endif
/*
* Set the current offset to 0
*/
- sys_clock_offset.l_ui = sys_clock_offset.l_uf = 0;
+ L_CLR(&sys_clock_offset);
}
#ifdef HAVE_LIBKVM
@@ -180,8 +180,8 @@ init_systime()
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
static struct nlist nl[] = {
#define N_TICKADJ 0
@@ -261,8 +261,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
*tick = 10000; /* microseconds */
*tickadj = 80; /* microseconds */
@@ -275,8 +275,13 @@ clock_parms(tickadj, tick)
#endif
#ifdef SYS_HPUX
+#if defined(hp9000s300)
#define K_TICKADJ_NAME "_tickadj"
#define K_TICK_NAME "_old_tick"
+#else
+#define K_TICKADJ_NAME "tickadj"
+#define K_TICK_NAME "old_tick"
+#endif
#endif
/* The defaults if not defined previously */
@@ -289,8 +294,8 @@ clock_parms(tickadj, tick)
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
register int i;
int kmem;
@@ -377,8 +382,8 @@ clock_parms(tickadj, tick)
}
close(kmem);
- *tickadj = (U_LONG)vars[K_TICKADJ];
- *tick = (U_LONG)vars[K_TICK];
+ *tickadj = (u_long)vars[K_TICKADJ];
+ *tick = (u_long)vars[K_TICK];
#undef K_TICKADJ
#undef K_TICK
@@ -398,8 +403,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
int hz;
@@ -427,8 +432,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
*tick = 10000;
*tickadj = 150;
@@ -448,8 +453,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
#ifdef RS6000
*tickadj = 1000;
@@ -481,8 +486,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
register int i;
int kmem;
@@ -560,8 +565,8 @@ clock_parms(tickadj, tick)
}
close(kmem);
- *tickadj = (U_LONG)vars[K_TICKADJ];
- *tick = (U_LONG)(1000000/sysconf(_SC_CLK_TCK));
+ *tickadj = (u_long)vars[K_TICKADJ];
+ *tick = (u_long)(1000000/sysconf(_SC_CLK_TCK));
#undef K_TICKADJ
#undef N_NAME
@@ -569,18 +574,18 @@ clock_parms(tickadj, tick)
#endif /* SOLARIS */
#ifdef SYS_LINUX
-#include <sys/timex.h>
+#include "sys/timex.h"
static void
clock_parms(tickadj, tick)
- U_LONG *tickadj;
- U_LONG *tick;
+ u_long *tickadj;
+ u_long *tick;
{
struct timex txc;
txc.mode = 0;
__adjtimex(&txc);
- *tickadj = (U_LONG)1; /* our adjtime is accurate */
- *tick = (U_LONG)txc.tick;
+ *tickadj = (u_long)1; /* our adjtime is accurate */
+ *tick = (u_long)txc.tick;
}
#endif /* SYS_LINUX */
diff --git a/usr.sbin/xntpd/xntpd/ntp_util.c b/usr.sbin/xntpd/xntpd/ntp_util.c
index 4cbb7ac27f53..540be62a675a 100644
--- a/usr.sbin/xntpd/xntpd/ntp_util.c
+++ b/usr.sbin/xntpd/xntpd/ntp_util.c
@@ -1,4 +1,4 @@
-/* ntp_util.c,v 3.1 1993/07/06 01:11:31 jbj Exp
+/*
* ntp_util.c - stuff I didn't have any other place for
*/
#include <stdio.h>
@@ -59,6 +59,12 @@ static FILEGEN clockstats;
*/
extern int errno;
+/*
+ * This controls whether stats are written to the fileset. Provided
+ * so that xntpdc can turn off stats when the file system fills up.
+ */
+int stats_control;
+
#ifdef DEBUG
extern int debug;
#endif
@@ -116,12 +122,11 @@ init_util()
void
hourly_stats()
{
- int fd;
- char *val;
- int vallen;
+ FILE *fp;
extern l_fp last_offset;
extern s_fp drift_comp;
- extern int time_constant;
+ extern u_char sys_poll;
+ extern int pll_status;
#ifdef DOSYNCTODR
struct timeval tv;
@@ -165,32 +170,21 @@ hourly_stats()
skip:
#endif
- syslog(LOG_INFO, "offset %s freq %s comp %d",
- lfptoa(&last_offset, 6), fptoa(drift_comp, 5), time_constant);
+ syslog(LOG_INFO, "offset %s freq %s poll %d",
+ lfptoa(&last_offset, 6), fptoa(drift_comp, 3),
+ sys_poll);
if (stats_drift_file != 0) {
- fd = open(stats_temp_file, O_WRONLY|O_TRUNC|O_CREAT, 0644);
- if (fd == -1) {
- syslog(LOG_ERR, "can't open %s: %m", stats_temp_file);
+ if ((fp = fopen(stats_temp_file, "w")) == NULL) {
+ syslog(LOG_ERR, "can't open %s: %m",
+ stats_temp_file);
return;
}
-
- val = fptoa(drift_comp, 5);
- vallen = strlen(val);
- /*
- * Hack here. Turn the trailing \0 into a \n and write it.
- */
- val[vallen] = '\n';
- if (write(fd, val, vallen+1) == -1) {
- syslog(LOG_ERR, "write to %s failed: %m",
- stats_temp_file);
- (void) close(fd);
- (void) unlink(stats_temp_file);
- } else {
- (void) close(fd);
- /* atomic */
- (void) rename(stats_temp_file, stats_drift_file);
- }
+ fprintf(fp, "%s %x\n", fptoa(drift_comp, 3),
+ pll_status);
+ (void)fclose(fp);
+ /* atomic */
+ (void) rename(stats_temp_file, stats_drift_file);
}
}
@@ -203,11 +197,11 @@ stats_config(item, value)
int item;
char *value; /* only one type so far */
{
- register char *cp;
FILE *fp;
- int len;
char buf[128];
l_fp old_drift;
+ int temp = 0;
+ int len;
switch(item) {
case STATS_FREQ_FILE:
@@ -222,19 +216,17 @@ stats_config(item, value)
break;
stats_drift_file = emalloc((u_int)(len + 1));
- stats_temp_file = emalloc((u_int)(len + sizeof(".TEMP")));
+ stats_temp_file = emalloc((u_int)(len +
+ sizeof(".TEMP")));
memmove(stats_drift_file, value, len+1);
memmove(stats_temp_file, value, len);
- memmove(stats_temp_file + len, ".TEMP", sizeof(".TEMP"));
+ memmove(stats_temp_file + len, ".TEMP",
+ sizeof(".TEMP"));
L_CLR(&old_drift);
-#ifdef DEBUG
- if (debug > 1) {
- printf("stats drift file %s\n", stats_drift_file);
- printf("stats temp file %s\n", stats_temp_file);
- }
-#endif
-
+ /*
+ * Open drift file and read frequency and mode.
+ */
if ((fp = fopen(stats_drift_file, "r")) == NULL) {
if (errno != ENOENT)
syslog(LOG_ERR, "can't open %s: %m",
@@ -243,71 +235,48 @@ stats_config(item, value)
break;
}
- if (fgets(buf, sizeof buf, fp) == NULL) {
+ if (fscanf(fp, "%s %x", buf, &temp) == 0) {
syslog(LOG_ERR, "can't read %s: %m",
stats_drift_file);
(void) fclose(fp);
loop_config(LOOP_DRIFTCOMP, &old_drift, 0);
break;
}
-
(void) fclose(fp);
-
- /*
- * We allow leading spaces, then the number. Terminate
- * at any trailing space or string terminator.
- */
- cp = buf;
- while (isspace(*cp))
- cp++;
- while (*cp != '\0' && !isspace(*cp))
- cp++;
- *cp = '\0';
-
if (!atolfp(buf, &old_drift)) {
syslog(LOG_ERR, "drift value %s invalid", buf);
break;
}
-
- /*
- * Finally! Give value to the loop filter.
- */
-#ifdef DEBUG
- if (debug > 1) {
- printf("loop_config finds old drift of %s\n",
- lfptoa(&old_drift, 9));
- }
-#endif
- loop_config(LOOP_DRIFTCOMP, &old_drift, 0);
+ loop_config(LOOP_DRIFTCOMP, &old_drift, temp);
break;
case STATS_STATSDIR:
if (strlen(value) >= sizeof(statsdir)) {
syslog(LOG_ERR,
- "value for statsdir too LONG (>%d, sigh)",
+ "value for statsdir too long (>%d, sigh)",
sizeof(statsdir)-1);
} else {
l_fp now;
- strcpy(statsdir,value);
gettstamp(&now);
+ strcpy(statsdir,value);
if(peerstats.prefix == &statsdir[0] &&
peerstats.fp != NULL) {
fclose(peerstats.fp);
peerstats.fp = NULL;
- filegen_setup(&peerstats,now.l_ui);
+ filegen_setup(&peerstats, now.l_ui);
}
if(loopstats.prefix == &statsdir[0] &&
loopstats.fp != NULL) {
fclose(loopstats.fp);
loopstats.fp = NULL;
- filegen_setup(&loopstats,now.l_ui);
+ filegen_setup(&loopstats, now.l_ui);
}
if(clockstats.prefix == &statsdir[0] &&
clockstats.fp != NULL) {
fclose(clockstats.fp);
clockstats.fp = NULL;
- filegen_setup(&clockstats,now.l_ui);
+ filegen_setup(&clockstats, now.l_ui);
}
}
break;
@@ -348,14 +317,16 @@ record_peer_stats(addr, status, offset, delay, dispersion)
u_fp dispersion;
{
struct timeval tv;
- U_LONG day, sec, msec;
+ u_long day, sec, msec;
+ if (!stats_control)
+ return;
GETTIMEOFDAY(&tv, (struct timezone *)NULL);
- day = (U_LONG)tv.tv_sec / 86400 + MJD_1970;
- sec = (U_LONG)tv.tv_sec % 86400;
- msec = (U_LONG)tv.tv_usec / 1000;
+ day = tv.tv_sec / 86400 + MJD_1970;
+ sec = tv.tv_sec % 86400;
+ msec = tv.tv_usec / 1000;
- filegen_setup(&peerstats, (U_LONG)(tv.tv_sec + JAN_1970));
+ filegen_setup(&peerstats, (u_long)(tv.tv_sec + JAN_1970));
if (peerstats.fp != NULL) {
fprintf(peerstats.fp, "%lu %lu.%03lu %s %x %s %s %s\n",
day, sec, msec, ntoa(addr), status, lfptoa(offset, 6),
@@ -374,24 +345,26 @@ record_peer_stats(addr, status, offset, delay, dispersion)
* time constant (log base 2)
*/
void
-record_loop_stats(offset, drift_comp, time_constant)
+record_loop_stats(offset, freq, poll)
l_fp *offset;
- s_fp *drift_comp;
- int time_constant;
+ s_fp freq;
+ u_char poll;
{
struct timeval tv;
- U_LONG day, sec, msec;
+ u_long day, sec, msec;
+ if (!stats_control)
+ return;
GETTIMEOFDAY(&tv, (struct timezone *)NULL);
- day = (U_LONG)tv.tv_sec / 86400 + MJD_1970;
- sec = (U_LONG)tv.tv_sec % 86400;
- msec = (U_LONG)tv.tv_usec / 1000;
+ day = tv.tv_sec / 86400 + MJD_1970;
+ sec = tv.tv_sec % 86400;
+ msec = tv.tv_usec / 1000;
- filegen_setup(&loopstats, (U_LONG)(tv.tv_sec + JAN_1970));
+ filegen_setup(&loopstats, (u_long)(tv.tv_sec + JAN_1970));
if (loopstats.fp != NULL) {
fprintf(loopstats.fp, "%lu %lu.%03lu %s %s %d\n",
day, sec, msec, lfptoa(offset, 6),
- fptoa(*drift_comp, 4), time_constant);
+ fptoa(freq, 4), poll);
fflush(loopstats.fp);
}
}
@@ -411,14 +384,16 @@ record_clock_stats(addr, text)
char *text;
{
struct timeval tv;
- U_LONG day, sec, msec;
+ u_long day, sec, msec;
+ if (!stats_control)
+ return;
GETTIMEOFDAY(&tv, (struct timezone *)NULL);
- day = (U_LONG)tv.tv_sec / 86400 + MJD_1970;
- sec = (U_LONG)tv.tv_sec % 86400;
- msec = (U_LONG)tv.tv_usec / 1000;
+ day = tv.tv_sec / 86400 + MJD_1970;
+ sec = tv.tv_sec % 86400;
+ msec = tv.tv_usec / 1000;
- filegen_setup(&clockstats, (U_LONG)(tv.tv_sec + JAN_1970));
+ filegen_setup(&clockstats, (u_long)(tv.tv_sec + JAN_1970));
if (clockstats.fp != NULL) {
fprintf(clockstats.fp, "%lu %lu.%03lu %s %s\n",
day, sec, msec, ntoa(addr), text);
diff --git a/usr.sbin/xntpd/xntpd/ntpd.c b/usr.sbin/xntpd/xntpd/ntpd.c
index 9ed43c5c4a81..43ae699c97a2 100644
--- a/usr.sbin/xntpd/xntpd/ntpd.c
+++ b/usr.sbin/xntpd/xntpd/ntpd.c
@@ -1,4 +1,4 @@
-/* ntpd.c,v 3.1 1993/07/06 01:11:32 jbj Exp
+/*
* ntpd.c - main program for the fixed point NTP daemon
*/
#include <stdio.h>
@@ -75,7 +75,7 @@ extern char *Version;
*/
extern int alarm_flag;
-#if !defined(SYS_386BSD) && !defined(SYS_BSDI)
+#if !defined(SYS_386BSD) && !defined(SYS_BSDI) && !defined(SYS_44BSD)
/*
* We put this here, since the argument profile is syscall-specific
*/
@@ -130,7 +130,7 @@ main(argc, argv)
exit(0);
{
- unsigned long s;
+ u_long s;
int max_fd;
#if defined(NTP_POSIX_SOURCE) && !defined(SYS_386BSD)
max_fd = sysconf(_SC_OPEN_MAX);
@@ -169,7 +169,7 @@ main(argc, argv)
fid = open("/dev/tty", 2);
if (fid >= 0) {
- (void) ioctl(fid, (U_LONG) TIOCNOTTY,
+ (void) ioctl(fid, (u_long) TIOCNOTTY,
(char *) 0);
(void) close(fid);
}
@@ -279,6 +279,13 @@ main(argc, argv)
#endif /* DEBUG */
/*
+ * Set up signals we should never pay attention to.
+ */
+#ifdef SIGPIPE
+ (void) signal_no_reset(SIGPIPE, SIG_IGN);
+#endif /* SIGPIPE */
+
+ /*
* Call the init_ routines to initialize the data structures.
* Note that init_systime() may run a protocol to get a crude
* estimate of the time as an NTP client when running on the
@@ -307,6 +314,9 @@ main(argc, argv)
init_io();
init_loopfilter();
+ mon_start(MON_ON); /* monitor on by default now */
+ /* turn off in config if unwanted */
+
/*
* Get configuration. This (including argument list parsing) is
* done in a separate module since this will definitely be different
@@ -361,10 +371,8 @@ main(argc, argv)
get_systime(&ts);
(void)input_handler(&ts);
- }
- else if (nfound == -1 && errno != EINTR) {
+ } else if (nfound == -1 && errno != EINTR)
syslog(LOG_ERR, "select() error: %m");
- }
#else
wait_for_signal();
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_acts.c b/usr.sbin/xntpd/xntpd/refclock_acts.c
new file mode 100644
index 000000000000..af3cabf11c82
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_acts.c
@@ -0,0 +1,895 @@
+/*
+ * refclock_acts - clock driver for the NIST Automated Computer Time
+ * Service aka Amalgamated Containerized Trash Service (ACTS)
+ */
+#if defined(REFCLOCK) && defined(ACTS)
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the NIST Automated Computer Time Service (ACTS).
+ * It periodically dials a prespecified telephone number, receives the
+ * NIST timecode data and calculates the local clock correction. It is
+ * designed primarily for use as a backup when neither a radio clock nor
+ * connectivity to Internet time servers is available. For the best
+ * accuracy, the individual telephone line/modem delay needs to be
+ * calibrated using outside sources.
+ *
+ * The ACTS is located at NIST Boulder, CO, telephone 303 494 4774. A
+ * toll call from a residence telephone in Newark, DE, costs between 14
+ * and 27 cents, depending on time of day, and from a campus telephone
+ * between 3 and 4 cents, although it is not clear what carrier and time
+ * of day discounts apply in this case. The modem dial string will
+ * differ depending on local telephone configuration, etc., and is
+ * specified by the phone command in the configuration file. The
+ * argument to this command is an AT command for a Hayes compatible
+ * modem.
+ *
+ * The accuracy produced by this driver should be in the range of a
+ * millisecond or two, but may need correction due to the delay
+ * characteristics of the individual modem involved. For undetermined
+ * reasons, some modems work with the ACTS echo-delay measurement scheme
+ * and some don't. This driver tries to do the best it can with what it
+ * gets. Initial experiments with a Practical Peripherals 9600SA modem
+ * here in Delaware suggest an accuracy of a millisecond or two can be
+ * achieved without the scheme by using a fudge time1 value of 65.0 ms.
+ * In either case, the dispersion for a single call involving ten
+ * samples is about 1.3 ms.
+ *
+ * The driver can operate in either of three modes, as determined by
+ * the mode parameter in the server configuration command. In mode 0
+ * (automatic) the driver operates continuously at intervals depending
+ * on the prediction error, as measured by the driver, usually in the
+ * order of several hours. In mode 1 (backup) the driver is enabled in
+ * automatic mode only when no other source of synchronization is
+ * available and when more than MAXOUTAGE (3600 s) have elapsed since
+ * last synchronized by other sources. In mode 2 (manual) the driver
+ * operates only when enabled using a fudge flags switch, as described
+ * below.
+ *
+ * For reliable call management, this driver requires a 1200-bps modem
+ * with a Hayes-compatible command set and control over the modem data
+ * terminal ready (DTR) control line. Present restrictions require the
+ * use of a POSIX-compatible programming interface, although other
+ * interfaces may work as well. The modem setup string is hard-coded in
+ * the driver and may require changes for nonstandard modems or special
+ * circumstances.
+ *
+ * Further information can be found in the README.refclock file in the
+ * xntp3 distribution.
+ *
+ * Fudge Factors
+ *
+ * Ordinarily, the propagation time correction is computed automatically
+ * by ACTS and the driver. When this is not possible or erratic due to
+ * individual modem characteristics, the fudge flag2 switch should be
+ * set to disable the ACTS echo-delay scheme. In any case, the fudge
+ * time1 parameter can be used to adjust the propagation delay as
+ * required.
+ *
+ * The ACTS call interval is determined in one of three ways. In manual
+ * mode a call is initiated by setting fudge flag1 using xntpdc, either
+ * manually or via a cron job. In AUTO mode this flag is set by the peer
+ * timer, which is controlled by the sys_poll variable in response to
+ * measured errors. In backup mode the driver is ordinarily asleep, but
+ * awakes (in auto mode) if all other synchronization sources are lost.
+ * In either auto or backup modes, the call interval increases as long
+ * as the measured errors do not exceed the value of the fudge time2
+ * parameter.
+ *
+ * When the fudge flag1 is set, the ACTS calling program is activated.
+ * This program dials each number listed in the phones command of the
+ * configuration file in turn. If a call attempt fails, the next number
+ * in the list is dialed. The fudge flag1 and counter are reset and the
+ * calling program terminated if (a) a valid clock update has been
+ * determined, (b) no more numbers remain in the list, (c) a device
+ * fault or timeout occurs or (d) fudge flag1 is reset manually using
+ * xntpdc.
+ *
+ * In automatic and backup modes, the driver determines the call
+ * interval using a procedure depending on the measured prediction
+ * error and the fudge time2 parameter. If the error exceeds time2 for a
+ * number of times depending on the current interval, the interval is
+ * decreased, but not less than about 1000 s. If the error is less than
+ * time2 for some number of times, the interval is increased, but not
+ * more than about 18 h. With the default value of zero for fudge time2,
+ * the interval will increase from 1000 s to the 4000-8000-s range, in
+ * which the expected accuracy should be in the 1-2-ms range. Setting
+ * fudge time2 to a large value, like 0.1 s, may result in errors of
+ * that order, but increase the call interval to the maximum. The exact
+ * value for each configuration will depend on the modem and operating
+ * system involved, so some experimentation may be necessary.
+ */
+
+/*
+ * DESCRIPTION OF THE AUTOMATED COMPUTER TELEPHONE SERVICE (ACTS)
+ * (reformatted from ACTS on-line computer help information)
+ *
+ * The following is transmitted (at 1200 baud) following completion of
+ * the telephone connection.
+ *
+ * National Institute of Standards and Technology
+ * Telephone Time Service, Generator 3B
+ * Enter question mark "?" for HELP
+ * D L D
+ * MJD YR MO DA H M S ST S UT1 msADV <OTM>
+ * 47999 90-04-18 21:39:15 50 0 +.1 045.0 UTC(NIST) *
+ * 47999 90-04-18 21:39:16 50 0 +.1 045.0 UTC(NIST) *
+ * 47999 90-04-18 21:39:17 50 0 +.1 045.0 UTC(NIST) *
+ * 47999 90-04-18 21:39:18 50 0 +.1 045.0 UTC(NIST) *
+ * 47999 90-04-18 21:39:19 50 0 +.1 037.6 UTC(NIST) #
+ * 47999 90-04-18 21:39:20 50 0 +.1 037.6 UTC(NIST) #
+ * etc..etc...etc.......
+ *
+ * UTC = Universal Time Coordinated, the official world time referred to
+ * the zero meridian.
+ *
+ * DST Daylight savings time characters, valid for the continental
+ * U.S., are set as follows:
+ *
+ * 00 We are on standard time (ST).
+ * 01-49 Now on DST, go to ST when your local time is 2:00 am and
+ * the count is 01. The count is decremented daily at 00
+ * (UTC).
+ * 50 We are on DST.
+ * 51-99 Now on ST, go to DST when your local time is 2:00 am and
+ * the count is 51. The count is decremented daily at 00
+ * (UTC).
+ *
+ * The two DST characters provide up to 48 days advance notice of a
+ * change in time. The count remains at 00 or 50 at other times.
+ *
+ * LS Leap second flag is set to "1" to indicate that a leap second is
+ * to be added as 23:59:60 (UTC) on the last day of the current UTC
+ * month. The LS flag will be reset to "0" starting with 23:59:60
+ * (UTC). The flag will remain on for the entire month before the
+ * second is added. Leap seconds are added as needed at the end of
+ * any month. Usually June and/or December are chosen.
+ *
+ * The leap second flag will be set to a "2" to indicate that a
+ * leap second is to be deleted at 23:59:58--00:00:00 on the last
+ * day of the current month. (This latter provision is included per
+ * international recommendation, however it is not likely to be
+ * required in the near future.)
+ *
+ * DUT1 Approximate difference between earth rotation time (UT1) and
+ * UTC, in steps of 0.1 second: DUT1 = UT1 - UTC.
+ *
+ * MJD Modified Julian Date, often used to tag certain scientific data.
+ *
+ * The full time format is sent at 1200 baud, 8 bit, 1 stop, no parity.
+ * The format at 300 Baud is also 8 bit, 1 stop, no parity. At 300 Baud
+ * the MJD and DUT1 values are deleted and the time is transmitted only
+ * on even seconds.
+ *
+ * Maximum on line time will be 56 seconds. If all lines are busy at any
+ * time, the oldest call will be terminated if it has been on line more
+ * than 28 seconds, otherwise, the call that first reaches 28 seconds
+ * will be terminated.
+ *
+ * Current time is valid at the "on-time" marker (OTM), either "*" or
+ * "#". The nominal on-time marker (*) will be transmitted 45 ms early
+ * to account for the 8 ms required to send 1 character at 1200 Baud,
+ * plus an additional 7 ms for delay from NIST to the user, and
+ * approximately 30 ms "scrambler" delay inherent in 1200 Baud modems.
+ * If the caller echoes all characters, NIST will measure the round trip
+ * delay and advance the on-time marker so that the midpoint of the stop
+ * bit arrives at the user on time. The amount of msADV will reflect the
+ * actual required advance in milliseconds and the OTM will be a "#".
+ *
+ * (The NIST system requires 4 or 5 consecutive delay measurements which
+ * are consistent before switching from "*" to "#". If the user has a
+ * 1200 Baud modem with the same internal delay as that used by NIST,
+ * then the "#" OTM should arrive at the user within +-2 ms of the
+ * correct time.
+ *
+ * However, NIST has studied different brands of 1200 Baud modems and
+ * found internal delays from 24 ms to 40 ms and offsets of the "#" OTM
+ * of +-10 ms. For many computer users, +-10 ms accuracy should be more
+ * than adequate since many computer internal clocks can only be set
+ * with granularity of 20 to 50 ms. In any case, the repeatability of
+ * the offset for the "#" OTM should be within +-2 ms, if the dial-up
+ * path is reciprocal and the user doesn't change the brand or model of
+ * modem used.
+ *
+ * This should be true even if the dial-up path on one day is a land-
+ * line of less than 40 ms (one way) and on the next day is a satellite
+ * link of 260 to 300 ms. In the rare event that the path is one way by
+ * satellite and the other way by land line with a round trip
+ * measurement in the range of 90 to 260 ms, the OTM will remain a "*"
+ * indicating 45 ms advance.
+ *
+ * For user comments write:
+ * NIST-ACTS
+ * Time and Frequency Division
+ * Mail Stop 847
+ * 325 Broadway
+ * Boulder, CO 80303
+ *
+ * Software for setting (PC)DOS compatable machines is available on a
+ * 360-kbyte diskette for $35.00 from: NIST Office of Standard Reference
+ * Materials B311-Chemistry Bldg, NIST, Gaithersburg, MD, 20899, (301)
+ * 975-6776
+ */
+
+/*
+ * Interface definitions
+ */
+#define DEVICE "/dev/acts%d" /* device name and unit */
+#define SPEED232 B1200 /* uart speed (1200 cowardly baud) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "ACTS" /* reference ID */
+#define DESCRIPTION "NIST Automated Computer Time Service" /* WRU */
+
+#define MODE_AUTO 0 /* automatic mode */
+#define MODE_BACKUP 1 /* backup mode */
+#define MODE_MANUAL 2 /* manual mode */
+
+#define NSAMPLES 3 /* stages of median filter */
+#define MSGCNT 10 /* we need this many ACTS messages */
+#define SMAX 80 /* max token string length */
+#define LENCODE 50 /* length of valid timecode string */
+#define ACTS_MINPOLL 10 /* log2 min poll interval (1024 s) */
+#define ACTS_MAXPOLL 14 /* log2 max poll interval (16384 s) */
+#define MAXOUTAGE 3600 /* max before ACTS kicks in (s) */
+
+/*
+ * Modem control strings. These may have to be changed for some modems.
+ *
+ * AT command prefix
+ * B1 initiate call negotiation using Bell 212A
+ * &C1 enable carrier detect
+ * &D2 hang up and return to command mode on DTR transition
+ * E0 modem command echo disabled
+ * l1 set modem speaker volume to low level
+ * M1 speaker enabled untill carrier detect
+ * Q0 return result codes
+ * V1 return result codes as English words
+ */
+#define MODEM_SETUP "ATB1&C1&D2E0L1M1Q0V1" /* modem setup */
+#define MODEM_HANGUP "ATH" /* modem disconnect */
+
+/*
+ * Timeouts
+ */
+#define IDLE 60 /* idle timeout (s) */
+#define WAIT 2 /* wait timeout (s) */
+#define ANSWER 30 /* answer timeout (s) */
+#define CONNECT 10 /* connect timeout (s) */
+#define TIMECODE 15 /* timecode timeout (s) */
+
+/*
+ * Imported from ntp_timer module
+ */
+extern u_long current_time; /* current time (s) */
+extern u_long last_time; /* last clock update time (s) */
+extern struct event timerqueue[]; /* inner space */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * Imported from ntp_config module
+ */
+extern char sys_phone[][MAXDIAL]; /* modem dial strings */
+
+/*
+ * Imported from ntp_proto module
+ */
+extern struct peer *sys_peer; /* who is running the show */
+extern u_char sys_poll; /* log2 of system poll interval */
+extern struct peer *sys_peer; /* system peer structure pointer */
+
+/*
+ * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
+ * leap.
+ */
+static day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ * Unit control structure
+ */
+struct actsunit {
+ struct event timer; /* timeout timer */
+ int pollcnt; /* poll message counter */
+
+ int state; /* the first one was Delaware */
+ int run; /* call program run switch */
+ int msgcnt; /* count of ACTS messages received */
+ long redial; /* interval to next automatic call */
+ double msADV; /* millisecond advance of last message */
+};
+
+/*
+ * Function prototypes
+ */
+static int acts_start P((int, struct peer *));
+static void acts_shutdown P((int, struct peer *));
+static void acts_receive P((struct recvbuf *));
+static void acts_poll P((int, struct peer *));
+static void acts_timeout P((struct peer *));
+static void acts_disc P((struct peer *));
+static int acts_write P((struct peer *, char *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_acts = {
+ acts_start, /* start up driver */
+ acts_shutdown, /* shut down driver */
+ acts_poll, /* transmit poll message */
+ noentry, /* not used (old acts_control) */
+ noentry, /* not used (old acts_init) */
+ noentry, /* not used (old acts_buginfo) */
+ NOFLAGS /* not used */
+};
+
+
+/*
+ * acts_start - open the devices and initialize data for processing
+ */
+static int
+acts_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
+ int dtr = TIOCM_DTR;
+
+ /*
+ * Open serial port. Use ACTS line discipline, if available. It
+ * pumps a timestamp into the data stream at every on-time
+ * character '*' found. Note: the port must have modem control
+ * or deep pockets for the phone bill. HP-UX 9.03 users should
+ * have very deep pockets.
+ */
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS)))
+ return (0);
+ if (ioctl(fd, TIOCMBIC, (char *)&dtr) < 0) {
+ syslog(LOG_ERR, "clock %s ACTS no modem control",
+ ntoa(&peer->srcadr));
+ return (0);
+ }
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct actsunit *)
+ emalloc(sizeof(struct actsunit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct actsunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = acts_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ peer->minpoll = ACTS_MINPOLL;
+ peer->maxpoll = ACTS_MAXPOLL;
+
+ /*
+ * Initialize modem and kill DTR. We skedaddle if this comes
+ * bum.
+ */
+ if (!acts_write(peer, MODEM_SETUP)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+
+ /*
+ * Set up the driver timeout
+ */
+ up->timer.peer = (struct peer *)peer;
+ up->timer.event_handler = acts_timeout;
+ up->timer.event_time = current_time + WAIT;
+ TIMER_INSERT(timerqueue, &up->timer);
+ return (1);
+}
+
+
+/*
+ * acts_shutdown - shut down the clock
+ */
+static void
+acts_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ TIMER_DEQUEUE(&up->timer);
+ io_closeclock(&pp->io);
+ free(up);
+}
+
+
+/*
+ * acts_receive - receive data from the serial interface
+ */
+static void
+acts_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ char str[SMAX];
+ int i;
+ l_fp tstmp;
+ u_fp disp;
+ char hangup = '%'; /* ACTS hangup */
+ int day; /* day of the month */
+ int month; /* month of the year */
+ u_long mjd; /* Modified Julian Day */
+ u_int dst; /* daylight/standard time indicator */
+ u_int leap; /* leap-second indicator */
+ double dut1; /* DUT adjustment */
+ double msADV; /* ACTS transmit advance (ms) */
+ char utc[10]; /* this is NIST and you're not */
+ char flag; /* calibration flag */
+
+ /*
+ * Initialize pointers and read the timecode and timestamp. If
+ * the OK modem status code, leave it where folks can find it.
+ */
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX,
+ &pp->lastrec);
+ if (pp->lencode == 0) {
+ if (strcmp(pp->lastcode, "OK") == 0)
+ pp->lencode = 2;
+ return;
+ }
+#ifdef DEBUG
+ if (debug)
+ printf("acts: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
+#endif
+
+ switch (up->state) {
+
+ case 0:
+
+ /*
+ * State 0. We are not expecting anything. Probably
+ * modem disconnect noise. Go back to sleep.
+ */
+ return;
+
+ case 1:
+
+ /*
+ * State 1. We are waiting for the call to be answered.
+ * All we care about here is CONNECT as the first token
+ * in the string. If the modem signals BUSY, ERROR, NO
+ * ANSWER, NO CARRIER or NO DIALTONE, we immediately
+ * hang up the phone. If CONNECT doesn't happen after
+ * ANSWER seconds, hang up the phone. If everything is
+ * okay, start the connect timeout and slide into state
+ * 2.
+ */
+ (void)strncpy(str, strtok(pp->lastcode, " "), SMAX);
+ if (strcmp(str, "BUSY") == 0 || strcmp(str, "ERROR") ==
+ 0 || strcmp(str, "NO") == 0) {
+ TIMER_DEQUEUE(&up->timer);
+ syslog(LOG_NOTICE,
+ "clock %s ACTS modem status %s",
+ ntoa(&peer->srcadr), pp->lastcode);
+ acts_disc(peer);
+ } else if (strcmp(str, "CONNECT") == 0) {
+ TIMER_DEQUEUE(&up->timer);
+ up->timer.event_time = current_time + CONNECT;
+ TIMER_INSERT(timerqueue, &up->timer);
+ up->msgcnt = 0;
+ up->state++;
+ }
+ return;
+
+ case 2:
+
+ /*
+ * State 2. The call has been answered and we are
+ * waiting for the first ACTS message. If this doesn't
+ * happen within the timecode timeout, hang up the
+ * phone. We probably got a wrong number or ACTS is
+ * down.
+ */
+ TIMER_DEQUEUE(&up->timer);
+ up->timer.event_time = current_time + TIMECODE;
+ TIMER_INSERT(timerqueue, &up->timer);
+ up->state++;
+ }
+
+ /*
+ * Real yucky things here. Ignore everything except timecode
+ * messages, as determined by the message length. We told the
+ * terminal routines to end the line with '*' and the line
+ * discipline to strike a timestamp on that character. However,
+ * when the ACTS echo-delay scheme works, the '*' eventually
+ * becomes a '#'. In this case the message is ended by the <CR>
+ * that comes about 200 ms after the '#' and the '#' cannot be
+ * echoed at the proper time. But, this may not be a lose, since
+ * we already have good data from prior messages and only need
+ * the millisecond advance calculated by ACTS. So, if the
+ * message is long enough and has an on-time character at the
+ * right place, we consider the message (but not neccesarily the
+ * timestmap) to be valid.
+ */
+ if (pp->lencode != LENCODE)
+ return;
+
+ /*
+ * We apparently have a valid timecode message, so dismember it
+ * with sscan(). This routine does a good job in spotting syntax
+ * errors without becoming overly pedantic.
+ *
+ * D L D
+ * MJD YR MO DA H M S ST S UT1 msADV OTM
+ * 47222 88-03-02 21:39:15 83 0 +.3 045.0 UTC(NBS) *
+ */
+ if (sscanf(pp->lastcode,
+ "%5ld %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3lf %5lf %s %c",
+ &mjd, &pp->year, &month, &day, &pp->hour, &pp->minute,
+ &pp->second, &dst, &leap, &dut1, &msADV, utc, &flag) != 13) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Some modems can't be trusted (the Practical Peripherals
+ * 9600SA comes to mind) and, even if they manage to unstick
+ * ACTS, the millisecond advance is wrong, so we use CLK_FLAG2
+ * to disable echoes, if neccessary.
+ */
+ if ((flag == '*' || flag == '#') && !(pp->sloppyclockflag &
+ CLK_FLAG2))
+ (void)write(pp->io.fd, &flag, 1);
+
+ /*
+ * Yes, I know this code incorrectly thinks that 2000 is a leap
+ * year. The ACTS timecode format croaks then anyway. Life is
+ * short. Would only the timecode mavens resist the urge to
+ * express months of the year and days of the month in favor of
+ * days of the year.
+ */
+ if (month < 1 || month > 12 || day < 1) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ if (pp->year % 4) {
+ if (day > day1tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day1tab[i];
+ } else {
+ if (day > day2tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day2tab[i];
+ }
+ pp->day = day;
+ if (leap == 1)
+ pp->leap = LEAP_ADDSECOND;
+ else if (pp->leap == 2)
+ pp->leap = LEAP_DELSECOND;
+ else
+ pp->leap = 0;
+ pp->lasttime = current_time;
+
+ /*
+ * Colossal hack here. We process each sample in a trimmed-mean
+ * filter and determine the reference clock offset and
+ * dispersion. The fudge time1 value is added to each sample as
+ * received. If we collect MSGCNT samples before the '#' on-time
+ * character, we use the results of the filter as is. If the '#'
+ * is found before that, the adjusted msADV is used to correct
+ * the propagation delay.
+ */
+ up->msgcnt++;
+ if (flag == '#') {
+ L_CLR(&tstmp);
+ TVUTOTSF((long)((msADV - up->msADV) * 1000.),
+ tstmp.l_uf);
+ L_ADD(&pp->offset, &tstmp);
+ } else {
+ up->msADV = msADV;
+ if (!refclock_process(pp, up->msgcnt, up->msgcnt -
+ up->msgcnt / 3)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ } else if (up->msgcnt < MSGCNT)
+ return;
+ }
+
+ /*
+ * We have a filtered sample offset ready for peer processing.
+ * We use lastrec as both the reference time and receive time in
+ * order to avoid being cute, like setting the reference time
+ * later than the receive time, which may cause a paranoid
+ * protocol module to chuck out the data. Finaly, we unhook the
+ * timeout, arm for the next call, fold the tent and go home.
+ * The little dance with the '%' character is an undocumented
+ * ACTS feature that hangs up the phone real quick without
+ * waiting for carrier loss or long-space disconnect, but we do
+ * these clumsy things anyway.
+ */
+ disp = LFPTOFP(&pp->fudgetime2);
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion +
+ (u_fp)disp, &pp->lastrec, &pp->lastrec, pp->leap);
+ pp->sloppyclockflag &= ~CLK_FLAG1;
+ up->pollcnt = 0;
+ TIMER_DEQUEUE(&up->timer);
+ (void)write(pp->io.fd, &hangup, 1);
+ up->state = 0;
+ acts_disc(peer);
+}
+
+
+/*
+ * acts_poll - called by the transmit routine
+ */
+static void
+acts_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+
+ /*
+ * If the driver is running, we set the enable flag (fudge
+ * flag1), which causes the driver timeout routine to initiate a
+ * call to ACTS. If not, the enable flag can be set using
+ * xntpdc. If this is the sustem peer, then follow the system
+ * poll interval.
+ */
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ if (up->run) {
+ pp->sloppyclockflag |= CLK_FLAG1;
+ if (peer == sys_peer)
+ peer->hpoll = sys_poll;
+ else
+ peer->hpoll = peer->minpoll;
+ }
+}
+
+
+/*
+ * acts_timeout - called by the timer interrupt
+ */
+static void
+acts_timeout(peer)
+ struct peer *peer;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+ int dtr = TIOCM_DTR;
+
+ /*
+ * If a timeout occurs in other than state 0, the call has
+ * failed. If in state 0, we just see if there is other work to
+ * do.
+ */
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ if (up->state) {
+ acts_disc(peer);
+ return;
+ }
+ switch (peer->ttl) {
+
+ /*
+ * In manual mode the ACTS calling program is activated
+ * by the xntpdc program using the enable flag (fudge
+ * flag1), either manually or by a cron job.
+ */
+ case MODE_MANUAL:
+ up->run = 0;
+ break;
+
+ /*
+ * In automatic mode the ACTS calling program runs
+ * continuously at intervals determined by the sys_poll
+ * variable.
+ */
+ case MODE_AUTO:
+ if (!up->run)
+ pp->sloppyclockflag |= CLK_FLAG1;
+ up->run = 1;
+ break;
+
+ /*
+ * In backup mode the ACTS calling program is disabled,
+ * unless no system peer has been selected for MAXOUTAGE
+ * (3600 s). Once enabled, it runs until some other NTP
+ * peer shows up.
+ */
+ case MODE_BACKUP:
+ if (!up->run && sys_peer == 0) {
+ if (current_time - last_time > MAXOUTAGE) {
+ up->run = 1;
+ peer->hpoll = peer->minpoll;
+ syslog(LOG_NOTICE,
+ "clock %s ACTS backup started ",
+ ntoa(&peer->srcadr));
+ }
+ } else if (up->run && sys_peer->refclktype !=
+ REFCLK_NIST_ACTS) {
+ peer->hpoll = peer->minpoll;
+ up->run = 0;
+ syslog(LOG_NOTICE,
+ "clock %s ACTS backup stopped",
+ ntoa(&peer->srcadr));
+ }
+ break;
+
+ default:
+ syslog(LOG_NOTICE,
+ "clock %s ACTS invalid mode", ntoa(&peer->srcadr));
+
+ }
+
+ /*
+ * The fudge flag1 is used as an enable/disable; if set either
+ * by the code or via xntpdc, the ACTS calling program is
+ * started; if reset, the phones stop ringing.
+ */
+ if (!(pp->sloppyclockflag & CLK_FLAG1)) {
+ up->pollcnt = 0;
+ up->timer.event_time = current_time + IDLE;
+ TIMER_INSERT(timerqueue, &up->timer);
+ return;
+ }
+
+ /*
+ * Initiate a call to the ACTS service. If we wind up here in
+ * other than state 0, a successful call could not be completed
+ * within minpoll seconds. We advance to the next modem dial
+ * string. If none are left, we log a notice and clear the
+ * enable flag. For future enhancement: call the site RP and
+ * leave an obscene message in his voicemail.
+ */
+ if (sys_phone[up->pollcnt][0] == '\0') {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ syslog(LOG_NOTICE,
+ "clock %s ACTS calling program terminated",
+ ntoa(&peer->srcadr));
+ pp->sloppyclockflag &= ~CLK_FLAG1;
+#ifdef DEBUG
+ if (debug)
+ printf("acts: calling program terminated\n");
+#endif
+ up->pollcnt = 0;
+ up->timer.event_time = current_time + IDLE;
+ TIMER_INSERT(timerqueue, &up->timer);
+ return;
+ }
+
+ /*
+ * Raise DTR, call ACTS and start the answer timeout. We think
+ * it strange if the OK status has not been received from the
+ * modem, but plow ahead anyway.
+ */
+ if (strcmp(pp->lastcode, "OK") != 0)
+ syslog(LOG_NOTICE, "clock %s ACTS no modem status",
+ ntoa(&peer->srcadr));
+ (void)ioctl(pp->io.fd, TIOCMBIS, (char *)&dtr);
+ (void)acts_write(peer, sys_phone[up->pollcnt]);
+ syslog(LOG_NOTICE, "clock %s ACTS calling %s\n",
+ ntoa(&peer->srcadr), sys_phone[up->pollcnt]);
+ up->state = 1;
+ up->pollcnt++;
+ pp->polls++;
+ up->timer.event_time = current_time + ANSWER;
+ TIMER_INSERT(timerqueue, &up->timer);
+}
+
+
+/*
+ * acts_disc - disconnect the call and wait for the ruckus to cool
+ */
+static void
+acts_disc(peer)
+ struct peer *peer;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+ int dtr = TIOCM_DTR;
+
+ /*
+ * We should never get here other than in state 0, unless a call
+ * has timed out. We drop DTR, which will reliably get the modem
+ * off the air, even while ACTS is hammering away full tilt.
+ */
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ (void)ioctl(pp->io.fd, TIOCMBIC, (char *)&dtr);
+ if (up->state > 0) {
+ up->state = 0;
+ syslog(LOG_NOTICE, "clock %s ACTS call failed %d",
+ ntoa(&peer->srcadr), up->state);
+#ifdef DEBUG
+ if (debug)
+ printf("acts: call failed %d\n", up->state);
+#endif
+ }
+ up->timer.event_time = current_time + WAIT;
+ TIMER_INSERT(timerqueue, &up->timer);
+}
+
+
+/*
+ * acts_write - write a message to the serial port
+ */
+static int
+acts_write(peer, str)
+ struct peer *peer;
+ char *str;
+{
+ register struct actsunit *up;
+ struct refclockproc *pp;
+ int len;
+ int code;
+ char cr = '\r';
+
+ /*
+ * Not much to do here, other than send the message, handle
+ * debug and report faults.
+ */
+ pp = peer->procptr;
+ up = (struct actsunit *)pp->unitptr;
+ len = strlen(str);
+#ifdef DEBUG
+ if (debug)
+ printf("acts: state %d send %d %s\n", up->state, len,
+ str);
+#endif
+ code = write(pp->io.fd, str, len) == len;
+ code |= write(pp->io.fd, &cr, 1) == 1;
+ if (!code)
+ refclock_report(peer, CEVNT_FAULT);
+ return (code);
+}
+
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_as2201.c b/usr.sbin/xntpd/xntpd/refclock_as2201.c
index 97b5837c2f3b..6c60fd0b9447 100644
--- a/usr.sbin/xntpd/xntpd/refclock_as2201.c
+++ b/usr.sbin/xntpd/xntpd/refclock_as2201.c
@@ -1,7 +1,8 @@
/*
- * refclock_gps - clock driver for the Austron 2201A GPS Timing Receiver
+ * refclock_as2201 - clock driver for the Austron 2201A GPS
+ * Timing Receiver
*/
-#if defined(REFCLOCK) && (defined(AS2201) || defined(AS2201CLK) || defined(AS2201PPS))
+#if defined(REFCLOCK) && defined(AS2201)
#include <stdio.h>
#include <ctype.h>
@@ -11,30 +12,11 @@
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
+#include "ntp_stdlib.h"
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#if defined(AS2201CLK)
-#include <sys/clkdefs.h>
-#endif /* AS2201CLK */
-#endif /* STREAM */
-
-#if defined (AS2201PPS)
+#ifdef PPS
#include <sys/ppsclock.h>
-#endif /* AS2201PPS */
-
-#include "ntp_stdlib.h"
+#endif /* PPS */
/*
* This driver supports the Austron 2200A/2201A GPS Receiver with
@@ -49,7 +31,9 @@
* a multi-line reply showing the corresponding statistics or other
* selected data. Statistics commands are sent in order as determined by
* a vector of commands; these might have to be changed with different
- * radio options.
+ * radio options. If flag4 of the fudge configuration command is set to
+ * 1, the statistics data are written to the clockstats file for later
+ * processing.
*
* In order for this code to work, the radio must be placed in non-
* interactive mode using the "off" command and with a single <cr>
@@ -58,105 +42,68 @@
* timescale using the "ts utc" command.
*
* There are two modes of operation for this driver. The first with
- * undefined AS2201PPS is used with stock kernels and serial-line drivers
- * and works with almost any machine. In this mode the driver assumes
- * the radio captures a timestamp upon receipt of the "*" that begins
- * the driver query. Accuracies in this mode are in the order of a
- * millisecond or two and the receiver can be connected to only one
- * host. The second with AS2201PPS defined can be used for SunOS kernels
- * that have been modified with the ppsclock streams module included in
- * this distribution. In this mode a precise timestamp is available
- * using a gadget box and 1-pps signal from the receiver; however, the
- * sample rate is limited to the polling rate, normally about one poll
- * every 16 seconds. This improves the accuracy to the order of a few
- * tens of microseconds. In addition, the serial output and 1-pps signal
- * can be bussed to additional receivers. For the utmost accuracy, the
- * sample rate can be increased to one per second using the PPSCD
- * define. This improves the accuracy to the order of a few
- * microseconds.
- */
-
-/*
- * Definitions
+ * default configuration is used with stock kernels and serial-line
+ * drivers and works with almost any machine. In this mode the driver
+ * assumes the radio captures a timestamp upon receipt of the "*" that
+ * begins the driver query. Accuracies in this mode are in the order of
+ * a millisecond or two and the receiver can be connected to only one
+ * host.
+ *
+ * The second mode of operation can be used for SunOS kernels that have
+ * been modified with the ppsclock streams module included in this
+ * distribution. The mode is enabled if flag3 of the fudge configuration
+ * command has been set to 1. In this mode a precise timestamp is
+ * available using a gadget box and 1-pps signal from the receiver. This
+ * improves the accuracy to the order of a few tens of microseconds. In
+ * addition, the serial output and 1-pps signal can be bussed to
+ * additional receivers.
*/
-#define MAXUNITS 4 /* max number of GPS units */
-#define GPS232 "/dev/gps%d" /* name of radio device */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
/*
- * Radio interface parameters
+ * GPS Definitions
*/
-#define GPSPRECISION (-15) /* precision assumed (about 30 us) */
-#define GPSREFID "GPS" /* reference id */
-#define GPSDESCRIPTION "Austron 2201A GPS Receiver" /* who we are */
-#define GPSHSREFID 0x7f7f040a /* 127.127.4.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
-#define NCODES 3 /* stages of median filter */
-#define LENTOC 19 /* yy:ddd:hh:mm:ss.mmm datecode length */
-#define BMAX 100 /* timecode buffer length */
#define SMAX 200 /* statistics buffer length */
-#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define DEVICE "/dev/gps%d" /* device name and unit */
+#define SPEED232 B9600 /* uart speed (9600 baud) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "GPS\0" /* reference ID */
+#define DESCRIPTION "Austron 2201A GPS Receiver" /* WRU */
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
- */
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
+#define NSAMPLES 3 /* stages of median filter */
+#define LENTOC 19 /* yy:ddd:hh:mm:ss.mmm timecode lngth */
/*
* Imported from ntp_timer module
*/
-extern U_LONG current_time; /* current time (s) */
+extern u_long current_time; /* current time (s) */
/*
- * Imported from ntp_loopfilter module
+ * Imported from ntpd module
*/
-extern int fdpps; /* pps file descriptor */
+extern int debug; /* global debug flag */
+#ifdef PPS
/*
- * Imported from ntpd module
+ * Imported from loop_filter module
*/
-extern int debug; /* global debug flag */
+extern int fdpps; /* ppsclock file descriptor */
+#endif /* PPS */
/*
- * GPS unit control structure.
+ * AS2201 unit control structure.
*/
-struct gpsunit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp lastrec; /* last data receive time */
- l_fp lastref; /* last timecode time */
- l_fp offset[NCODES]; /* recent sample offsets */
- char lastcode[BMAX]; /* last timecode received */
- char *lastptr; /* statistics buffer pointer */
- char stats[SMAX]; /* statistics buffer */
- u_char lencode; /* length of last received ASCII string */
- U_LONG lasttime; /* last time clock heard from */
-#ifdef AS2201PPS
- U_LONG lastev; /* last ppsclock second */
-#endif /* AS2201PPS */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char reason; /* reason for last abort */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- u_short msec; /* milliseconds of second */
- u_char leap; /* leap indicators */
- U_LONG yearstart; /* start of current year */
- int linect; /* count of lines remaining */
- int index; /* current statistics command */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
+struct as2201unit {
+ int pollcnt; /* poll message counter */
+
+ char *lastptr; /* statistics buffer pointer */
+ char stats[SMAX]; /* statistics buffer */
+
+#ifdef PPS
+ u_long lastev; /* last ppsclock second */
+#endif /* PPS */
+
+ int linect; /* count of lines remaining */
+ int index; /* current statistics command */
};
/*
@@ -205,385 +152,129 @@ static char stat_command[][30] = {
};
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct gpsunit *gpsunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-/*
* Function prototypes
*/
-static void as2201_init P(());
-static int as2201_start P((u_int, struct peer *));
-static void as2201_shutdown P((int));
-static void as2201_report_event P((struct gpsunit *, int));
+static int as2201_start P((int, struct peer *));
+static void as2201_shutdown P((int, struct peer *));
static void as2201_receive P((struct recvbuf *));
-static char as2201_process P((struct gpsunit *, l_fp *, u_fp *));
-static void as2201_poll P((int unit, struct peer *));
-static void as2201_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void as2201_buginfo P((int, struct refclockbug *));
+static void as2201_poll P((int, struct peer *));
/*
* Transfer vector
*/
-struct refclock refclock_as2201 = {
- as2201_start, as2201_shutdown, as2201_poll,
- as2201_control, as2201_init, as2201_buginfo, NOFLAGS
+struct refclock refclock_as2201 = {
+ as2201_start, /* start up driver */
+ as2201_shutdown, /* shut down driver */
+ as2201_poll, /* transmit poll message */
+ noentry, /* not used (old as2201_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old as2201_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * as2201_init - initialize internal gps driver data
- */
-static void
-as2201_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)gpsunits, 0, sizeof gpsunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = 0;
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
/*
- * as2201_start - open the GPS devices and initialize data for processing
+ * as2201_start - open the devices and initialize data for processing
*/
static int
as2201_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct gpsunit *gps;
- register int i;
- int fd232;
- char as2201dev[20];
-#ifdef AS2201PPS
- struct ppsclockev ev;
-#endif /* AS2201PPS */
+ register struct as2201unit *up;
+ struct refclockproc *pp;
+ int fd;
+ char gpsdev[20];
/*
- * Check configuration info
+ * Open serial port. Use CLK line discipline, if available.
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "gps_start: unit %d invalid", unit);
- return (0);
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "gps_start: unit %d in use", unit);
+ (void)sprintf(gpsdev, DEVICE, unit);
+ if (!(fd = refclock_open(gpsdev, SPEED232, LDISC_CLK)))
return (0);
- }
/*
- * Open serial port
+ * Allocate and initialize unit structure
*/
- (void) sprintf(as2201dev, GPS232, unit);
- fd232 = open(as2201dev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "gps_start: open of %s: %m", as2201dev);
+ if (!(up = (struct as2201unit *)
+ emalloc(sizeof(struct as2201unit)))) {
+ (void) close(fd);
return (0);
}
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- *
- */
- { struct termio ttyb;
- if (ioctl(fd232, TCGETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, TCGETA): %m", as2201dev);
- goto screwed;
- }
- ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyb.c_oflag = 0;
- ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyb.c_lflag = ICANON;
- ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
- if (ioctl(fd232, TCSETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, TCSETA): %m", as2201dev);
- goto screwed;
- }
- }
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The AS2201CLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
- *
- * The AS2201PPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "as2201_start: tcgetattr(%s): %m", as2201dev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "as2201_start: tcsetattr(%s): %m", as2201dev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "as2201_start: tcflush(%s): %m", as2201dev);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#ifdef STREAM
-#if defined(AS2201CLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, I_PUSH, clk): %m", as2201dev);
- if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, CLK_SETSTR): %m", as2201dev);
-#endif /* AS2201CLK */
-#if defined(AS2201PPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, I_PUSH, ppsclock): %m", as2201dev);
- else
- fdpps = fd232;
-#endif /* AS2201PPS */
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The AS2201CLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
- */
- { struct sgttyb ttyb;
-#if defined(AS2201CLK)
- int ldisc = CLKLDISC;
-#endif /* AS2201CLK */
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, TIOCGETP): %m", as2201dev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(AS2201CLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
- ttyb.sg_erase = ttyb.sg_kill = '\0';
- ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* AS2201CLK */
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, TIOCSETP): %m", as2201dev);
- goto screwed;
- }
-#if defined(AS2201CLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "as2201_start: ioctl(%s, TIOCSETD): %m",as2201dev);
- goto screwed;
- }
-#endif /* AS2201CLK */
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (gpsunits[unit] != 0) {
- gps = gpsunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && gpsunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- gps = gpsunits[i];
- gpsunits[i] = 0;
- } else {
- gps = (struct gpsunit *)
- emalloc(sizeof(struct gpsunit));
- }
+ memset((char *)up, 0, sizeof(struct as2201unit));
+ pp = peer->procptr;
+ pp->io.clock_recv = as2201_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- memset((char *)gps, 0, sizeof(struct gpsunit));
- gpsunits[unit] = gps;
+ pp->unitptr = (caddr_t)up;
/*
- * Set up the structures
+ * Initialize miscellaneous variables
*/
- gps->peer = peer;
- gps->unit = (u_char)unit;
- gps->timestarted = current_time;
- gps->lastptr = gps->stats;
- gps->index = 0;
-
- gps->io.clock_recv = as2201_receive;
- gps->io.srcclock = (caddr_t)gps;
- gps->io.datalen = 0;
- gps->io.fd = fd232;
-#ifdef AS2201PPS
- if (ioctl(fd232, CIOGETEV, (caddr_t)&ev) < 0) {
- syslog(LOG_ERR,
- "gps_start: ioctl(%s, CIOGETEV): %m", as2201dev);
- goto screwed;
- } else
- gps->lastev = ev.tv.tv_sec;
-#endif /* AS2201PPS */
- if (!io_addclock(&gps->io)) {
- goto screwed;
- }
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
- /*
- * All done. Initialize a few random peer variables, then
- * return success. Note that root delay and root dispersion are
- * always zero for this clock.
- */
- peer->precision = GPSPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, GPSREFID, 4);
- else
- peer->refid = htonl(GPSHSREFID);
- unitinuse[unit] = 1;
+ up->lastptr = up->stats;
+ up->index = 0;
return (1);
-
- /*
- * Something broke; abandon ship.
- */
-screwed:
- (void) close(fd232);
- return (0);
-}
-
-/*
- * as2201_shutdown - shut down a GPS clock
- */
-static void
-as2201_shutdown(unit)
- int unit;
-{
- register struct gpsunit *gps;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "gps_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "gps_shutdown: unit %d not in use", unit);
- return;
- }
-
- /*
- * Tell the I/O module to turn us off. We're history.
- */
- gps = gpsunits[unit];
- io_closeclock(&gps->io);
- unitinuse[unit] = 0;
}
/*
- * as2201_report_event - note the occurance of an event
- *
- * This routine presently just remembers the report and logs it, but
- * does nothing heroic for the trap handler.
+ * as2201_shutdown - shut down the clock
*/
static void
-as2201_report_event(gps, code)
- struct gpsunit *gps;
- int code;
-{
+as2201_shutdown(unit, peer)
+ int unit;
struct peer *peer;
+{
+ register struct as2201unit *up;
+ struct refclockproc *pp;
- peer = gps->peer;
- if (gps->status != (u_char)code) {
- gps->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- gps->lastevent = (u_char)code;
- syslog(LOG_INFO,
- "clock %s event %x\n", ntoa(&peer->srcadr), code);
- }
+ pp = peer->procptr;
+ up = (struct as2201unit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
/*
- * as2201_receive - receive data from the serial interface
+ * as2201__receive - receive data from the serial interface
*/
static void
as2201_receive(rbufp)
struct recvbuf *rbufp;
{
- register int i;
- register struct gpsunit *gps;
-
-#if defined(AS2201PPS)
- struct ppsclockev ev;
+ register struct as2201unit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
l_fp trtmp;
-#endif /* AS2201PPS */
- register u_char *dpt;
- register char *cp, *dp;
- int dpend;
- l_fp tstmp;
- u_fp dispersion;
+#ifdef PPS
+ long ltemp;
+ struct ppsclockev ev;
+#endif /* PPS */
/*
- * Get the clock this applies to and pointers to the data.
- * Edit the timecode to remove control chars and trashbits.
+ * Initialize pointers and read the timecode and timestamp.
*/
- gps = (struct gpsunit *)rbufp->recv_srcclock;
- dpt = (u_char *)&rbufp->recv_space;
- dpend = rbufp->recv_length;
- if (dpend > BMAX - 1)
- dpend = BMAX - 1;
- cp = dp = gps->lastcode;
- for (i = 0; i < dpend; i++)
- if ((*dp = 0x7f & *dpt++) >= ' ') dp++;
- *dp = '\0';
- gps->lencode = dp - cp;
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct as2201unit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX, &trtmp);
#ifdef DEBUG
if (debug)
printf("gps: timecode %d %d %s\n",
- gps->linect, gps->lencode, gps->lastcode);
+ up->linect, pp->lencode, pp->lastcode);
#endif
- if (gps->lencode == 0)
+ if (pp->lencode == 0)
return;
/*
@@ -597,252 +288,136 @@ as2201_receive(rbufp)
* the timecode; in the later case, save the number of lines and
* quietly return.
*/
- if (gps->linect > 0) {
- gps->linect--;
- if ((int)(gps->lastptr - gps->stats + gps->lencode) > SMAX - 2)
+ if (up->linect > 0) {
+ up->linect--;
+ if (up->lastptr - up->stats + pp->lencode > SMAX - 2)
return;
- *gps->lastptr++ = ' ';
- (void)strcpy(gps->lastptr, gps->lastcode);
- gps->lastptr += gps->lencode;
+ *up->lastptr++ = ' ';
+ (void)strcpy(up->lastptr, pp->lastcode);
+ up->lastptr += pp->lencode;
return;
} else {
- if (gps->lencode == 1) {
- gps->linect = atoi(gps->lastcode);
+ if (pp->lencode == 1) {
+ up->linect = atoi(pp->lastcode);
return;
} else {
- record_clock_stats(&(gps->peer->srcadr), gps->stats);
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, up->stats);
#ifdef DEBUG
if (debug)
- printf("gps: stat %s\n", gps->stats);
+ printf("gps: stat %s\n", up->stats);
#endif
}
}
- gps->lastptr = gps->stats;
- *gps->lastptr = '\0';
-
- /*
- * We check the timecode format and decode its contents. The
- * timecode has format yy:ddd:hh:mm:ss.mmm). If it has invalid
- * length or is not in proper format, the driver declares bad
- * format and exits. If the converted decimal values are out of
- * range, the driver declares bad data and exits.
- */
- if (gps->lencode != LENTOC || !isdigit(cp[0]) ||
- !isdigit(cp[1]) || !isdigit(cp[3]) || !isdigit(cp[4]) ||
- !isdigit(cp[5]) || !isdigit(cp[7]) || !isdigit(cp[8]) ||
- !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[13]) ||
- !isdigit(cp[14]) || !isdigit(cp[16]) || !isdigit(cp[17]) ||
- !isdigit(cp[18])) {
- gps->badformat++;
- as2201_report_event(gps, CEVNT_BADREPLY);
- return;
- }
+ up->lastptr = up->stats;
+ *up->lastptr = '\0';
/*
- * Convert date and check values.
+ * We get down to business, check the timecode format and decode
+ * its contents. If the timecode has invalid length or is not in
+ * proper format, we declare bad format and exit.
*/
- gps->day = cp[3] - '0';
- gps->day = MULBY10(gps->day) + cp[4] - '0';
- gps->day = MULBY10(gps->day) + cp[5] - '0';
- if (gps->day < 1 || gps->day > 366) {
- gps->baddata++;
- as2201_report_event(gps, CEVNT_BADDATE);
+ if (pp->lencode < LENTOC) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
/*
- * Convert time and check values.
+ * Timecode format: "yy:ddd:hh:mm:ss.mmm"
*/
- gps->hour = MULBY10(cp[7] - '0') + cp[8] - '0';
- gps->minute = MULBY10(cp[10] - '0') + cp[11] - '0';
- gps->second = MULBY10(cp[13] - '0') + cp[14] - '0';
- gps->msec = MULBY10(MULBY10(cp[16] - '0') + cp[17] - '0')
- + cp[18] - '0';
- if (gps->hour > 23 || gps->minute > 59 || gps->second > 59) {
- gps->baddata++;
- as2201_report_event(gps, CEVNT_BADTIME);
+ if (sscanf(pp->lastcode, "%2d:%3d:%2d:%2d:%2d.%3d", &pp->year,
+ &pp->day, &pp->hour, &pp->minute, &pp->second, &pp->msec)
+ != 6) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
/*
* Test for synchronization (this is a temporary crock).
*/
- if (cp[2] != ':')
- gps->leap = LEAP_NOTINSYNC;
- else
- gps->lasttime = current_time;
-
- /*
- * Now, compute the reference time value. Use the heavy
- * machinery for the second, which presumably is the one which
- * occured at the last pps pulse and which was captured by the
- * loop_filter module. All we have to do here is present a
- * reasonable facsimile of the time at that pulse so the clock-
- * filter and selection machinery declares us truechimer. The
- * precision offset within the second is really tuned by the
- * loop_filter module. Note that this code does not yet know how
- * to do the years and relies on the clock-calendar chip for
- * sanity.
- */
- if (!clocktime(gps->day, gps->hour, gps->minute,
- gps->second, GMT, gps->lastrec.l_ui,
- &gps->yearstart, &gps->lastref.l_ui)) {
- gps->baddata++;
- as2201_report_event(gps, CEVNT_BADTIME);
-
- printf("gps: bad data\n");
-
- return;
+ if (pp->lastcode[2] != ':') {
+ pp->leap = LEAP_NOTINSYNC;
+ } else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
}
- MSUTOTSF(gps->msec, gps->lastref.l_uf);
-#if defined(AS2201PPS)
+#ifdef PPS
/*
- * If the pps signal is available and the local time is within
- * +-0.5 second of the timecode, use the pps offset instead.
- * Note that we believe the ppsclock timestamp only if the ioctl
- * works and the new timestamp is greater than the previous one.
+ * If CLK_FLAG3 is set and the local time is within +-0.5 second
+ * of the timecode, use the pps offset instead. Note that we
+ * believe the ppsclock timestamp only if the ioctl works and
+ * the new timestamp is greater than the previous one.
*/
- gps->lastrec = rbufp->recv_time;
- tstmp = gps->lastref;
- L_SUB(&tstmp, &gps->lastrec);
- L_ADD(&tstmp, &(fudgefactor[gps->unit]));
- trtmp = tstmp;
- if (L_ISNEG(&trtmp))
- L_NEG(&trtmp);
- if (trtmp.l_i < CLOCK_MAX_I || (trtmp.l_i == CLOCK_MAX_I
- && (U_LONG)trtmp.l_uf < (U_LONG)CLOCK_MAX_F)) {
- if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
- if (gps->lastev < ev.tv.tv_sec) {
- trtmp.l_ui = ev.tv.tv_sec + (U_LONG)JAN_1970;
- TVUTOTSF(ev.tv.tv_usec, trtmp.l_uf);
- L_NEG(&trtmp);
- tstmp.l_i = tstmp.l_f = 0;
- M_ADDF(tstmp.l_i, tstmp.l_f, trtmp.l_f);
+ if (pp->sloppyclockflag & CLK_FLAG3 && fdpps != -1) {
+ if (!clocktime(pp->day, pp->hour, pp->minute,
+ pp->second, GMT, pp->lastrec.l_ui, &pp->yearstart,
+ &pp->lastref.l_ui)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(pp->msec, pp->lastref.l_uf);
+ pp->lastrec = trtmp;
+ L_SUB(&trtmp, &pp->lastref);
+ if (L_ISNEG(&trtmp))
+ L_NEG(&trtmp);
+ if (trtmp.l_i < CLOCK_MAX_I || (trtmp.l_i == CLOCK_MAX_I
+ && trtmp.l_uf < CLOCK_MAX_F)) {
+ if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
+ if (up->lastev < ev.tv.tv_sec) {
+ TVUTOTSF(ev.tv.tv_usec, ltemp);
+ pp->lastrec = pp->lastref;
+ L_ADDF(&pp->lastrec, ltemp);
+ }
+ up->lastev = ev.tv.tv_sec;
}
- gps->lastev = ev.tv.tv_sec;
}
}
-#else
- tstmp = gps->lastref;
- L_SUB(&tstmp, &gps->lastrec);
- L_ADD(&tstmp, &(fudgefactor[gps->unit]));
-#endif /* AS2201PPS */
- i = ((int)(gps->coderecv)) % NCODES;
- gps->offset[i] = tstmp;
- gps->coderecv++;
-#if DEBUG
+#endif /* PPS */
+#ifdef DEBUG
if (debug)
printf("gps: times %s %s %s\n",
- ulfptoa(&gps->lastref, 6), ulfptoa(&gps->lastrec, 6),
- lfptoa(&tstmp, 6));
+ ulfptoa(&pp->lastref, 6), ulfptoa(&pp->lastrec, 6),
+ lfptoa(&trtmp, 6));
#endif
/*
- * If the statistics-record switch (CLK_FLAG4) is set,
- * initialize the statistics buffer and send the next command.
- * If not, simply write the timecode to the clockstats file.
- */
- (void)strcpy(gps->lastptr, gps->lastcode);
- gps->lastptr += gps->lencode;
- if (sloppyclockflag[gps->unit] & CLK_FLAG4) {
- *gps->lastptr++ = ' ';
- (void)strcpy(gps->lastptr, stat_command[gps->index]);
- gps->lastptr += strlen(stat_command[gps->index]);
- gps->lastptr--;
- *gps->lastptr = '\0';
- (void)write(gps->io.fd, stat_command[gps->index],
- strlen(stat_command[gps->index]));
- gps->index++;
- if (*stat_command[gps->index] == '\0')
- gps->index = 0;
- }
-
- /*
- * Process the samples in the median filter, add the fudge
- * factor and pass the offset and dispersion along. We use
- * lastref as both the reference time and receive time in order
- * to avoid being cute, like setting the reference time later
- * than the receive time, which may cause a paranoid protocol
- * module to chuck out the data.
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
*/
- if (gps->coderecv < NCODES)
- return;
- if (!as2201_process(gps, &tstmp, &dispersion)) {
- gps->baddata++;
- as2201_report_event(gps, CEVNT_BADTIME);
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
- refclock_receive(gps->peer, &tstmp, GMT, dispersion,
- &gps->lastrec, &gps->lastrec, gps->leap);
-}
-
-/*
- * as2201_process - process a pile of samples from the clock
- *
- * This routine uses a three-stage median filter to calculate offset and
- * dispersion and reduce jitter. The dispersion is calculated as the
- * span of the filter (max - min).
- */
-static char
-as2201_process(gps, offset, dispersion)
- struct gpsunit *gps;
- l_fp *offset;
- u_fp *dispersion;
-{
- register int i, j;
- register U_LONG tmp_ui, tmp_uf;
- int not_median1 = -1; /* XXX correct? */
- int not_median2 = -1; /* XXX correct? */
- int median;
- u_fp disp_tmp, disp_tmp2;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
/*
- * This code implements a three-stage median filter. First, we
- * check if the samples are within 125 ms of each other. If not,
- * dump the sample set. We take the median of the three offsets
- * and use that as the sample offset. There probably is not much
- * to be gained by a longer filter, since the clock filter in
- * ntp_proto should do its thing.
+ * If CLK_FLAG4 is set, initialize the statistics buffer and
+ * send the next command. If not, simply write the timecode to
+ * the clockstats file.
*/
- disp_tmp2 = 0;
- for (i = 0; i < NCODES-1; i++) {
- for (j = i+1; j < NCODES; j++) {
- tmp_ui = gps->offset[i].l_ui;
- tmp_uf = gps->offset[i].l_uf;
- M_SUB(tmp_ui, tmp_uf, gps->offset[j].l_ui,
- gps->offset[j].l_uf);
- if (M_ISNEG(tmp_ui, tmp_uf)) {
- M_NEG(tmp_ui, tmp_uf);
- }
- if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
- return (0);
- }
- disp_tmp = MFPTOFP(0, tmp_uf);
- if (disp_tmp > disp_tmp2) {
- disp_tmp2 = disp_tmp;
- not_median1 = i;
- not_median2 = j;
- }
- }
+ (void)strcpy(up->lastptr, pp->lastcode);
+ up->lastptr += pp->lencode;
+ if (pp->sloppyclockflag & CLK_FLAG4) {
+ *up->lastptr++ = ' ';
+ (void)strcpy(up->lastptr, stat_command[up->index]);
+ up->lastptr += strlen(stat_command[up->index]);
+ up->lastptr--;
+ *up->lastptr = '\0';
+ (void)write(pp->io.fd, stat_command[up->index],
+ strlen(stat_command[up->index]));
+ up->index++;
+ if (*stat_command[up->index] == '\0')
+ up->index = 0;
}
- if (gps->lasttime == 0)
- disp_tmp2 = NTP_MAXDISPERSE;
- else
- disp_tmp2 = current_time - gps->lasttime;
- if (not_median1 == 0) {
- if (not_median2 == 1)
- median = 2;
- else
- median = 1;
- } else {
- median = 0;
- }
- *offset = gps->offset[median];
- *dispersion = disp_tmp2;
- return (1);
}
+
/*
* as2201_poll - called by the transmit procedure
*
@@ -854,142 +429,25 @@ as2201_poll(unit, peer)
int unit;
struct peer *peer;
{
- struct gpsunit *gps;
+ register struct as2201unit *up;
+ struct refclockproc *pp;
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "gps_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "gps_poll: unit %d not in use", unit);
- return;
- }
- gps = gpsunits[unit];
- if ((current_time - gps->lasttime) > 150)
- as2201_report_event(gpsunits[unit], CEVNT_TIMEOUT);
- gettstamp(&gps->lastrec);
- if (write(gps->io.fd, "\r*toc\r", 6) != 6) {
- syslog(LOG_ERR, "gps_poll: unit %d: %m", gps->unit);
- as2201_report_event(gps, CEVNT_FAULT);
+ /*
+ * Send a "\r*toc\r" to get things going. We go to great pains
+ * to avoid changing state, since there may be more than one
+ * eavesdropper watching the radio.
+ */
+ pp = peer->procptr;
+ up = (struct as2201unit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ gettstamp(&pp->lastrec);
+ if (write(pp->io.fd, "\r*toc\r", 6) != 6) {
+ refclock_report(peer, CEVNT_FAULT);
} else
- gps->polls++;
+ pp->polls++;
}
-/*
- * as2201_control - set fudge factors, return statistics
- */
-static void
-as2201_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct gpsunit *gps;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "gps_control: unit %d invalid", unit);
- return;
- }
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- gps = gpsunits[unit];
- peer = gps->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- GPSREFID, 4);
- else
- peer->refid = htonl(GPSHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG4) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG4;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_GPS_AS2201;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4;
- out->clockdesc = GPSDESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- gps = gpsunits[unit];
- out->lencode = LENTOC;
- out->lastcode = gps->stats;
- out->timereset = current_time - gps->timestarted;
- out->polls = gps->polls;
- out->noresponse = gps->noreply;
- out->badformat = gps->badformat;
- out->baddata = gps->baddata;
- out->lastevent = gps->lastevent;
- out->currentstatus = gps->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
-}
-
-/*
- * as2201_buginfo - return clock dependent debugging info
- */
-static void
-as2201_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct gpsunit *gps;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "gps_buginfo: unit %d invalid", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- gps = gpsunits[unit];
-
- bug->nvalues = 10;
- bug->ntimes = 5;
- if (gps->lasttime != 0)
- bug->values[0] = current_time - gps->lasttime;
- else
- bug->values[0] = 0;
- bug->values[1] = (U_LONG)gps->reason;
- bug->values[2] = (U_LONG)gps->year;
- bug->values[3] = (U_LONG)gps->day;
- bug->values[4] = (U_LONG)gps->hour;
- bug->values[5] = (U_LONG)gps->minute;
- bug->values[6] = (U_LONG)gps->second;
- bug->values[7] = (U_LONG)gps->msec;
- bug->values[8] = gps->noreply;
- bug->values[9] = gps->yearstart;
- bug->stimes = 0x1c;
- bug->times[0] = gps->lastref;
- bug->times[1] = gps->lastrec;
- bug->times[2] = gps->offset[0];
- bug->times[3] = gps->offset[1];
- bug->times[4] = gps->offset[2];
-}
-#endif
+#endif /* REFCLOCK */
diff --git a/usr.sbin/xntpd/xntpd/refclock_atom.c b/usr.sbin/xntpd/xntpd/refclock_atom.c
new file mode 100644
index 000000000000..71fe05d8f0da
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_atom.c
@@ -0,0 +1,499 @@
+/*
+ * refclock_atom - clock driver for 1-pps signals
+ */
+#if defined(REFCLOCK) && defined(ATOM)
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_unixtime.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+
+#ifdef PPS
+#include <sys/ppsclock.h>
+#endif /* PPS */
+
+/*
+ * This driver furnishes an interface for pulse-per-second (PPS) signals
+ * produced by a cesium clock, timing receiver or related equipment. It
+ * can be used to remove accumulated jitter and retime a secondary
+ * server when synchronized to a primary server over a congested, wide-
+ * area network and before redistributing the time to local clients.
+ *
+ * In order for this driver to work, the local clock must be set to
+ * within +-500 ms by another means, such as a radio clock or NTP
+ * itself. The 1-pps signal is connected via a serial port and gadget
+ * box consisting of a one-shot and RS232 level converter. When operated
+ * at 38.4 kbps with a SPARCstation IPC, this arrangement has a worst-
+ * case jitter less than 26 us.
+ *
+ * There are three ways in which this driver can be used. The first way
+ * uses the LDISC_PPS line discipline and works only for the baseboard
+ * serial ports of the Sun SPARCstation. The PPS signal is connected via
+ * a gadget box to the carrier detect (CD) line of a serial port and
+ * flag3 of the driver configured for that port is set. This causes the
+ * ppsclock streams module to be configured for that port and capture a
+ * timestamp at the on-time transition of the PPS signal. This driver
+ * then reads the timestamp directly by a designated ioctl() system
+ * call. This provides the most accurate time and least jitter of any
+ * other scheme. There is no need to configure a dedicated device for
+ * this purpose, which ordinarily is the device used for the associated
+ * radio clock.
+ *
+ * The second way uses the LDISC_CLKPPS line discipline and works for
+ * any architecture supporting a serial port. If after a few seconds
+ * this driver finds no ppsclock module configured, it attempts to open
+ * a serial port device /dev/pps%d, where %d is the unit number, and
+ * assign the LDISC_CLKPPS line discipline to it. If the line discipline
+ * fails, no harm is done except the accuracy is reduced somewhat. The
+ * pulse generator in the gadget box is adjusted to produce a start bit
+ * of length 26 usec at 38400 bps. Used with the LDISC_CLKPPS line
+ * discipline, this produces an ASCII DEL character ('\377') followed by
+ * a timestamp at each seconds epoch.
+ *
+ * The third way involves an auxiliary radio clock driver which calls
+ * the PPS driver with a timestamp captured by that driver. This use is
+ * documented in the source code for the driver(s) involved.
+ *
+ * Fudge Factors
+ *
+ * There are no special fudge factors other than the generic and those
+ * explicitly defined above. The fudge time1 parameter can be used to
+ * compensate for miscellaneous UART and OS delays. Allow about 247 us
+ * for uart delays at 38400 bps and about 1 ms for SunOS streams
+ * nonsense.
+ */
+
+/*
+ * Interface definitions
+ */
+#define DEVICE "/dev/pps%d" /* device name and unit */
+#ifdef B38400
+#define SPEED232 B38400 /* uart speed (38400 baud) */
+#else
+#define SPEED232 EXTB /* as above */
+#endif
+#define PRECISION (-20) /* precision assumed (about 1 usec) */
+#define REFID "PPS\0" /* reference ID */
+#define DESCRIPTION "PPS Clock Discipline" /* WRU */
+
+#define PPSMAXDISPERSE (FP_SECOND / 100) /* max sample dispersion */
+#define NSAMPLES 32 /* final stages of median filter */
+#ifdef PPS
+#define PPS_POLL 2 /* ppsclock poll interval (s) */
+#endif /* PPS */
+
+/*
+ * Imported from ntp_timer module
+ */
+extern u_long current_time; /* current time (s) */
+extern struct event timerqueue[]; /* inner space */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+extern int pps_update; /* prefer peer valid update */
+
+/*
+ * Imported from ntp_proto module
+ */
+extern struct peer *sys_peer; /* somebody in charge */
+
+/*
+ * Unit control structure
+ */
+struct atomunit {
+#ifdef PPS
+ struct event timer; /* pps poll interval timer */
+ struct ppsclockev ev; /* ppsclock control */
+#endif /* PPS */
+ int pollcnt; /* poll message counter */
+};
+
+/*
+ * Global variables
+ */
+struct peer *last_atom_peer; /* peer structure pointer */
+
+/*
+ * Function prototypes
+ */
+static int atom_start P((int, struct peer *));
+static void atom_shutdown P((int, struct peer *));
+static void atom_receive P((struct recvbuf *));
+static void atom_poll P((int, struct peer *));
+#ifdef PPS
+static void atom_pps P((struct peer *));
+#endif /* PPS */
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_atom = {
+ atom_start, /* start up driver */
+ atom_shutdown, /* shut down driver */
+ atom_poll, /* transmit poll message */
+ noentry, /* not used (old atom_control) */
+ noentry, /* initialize driver */
+ noentry, /* not used (old atom_buginfo) */
+ NOFLAGS /* not used */
+};
+
+
+/*
+ * atom_start - initialize data for processing
+ */
+static int
+atom_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct atomunit *up;
+ struct refclockproc *pp;
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct atomunit *)
+ emalloc(sizeof(struct atomunit))))
+ return (0);
+ memset((char *)up, 0, sizeof(struct atomunit));
+ pp = peer->procptr;
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
+ pp->nstages = MAXSTAGE;
+
+#ifdef PPS
+ /*
+ * Arm the timer for the first interrupt. Give it ten seconds to
+ * allow the ppsclock line to be configured, since it could be
+ * assigned to another driver.
+ */
+ up->timer.peer = (struct peer *)peer;
+ up->timer.event_handler = atom_pps;
+ up->timer.event_time = current_time + 10;
+ TIMER_INSERT(timerqueue, &up->timer);
+#endif /* PPS */
+ last_atom_peer = peer;
+ return (1);
+}
+
+
+/*
+ * atom_shutdown - shut down the clock
+ */
+static void
+atom_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct atomunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct atomunit *)pp->unitptr;
+
+ if (last_atom_peer == peer)
+ last_atom_peer = 0;
+#ifdef PPS
+ TIMER_DEQUEUE(&up->timer);
+#endif /* PPS */
+ if (pp->io.fd)
+ io_closeclock(&pp->io);
+ free(up);
+}
+
+/*
+ * pps_sample - process pps sample offset -- backwards compatible
+ * interface
+ */
+int
+pps_sample(tsr)
+ l_fp *tsr;
+{
+ struct peer *peer;
+ struct refclockproc *pp;
+ register struct atomunit *up;
+ int i;
+ l_fp lftemp; /* l_fp temps */
+
+ /*
+ * This routine is called once per second by an auxilliary
+ * routine in another driver. It saves the sign-extended
+ * fraction supplied in the argument in a circular buffer for
+ * processing at the next poll event.
+ */
+ peer = last_atom_peer;
+ if (!peer)
+ return (-1); /* no ATOM configured ? Forget it ! */
+
+ pp = peer->procptr;
+ up = (struct atomunit *)pp->unitptr;
+
+ L_CLR(&lftemp);
+ L_ADDF(&lftemp, tsr->l_f);
+ i = ((int)(pp->coderecv)) % pp->nstages;
+ pp->filter[i] = lftemp;
+ if (pp->coderecv == 0)
+ for (i = 1; i < pp->nstages; i++)
+ pp->filter[i] = pp->filter[0];
+ pp->coderecv++;
+ up->pollcnt = 2;
+
+ /* HACK -- use the local UN*X clock to get the time -- this is wrong */
+ pp->lastrec.l_ui = time(0) - 2 + JAN_1970;
+ pp->lastrec.l_uf = 0;
+
+ return (0);
+}
+
+#ifdef PPS
+/*
+ * atom_pps - receive data from the LDISC_PPS discipline
+ */
+static void
+atom_pps(peer)
+ struct peer *peer;
+{
+ register struct atomunit *up;
+ struct refclockproc *pp;
+ l_fp lftmp;
+ int i;
+
+ /*
+ * This routine is called once per second when the LDISC_PPS
+ * discipline is present. It snatches the pps timestamp from the
+ * kernel and saves the sign-extended fraction in a circular
+ * buffer for processing at the next poll event.
+ */
+ pp = peer->procptr;
+ up = (struct atomunit *)pp->unitptr;
+
+ /*
+ * Arm the timer for the next interrupt
+ */
+ up->timer.event_time = current_time + PPS_POLL;
+ TIMER_INSERT(timerqueue, &up->timer);
+
+ /*
+ * Convert the timeval to l_fp and save for billboards. Sign-
+ * extend the fraction and stash in the buffer. No harm is done
+ * if previous data are overwritten. If the discipline comes bum
+ * or the data grow stale, just forget it.
+ */
+ i = up->ev.serial;
+ if (ioctl(fdpps, CIOGETEV, (caddr_t)&up->ev) < 0)
+ return;
+ if (i == up->ev.serial)
+ return;
+ pp->lastrec.l_ui = up->ev.tv.tv_sec + JAN_1970;
+ TVUTOTSF(up->ev.tv.tv_usec, pp->lastrec.l_uf);
+ L_CLR(&lftmp);
+ L_ADDF(&lftmp, pp->lastrec.l_f);
+ L_NEG(&lftmp);
+ i = ((int)(pp->coderecv)) % pp->nstages;
+ pp->filter[i] = lftmp;
+ if (pp->coderecv == 0)
+ for (i = 1; i < pp->nstages; i++)
+ pp->filter[i] = pp->filter[0];
+ pp->coderecv++;
+ up->pollcnt = 2;
+}
+#endif /* PPS */
+
+/*
+ * atom_receive - receive data from the serial line interface
+ */
+static void
+atom_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct atomunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp lftmp;
+ int i;
+
+ /*
+ * This routine is called once per second when the serial
+ * interface is in use. It snatches the timestamp from the
+ * buffer and saves the sign-extended fraction in a circular
+ * buffer for processing at the next poll event.
+ */
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct atomunit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX,
+ &pp->lastrec);
+
+ /*
+ * Save the timestamp for billboards. Sign-extend the fraction
+ * and stash in the buffer. No harm is done if previous data are
+ * overwritten.
+ */
+ L_CLR(&lftmp);
+ L_ADDF(&lftmp, pp->lastrec.l_f);
+ L_NEG(&lftmp);
+ i = ((int)(pp->coderecv)) % pp->nstages;
+ pp->filter[i] = lftmp;
+ if (pp->coderecv == 0)
+ for (i = 1; i < pp->nstages; i++)
+ pp->filter[i] = pp->filter[0];
+ pp->coderecv++;
+ up->pollcnt = 2;
+}
+
+/*
+ * Compare two l_fp's - used with qsort()
+ */
+static int
+atom_cmpl_fp(p1, p2)
+ register void *p1, *p2; /* l_fp to compare */
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+/*
+ * atom_poll - called by the transmit procedure
+ */
+static void
+atom_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct atomunit *up;
+ struct refclockproc *pp;
+ int i, n;
+ l_fp median, lftmp;
+ l_fp off[MAXSTAGE];
+ u_fp disp;
+
+ /*
+ * At each poll we check for timeout. At the first timeout we
+ * test to see if the LDISC_PPS discipline is present and, if
+ * so, use that. If not, we attempt to open a serial line with
+ * LDISC_CLKPPS discipline. If that fails, we bitch to the log
+ * and clam up.
+ */
+ pp = peer->procptr;
+ up = (struct atomunit *)pp->unitptr;
+ pp->polls++;
+ if (up->pollcnt == 0) {
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+ up->pollcnt--;
+ if (up->pollcnt == 0) {
+ if (!pp->io.fd && fdpps == -1) {
+ int fd;
+ char device[20];
+
+ /*
+ * Open serial port. Use CLKPPS line discipline,
+ * if available. If unavailable, the code works
+ * anyway, but at reduced accuracy.
+ */
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232,
+ LDISC_CLKPPS))) {
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+ pp->io.clock_recv = atom_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ refclock_report(peer, CEVNT_FAULT);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Valid time (leap bits zero) is returned only if the prefer
+ * peer has survived the intersection algorithm and within
+ * CLOCK_MAX of local time and not too long ago. This insures
+ * the pps time is within +-0.5 s of the local time and the
+ * seconds numbering is unambiguous.
+ */
+ if (pps_update) {
+ pp->leap = 0;
+ pp->lasttime = current_time;
+ } else
+ pp->leap = LEAP_NOTINSYNC;
+
+ /*
+ * Copy the raw offsets and sort into ascending order
+ */
+ for (i = 0; i < MAXSTAGE; i++)
+ off[i] = pp->filter[i];
+ qsort((char *)off, pp->nstages, sizeof(l_fp), atom_cmpl_fp);
+
+ /*
+ * Reject the furthest from the median of nstages samples until
+ * nskeep samples remain.
+ */
+ i = 0;
+ n = pp->nstages;
+ while ((n - i) > NSAMPLES) {
+ lftmp = off[n - 1];
+ median = off[(n + i) / 2];
+ L_SUB(&lftmp, &median);
+ L_SUB(&median, &off[i]);
+ if (L_ISHIS(&median, &lftmp)) {
+ /* reject low end */
+ i++;
+ } else {
+ /* reject high end */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets. Add to this the time since
+ * the last clock update, which represents the dispersion
+ * increase with time. We know that NTP_MAXSKEW is 16. If the
+ * sum is greater than the allowed sample dispersion, bail out.
+ * Otherwise, return the median offset plus the configured
+ * fudgetime1 value.
+ */
+ lftmp = off[n - 1];
+ L_SUB(&lftmp, &off[i]);
+ disp = LFPTOFP(&lftmp) + current_time - pp->lasttime;
+ if (disp > PPSMAXDISPERSE) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ pp->offset = off[(n + 1) / 2];
+ L_ADD(&pp->offset, &pp->fudgetime1);
+ pp->dispersion = disp;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
+}
+
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_chu.c b/usr.sbin/xntpd/xntpd/refclock_chu.c
index 4596db22e2f5..2488da62e9c0 100644
--- a/usr.sbin/xntpd/xntpd/refclock_chu.c
+++ b/usr.sbin/xntpd/xntpd/refclock_chu.c
@@ -1,7 +1,7 @@
/*
* refclock_chu - clock driver for the CHU time code
*/
-#if defined(REFCLOCK) && (defined(CHU) || defined(CHUCLK) || defined(CHUPPS))
+#if defined(REFCLOCK) && defined(CHU)
#include <stdio.h>
#include <ctype.h>
@@ -11,28 +11,7 @@
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
-
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#endif /* STREAM */
-
-#if defined (CHUPPS)
-#include <sys/ppsclock.h>
-#endif /* CHUPPS */
-
#include <sys/chudefs.h>
-
#include "ntp_stdlib.h"
/*
@@ -79,29 +58,30 @@
* in this nibble.
*
* The start bit in each character has a precise relationship to
- * the on-time second. Most often UART's synchronize themselves to the
+ * the on-time second. Most often UART's synchronize themselves to the
* start bit and will post an interrupt at the center of the first stop
* bit. Thus each character's interrupt should occur at a fixed offset
- * from the on-time second. This means that a timestamp taken at the
+ * from the on-time second. This means that a timestamp taken at the
* arrival of each character in the code will provide an independent
* estimate of the offset. Since there are 10 characters in the time
- * code and the code is sent 9 times per minute, this means you potentially
- * get 90 offset samples per minute. Much of the code in here is dedicated
- * to producing a single offset estimate from these samples.
+ * code and the code is sent 9 times per minute, this means you
+ * potentially get 90 offset samples per minute. Much of the code in
+ * here is dedicated to producing a single offset estimate from these
+ * samples.
*
- * A note about the line discipline. It is possible to receive the
- * CHU time code in raw mode, but this has disadvantages. In particular,
+ * A note about the line discipline. It is possible to receive the
+ * CHU time code in raw mode, but this has disadvantages. In particular,
* this puts a lot of code between the interrupt and the time you freeze
- * a time stamp, decreasing precision. It is also expensive in terms of
+ * a time stamp, decreasing precision. It is also expensive in terms of
* context switches, and made even more expensive by the way I do I/O.
* Worse, since you are listening directly to the output of your radio,
* CHU is noisy and will make you spend a lot of time receiving noise.
*
- * The line discipline fixes a lot of this. It knows that the CHU time
+ * The line discipline fixes a lot of this. It knows that the CHU time
* code consists of 10 bytes which arrive with an intercharacter
* spacing of about 37 ms, and that the data is BCD, and filters on this
- * basis. It delivers block of ten characters plus their associated time
- * stamps all at once. The time stamps are hence about as accurate as
+ * basis. It delivers block of ten characters plus their associated time
+ * stamps all at once. The time stamps are hence about as accurate as
* a Unix machine can get them, and much of the noise disappears in the
* kernel with no context switching cost.
*
@@ -112,13 +92,18 @@
*/
/*
- * Definitions
+ * CHU definitions
*/
-#define MAXUNITS 4 /* maximum number of CHU units permitted */
-#define CHUDEV "/dev/chu%d" /* device we open. %d is unit number */
-#define SPEED232 B300 /* uart speed (300 baud) */
+#define DEVICE "/dev/chu%d" /* device name and unit */
+#define SPEED232 B300 /* uart speed (300 baud) */
+#define PRECISION (-9) /* what the heck */
+#define REFID "CHU\0" /* reference ID */
+#define DESCRIPTION "Scratchbuilt CHU Receiver" /* WRU */
+
#define NCHUCODES 8 /* expect 8 CHU codes per minute */
+#ifndef CHULDISC
#define CHULDISC 10 /* XXX temp CHU line discipline */
+#endif
/*
* To compute a quality for the estimate (a pseudo dispersion) we add a
@@ -129,14 +114,6 @@
#define CHUDELAYPENALTY 0x0000028f
/*
- * Other constant stuff
- */
-#define CHUPRECISION (-9) /* what the heck */
-#define CHUREFID "CHU\0"
-#define CHUDESCRIPTION "Direct synchronized to CHU timecode"
-#define CHUHSREFID 0x7f7f070a /* 127.127.7.10 refid for hi strata */
-
-/*
* Default fudge factors
*/
#define DEFPROPDELAY 0x00624dd3 /* 0.0015 seconds, 1.5 ms */
@@ -160,37 +137,27 @@
static char hexstring[]="0123456789abcdef";
/*
- * CHU unit control structure.
+ * Unit control structure.
*/
struct chuunit {
- struct peer *peer; /* associated peer structure */
- struct event chutimer; /* timeout timer structure */
- struct refclockio chuio; /* given to the I/O handler */
- l_fp offsets[NCHUCODES]; /* offsets computed from each code */
- l_fp rectimes[NCHUCODES]; /* times we received this stuff */
- U_LONG reftimes[NCHUCODES]; /* time of last code received */
- u_char lastcode[NCHUCHARS*4]; /* last code we received */
- u_char asciicode[NCHUCHARS*4+1]; /* last code translated to ascii */
- u_char expect; /* the next offset expected */
- u_char unit; /* unit number for this guy */
- u_short haveoffset; /* flag word indicating valid offsets */
- u_short flags; /* operational flags */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char unused[2];
- U_LONG lastupdate; /* last time data received */
- U_LONG responses; /* number of responses */
- U_LONG badformat; /* number of bad format responses */
- U_LONG baddata; /* number of invalid time codes */
- U_LONG timestarted; /* time we started this */
- u_char leap; /* leap status */
+ struct peer *peer; /* peer structure pointer */
+ struct event chutimer; /* timeout timer structure */
+ l_fp offsets[NCHUCODES]; /* offsets computed from each code */
+ l_fp rectimes[NCHUCODES]; /* times we received this stuff */
+ u_long reftimes[NCHUCODES]; /* time of last code received */
+ u_char lastcode[NCHUCHARS * 4]; /* last code we received */
+ u_char expect; /* the next offset expected */
+ u_short haveoffset; /* flag word indicating valid offsets */
+ u_short flags; /* operational flags */
+ u_long responses; /* number of responses */
+ int pollcnt; /* poll message counter */
};
-#define CHUTIMERSET 0x1 /* timer is set to fire */
+#define CHUTIMERSET 0x1 /* timer is set to fire */
/*
- * The CHU table. This gives the expected time of arrival of each
+ * The CHU table. This gives the expected time of arrival of each
* character after the on-time second and is computed as follows:
* The CHU time code is sent at 300 bps. Your average UART will
* synchronize at the edge of the start bit and will consider the
@@ -198,12 +165,11 @@ struct chuunit {
* 0.031667 ms later (some UARTS may complete the character at the
* end of the stop bit instead of the middle, but you can fudge this).
* Thus the expected time of each interrupt is the start bit time plus
- * 0.031667 seconds. These times are in chutable[]. To this we add
- * such things as propagation delay and delay fudge factor.
+ * 0.031667 seconds. These times are in chutable[].
*/
#define CHARDELAY 0x081b4e82
-static U_LONG chutable[NCHUCHARS] = {
+static u_long chutable[NCHUCHARS] = {
0x22222222 + CHARDELAY, /* 0.1333333333 */
0x2b851eb8 + CHARDELAY, /* 0.170 (exactly) */
0x34e81b4e + CHARDELAY, /* 0.2066666667 */
@@ -217,348 +183,110 @@ static U_LONG chutable[NCHUCHARS] = {
};
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct chuunit *chuunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp propagation_delay[MAXUNITS];
-static l_fp fudgefactor[MAXUNITS];
-static l_fp offset_fudge[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-/*
- * We keep track of the start of the year, watching for changes.
- * We also keep track of whether the year is a leap year or not.
- * All because stupid CHU doesn't include the year in the time code.
- */
-static U_LONG yearstart;
-
-/*
* Imported from the timer module
*/
-extern U_LONG current_time;
+extern u_long current_time;
extern struct event timerqueue[];
/*
- * Imported from ntp_loopfilter module
- */
-extern int fdpps; /* pps file descriptor */
-
-/*
* Imported from ntpd module
*/
extern int debug; /* global debug flag */
/*
- * Event reporting. This optimizes things a little.
+ * Function prototypes
*/
-#define chu_event(chu, evcode) \
- do { \
- if ((chu)->status != (u_char)(evcode)) \
- chu_report_event((chu), (evcode)); \
- } while (0)
-
-static void chu_init P((void));
-static int chu_start P((u_int, struct peer *));
-static void chu_shutdown P((int));
-static void chu_report_event P((struct chuunit *, int));
+static int chu_start P((int, struct peer *));
+static void chu_shutdown P((int, struct peer *));
static void chu_receive P((struct recvbuf *));
static void chu_process P((struct chuunit *));
static void chu_poll P((int, struct peer *));
-static void chu_control P((u_int, struct refclockstat *, struct refclockstat *));
static void chu_timeout P((struct peer *));
/*
* Transfer vector
*/
struct refclock refclock_chu = {
- chu_start, chu_shutdown, chu_poll,
- chu_control, chu_init, noentry, NOFLAGS
+ chu_start, /* start up driver */
+ chu_shutdown, /* shut down driver */
+ chu_poll, /* transmit poll message */
+ noentry, /* not used (old chu_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old chu_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * chu_init - initialize internal chu driver data
- */
-static void
-chu_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)chuunits, 0, sizeof chuunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- propagation_delay[i].l_ui = 0;
- propagation_delay[i].l_uf = DEFPROPDELAY;
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = DEFFILTFUDGE;
- offset_fudge[i] = propagation_delay[i];
- L_ADD(&offset_fudge[i], &fudgefactor[i]);
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
/*
* chu_start - open the CHU device and initialize data for processing
*/
static int
chu_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct chuunit *chu;
- register int i;
- int fd232;
- char chudev[20];
- l_fp ts;
+ register struct chuunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
/*
- * Check configuration info
+ * Open serial port and set CHU line discipline
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "chu_start: unit %d invalid", unit);
- return 0;
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "chu_start: unit %d in use", unit);
- return 0;
- }
+ (void) sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CHU)))
+ return (0);
/*
- * Open serial port
+ * Allocate and initialize unit structure
*/
- (void) sprintf(chudev, CHUDEV, unit);
- fd232 = open(chudev, O_RDONLY, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "chu_start: open of %s: %m", chudev);
- return 0;
+ if (!(up = (struct chuunit *)
+ emalloc(sizeof(struct chuunit)))) {
+ (void) close(fd);
+ return (0);
}
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- */
- CHU SUPPORT NOT AVAILABLE IN TERMIO INTERFACE
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The CHUCLK support uses a 300-baud modem and level converter
- * (gadget box). It requires the chu_clk streams module and
- * SunOS 4.1.1 or later.
- *
- * The CHUPPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "chu_start: tcgetattr(%s): %m", chudev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = 0;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- ttyp->c_cc[VMIN] = 1;
- ttyp->c_cc[VTIME] = 0;
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "chu_start: tcsetattr(%s): %m", chudev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "chu_start: tcflush(%s): %m", chudev);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#ifdef STREAM
- while (ioctl(fd232, I_POP, 0 ) >= 0) ;
- if (ioctl(fd232, I_PUSH, "chu" ) < 0) {
- syslog(LOG_ERR,
- "chu_start: ioctl(%s, I_PUSH, chu): %m", chudev);
- goto screwed;
- }
-#if defined(CHUPPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "chu_start: ioctl(%s, I_PUSH, ppsclock): %m", chudev);
- else
- fdpps = fd232;
-#endif /* CHUPPS */
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The CHUCLK support uses a 300-baud modem and level converter
- * (gadget box). It requires the chu_clk streams module and
- * 4.3bsd or later.
- */
- { struct sgttyb ttyb;
- int ldisc = CHULDISC;
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "chu_start: ioctl(%s, TIOCGETP): %m", chudev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "chu_start: ioctl(%s, TIOCSETP): %m", chudev);
- goto screwed;
+ memset((char *)up, 0, sizeof(struct chuunit));
+ up->chutimer.peer = (struct peer *)up;
+ up->chutimer.event_handler = chu_timeout;
+ up->peer = peer;
+ pp = peer->procptr;
+ pp->io.clock_recv = chu_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "chu_start: ioctl(%s, TIOCSETD): %m",chudev);
- goto screwed;
- }
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (chuunits[unit] != 0) {
- chu = chuunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && chuunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- chu = chuunits[i];
- chuunits[i] = 0;
- } else {
- chu = (struct chuunit *)emalloc(sizeof(struct chuunit));
- }
- }
- memset((char *)chu, 0, sizeof(struct chuunit));
- chuunits[unit] = chu;
+ pp->unitptr = (caddr_t)up;
/*
- * Set up the structure
+ * Initialize miscellaneous variables
*/
- chu->peer = peer;
- chu->unit = (u_char)unit;
- chu->timestarted = current_time;
-
- chu->chutimer.peer = (struct peer *)chu;
- chu->chutimer.event_handler = chu_timeout;
-
- chu->chuio.clock_recv = chu_receive;
- chu->chuio.srcclock = (caddr_t)chu;
- chu->chuio.datalen = sizeof(struct chucode);
- chu->chuio.fd = fd232;
-
- /*
- * Initialize the year from the system time in case this is the
- * first open.
- */
- get_systime(&ts);
- yearstart = calyearstart(ts.l_ui);
- if (!io_addclock(&chu->chuio)) {
- goto screwed;
- }
-
- /*
- * All done. Initialize a few random peer variables, then
- * return success.
- */
- peer->precision = CHUPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, CHUREFID, 4);
- else
- peer->refid = htonl(CHUHSREFID);
- unitinuse[unit] = 1;
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
return (1);
-
- /*
- * Something broke; abandon ship.
- */
-screwed:
- (void) close(fd232);
- return (0);
}
/*
- * chu_shutdown - shut down a CHU clock
+ * chu_shutdown - shut down the clock
*/
static void
-chu_shutdown(unit)
+chu_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
- register struct chuunit *chu;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "chu_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "chu_shutdown: unit %d not in use", unit);
- return;
- }
+ register struct chuunit *up;
+ struct refclockproc *pp;
- /*
- * Tell the I/O module to turn us off, and dequeue timer
- * if any. We're history.
- */
- chu = chuunits[unit];
- if (chu->flags & CHUTIMERSET)
- TIMER_DEQUEUE(&chu->chutimer);
- io_closeclock(&chu->chuio);
- unitinuse[unit] = 0;
-}
-
-/*
- * chu_report_event - record an event and report it
- */
-static void
-chu_report_event(chu, code)
- struct chuunit *chu;
- int code;
-{
- /*
- * Trap support isn't up to handling this, so just
- * record it.
- */
- if (chu->status != (u_char)code) {
- chu->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- chu->lastevent = (u_char)code;
- }
+ pp = peer->procptr;
+ up = (struct chuunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
@@ -570,14 +298,16 @@ static void
chu_receive(rbufp)
struct recvbuf *rbufp;
{
- register int i;
- register U_LONG date_ui;
- register U_LONG tmp;
- register u_char *code;
- register struct chuunit *chu;
- register struct chucode *chuc;
+ register struct chuunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ int i;
+ u_long date_ui;
+ u_long tmp;
+ u_char *code;
+ struct chucode *chuc;
int isneg;
- U_LONG reftime;
+ u_long reftime;
l_fp off[NCHUCHARS];
int day, hour, minute, second;
@@ -585,7 +315,8 @@ chu_receive(rbufp)
* Do a length check on the data. Should be what we asked for.
*/
if (rbufp->recv_length != sizeof(struct chucode)) {
- syslog(LOG_ERR, "chu_receive: received %d bytes, expected %d",
+ syslog(LOG_ERR,
+ "chu_receive: received %d bytes, expected %d",
rbufp->recv_length, sizeof(struct chucode));
return;
}
@@ -593,27 +324,39 @@ chu_receive(rbufp)
/*
* Get the clock this applies to and a pointer to the data
*/
- chu = (struct chuunit *)rbufp->recv_srcclock;
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct chuunit *)pp->unitptr;
chuc = (struct chucode *)&rbufp->recv_space;
- chu->responses++;
- chu->lastupdate = current_time;
+ up->responses++;
/*
* Just for fun, we can debug the whole frame if
* we want.
*/
-
-#ifdef CHU_DEBUG
- syslog(LOG_DEBUG, "CHU %s packet:", (chuc->chutype == CHU_YEAR)?
- "year":"time");
- for (i=0; i < NCHUCHARS; i++) {
- char c[64];
-
- sprintf(c,"%c%c %s",hexstring[chuc->codechars[i]&0xf],
- hexstring[chuc->codechars[i]>>4],
- ctime(&(chuc->codetimes[i].tv_sec)));
- c[strlen(c)-1]=0; /* ctime() adds a damn \n */
- syslog(LOG_DEBUG, "%s .%06d", c, chuc->codetimes[i].tv_usec);
+ for (i = 0; i < NCHUCHARS; i++) {
+ pp->lastcode[2 * i] = hexstring[chuc->codechars[i] &
+ 0xf];
+ pp->lastcode[2 * i + 1] = hexstring[chuc->codechars[i]
+ >> 4];
+ }
+ pp->lencode = 2 * i;
+ pp->lastcode[pp->lencode] = '\0';
+#ifdef DEBUG
+ if (debug > 3) {
+ printf("chu: %s packet\n", (chuc->chutype == CHU_YEAR)?
+ "year":"time");
+ for (i = 0; i < NCHUCHARS; i++) {
+ char c[64];
+
+ sprintf(c,"%c%c %s",
+ hexstring[chuc->codechars[i] & 0xf],
+ hexstring[chuc->codechars[i] >> 4],
+ ctime(&(chuc->codetimes[i].tv_sec)));
+ c[strlen(c) - 1] = 0; /* ctime() adds \n */
+ printf("chu: %s .%06d\n", c,
+ chuc->codetimes[i].tv_usec);
+ }
}
#endif
@@ -633,7 +376,7 @@ chu_receive(rbufp)
* Break out the code into the BCD nibbles.
* Put it in the half of lastcode.
*/
- code = chu->lastcode;
+ code = up->lastcode;
code += 2*NCHUCHARS;
for (i = 0; i < NCHUCHARS; i++) {
*code++ = chuc->codechars[i] & 0xf;
@@ -651,8 +394,7 @@ chu_receive(rbufp)
parity = (parity ^ (parity>>1))&0x1;
if (parity)
{
- chu->badformat++;
- chu_event(chu, CEVNT_BADREPLY);
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
@@ -660,15 +402,14 @@ chu_receive(rbufp)
* This just happens to work. :-)
*/
- chu->leap = (leapbits >> 1) & 0x3;
+ pp->leap = (leapbits >> 1) & 0x3;
return;
}
if (chuc->chutype != CHU_TIME)
{
- chu->badformat++;
- chu_event(chu, CEVNT_BADREPLY);
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
@@ -677,7 +418,7 @@ chu_receive(rbufp)
* with the first half since both are identical. Note the first
* BCD character is the low order nibble, the second the high order.
*/
- code = chu->lastcode;
+ code = up->lastcode;
for (i = 0; i < NCHUCHARS; i++) {
*code++ = chuc->codechars[i] & 0xf;
*code++ = (chuc->codechars[i] >> 4) & 0xf;
@@ -688,19 +429,18 @@ chu_receive(rbufp)
* There's really no need for this, but it can't hurt.
*/
for (i = 0; i < NCHUCHARS/2; i++)
- if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
- chu->badformat++;
- chu_event(chu, CEVNT_BADREPLY);
+ if (chuc->codechars[i] !=
+ chuc->codechars[i+(NCHUCHARS/2)]) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
/*
* If the first nibble isn't a 6, we're up the creek
*/
- code = chu->lastcode;
+ code = up->lastcode;
if (*code++ != 6) {
- chu->badformat++;
- chu_event(chu, CEVNT_BADREPLY);
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
@@ -725,11 +465,11 @@ chu_receive(rbufp)
if (day < 1 || day > 366
|| hour > 23 || minute > 59
|| second < 32 || second > 39) {
- chu->baddata++;
+ pp->baddata++;
if (day < 1 || day > 366) {
- chu_event(chu, CEVNT_BADDATE);
+ refclock_report(peer, CEVNT_BADDATE);
} else {
- chu_event(chu, CEVNT_BADTIME);
+ refclock_report(peer, CEVNT_BADTIME);
}
return;
}
@@ -740,8 +480,8 @@ chu_receive(rbufp)
* date as bad and forget it.
*/
if (!clocktime(day, hour, minute, second, 0,
- rbufp->recv_time.l_ui, &yearstart, &reftime)) {
- chu_event(chu, CEVNT_BADDATE);
+ rbufp->recv_time.l_ui, &pp->yearstart, (U_LONG *)&reftime)) {
+ refclock_report(peer, CEVNT_BADDATE);
return;
}
date_ui = reftime;;
@@ -752,7 +492,7 @@ chu_receive(rbufp)
* the offsets for each character.
*/
for (i = 0; i < NCHUCHARS; i++) {
- register U_LONG tmp2;
+ register u_long tmp2;
off[i].l_ui = date_ui;
off[i].l_uf = chutable[i];
@@ -761,7 +501,7 @@ chu_receive(rbufp)
M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
}
- if (!sloppyclockflag[chu->unit]) {
+ if (!pp->sloppyclockflag) {
u_short ord[NCHUCHARS];
/*
* In here we assume the clock has adequate bits
@@ -798,7 +538,7 @@ chu_receive(rbufp)
for (tmp = 0; tmp < (NCHUCHARS-1); tmp++) {
for (i = (int)tmp+1; i < NCHUCHARS; i++) {
if (!L_ISGEQ(&off[ord[i]], &off[ord[tmp]])) {
- date_ui = (U_LONG)ord[i];
+ date_ui = (u_long)ord[i];
ord[i] = ord[tmp];
ord[tmp] = (u_short)date_ui;
}
@@ -853,8 +593,8 @@ chu_receive(rbufp)
* out of a 64 bit product, even after rounding.
*/
if (date_ui < 9 || date_ui > 0xfffffff7) {
- register U_LONG prod_ui;
- register U_LONG prod_uf;
+ register u_long prod_ui;
+ register u_long prod_uf;
prod_ui = prod_uf = 0;
/*
@@ -881,10 +621,10 @@ chu_receive(rbufp)
* date_ui is integral part, tmp is fraction.
*/
} else {
- register U_LONG prod_ovr;
- register U_LONG prod_ui;
- register U_LONG prod_uf;
- register U_LONG highbits;
+ register u_long prod_ovr;
+ register u_long prod_ui;
+ register u_long prod_uf;
+ register u_long highbits;
prod_ovr = prod_ui = prod_uf = 0;
if (isneg)
@@ -902,7 +642,7 @@ chu_receive(rbufp)
}
if (prod_uf & 0x80000000)
- M_ADDUF(prod_ovr, prod_ui, (U_LONG)1);
+ M_ADDUF(prod_ovr, prod_ui, (u_long)1);
date_ui = prod_ovr;
tmp = prod_ui;
}
@@ -914,56 +654,50 @@ chu_receive(rbufp)
* it in the structure.
*/
i = second - 32; /* gives a value 0 through 8 */
- if (i < (int)chu->expect) {
+ if (i < (int)up->expect) {
/*
* This shouldn't actually happen, but might if a single
* bit error occurred in the code which fooled us.
* Throw away all previous data.
*/
- chu->expect = 0;
- chu->haveoffset = 0;
- if (chu->flags & CHUTIMERSET) {
- TIMER_DEQUEUE(&chu->chutimer);
- chu->flags &= ~CHUTIMERSET;
+ up->expect = 0;
+ up->haveoffset = 0;
+ if (up->flags & CHUTIMERSET) {
+ TIMER_DEQUEUE(&up->chutimer);
+ up->flags &= ~CHUTIMERSET;
}
}
- /*
- * Add in fudge factor.
- */
- M_ADD(date_ui, tmp, offset_fudge[chu->unit].l_ui,
- offset_fudge[chu->unit].l_uf);
-
- chu->offsets[i].l_ui = date_ui;
- chu->offsets[i].l_uf = tmp;
- chu->rectimes[i] = rbufp->recv_time;
- chu->reftimes[i] = reftime;
+ up->offsets[i].l_ui = date_ui;
+ up->offsets[i].l_uf = tmp;
+ up->rectimes[i] = rbufp->recv_time;
+ up->reftimes[i] = reftime;
- chu->expect = i + 1;
- chu->haveoffset |= (1<<i);
+ up->expect = i + 1;
+ up->haveoffset |= (1 << i);
- if (chu->expect >= NCHUCODES) {
+ if (up->expect >= NCHUCODES) {
/*
* Got a full second's worth. Dequeue timer and
* process this.
*/
- if (chu->flags & CHUTIMERSET) {
- TIMER_DEQUEUE(&chu->chutimer);
- chu->flags &= ~CHUTIMERSET;
+ if (up->flags & CHUTIMERSET) {
+ TIMER_DEQUEUE(&up->chutimer);
+ up->flags &= ~CHUTIMERSET;
}
- chu_process(chu);
- } else if (!(chu->flags & CHUTIMERSET)) {
+ chu_process(up);
+ } else if (!(up->flags & CHUTIMERSET)) {
/*
* Try to take an interrupt sometime after the
* 42 second mark (leaves an extra 2 seconds for
* slop). Round it up to an even multiple of
* 4 seconds.
*/
- chu->chutimer.event_time =
- current_time + (U_LONG)(10 - i) + (1<<EVENT_TIMEOUT);
- chu->chutimer.event_time &= ~((1<<EVENT_TIMEOUT) - 1);
- TIMER_INSERT(timerqueue, &chu->chutimer);
- chu->flags |= CHUTIMERSET;
+ up->chutimer.event_time =
+ current_time + (u_long)(10 - i) + (1<<EVENT_TIMEOUT);
+ up->chutimer.event_time &= ~((1<<EVENT_TIMEOUT) - 1);
+ TIMER_INSERT(timerqueue, &up->chutimer);
+ up->flags |= CHUTIMERSET;
}
}
@@ -990,62 +724,57 @@ chu_timeout(fakepeer)
* the results on to the NTP clock filters.
*/
static void
-chu_process(chu)
- register struct chuunit *chu;
+chu_process(up)
+ register struct chuunit *up;
{
- register int i;
- register s_fp bestoff;
- register s_fp tmpoff;
+ struct peer *peer;
+ struct refclockproc *pp;
+ int i;
+ s_fp bestoff;
+ s_fp tmpoff;
u_fp dispersion;
int imax;
- l_fp ts;
/*
* The most positive offset.
*/
+ peer = up->peer;
+ pp = peer->procptr;
imax = NCHUCODES;
for (i = 0; i < NCHUCODES; i++)
- if (chu->haveoffset & (1<<i))
- if (i < imax || L_ISGEQ(&chu->offsets[i],
- &chu->offsets[imax]))
+ if (up->haveoffset & (1<<i))
+ if (i < imax || L_ISGEQ(&up->offsets[i],
+ &up->offsets[imax]))
imax = i;
/*
* The most positive estimate is our best bet. Go through
* the list again computing the dispersion.
*/
- bestoff = LFPTOFP(&chu->offsets[imax]);
+ bestoff = LFPTOFP(&up->offsets[imax]);
dispersion = 0;
for (i = 0; i < NCHUCODES; i++) {
- if (chu->haveoffset & (1<<i)) {
- tmpoff = LFPTOFP(&chu->offsets[i]);
+ if (up->haveoffset & (1<<i)) {
+ tmpoff = LFPTOFP(&up->offsets[i]);
dispersion += (bestoff - tmpoff);
} else {
dispersion += CHUDELAYPENALTY;
}
}
- /*
- * Make up a reference time stamp, then give it to the
- * reference clock support code for further processing.
- */
- ts.l_ui = chu->reftimes[imax];
- ts.l_uf = chutable[NCHUCHARS-1];
-
- for (i = 0; i < NCHUCHARS*4; i++) {
- chu->asciicode[i] = hexstring[chu->lastcode[i]];
- }
- chu->asciicode[i] = '\0';
- record_clock_stats(&(chu->peer->srcadr), chu->asciicode);
- refclock_receive(chu->peer, &chu->offsets[imax], 0,
- dispersion, &ts, &chu->rectimes[imax], chu->leap);
+ pp->lasttime = current_time;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+ refclock_receive(peer, &up->offsets[imax], 0,
+ dispersion, &up->rectimes[imax], &up->rectimes[imax],
+ pp->leap);
/*
* Zero out unit for next code series
*/
- chu->haveoffset = 0;
- chu->expect = 0;
- chu_event(chu, CEVNT_NOMINAL);
+ up->haveoffset = 0;
+ up->expect = 0;
+ refclock_report(peer, CEVNT_NOMINAL);
}
@@ -1057,103 +786,15 @@ chu_poll(unit, peer)
int unit;
struct peer *peer;
{
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "chu_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "chu_poll: unit %d not in use", unit);
- return;
- }
+ register struct chuunit *up;
+ struct refclockproc *pp;
- if ((current_time - chuunits[unit]->lastupdate) > 150) {
- chu_event(chuunits[unit], CEVNT_PROP);
- }
+ pp = peer->procptr;
+ up = (struct chuunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
}
-
-
-/*
- * chu_control - set fudge factors, return statistics
- */
-static void
-chu_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct chuunit *chu;
- U_LONG npolls;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "chu_control: unit %d invalid", unit);
- return;
- }
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- propagation_delay[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVETIME2)
- fudgefactor[unit] = in->fudgetime2;
- offset_fudge[unit] = propagation_delay[unit];
- L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- peer = chuunits[unit]->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- CHUREFID, 4);
- else
- peer->refid = htonl(CHUHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG1;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_CHU;
- out->flags = 0;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
- CLK_HAVEVAL2|CLK_HAVEFLAG1;
- out->clockdesc = CHUDESCRIPTION;
- out->fudgetime1 = propagation_delay[unit];
- out->fudgetime2 = fudgefactor[unit];
- out->fudgeval1 = (long)stratumtouse[unit];
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- chu = chuunits[unit];
- out->lencode = NCHUCHARS*4;
- out->fudgeval2 = chu->lastcode[2*NCHUCHARS+1];
- out->fudgeval2 *= (chu->lastcode[2*NCHUCHARS]&1)?-1:1;
- out->lastcode = chu->asciicode;
- out->timereset = current_time - chu->timestarted;
- npolls = out->timereset / 6; /* **divide** */
- out->polls = npolls;
- out->noresponse = (npolls - chu->responses);
- out->badformat = chu->badformat;
- out->baddata = chu->baddata;
- out->lastevent = chu->lastevent;
- out->currentstatus = chu->status;
- } else {
- out->fudgeval2 = 0;
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
-}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_conf.c b/usr.sbin/xntpd/xntpd/refclock_conf.c
index 535ca27e9ebe..c0674d917311 100644
--- a/usr.sbin/xntpd/xntpd/refclock_conf.c
+++ b/usr.sbin/xntpd/xntpd/refclock_conf.c
@@ -15,95 +15,137 @@ static struct refclock refclock_none = {
};
#ifdef LOCAL_CLOCK
-extern struct refclock refclock_local;
+extern struct refclock refclock_local;
#else
#define refclock_local refclock_none
#endif
#if defined(TRAK) || defined(TRAKCLK) || defined(TRAKPPS)
-extern struct refclock refclock_trak;
+extern struct refclock refclock_trak;
#else
#define refclock_trak refclock_none
#endif
-#if defined(PST) || defined(PSTCLK) || defined(PSTPPS)
-extern struct refclock refclock_pst;
+#if defined(PST)
+extern struct refclock refclock_pst;
#else
#define refclock_pst refclock_none
#endif
-#if defined(CHU) || defined(CHUCLK) || defined(CHUPPS)
-extern struct refclock refclock_chu;
+#if defined(CHU)
+extern struct refclock refclock_chu;
#else
#define refclock_chu refclock_none
#endif
#if defined(GOES) || defined(GOESCLK) || defined(GOESPPS)
-extern struct refclock refclock_goes;
+extern struct refclock refclock_goes;
#else
#define refclock_goes refclock_none
#endif
-#if defined(WWVB) || defined(WWVBCLK) || defined(WWVBPPS)
-extern struct refclock refclock_wwvb;
+#if defined(WWVB)
+extern struct refclock refclock_wwvb;
#else
#define refclock_wwvb refclock_none
#endif
#if defined(PARSE) || defined(PARSEPPS)
-extern struct refclock refclock_parse;
+extern struct refclock refclock_parse;
#else
#define refclock_parse refclock_none
#endif
-#if defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS)
-extern struct refclock refclock_mx4200;
+#if defined(PPS) && (defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS))
+extern struct refclock refclock_mx4200;
#else
#define refclock_mx4200 refclock_none
#endif
-#if defined(AS2201) || defined(AS2201CLK) || defined(AS2201PPS)
-extern struct refclock refclock_as2201;
+#if defined(AS2201)
+extern struct refclock refclock_as2201;
#else
#define refclock_as2201 refclock_none
#endif
#if defined(OMEGA) || defined(OMEGACLK) || defined(OMEGAPPS)
-extern struct refclock refclock_omega;
+extern struct refclock refclock_omega;
#else
#define refclock_omega refclock_none
#endif
-#ifdef TPRO
-extern struct refclock refclock_tpro;
+#if defined(TPRO) && defined(sun) /* XXX sun only */
+extern struct refclock refclock_tpro;
#else
#define refclock_tpro refclock_none
#endif
#if defined(LEITCH) || defined(LEITCHCLK) || defined(LEITCHPPS)
-extern struct refclock refclock_leitch;
+extern struct refclock refclock_leitch;
#else
#define refclock_leitch refclock_none
#endif
-#ifdef IRIG
-extern struct refclock refclock_irig;
+#if defined(IRIG) && defined(sun) /* XXX sun only */
+extern struct refclock refclock_irig;
#else
#define refclock_irig refclock_none
#endif
#if defined(MSFEESPPS)
-extern struct refclock refclock_msfees;
+extern struct refclock refclock_msfees;
#else
#define refclock_msfees refclock_none
#endif
#if defined(GPSTM) || defined(GPSTMCLK) || defined(GPSTMPPS)
-extern struct refclock refclock_gpstm;
+extern struct refclock refclock_gpstm;
#else
#define refclock_gpstm refclock_none
#endif
+#if defined(BANC) || defined(BANCCLK) || defined(BANCPPS)
+extern struct refclock refclock_bancomm;
+#else
+#define refclock_bancomm refclock_none
+#endif
+
+#ifdef DATUM
+extern struct refclock refclock_datum;
+#else
+#define refclock_datum refclock_none
+#endif
+
+#ifdef ACTS
+extern struct refclock refclock_acts;
+#else
+#define refclock_acts refclock_none
+#endif
+
+#ifdef HEATH
+extern struct refclock refclock_heath;
+#else
+#define refclock_heath refclock_none
+#endif
+
+#ifdef NMEA
+extern struct refclock refclock_nmea;
+#else
+#define refclock_nmea refclock_none
+#endif
+
+#ifdef MOTO
+extern struct refclock refclock_moto;
+#else
+#define refclock_moto refclock_none
+#endif
+
+#ifdef ATOM
+extern struct refclock refclock_atom;
+#else
+#define refclock_atom refclock_none
+#endif
+
/*
* Order is clock_start(), clock_shutdown(), clock_poll(),
* clock_control(), clock_init(), clock_buginfo, clock_flags;
@@ -127,6 +169,15 @@ struct refclock *refclock_conf[] = {
&refclock_leitch, /* 13 REFCLK_ATOM_LEITCH */
&refclock_msfees, /* 14 REFCLK_MSF_EES */
&refclock_gpstm, /* 15 REFCLK_GPSTM_TRUETIME */
+ &refclock_bancomm, /* 16 REFCLK_IRIG_BANCOMM */
+ &refclock_datum, /* 17 REFCLK_GPS_DATUM */
+ &refclock_acts, /* 18 REFCLK_NIST_ACTS */
+ &refclock_heath, /* 19 REFCLK_WWV_HEATH */
+ &refclock_nmea, /* 20 REFCLK_GPS_NMEA */
+ &refclock_moto, /* 21 REFCLK_GPS_MOTO */
+ &refclock_atom, /* 22 REFCLK_ATOM_PPS */
+ &refclock_none, /* 23 reserved */
+ &refclock_none, /* 24 reserved */
};
u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff --git a/usr.sbin/xntpd/xntpd/refclock_datum.c b/usr.sbin/xntpd/xntpd/refclock_datum.c
new file mode 100644
index 000000000000..825dee7ad7df
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_datum.c
@@ -0,0 +1,871 @@
+/*
+** refclock_datum - clock driver for the Datum Programmable Time Server
+**
+** Important note: This driver assumes that you have termios. If you have
+** a system that does not have termios, you will have to modify this driver.
+**
+** Sorry, I have only tested this driver on SUN and HP platforms.
+*/
+
+#if defined(REFCLOCK) && (defined(DATUM) || defined(DATUMCLK) || defined(DATUMPPS))
+
+/*
+** Include Files
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(WWVBCLK)
+#include <sys/clkdefs.h>
+#endif /* WWVBCLK */
+#endif /* STREAM */
+
+#if defined (WWVBPPS)
+#include <sys/ppsclock.h>
+#endif /* WWVBPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+** This driver supports the Datum Programmable Time System (PTS) clock.
+** The clock works in very straight forward manner. When it receives a
+** time code request (e.g., the ascii string "//k/mn"), it responds with
+** a seven byte BCD time code. This clock only responds with a
+** time code after it first receives the "//k/mn" message. It does not
+** periodically send time codes back at some rate once it is started.
+** the returned time code can be broken down into the following fields.
+**
+** _______________________________
+** Bit Index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+** ===============================
+** byte 0: | - - - - | H D |
+** ===============================
+** byte 1: | T D | U D |
+** ===============================
+** byte 2: | - - | T H | U H |
+** ===============================
+** byte 3: | - | T M | U M |
+** ===============================
+** byte 4: | - | T S | U S |
+** ===============================
+** byte 5: | t S | h S |
+** ===============================
+** byte 6: | m S | - - - - |
+** ===============================
+**
+** In the table above:
+**
+** "-" means don't care
+** "H D", "T D", and "U D" means Hundreds, Tens, and Units of Days
+** "T H", and "UH" means Tens and Units of Hours
+** "T M", and "U M" means Tens and Units of Minutes
+** "T S", and "U S" means Tens and Units of Seconds
+** "t S", "h S", and "m S" means tenths, hundredths, and thousandths
+** of seconds
+**
+** The Datum PTS communicates throught the RS232 port on your machine.
+** Right now, it assumes that you have termios. This driver has been tested
+** on SUN and HP workstations. The Datum PTS supports various IRIG and
+** NASA input codes. This driver assumes that the name of the device is
+** /dev/datum. You will need to make a soft link to your RS232 device or
+** create a new driver to use this refclock.
+*/
+
+/*
+** Datum PTS defines
+*/
+
+/*
+** Note that if GMT is defined, then the Datum PTS must use Greenwich
+** time. Otherwise, this driver allows the Datum PTS to use the current
+** wall clock for its time. It determines the time zone offset by minimizing
+** the error after trying several time zone offsets. If the Datum PTS
+** time is Greenwich time and GMT is not defined, everything should still
+** work since the time zone will be found to be 0. What this really means
+** is that your system time (at least to start with) must be within the
+** correct time by less than +- 30 minutes. The default is for GMT to not
+** defined. If you really want to force GMT without the funny +- 30 minute
+** stuff then you must define (uncomment) GMT below.
+*/
+
+/*
+#define GMT
+#define DEBUG_DATUM_PTC
+#define LOG_TIME_ERRORS
+*/
+
+
+#define PTSPRECISION (-10) /* precision assumed 1/1024 ms */
+#define DATMREFID "DATM" /* reference id */
+#define DATUM_DISPERSION 0 /* fixed dispersion = 0 ms */
+#define DATUM_MAX_ERROR 0.100 /* limits on sigma squared */
+
+#define DATUM_MAX_ERROR2 (DATUM_MAX_ERROR*DATUM_MAX_ERROR)
+
+/*
+** External Variables
+*/
+
+extern u_long current_time; /* current time (s) - not really used */
+extern int debug; /* global debug flag - not relly used */
+
+/*
+** The Datum PTS structure
+*/
+
+/*
+** I don't use a fixed array of MAXUNITS like everyone else just because
+** I don't like to program that way. Sorry if this bothers anyone. I assume
+** that you can use any id for your unit and I will search for it in a
+** dynamic array of units until I find it. I was worried that users might
+** enter a bad id in their configuration file (larger than MAXUNITS) and
+** besides, it is just cleaner not to have to assume that you have a fixed
+** number of anything in a program.
+*/
+
+struct datum_pts_unit {
+ struct peer *peer; /* peer used by xntp */
+ struct refclockio io; /* io structure used by xntp */
+ int PTS_fd; /* file descriptor for PTS */
+ u_int unit; /* id for unit */
+ u_long timestarted; /* time started */
+ l_fp lastrec; /* time tag for the receive time (system) */
+ l_fp lastref; /* reference time (Datum time) */
+ u_long yearstart; /* the year that this clock started */
+ int coderecv; /* number of time codes received */
+ int day; /* day */
+ int hour; /* hour */
+ int minute; /* minutes */
+ int second; /* seconds */
+ int msec; /* miliseconds */
+ int usec; /* miliseconds */
+ u_char leap; /* funny leap character code */
+ char retbuf[8]; /* returned time from the datum pts */
+ char nbytes; /* number of bytes received from datum pts */
+ double sigma2; /* average squared error (roughly) */
+ int tzoff; /* time zone offest from GMT */
+};
+
+/*
+** PTS static constant variables for internal use
+*/
+
+static char TIME_REQUEST[6]; /* request message sent to datum for time */
+static FILE *logfile; /* log file for logging information */
+static int nunits; /* number of active units */
+static struct datum_pts_unit
+ **datum_pts_unit; /* dynamic array of datum PTS structures */
+
+/*
+** Callback function prototypes that xntpd needs to know about.
+*/
+
+static int datum_pts_start P((int, struct peer *));
+static void datum_pts_shutdown P((int, struct peer *));
+static void datum_pts_poll P((int, struct peer *));
+static void datum_pts_control P((int, struct refclockstat *,
+ struct refclockstat *));
+static void datum_pts_init P((void));
+static void datum_pts_buginfo P((int, struct refclockbug *));
+
+/*
+** This is the call back function structure that xntpd actually uses for
+** this refclock.
+*/
+
+struct refclock refclock_datum = {
+ datum_pts_start, /* start up a new Datum refclock */
+ datum_pts_shutdown, /* shutdown a Datum refclock */
+ datum_pts_poll, /* sends out the time request */
+ datum_pts_control, /* not used */
+ datum_pts_init, /* initialization (called first) */
+ datum_pts_buginfo, /* not used */
+ NOFLAGS /* we are not setting any special flags */
+};
+
+/*
+** The datum_pts_receive callback function is handled differently from the
+** rest. It is passed to the xntpd io data structure. Basically, every
+** 64 seconds, the datum_pts_poll() routine is called. It sends out the time
+** request message to the Datum Programmable Time System. Then, xntpd
+** waits on a select() call to receive data back. The datum_pts_receive()
+** function is called as data comes back. We expect a seven byte time
+** code to be returned but the datum_pts_receive() function may only get
+** a few bytes passed to it at a time. In other words, this routine may
+** get called by the io stuff in xntpd a few times before we get all seven
+** bytes. Once the last byte is received, we process it and then pass the
+** new time measurement to xntpd for updating the system time. For now,
+** there is no 3 state filtering done on the time measurements. The
+** jitter may be a little high but at least for its current use, it is not
+** a problem. We have tried to keep things as simple as possible. This
+** clock should not jitter more than 1 or 2 mseconds at the most once
+** things settle down. It is important to get the right drift calibrated
+** in the xntpd.drift file as well as getting the right tick set up right
+** using tickadj for SUNs. Tickadj is not used for the HP but you need to
+** remember to bring up the adjtime daemon because HP does not support
+** the adjtime() call.
+*/
+
+static void datum_pts_receive P((struct recvbuf *));
+
+/*......................................................................*/
+/* datum_pts_start - start up the datum PTS. This means open the */
+/* RS232 device and set up the data structure for my unit. */
+/*......................................................................*/
+
+static int datum_pts_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct datum_pts_unit **temp_datum_pts_unit;
+ struct datum_pts_unit *datum_pts;
+
+#ifdef HAVE_TERMIOS
+ struct termios arg;
+#endif
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile, "Starting Datum PTS unit %d\n", unit);
+ fflush(logfile);
+#endif
+
+/*
+** Create the memory for the new unit
+*/
+
+ temp_datum_pts_unit = (struct datum_pts_unit **)
+ malloc((nunits+1)*sizeof(struct datum_pts_unit *));
+ if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
+ nunits*sizeof(struct datum_pts_unit *));
+ free(datum_pts_unit);
+ datum_pts_unit = temp_datum_pts_unit;
+ datum_pts_unit[nunits] = (struct datum_pts_unit *)
+ malloc(sizeof(struct datum_pts_unit));
+ datum_pts = datum_pts_unit[nunits];
+
+ datum_pts->unit = unit; /* set my unit id */
+ datum_pts->yearstart = 0; /* initialize the yearstart to 0 */
+ datum_pts->sigma2 = 0.0; /* initialize the sigma2 to 0 */
+
+/*
+** Open the Datum PTS device
+*/
+
+ datum_pts->PTS_fd = open("/dev/datum",O_RDWR);
+
+ fcntl(datum_pts->PTS_fd, F_SETFL, 0); /* clear the descriptor flags */
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Opening RS232 port with file descriptor %d\n",
+ datum_pts->PTS_fd);
+ fflush(logfile);
+#endif
+
+/*
+** Set up the RS232 terminal device information. Note that we assume that
+** we have termios. This code has only been tested on SUNs and HPs. If your
+** machine does not have termios then this program exits. You can change this
+** if you want by editing this source. Please give the changes back to the
+** xntp folks so that it can become part of their regular distribution.
+*/
+
+#ifdef HAVE_TERMIOS
+
+ arg.c_iflag = IGNBRK;
+ arg.c_oflag = 0;
+ arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL;
+ arg.c_lflag = 0;
+ arg.c_cc[VMIN] = 0; /* start timeout timer right away (not used) */
+ arg.c_cc[VTIME] = 30; /* 3 second timout on reads (not used) */
+
+ tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
+
+#else
+
+ syslog(LOG_ERR, "Datum_PTS: Exiting - Termios not supported in this driver");
+ exit(1);
+
+#endif
+
+/*
+** Initialize the xntpd IO structure
+*/
+
+ datum_pts->peer = peer;
+ datum_pts->timestarted = current_time;
+
+ datum_pts->io.clock_recv = datum_pts_receive;
+ datum_pts->io.srcclock = (caddr_t)datum_pts;
+ datum_pts->io.datalen = 0;
+ datum_pts->io.fd = datum_pts->PTS_fd;
+
+ if (!io_addclock(&(datum_pts->io))) {
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Problem adding clock\n");
+ fflush(logfile);
+#endif
+
+ syslog(LOG_ERR, "Datum_PTS: Problem adding clock");
+
+ }
+
+ peer->precision = PTSPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = 0;
+ memcpy((char *)&peer->refid, DATMREFID, 4);
+
+/*
+** Now add one to the number of units and return a successful code
+*/
+
+ nunits++;
+ return 1;
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_shutdown - this routine shuts doen the device and */
+/* removes the memory for the unit. */
+/*......................................................................*/
+
+static void datum_pts_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ int i,j;
+ struct datum_pts_unit **temp_datum_pts_unit;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Shutdown Datum PTS\n");
+ fflush(logfile);
+#endif
+
+ syslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS");
+
+/*
+** First we have to find the right unit (i.e., the one with the same id).
+** We do this by looping through the dynamic array of units intil we find
+** it. Note, that I don't simply use an array with a maximimum number of
+** Datum PTS units. Everything is completely dynamic.
+*/
+
+ for (i=0; i<nunits; i++) {
+ if (datum_pts_unit[i]->unit == unit) {
+
+/*
+** We found the unit so close the file descriptor and free up the memory used
+** by the structure.
+*/
+
+ io_closeclock(&datum_pts_unit[i]->io);
+ close(datum_pts_unit[i]->PTS_fd);
+ free(datum_pts_unit[i]);
+
+/*
+** Now clean up the datum_pts_unit dynamic array so that there are no holes.
+** This may mean moving pointers around, etc., to keep things compact.
+*/
+
+ if (nunits > 1) {
+
+ temp_datum_pts_unit = (struct datum_pts_unit **)
+ malloc((nunits-1)*sizeof(struct datum_pts_unit *));
+ if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
+ i*sizeof(struct datum_pts_unit *));
+
+ for (j=i+1; j<nunits; j++) {
+ temp_datum_pts_unit[j-1] = datum_pts_unit[j];
+ }
+
+ free(datum_pts_unit);
+ datum_pts_unit = temp_datum_pts_unit;
+
+ }else{
+
+ free(datum_pts_unit);
+ datum_pts_unit = NULL;
+
+ }
+
+ return;
+
+ }
+ }
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error, could not shut down unit %d\n",unit);
+ fflush(logfile);
+#endif
+
+ syslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit);
+
+}
+
+/*......................................................................*/
+/* datum_pts_poll - this routine sends out the time request to the */
+/* Datum PTS device. The time will be passed back in the */
+/* datum_pts_receive() routine. */
+/*......................................................................*/
+
+static void datum_pts_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ int i;
+ int index;
+ int error_code;
+ struct datum_pts_unit *datum_pts;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Poll Datum PTS\n");
+ fflush(logfile);
+#endif
+
+/*
+** Find the right unit and send out a time request once it is found.
+*/
+
+ index = -1;
+ for (i=0; i<nunits; i++) {
+ if (datum_pts_unit[i]->unit == unit) {
+ index = i;
+ datum_pts = datum_pts_unit[i];
+ error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
+ if (error_code != 6) perror("TIME_REQUEST");
+ datum_pts->nbytes = 0;
+ break;
+ }
+ }
+
+/*
+** Print out an error message if we could not find the right unit.
+*/
+
+ if (index == -1) {
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error, could not poll unit %d\n",unit);
+ fflush(logfile);
+#endif
+
+ syslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit);
+ return;
+
+ }
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_control - not used */
+/*......................................................................*/
+
+static void datum_pts_control(unit, in, out)
+ int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Control Datum PTS\n");
+ fflush(logfile);
+#endif
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_init - initializes things for all possible Datum */
+/* time code generators that might be used. In practice, this is */
+/* only called once at the beginning before anything else is */
+/* called. */
+/*......................................................................*/
+
+static void datum_pts_init()
+{
+
+/* */
+/*...... open up the log file if we are debugging ......................*/
+/* */
+
+/*
+** Open up the log file if we are debugging. For now, send data out to the
+** screen (stdout).
+*/
+
+#if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS)
+/*
+ logfile = fopen("xntpd.log", "w");
+*/
+#endif
+
+ logfile = stdout;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Init Datum PTS\n");
+ fflush(logfile);
+#endif
+
+/*
+** Initialize the time request command string. This is the only message
+** that we ever have to send to the Datum PTS (although others are defined).
+*/
+
+ memcpy(TIME_REQUEST, "//k/mn",6);
+
+/*
+** Initialize the number of units to 0 and set the dynamic array of units to
+** NULL since there are no units defined yet.
+*/
+
+ datum_pts_unit = NULL;
+ nunits = 0;
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_buginfo - not used */
+/*......................................................................*/
+
+static void datum_pts_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Buginfo Datum PTS\n");
+ fflush(logfile);
+#endif
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_receive - receive the time buffer that was read in */
+/* by the xntpd io handling routines. When 7 bytes have been */
+/* received (it may take several tries before all 7 bytes are */
+/* received), then the time code must be unpacked and sent to */
+/* the xntpd clock_receive() routine which causes the systems */
+/* clock to be updated (several layers down). */
+/*......................................................................*/
+
+static void datum_pts_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ int i;
+ l_fp tstmp;
+ struct datum_pts_unit *datum_pts;
+ char *dpt;
+ int dpend;
+ int tzoff;
+ int timerr;
+ double ftimerr, abserr;
+ u_fp dispersion;
+ int goodtime;
+
+/*
+** Get the time code (maybe partial) message out of the rbufp buffer.
+*/
+
+ datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock;
+ dpt = (char *)&rbufp->recv_space;
+ dpend = rbufp->recv_length;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Receive Datum PTS: %d bytes\n", dpend);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... save the ntp system time when the first byte is received ......*/
+/* */
+
+/*
+** Save the ntp system time when the first byte is received. Note that
+** because it may take several calls to this routine before all seven
+** bytes of our return message are finally received by the io handlers in
+** xntpd, we really do want to use the time tag when the first byte is
+** received to reduce the jitter.
+*/
+
+ if (datum_pts->nbytes == 0) {
+ datum_pts->lastrec = rbufp->recv_time;
+ }
+
+/*
+** Increment our count to the number of bytes received so far. Return if we
+** haven't gotten all seven bytes yet.
+*/
+
+ for (i=0; i<dpend; i++) {
+ datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i];
+ }
+
+ datum_pts->nbytes += dpend;
+
+ if (datum_pts->nbytes != 7) {
+ return;
+ }
+
+/*
+** Convert the seven bytes received in our time buffer to day, hour, minute,
+** second, and msecond values. The usec value is not used for anything
+** currently. It is just the fractional part of the time stored in units
+** of microseconds.
+*/
+
+ datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) +
+ 10*((datum_pts->retbuf[1] & 0xf0)>>4) +
+ (datum_pts->retbuf[1] & 0x0f);
+
+ datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) +
+ (datum_pts->retbuf[2] & 0x0f);
+
+ datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) +
+ (datum_pts->retbuf[3] & 0x0f);
+
+ datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) +
+ (datum_pts->retbuf[4] & 0x0f);
+
+ datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) +
+ 10*(datum_pts->retbuf[5] & 0x0f) +
+ ((datum_pts->retbuf[6] & 0xf0)>>4);
+
+ datum_pts->usec = 1000*datum_pts->msec;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"day %d, hour %d, minute %d, second %d, msec %d\n",
+ datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ datum_pts->msec);
+ fflush(logfile);
+#endif
+
+/*
+** Get the GMT time zone offset. Note that GMT should be zero if the Datum
+** reference time is using GMT as its time base. Otherwise we have to
+** determine the offset if the Datum PTS is using time of day as its time
+** base.
+*/
+
+ goodtime = 0; /* We are not sure about the time and offset yet */
+
+#ifdef GMT
+
+/*
+** This is the case where the Datum PTS is using GMT so there is no time
+** zone offset.
+*/
+
+ tzoff = 0; /* set time zone offset to 0 */
+
+#else
+
+/*
+** This is the case where the Datum PTS is using regular time of day for its
+** time so we must compute the time zone offset. The way we do it is kind of
+** funny but it works. We loop through different time zones (0 to 24) and
+** pick the one that gives the smallest error (+- one half hour). The time
+** zone offset is stored in the datum_pts structure for future use. Normally,
+** the clocktime() routine is only called once (unless the time zone offset
+** changes due to daylight savings) since the goodtime flag is set when a
+** good time is found (with a good offset). Note that even if the Datum
+** PTS is using GMT, this mechanism will still work since it should come up
+** with a value for tzoff = 0 (assuming that your system clock is within
+** a half hour of the Datum time (even with time zone differences).
+*/
+
+ for (tzoff=0; tzoff<24; tzoff++) {
+ if (clocktime( datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ (tzoff + datum_pts->tzoff) % 24,
+ datum_pts->lastrec.l_ui,
+ &datum_pts->yearstart,
+ &datum_pts->lastref.l_ui) ) {
+
+ error = datum_pts->lastref.l_ui - datum_pts->lastrec.l_ui;
+
+#ifdef DEBUG_DATUM_PTC
+ printf("Time Zone (clocktime method) = %d, error = %d\n", tzoff, error);
+#endif
+
+ if ((error < 1799) && (error > -1799)) {
+ tzoff = (tzoff + datum_pts->tzoff) % 24;
+ datum_pts->tzoff = tzoff;
+ goodtime = 1;
+
+#ifdef DEBUG_DATUM_PTC
+ printf("Time Zone found (clocktime method) = %d\n",tzoff);
+#endif
+
+ break;
+ }
+
+ }
+ }
+
+#endif
+
+/*
+** Make sure that we have a good time from the Datum PTS. Clocktime() also
+** sets yearstart and lastref.l_ui. We will have to set astref.l_uf (i.e.,
+** the fraction of a second) stuff later.
+*/
+
+ if (!goodtime) {
+
+ if (!clocktime( datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ tzoff,
+ datum_pts->lastrec.l_ui,
+ &datum_pts->yearstart,
+ &datum_pts->lastref.l_ui) ) {
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error: bad clocktime\n");
+ fprintf(logfile,"GMT %d, lastrec %d, yearstart %d, lastref %d\n",
+ tzoff,
+ datum_pts->lastrec.l_ui,
+ datum_pts->yearstart,
+ datum_pts->lastref.l_ui);
+ fflush(logfile);
+#endif
+
+ syslog(LOG_ERR, "Datum_PTS: Bad clocktime");
+
+ return;
+
+ }else{
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Good clocktime\n");
+ fflush(logfile);
+#endif
+
+ }
+
+ }
+
+/*
+** We have datum_pts->lastref.l_ui set (which is the integer part of the
+** time. Now set the microseconds field.
+*/
+
+ TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf);
+
+/*
+** Compute the time correction as the difference between the reference
+** time (i.e., the Datum time) minus the receive time (system time).
+*/
+
+ tstmp = datum_pts->lastref; /* tstmp is the datum ntp time */
+ L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is now the correction */
+ datum_pts->coderecv++; /* increment a counter */
+
+ dispersion = DATUM_DISPERSION; /* set the dispersion to 0 */
+
+#ifdef DEBUG_DATUM_PTC
+ ftimerr = dispersion;
+ ftimerr /= (1024.0 * 64.0);
+ fprintf(logfile,"dispersion = %d, %f\n", dispersion, ftimerr);
+ fflush(logfile);
+#endif
+
+/*
+** Pass the new time to xntpd through the refclock_receive function. Note
+** that we are not trying to make any corrections due to the time it takes
+** for the Datum PTS to send the message back. I am (erroneously) assuming
+** that the time for the Datum PTS to send the time back to us is negligable.
+** I suspect that this time delay may be as much as 15 ms or so (but probably
+** less). For our needs at JPL, this kind of error is ok so it is not
+** necessary to use fudge factors in the ntp.conf file. Maybe later we will.
+*/
+
+ refclock_receive( datum_pts->peer,
+ &tstmp,
+ tzoff,
+ dispersion,
+ &datum_pts->lastrec,
+ &datum_pts->lastrec,
+ datum_pts->leap );
+
+/*
+** Compute sigma squared (not used currently). Maybe later, this could be
+** used for the dispersion estimate. The problem is that xntpd does not link
+** in the math library so sqrt() is not available. Anyway, this is useful
+** for debugging. Maybe later I will just use absolute values for the time
+** error to come up with my dispersion estimate. Anyway, for now my dispersion
+** is set to 0.
+*/
+
+ timerr = tstmp.l_ui<<20;
+ timerr |= (tstmp.l_uf>>12) & 0x000fffff;
+ ftimerr = timerr;
+ ftimerr /= 1024*1024;
+ abserr = ftimerr;
+ if (ftimerr < 0.0) abserr = -ftimerr;
+
+ if (datum_pts->sigma2 == 0.0) {
+ if (abserr < DATUM_MAX_ERROR) {
+ datum_pts->sigma2 = abserr*abserr;
+ }else{
+ datum_pts->sigma2 = DATUM_MAX_ERROR2;
+ }
+ }else{
+ if (abserr < DATUM_MAX_ERROR) {
+ datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr;
+ }else{
+ datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2;
+ }
+ }
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Time error = %f seconds\n", ftimerr);
+ fflush(logfile);
+#endif
+
+#if defined(DEBUG_DATUM_PTC) || defined(LOG_TIME_ERRORS)
+ fprintf(logfile,
+ "PTS: day %d, hour %d, minute %d, second %d, msec %d, Time Error %f\n",
+ datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ datum_pts->msec,
+ ftimerr);
+ fflush(logfile);
+#endif
+
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_goes.c b/usr.sbin/xntpd/xntpd/refclock_goes.c
index 0b53326dc5d2..512131b8625d 100644
--- a/usr.sbin/xntpd/xntpd/refclock_goes.c
+++ b/usr.sbin/xntpd/xntpd/refclock_goes.c
@@ -1,9 +1,12 @@
/*
- * refclock_goes - clock driver for the Kinimetrics Truetime GOES receiver
- * Version 2.0
+ * refclock_goes - clock driver for the Kinemetrics Truetime GOES
+ * Receiver Version 3.0C - tested plain, with CLKLDISC
+ * Developement work being done:
+ * - Properly handle varying satellite positions (more acurately)
+ * - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers
*/
-#if defined(REFCLOCK) && (defined(GOES) || defined(GOESCLK) || defined(GOESPPS))
+#if defined(REFCLOCK) && defined(GOES)
#include <stdio.h>
#include <ctype.h>
@@ -13,113 +16,102 @@
#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_unixtime.h"
-
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#if defined(GOESCLK)
-#include <clkdefs.h>
-#endif /* GOESCLK */
-#endif /* STREAM */
-
-#if defined (GOESPPS)
-#include <sys/ppsclock.h>
-#endif /* GOESPPS */
-
#include "ntp_stdlib.h"
/*
* Support for Kinemetrics Truetime 468-DC GOES Receiver
+ * OM-DC OMEGA and GPS-TM/TMD support in progress...
+ *
+ * Most of this code is originally from refclock_wwvb.c with thanks.
+ * It has been so mangled that wwvb is not a recognizable ancestor.
+ *
+ * Timcode format: ADDD:HH:MM:SSQCL
+ * A - control A
+ * Q Quality indication: indicates possible error of
+ * C - Carriage return
+ * L - Line feed
*
- * Most of this code is copied from refclock_goes.c with thanks.
+ * Quality codes indicate possible error of
+ * 468-DC GOES Receiver:
+ * GPS-TM/TMD Receiver:
+ * ? +/- 500 milliseconds # +/- 50 milliseconds
+ * * +/- 5 milliseconds . +/- 1 millisecond
+ * space less than 1 millisecond
+ * OM-DC OMEGA Receiver:
+ * > >+- 5 seconds
+ * ? >+/- 500 milliseconds # >+/- 50 milliseconds
+ * * >+/- 5 milliseconds . >+/- 1 millisecond
+ * A-H less than 1 millisecond. Character indicates which station
+ * is being received as follows:
+ * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
+ * E = La Reunion, F = Argentina, G = Australia, H = Japan.
*
- * the time code looks like follows; Send the clock a R or C and once per
- * second a timestamp will appear that looks like this:
- * ADDD:HH:MM:SSQCL
- * A - control A
- * Q Quality indication: indicates possible error of
- * ? +/- 500 milliseconds # +/- 50 milliseconds
- * * +/- 5 milliseconds . +/- 1 millisecond
- * space less than 1 millisecond
- * C - Carriage return
- * L - Line feed
- * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ * The carriage return start bit begins on 0 seconds and extends to 1
+ * bit time
+ *
+ * Notes on 468-DC and OMEGA receiver:
+ *
+ * Send the clock a 'R' or 'C' and once per second a timestamp will
+ * appear. Send a 'P' to get the satellite position once.
+ *
+ * Notes on the 468-DC receiver:
+ *
+ * Unless you live on 125 degrees west longitude, you can't
+ * set your clock propagation delay settings correctly and still use
+ * automatic mode. The manual says to use a compromise when setting the
+ * switches. This results in significant errors. The solution; use fudge
+ * time1 and time2 to incorporate corrections. If your clock is set for
+ * 50 and it should be 58 for using the west and 46 for using the east,
+ * use the line
*
- * Unless you live on 125 degrees west longitude, you can't set your clock
- * propagation delay settings correctly and still use automatic mode.
- * The manual says to use a compromise when setting the switches. This
- * results in significant errors. The solution; use fudge time1 and time2
- * to incorporate corrections. If your clock is set for 50 and it should
- * be 58 for using the west and 46 for using the east, use the line
* fudge 127.127.5.0 time1 +0.008 time2 -0.004
- * This corrects the 4 milliseconds advance and 5 milliseconds retard needed.
- * The software will ask the clock which satellite it sees.
*
- * Flag1 set to 1 will silence the clock side of xntpd, just reading the
- * clock without trying to write to it. This is usefull if several
- * xntpds listen to the same clock. This has not been tested yet...
+ * This corrects the 4 milliseconds advance and 8 milliseconds retard
+ * needed. The software will ask the clock which satellite it sees.
+ *
+ * Ntp.conf parameters:
+ * time1 - offset applied to samples when reading WEST satellite (default = 0)
+ * time2 - offset applied to samples when reading EAST satellite (default = 0)
+ * val1 - stratum to assign to this clock (default = 0)
+ * val2 - refid assigned to this clock (default = "GOES", see below)
+ * flag1 - will silence the clock side of xntpd, just reading the clock
+ * without trying to write to it. (default = 0)
+ * flag2 - not assigned
+ * flag3 - enable ppsclock streams module
+ * flag4 - not assigned
+ *
*/
/*
* Definitions
*/
-#define MAXUNITS 4 /* max number of GOES units */
-#define GOES232 "/dev/goes%d"
+#define DEVICE "/dev/goes%d"
#define SPEED232 B9600 /* 9600 baud */
/*
* Radio interface parameters
*/
-#define GOESMAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
-#define GOESSKEWFACTOR 17 /* skew factor (for about 32 ppm) */
-#define GOESPRECISION (-10) /* precision assumed (about 1 ms) */
-#define GOESREFID "GOES" /* reference id */
-#define GOESDESCRIPTION "Kinemetrics GOES Receiver" /* who we are */
-#define GOESHSREFID 0x7f7f050a /* 127.127.5.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
-#define NCODES 3 /* stages of median filter */
-#define LENGOES0 13 /* format 0 timecode length */
-#define LENGOES2 21 /* format 2 timecode length */
-#define FMTGOESU 0 /* unknown format timecode id */
-#define FMTGOES0 1 /* format 0 timecode id */
-#define FMTGOES2 2 /* format 2 timecode id */
-#define DEFFUDGETIME 0 /* default fudge time (ms) */
-#define BMAX 50 /* timecode buffer length */
-#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define MAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "GOES" /* reference id */
+#define DESCRIPTION "TrueTime GPS/GOES Receivers" /* WRU */
+#define NSAMPLES 3 /* stages of median filter */
/*
- * Tag which satellite we see
+ * Tags which station (satellite) we see
*/
-#define GOES_SAT_NONE 0
-#define GOES_SAT_WEST 1
-#define GOES_SAT_EAST 2
-#define GOES_SAT_STAND 3
+#define GOES_WEST 0 /* Default to WEST satellite and apply time1 */
+#define GOES_EAST 1 /* until you discover otherwise */
/*
- * Hack to avoid excercising the multiplier. I have no pride.
+ * used by the state machine
*/
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
+enum goes_event {e_Init, e_F18, e_F50, e_F51, e_TS};
/*
* Imported from the timer module
*/
-extern U_LONG current_time;
-extern struct event timerqueue[];
-
-/*
- * Imported from ntp_loopfilter module
- */
-extern int fdpps; /* pps file descriptor */
+extern u_long current_time;
/*
* Imported from ntpd module
@@ -127,634 +119,294 @@ extern int fdpps; /* pps file descriptor */
extern int debug; /* global debug flag */
/*
- * GOES unit control structure
+ * unit control structure
*/
struct goesunit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp lastrec; /* last receive time */
- l_fp lastref; /* last timecode time */
- l_fp offset[NCODES]; /* recent sample offsets */
- char lastcode[BMAX]; /* last timecode received */
- u_short satellite; /* which satellite we saw */
- u_short polled; /* Hand in a time sample? */
- u_char format; /* timecode format */
- u_char lencode; /* length of last timecode */
- U_LONG lasttime; /* last time clock heard from */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char reason; /* reason for last abort */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- u_char leap; /* leap indicators */
- u_short msec; /* millisecond of second */
- u_char quality; /* quality char from format 2 */
- U_LONG yearstart; /* start of current year */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
+ int pollcnt; /* poll message counter */
+ u_short station; /* which station we are on */
+ u_short polled; /* Hand in a time sample? */
+ enum {Base, Start, F18, F50, F51, F08}
+ State; /* State machine */
};
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct goesunit *goesunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor1[MAXUNITS];
-static l_fp fudgefactor2[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char readonlyclockflag[MAXUNITS];
-
-/*
* Function prototypes
*/
-static void goes_init P((void));
-static int goes_start P((u_int, struct peer *));
-static void goes_shutdown P((int));
-static void goes_report_event P((struct goesunit *, int));
+static int goes_start P((int, struct peer *));
+static void goes_shutdown P((int, struct peer *));
static void goes_receive P((struct recvbuf *));
-static char goes_process P((struct goesunit *, l_fp *, u_fp *));
static void goes_poll P((int, struct peer *));
-static void goes_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void goes_buginfo P((int, struct refclockbug *));
-static void goes_send P((struct goesunit *, char *));
-
-struct refclock refclock_goes = {
- goes_start, goes_shutdown, goes_poll,
- goes_control, goes_init, goes_buginfo, NOFLAGS
-};
+static void goes_send P((struct peer *, char *));
+static void goes_initstate P((struct peer *));
+static void goes_doevent P((struct peer *, enum goes_event));
/*
- * goes_init - initialize internal goes driver data
+ * Transfer vector
*/
-static void
-goes_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)goesunits, 0, sizeof goesunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor1[i].l_ui = 0;
- fudgefactor1[i].l_uf = DEFFUDGETIME;
- fudgefactor2[i].l_ui = 0;
- fudgefactor2[i].l_uf = DEFFUDGETIME;
- stratumtouse[i] = 0;
- readonlyclockflag[i] = 0;
- }
-}
+struct refclock refclock_goes = {
+ goes_start, /* start up driver */
+ goes_shutdown, /* shut down driver */
+ goes_poll, /* transmit poll message */
+ noentry, /* not used (old goes_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old goes_buginfo) */
+ NOFLAGS /* not used */
+};
/*
- * goes_start - open the GOES devices and initialize data for processing
+ * goes_start - open the devices and initialize data for processing
*/
static int
goes_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct goesunit *goes;
- register int i;
- int fd232;
- char goesdev[20];
-
- /*
- * Check configuration info
- */
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "goes_start: unit %d invalid", unit);
- return 0;
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "goes_start: unit %d in use", unit);
- return 0;
- }
+ register struct goesunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
/*
* Open serial port
*/
- (void) sprintf(goesdev, GOES232, unit);
- fd232 = open(goesdev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "goes_start: open of %s: %m", goesdev);
- return 0;
- }
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- *
- */
- { struct termio ttyb;
- if (ioctl(fd232, TCGETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, TCGETA): %m", goesdev);
- goto screwed;
- }
- ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyb.c_oflag = 0;
- ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyb.c_lflag = ICANON;
- ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
- if (ioctl(fd232, TCSETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, TCSETA): %m", goesdev);
- goto screwed;
- }
- }
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The GOESCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
- *
- * The GOESPPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
- ttyp = &ttyb;
-
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "goes_start: tcgetattr(%s): %m", goesdev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "goes_start: tcsetattr(%s): %m", goesdev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "goes_start: tcflush(%s): %m", goesdev);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#ifdef STREAM
-#if defined(GOESCLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, I_PUSH, clk): %m", goesdev);
- if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, CLK_SETSTR): %m", goesdev);
-#endif /* GOESCLK */
-#if defined(GOESPPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, I_PUSH, ppsclock): %m", goesdev);
- else
- fdpps = fd232;
-#endif /* GOESPPS */
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The GOESCLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
- */
- { struct sgttyb ttyb;
-#if defined(GOESCLK)
- int ldisc = CLKLDISC;
-#endif /* GOESCLK */
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, TIOCGETP): %m", goesdev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(GOESCLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
- ttyb.sg_erase = ttyb.sg_kill = '\0';
- ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* GOESCLK */
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, TIOCSETP): %m", goesdev);
- goto screwed;
- }
-#if defined(GOESCLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "goes_start: ioctl(%s, TIOCSETD): %m",goesdev);
- goto screwed;
- }
-#endif /* GOESCLK */
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (goesunits[unit] != 0) {
- goes = goesunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && goesunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- goes = goesunits[i];
- goesunits[i] = 0;
- } else {
- goes = (struct goesunit *)
- emalloc(sizeof(struct goesunit));
- }
- }
- memset((char *)goes, 0, sizeof(struct goesunit));
- goesunits[unit] = goes;
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ return (0);
/*
- * Set up the structures
+ * Allocate and initialize unit structure
*/
- goes->peer = peer;
- goes->unit = (u_char)unit;
- goes->timestarted = current_time;
- goes->satellite = GOES_SAT_NONE;
-
- goes->io.clock_recv = goes_receive;
- goes->io.srcclock = (caddr_t)goes;
- goes->io.datalen = 0;
- goes->io.fd = fd232;
- if (!io_addclock(&goes->io)) {
- goto screwed;
+ if (!(up = (struct goesunit *)
+ emalloc(sizeof(struct goesunit)))) {
+ (void) close(fd);
+ return (0);
}
-
- /*
- * All done. Initialize a few random peer variables, then
- * return success.
- */
- peer->precision = GOESPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, GOESREFID, 4);
- else
- peer->refid = htonl(GOESHSREFID);
- unitinuse[unit] = 1;
- return 1;
-
- /*
- * Something broke; abandon ship
- */
-screwed:
- (void) close(fd232);
- return 0;
-}
-
-/*
- * goes_shutdown - shut down a GOES clock
- */
-static void
-goes_shutdown(unit)
- int unit;
-{
- register struct goesunit *goes;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "goes_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "goes_shutdown: unit %d not in use", unit);
- return;
+ memset((char *)up, 0, sizeof(struct goesunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = goes_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
+ pp->unitptr = (caddr_t)up;
/*
- * Tell the I/O module to turn us off. We're history.
+ * Initialize miscellaneous variables
*/
- goes = goesunits[unit];
- io_closeclock(&goes->io);
- unitinuse[unit] = 0;
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
+/* goes_initstate(peer);*/
+ return (1);
}
/*
- * goes_report_event - note the occurance of an event
+ * goes_shutdown - shut down the clock
*/
static void
-goes_report_event(goes, code)
- struct goesunit *goes;
- int code;
-{
+goes_shutdown(unit, peer)
+ int unit;
struct peer *peer;
+{
+ register struct goesunit *up;
+ struct refclockproc *pp;
- peer = goes->peer;
- if (goes->status != (u_char)code) {
- goes->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- goes->lastevent = (u_char)code;
- syslog(LOG_INFO,
- "clock %s event %x\n", ntoa(&peer->srcadr), code);
-#ifdef DEBUG
- if (debug) {
- printf("goes_report_event(goes%d, code %d)\n",
- goes->unit, code);
- }
-#endif
- }
+ pp = peer->procptr;
+ up = (struct goesunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
/*
- * goes_receive - receive data from the serial interface on a Kinimetrics
- * clock
+ * goes_receive - receive data from the serial interface on a
+ * Kinimetrics clock
*/
static void
goes_receive(rbufp)
struct recvbuf *rbufp;
{
- register int i;
- register struct goesunit *goes;
- register u_char *dpt;
- register char *cp;
- register u_char *dpend;
- l_fp tstmp;
- u_fp dispersion;
+ register struct goesunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp tmp_l_fp;
+ u_short new_station;
+ char sync, c1, c2;
+ int i;
+ int lat, lon, off; /* GOES Satellite position */
/*
- * Get the clock this applies to and a pointers to the data
+ * Get the clock this applies to and pointers to the data
*/
- goes = (struct goesunit *)rbufp->recv_srcclock;
- dpt = (u_char *)&rbufp->recv_space;
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct goesunit *)pp->unitptr;
/*
- * Edit timecode to remove control chars
+ * Read clock output. Automatically handles STREAMS, CLKLDISC
*/
- dpend = dpt + rbufp->recv_length;
- cp = goes->lastcode;
- while (dpt < dpend) {
- if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
-#ifdef GOESCLK
- else if (*cp == '\r') {
- if (dpend - dpt < 8) {
- /* short timestamp */
- return;
- }
- if (!buftvtots(dpt,&goes->lastrec)) {
- /* screwy timestamp */
- return;
- }
- dpt += 8;
- }
-#endif
- }
- *cp = '\0';
- goes->lencode = cp - goes->lastcode;
- if (goes->lencode == 0) return;
-#ifndef GOESCLK
- goes->lastrec = rbufp->recv_time;
-#endif /* GOESCLK */
- tstmp = goes->lastrec;
-
-#ifdef DEBUG
- if (debug)
- printf("goes: timecode %d %s\n",
- goes->lencode, goes->lastcode);
-#endif
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX,
+ &pp->lastrec);
/*
- * We get down to business, check the timecode format and decode
- * its contents. This code checks for and decodes both format 0
- * and format 2 and need not be told which in advance.
+ * There is a case where <cr><lf> generates 2 timestamps
*/
- cp = goes->lastcode;
- goes->leap = 0;
- goes->format = FMTGOESU;
- if (goes->lencode == LENGOES0) {
+ if (pp->lencode == 0)
+ return;
- /*
- * Check timecode format 0
- */
- if (!isdigit(cp[0]) || /* day of year */
- !isdigit(cp[1]) ||
- !isdigit(cp[2]) ||
- cp[3] != ':' || /* <sp> */
- !isdigit(cp[4]) || /* hours */
- !isdigit(cp[5]) ||
- cp[6] != ':' || /* : separator */
- !isdigit(cp[7]) || /* minutes */
- !isdigit(cp[8]) ||
- cp[9] != ':' || /* : separator */
- !isdigit(cp[10]) || /* seconds */
- !isdigit(cp[11])) {
- goes->badformat++;
- goes_report_event(goes, CEVNT_BADREPLY);
- return;
- }
- else goes->format = FMTGOES0;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
- /*
- * Convert format 0 and check values
- */
- goes->year = 0; /* fake */
- goes->day = cp[0] - '0';
- goes->day = MULBY10(goes->day) + cp[1] - '0';
- goes->day = MULBY10(goes->day) + cp[2] - '0';
- goes->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
- goes->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
- goes->second = MULBY10(cp[10] - '0') + cp[11] - '0';
- goes->msec = 0;
-
- if (cp[12] != ' ' && cp[12] != '.' && cp[12] != '*')
- goes->leap = LEAP_NOTINSYNC;
- else
- goes->lasttime = current_time;
-
- if (goes->day < 1 || goes->day > 366) {
- goes->baddata++;
- goes_report_event(goes, CEVNT_BADDATE);
- return;
- }
- if (goes->hour > 23 || goes->minute > 59
- || goes->second > 59) {
- goes->baddata++;
- goes_report_event(goes, CEVNT_BADTIME);
- return;
- }
+ /*
+ * We get down to business, check the timecode format and decode
+ * its contents. This code decodes a multitude of different
+ * clock messages. Timecodes are processed if needed. All replies
+ * will be run through the state machine to tweak driver options
+ * and program the clock.
+ */
- } else if (goes->lencode == LENGOES2) {
+ /*
+ * Timecode: "nnnnn+nnn-nnn"
+ */
+ if (sscanf(pp->lastcode, "%5d%c%3d%c%3d",
+ &lon, &c1, &lat, &c2, &off) == 5 &&
+ (c1 == '+' || c1 == '-') &&
+ (c2 == '+' || c2 == '-')) {
/*
- * Extended precision satelite location info
+ * This is less than perfect. Call the (satellite)
+ * either EAST or WEST and adjust slop accodingly
+ * Perfectionists would recalcuted the exact delay
+ * and adjust accordingly...
*/
- if (!isdigit(cp[0]) || /* longitude */
- !isdigit(cp[1]) ||
- !isdigit(cp[2]) ||
- cp[3] != '.' ||
- !isdigit(cp[4]) ||
- !isdigit(cp[5]) ||
- !isdigit(cp[6]) ||
- !isdigit(cp[7]) ||
- (cp[8] != '+' && cp[8] != '-') ||
- !isdigit(cp[9]) || /*latitude */
- cp[10] != '.' ||
- !isdigit(cp[11]) ||
- !isdigit(cp[12]) ||
- !isdigit(cp[13]) ||
- !isdigit(cp[14]) ||
- (cp[15] != '+' && cp[15] != '-') ||
- !isdigit(cp[16]) || /* height */
- !isdigit(cp[17]) ||
- !isdigit(cp[18]) ||
- cp[19] != '.' ||
- !isdigit(cp[20])) {
- goes->badformat++;
- goes_report_event(goes, CEVNT_BADREPLY);
- return;
+ if (lon > 7000 && lon < 14000) {
+ if (lon < 10000)
+ new_station = GOES_EAST;
+ else
+ new_station = GOES_WEST;
+#ifdef DEBUG
+ if (debug) {
+ if (new_station == GOES_EAST)
+ printf("goes: station EAST\n");
+ if (new_station == GOES_WEST)
+ printf("goes: station WEST\n");
}
- else goes->format = FMTGOES2;
-
- /*
- * Figure out which satellite this is.
- * This allows +-5 degrees from nominal.
- */
- if (cp[0] == '1' && (cp[1] == '3' || cp[1] == '2'))
- goes->satellite = GOES_SAT_WEST;
- else if (cp[0] == '1' && cp[1] == '0')
- goes->satellite = GOES_SAT_STAND;
- else if (cp[0] == '0' && cp[1] == '7')
- goes->satellite = GOES_SAT_EAST;
- else
- goes->satellite = GOES_SAT_NONE;
-
+#endif
+ if (new_station != up->station) {
+ tmp_l_fp = pp->fudgetime1;
+ pp->fudgetime1 = pp->fudgetime2;
+ pp->fudgetime2 = tmp_l_fp;
+ up->station = new_station;
+ }
+ }
+ else {
+ refclock_report(peer, CEVNT_BADREPLY);
#ifdef DEBUG
- if (debug)
- printf("goes_receive: select satellite %d\n",
- goes->satellite);
+ if (debug)
+ printf("goes: station UNKNONW\n");
#endif
-
+ }
/*
- * Switch back to on-second time codes.
+ * Switch back to on-second time codes and return.
*/
- goes_send(goes,"C");
+ goes_send(peer, "C");
- /*
- * Since this is not a time code, just return...
- */
- return;
- } else {
- goes_report_event(goes, CEVNT_BADREPLY);
return;
}
/*
- * The clock will blurt a timecode every second but we only
- * want one when polled. If we havn't been polled, bail out.
+ * Timecode: "Fnn"
*/
- if (!goes->polled)
- return;
+ if (sscanf(pp->lastcode, "F%2d", &i) == 1 &&
+ i > 0 && i < 80) {
+ enum goes_event event = 0;
+
+ if (i == 50) event = e_F50;
+ if (i == 51) event = e_F51;
+ if (i == 50 || i == 51) {
+ goes_doevent(peer, event);
+ return;
+ }
+ }
/*
- * Now, compute the reference time value. Use the heavy
- * machinery for the seconds and the millisecond field for the
- * fraction when present.
- *
- * this code does not yet know how to do the years
+ * Timecode:" TRUETIME Mk III"
*/
- tstmp = goes->lastrec;
- if (!clocktime(goes->day, goes->hour, goes->minute,
- goes->second, GMT, tstmp.l_ui,
- &goes->yearstart, &goes->lastref.l_ui)) {
- goes->baddata++;
- goes_report_event(goes, CEVNT_BADTIME);
+ if (strcmp(pp->lastcode, " TRUETIME Mk III") == 0) {
+ enum goes_event event;
+
+ event = e_F18;
+ goes_doevent(peer, event);
return;
}
- MSUTOTSF(goes->msec, goes->lastref.l_uf);
-
/*
- * Slop the read value by fudgefactor1 or fudgefactor2 depending
- * on which satellite we are viewing last time we checked.
- */
+ * Timecode: "ddd:hh:mm:ssQ"
+ */
+ if (sscanf(pp->lastcode, "%3d:%2d:%2d:%2d%c",
+ &pp->day, &pp->hour, &pp->minute,
+ &pp->second, &sync) == 5) {
-#ifdef DEBUG
- if (debug)
- printf("GOES_RECEIVE: Slopping for satellite %d\n",
- goes->satellite);
-#endif
- if (goes->satellite == GOES_SAT_WEST)
- L_ADD(&goes->lastref, &fudgefactor1[goes->unit]);
- else if (goes->satellite == GOES_SAT_EAST)
- L_ADD(&goes->lastref, &fudgefactor2[goes->unit]);
-/* else if (goes->satellite == GOES_SAT_STAND)
- L_ADD(&goes->lastref, &((fudgefactor1[goes->unit] +
- fudgefactor2[goes->unit]) / 2)); */
-
- i = ((int)(goes->coderecv)) % NCODES;
- goes->offset[i] = goes->lastref;
- L_SUB(&goes->offset[i], &tstmp);
- if (goes->coderecv == 0)
- for (i = 1; i < NCODES; i++)
- goes->offset[i] = goes->offset[0];
-
- goes->coderecv++;
+ /*
+ * Adjust the synchronize indicator according to timecode
+ */
+ if (sync !=' ' && sync !='.' && sync !='*')
+ pp->leap = LEAP_NOTINSYNC;
+ else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
+ }
- /*
- * Check the satellite position
- */
- goes_send(goes,"E");
+ /* goes_doevent(peer, e_TS); */
+
+ /*
+ * The clock will blurt a timecode every second but we only
+ * want one when polled. If we havn't been polled, bail out.
+ */
+ if (!up->polled)
+ return;
+
+ /*
+ * After each poll, check the station (satellite)
+ */
+ goes_send(peer, "P");
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
+
+ /*
+ * We have succedded in answering the poll.
+ * Turn off the flag and return
+ */
+ up->polled = 0;
- /*
- * Process the median filter, add the fudge factor and pass the
- * offset and dispersion along. We use lastrec as both the
- * reference time and receive time in order to avoid being cute,
- * like setting the reference time later than the receive time,
- * which may cause a paranoid protocol module to chuck out the
- * data.
- */
- if (!goes_process(goes, &tstmp, &dispersion)) {
- goes->baddata++;
- goes_report_event(goes, CEVNT_BADTIME);
return;
}
- refclock_receive(goes->peer, &tstmp, GMT, dispersion,
- &goes->lastrec, &goes->lastrec, goes->leap);
/*
- * We have succedded in answering the poll. Turn off the flag
+ * No match to known timecodes, report failure and return
*/
- goes->polled = 0;
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
}
@@ -762,95 +414,89 @@ goes_receive(rbufp)
* goes_send - time to send the clock a signal to cough up a time sample
*/
static void
-goes_send(goes,cmd)
- struct goesunit *goes;
+goes_send(peer, cmd)
+ struct peer *peer;
char *cmd;
{
- if (!readonlyclockflag[goes->unit]) {
- /*
- * Send a command to the clock. C for on-second timecodes.
- * E for extended resolution satelite postion information.
- */
- if (write(goes->io.fd, cmd, 1) != 1) {
- syslog(LOG_ERR, "goes_send: unit %d: %m", goes->unit);
- goes_report_event(goes, CEVNT_FAULT);
- } else {
- goes->polls++;
- }
+ struct refclockproc *pp;
+ register int len = strlen(cmd);
+
+ pp = peer->procptr;
+ if (!pp->sloppyclockflag & CLK_FLAG1) {
+#ifdef DEBUG
+ if (debug)
+ printf("goes: Send '%s'\n", cmd);
+#endif
+ if (write(pp->io.fd, cmd, len) != len) {
+ refclock_report(peer, CEVNT_FAULT);
+ } else {
+ pp->polls++;
+ }
}
}
+
/*
- * goes_process - process a pile of samples from the clock
+ * state machine for initializing the clock
*/
-static char
-goes_process(goes, offset, dispersion)
- struct goesunit *goes;
- l_fp *offset;
- u_fp *dispersion;
+static void
+goes_doevent(peer, event)
+ struct peer *peer;
+ enum goes_event event;
{
- register int i, j;
- register U_LONG tmp_ui, tmp_uf;
- int not_median1 = -1; /* XXX correct? */
- int not_median2 = -1; /* XXX correct? */
- int median;
- u_fp disp_tmp, disp_tmp2;
+ struct goesunit *up;
+ struct refclockproc *pp;
- /*
- * This code implements a three-stage median filter. First, we
- * check if the samples are within 125 ms of each other. If not,
- * dump the sample set. We take the median of the three offsets
- * and use that as the sample offset. We take the maximum
- * difference and use that as the sample dispersion. There
- * probably is not much to be gained by a longer filter, since
- * the clock filter in ntp_proto should do its thing.
- */
- disp_tmp2 = 0;
- for (i = 0; i < NCODES-1; i++) {
- for (j = i+1; j < NCODES; j++) {
- tmp_ui = goes->offset[i].l_ui;
- tmp_uf = goes->offset[i].l_uf;
- M_SUB(tmp_ui, tmp_uf, goes->offset[j].l_ui,
- goes->offset[j].l_uf);
- if (M_ISNEG(tmp_ui, tmp_uf)) {
- M_NEG(tmp_ui, tmp_uf);
- }
- if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
- return 0;
- }
- disp_tmp = MFPTOFP(0, tmp_uf);
- if (disp_tmp > disp_tmp2) {
- disp_tmp2 = disp_tmp;
- not_median1 = i;
- not_median2 = j;
- }
- }
+ pp = peer->procptr;
+ up = (struct goesunit *)pp->unitptr;
+
+#ifdef DEBUG
+ if (debug) {
+ printf("goes_doevent: %d\n", (int)event);
+ }
+#endif
+ if (event == e_TS && up->State != F51 && up->State != F08) {
+ goes_send(peer, "\03\r");
}
- /*
- * It seems as if all are within 125 ms of each other.
- * Now to determine the median of the three. Whlie the
- * 125 ms check was going on, we also subtly catch the
- * dispersion and set-up for a very easy median calculation.
- * The largest difference between any two samples constitutes
- * the dispersion. The sample not involve in the dispersion is
- * the median sample. EASY!
- */
- if (goes->lasttime == 0 || disp_tmp2 > GOESMAXDISPERSE)
- disp_tmp2 = GOESMAXDISPERSE;
- if (not_median1 == 0) {
- if (not_median2 == 1)
- median = 2;
- else
- median = 1;
- } else {
- median = 0;
- }
- *offset = goes->offset[median];
- *dispersion = disp_tmp2;
- return 1;
+ switch (event) {
+ case e_Init:
+ goes_send(peer, "F18\r");
+ up->State = Start;
+ break;
+ case e_F18:
+ goes_send(peer, "F50\r");
+ up->State = F18;
+ break;
+ case e_F50:
+ goes_send(peer, "F51\r");
+ up->State = F50;
+ break;
+ case e_F51:
+ goes_send(peer, "F08\r");
+ up->State = F51;
+ break;
+ case e_TS:
+ /* nothing to send - we like this mode */
+ up->State = F08;
+ break;
+ }
+}
+
+static void
+goes_initstate(peer)
+ struct peer *peer;
+{
+ struct goesunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct goesunit *)pp->unitptr;
+ up->State = Base; /* just in case */
+ goes_doevent(peer, e_Init);
}
+
/*
* goes_poll - called by the transmit procedure
*/
@@ -859,155 +505,29 @@ goes_poll(unit, peer)
int unit;
struct peer *peer;
{
- struct goesunit *goes;
+ struct goesunit *up;
+ struct refclockproc *pp;
/*
* You don't need to poll this clock. It puts out timecodes
* once per second. If asked for a timestamp, take note.
* The next time a timecode comes in, it will be fed back.
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "goes_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "goes_poll: unit %d not in use", unit);
- return;
- }
- goes = goesunits[unit];
- if ((current_time - goes->lasttime) > 150) {
- goes->noreply++;
- goes_report_event(goesunits[unit], CEVNT_TIMEOUT);
+ pp = peer->procptr;
+ up = (struct goesunit *)pp->unitptr;
+ if (up->pollcnt == 0) {
+ refclock_report(peer, CEVNT_TIMEOUT);
+ goes_send(peer, "C");
}
+ else
+ up->pollcnt--;
/*
- * polled every 64 seconds. Ask GOES_RECEIVE to hand in a timestamp.
+ * polled every 64 seconds. Ask goes_receive to hand in a
+ * timestamp.
*/
- goes->polled = 1;
- goes->polls++;
-
- goes_send(goes,"C");
-}
-
-/*
- * goes_control - set fudge factors, return statistics
- */
-static void
-goes_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct goesunit *goes;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "goes_control: unit %d invalid", unit);
- return;
- }
- goes = goesunits[unit];
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor1[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVETIME2)
- fudgefactor2[unit] = in->fudgetime2;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- peer = goes->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- GOESREFID, 4);
- else
- peer->refid = htonl(GOESHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- readonlyclockflag[unit] = in->flags & CLK_FLAG1;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_GOES_TRUETIME;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVETIME2|
- CLK_HAVEVAL1|CLK_HAVEVAL2|
- CLK_HAVEFLAG1|CLK_HAVEFLAG2;
- out->clockdesc = GOESDESCRIPTION;
- out->fudgetime1 = fudgefactor1[unit];
- out->fudgetime2 = fudgefactor2[unit];
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = readonlyclockflag[unit] |
- (goes->satellite << 1);
- if (unitinuse[unit]) {
- out->lencode = goes->lencode;
- out->lastcode = goes->lastcode;
- out->timereset = current_time - goes->timestarted;
- out->polls = goes->polls;
- out->noresponse = goes->noreply;
- out->badformat = goes->badformat;
- out->baddata = goes->baddata;
- out->lastevent = goes->lastevent;
- out->currentstatus = goes->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ up->polled = 1;
+ pp->polls++;
}
-/*
- * goes_buginfo - return clock dependent debugging info
- */
-static void
-goes_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct goesunit *goes;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "goes_buginfo: unit %d invalid", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- goes = goesunits[unit];
-
- bug->nvalues = 11;
- bug->ntimes = 5;
- if (goes->lasttime != 0)
- bug->values[0] = current_time - goes->lasttime;
- else
- bug->values[0] = 0;
- bug->values[1] = (U_LONG)goes->reason;
- bug->values[2] = (U_LONG)goes->year;
- bug->values[3] = (U_LONG)goes->day;
- bug->values[4] = (U_LONG)goes->hour;
- bug->values[5] = (U_LONG)goes->minute;
- bug->values[6] = (U_LONG)goes->second;
- bug->values[7] = (U_LONG)goes->msec;
- bug->values[8] = goes->noreply;
- bug->values[9] = goes->yearstart;
- bug->values[10] = goes->quality;
- bug->stimes = 0x1c;
- bug->times[0] = goes->lastref;
- bug->times[1] = goes->lastrec;
- bug->times[2] = goes->offset[0];
- bug->times[3] = goes->offset[1];
- bug->times[4] = goes->offset[2];
-}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_gpstm.c b/usr.sbin/xntpd/xntpd/refclock_gpstm.c
index 93abcf93773c..71eb015cb14b 100644
--- a/usr.sbin/xntpd/xntpd/refclock_gpstm.c
+++ b/usr.sbin/xntpd/xntpd/refclock_gpstm.c
@@ -78,13 +78,11 @@
* Radio interface parameters
*/
#define MAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
-#define PRECISION (-20) /* precision assumed (about 1 ms) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
#define REFID "GPS\0" /* reference id */
#define DESCRIPTION "Kinemetrics GPS-TM/TMD Receiver" /* who we are */
-#define HSREFID 0x7f7f0f0a /* 127.127.15.10 refid hi strata */
#define GMT 0 /* hour offset from Greenwich */
#define NCODES 3 /* stages of median filter */
-#define BMAX 99 /* timecode buffer length */
#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
#define TIMEOUT 180 /* ping the clock if it's silent this long */
@@ -93,7 +91,6 @@
*/
enum gpstm_event {e_Init, e_F18, e_F50, e_F51, e_TS};
static enum {Base, Start, F18, F50, F51, F08} State[MAXUNITS];
-static time_t Last[MAXUNITS];
static void gpstm_doevent P((int, enum gpstm_event));
static void gpstm_initstate P((int));
@@ -143,7 +140,7 @@ struct gpstm_unit {
u_char leap; /* leap indicators */
u_short msec; /* millisecond of second */
u_char quality; /* quality character */
- U_LONG yearstart; /* start of current year */
+ u_long yearstart; /* start of current year */
/*
* Status tallies
*/
@@ -170,18 +167,19 @@ static l_fp fudgefactor1[MAXUNITS];
static l_fp fudgefactor2[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char readonlyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
/*
* Function prototypes
*/
static void gpstm_init P((void));
-static int gpstm_start P((u_int, struct peer *));
-static void gpstm_shutdown P((int));
+static int gpstm_start P((int, struct peer *));
+static void gpstm_shutdown P((int, struct peer *));
static void gpstm_rep_event P((struct gpstm_unit *, int));
static void gpstm_receive P((struct recvbuf *));
static char gpstm_process P((struct gpstm_unit *, l_fp *, u_fp *));
static void gpstm_poll P((int, struct peer *));
-static void gpstm_control P((u_int, struct refclockstat *,
+static void gpstm_control P((int, struct refclockstat *,
struct refclockstat *));
static void gpstm_buginfo P((int, struct refclockbug *));
static void gpstm_send P((struct gpstm_unit *, char *));
@@ -214,6 +212,7 @@ gpstm_init()
fudgefactor2[i].l_uf = 0;
stratumtouse[i] = 0;
readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], REFID, 4);
}
}
@@ -223,7 +222,7 @@ gpstm_init()
*/
static int
gpstm_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
register struct gpstm_unit *gpstm;
@@ -417,10 +416,7 @@ gpstm_start(unit, peer)
peer->rootdelay = 0;
peer->rootdispersion = 0;
peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, REFID, 4);
- else
- peer->refid = htonl(HSREFID);
+ peer->refid = refid[unit];
unitinuse[unit] = 1;
gpstm_initstate(unit);
return 1;
@@ -437,8 +433,9 @@ screwed:
* gpstm_shutdown - shut down a clock
*/
static void
-gpstm_shutdown(unit)
+gpstm_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
register struct gpstm_unit *gpstm;
@@ -779,7 +776,9 @@ gpstm_doevent(unit, event)
}
static void
-gpstm_initstate(unit) {
+gpstm_initstate(unit)
+ int unit;
+ {
State[unit] = Base; /* just in case */
gpstm_doevent(unit, e_Init);
}
@@ -897,7 +896,7 @@ gpstm_poll(unit, peer)
*/
static void
gpstm_control(unit, in, out)
- u_int unit;
+ int unit;
struct refclockstat *in;
struct refclockstat *out;
{
@@ -907,48 +906,40 @@ gpstm_control(unit, in, out)
syslog(LOG_ERR, "gpstm_control: unit %d invalid", unit);
return;
}
- gpstm = gpstm_units[unit];
if (in != 0) {
if (in->haveflags & CLK_HAVETIME1)
fudgefactor1[unit] = in->fudgetime1;
if (in->haveflags & CLK_HAVETIME2)
fudgefactor2[unit] = in->fudgetime2;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- peer = gpstm->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- REFID, 4);
- else
- peer->refid = htonl(HSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = gpstm_units[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
}
}
if (out != 0) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
out->type = REFCLK_GPSTM_TRUETIME;
- out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2
- | CLK_HAVEVAL1 | CLK_HAVEVAL2
- | CLK_HAVEFLAG1;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2 | CLK_HAVEFLAG1;
out->clockdesc = DESCRIPTION;
out->fudgetime1 = fudgefactor1[unit];
out->fudgetime2 = fudgefactor2[unit];
out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
+ out->fudgeval2 = refid[unit];
out->flags = readonlyclockflag[unit];
if (unitinuse[unit]) {
+ gpstm = gpstm_units[unit];
out->lencode = gpstm->lencode;
out->lastcode = gpstm->lastcode;
out->timereset = current_time - gpstm->timestarted;
@@ -958,13 +949,6 @@ gpstm_control(unit, in, out)
out->baddata = gpstm->baddata;
out->lastevent = gpstm->lastevent;
out->currentstatus = gpstm->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
}
}
}
diff --git a/usr.sbin/xntpd/xntpd/refclock_heath.c b/usr.sbin/xntpd/xntpd/refclock_heath.c
new file mode 100644
index 000000000000..1fbb9b7e6876
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_heath.c
@@ -0,0 +1,393 @@
+/*
+ * refclock_heath - clock driver for Heath GC-1000 Most Accurate Clock
+ */
+#if defined(REFCLOCK) && defined(HEATH)
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the Heath GC-1000 Most Accurate Clock, with
+ * RS232C Output Accessory. This is a WWV/WWVH receiver somewhat less
+ * robust than other supported receivers. Its claimed accuracy is 100 ms
+ * when actually synchronized to the broadcast signal, but this doesn't
+ * happen even most of the time, due to propagation conditions, ambient
+ * noise sources, etc. When not synchronized, the accuracy is at the
+ * whim of the internal clock oscillator, which can wander into the
+ * sunset without warning. Since the indicated precision is 100 ms,
+ * expect a host synchronized only to this thing to wander to and fro,
+ * occasionally being rudely stepped when the offset exceeds the default
+ * CLOCK_MAX of 128 ms.
+ *
+ * The internal DIPswitches should be set to operate at 1200 baud in
+ * MANUAL mode and the current year. The external DIPswitches should be
+ * set to GMT and 24-hour format, or to the host local time zone (with
+ * DST) and 12-hour format. It is very important that the year be
+ * set correctly in the DIPswitches. Otherwise, the day of year will be
+ * incorrect after 28 April of a normal or leap year. In 12-hour mode
+ * with DST selected the clock will be incorrect by an hour for an
+ * indeterminate amount of time between 0000Z and 0200 on the day DST
+ * changes.
+ *
+ * In MANUAL mode the clock responds to a rising edge of the request to
+ * send (RTS) modem control line by sending the timecode. Therefore, it
+ * is necessary that the operating system implement the TIOCMBIC and
+ * TIOCMBIS ioctl system calls and TIOCM_RTS control bit. Present
+ * restrictions require the use of a POSIX-compatible programming
+ * interface, although other interfaces may work as well.
+ *
+ * A simple hardware modification to the clock can be made which
+ * prevents the clock hearing the request to send (RTS) if the HI SPEC
+ * lamp is out. Route the HISPEC signal to the tone decoder board pin
+ * 19, from the display, pin 19. Isolate pin 19 of the decoder board
+ * first, but maintain connection with pin 10. Also isolate pin 38 of
+ * the CPU on the tone board, and use half an added 7400 to gate the
+ * original signal to pin 38 with that from pin 19.
+ *
+ * The clock message consists of 23 ASCII printing characters in the
+ * following format:
+ *
+ * hh:mm:ss.f AM dd/mm/yr<cr>
+ *
+ * hh:mm:ss.f = hours, minutes, seconds
+ * f = deciseconds ('?' when out of spec)
+ * AM/PM/bb = blank in 24-hour mode
+ * dd/mm/yr = day, month, year
+ *
+ * The alarm condition is indicated by '?', rather than a digit, at f.
+ * Note that 0?:??:??.? is displayed before synchronization is first
+ * established and hh:mm:ss.? once synchronization is established and
+ * then lost again for about a day.
+ *
+ * Fudge Factors
+ *
+ * A fudge time1 value of .04 s appears to center the clock offset
+ * residuals. The fudge time2 parameter is the local time offset east of
+ * Greenwich, which depends on DST. Sorry about that, but the clock
+ * gives no hint on what the DIPswitches say.
+ */
+
+/*
+ * Interface definitions
+ */
+#define DEVICE "/dev/heath%d" /* device name and unit */
+#define SPEED232 B1200 /* uart speed (1200 baud) */
+#define PRECISION (-4) /* precision assumed (about 100 ms) */
+#define REFID "WWV\0" /* reference ID */
+#define DESCRIPTION "Heath GC-1000 Most Accurate Clock" /* WRU */
+
+#define NSAMPLES 3 /* stages of median filter */
+#define LENHEATH 23 /* min timecode length */
+
+/*
+ * Imported from ntp_timer module
+ */
+extern u_long current_time; /* current time (s) */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
+ * leap.
+ */
+static day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ * Unit control structure
+ */
+struct heathunit {
+ int pollcnt; /* poll message counter */
+ l_fp tstamp; /* timestamp of last poll */
+};
+
+/*
+ * Function prototypes
+ */
+static int heath_start P((int, struct peer *));
+static void heath_shutdown P((int, struct peer *));
+static void heath_receive P((struct recvbuf *));
+static void heath_poll P((int, struct peer *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_heath = {
+ heath_start, /* start up driver */
+ heath_shutdown, /* shut down driver */
+ heath_poll, /* transmit poll message */
+ noentry, /* not used (old heath_control) */
+ noentry, /* initialize driver */
+ noentry, /* not used (old heath_buginfo) */
+ NOFLAGS /* not used */
+};
+
+
+/*
+ * heath_start - open the devices and initialize data for processing
+ */
+static int
+heath_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct heathunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
+
+ /*
+ * Open serial port
+ */
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, 0)))
+ return (0);
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct heathunit *)
+ emalloc(sizeof(struct heathunit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct heathunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = heath_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
+ return (1);
+}
+
+
+/*
+ * heath_shutdown - shut down the clock
+ */
+static void
+heath_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct heathunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct heathunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
+}
+
+
+/*
+ * heath_receive - receive data from the serial interface
+ */
+static void
+heath_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct heathunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp trtmp;
+ int month, day;
+ int i;
+ char dsec, a[5];
+
+ /*
+ * Initialize pointers and read the timecode and timestamp
+ */
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct heathunit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX, &trtmp);
+
+ /*
+ * We get a buffer and timestamp for each <cr>; however, we use
+ * the timestamp captured at the RTS modem control line toggle
+ * on the assumption that's what the radio bases the timecode
+ * on. Apparently, the radio takes about a second to make up its
+ * mind to send a timecode, so the receive timestamp is
+ * worthless.
+ */
+ pp->lastrec = up->tstamp;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+#ifdef DEBUG
+ if (debug)
+ printf("heath: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
+#endif
+
+ /*
+ * We get down to business, check the timecode format and decode
+ * its contents. If the timecode has invalid length or is not in
+ * proper format, we declare bad format and exit.
+ */
+ if (pp->lencode < LENHEATH) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Timecode format: "hh:mm:ss.f AM mm/dd/yy"
+ */
+ if (sscanf(pp->lastcode, "%2d:%2d:%2d.%c%5c%2d/%2d/%2d",
+ &pp->hour, &pp->minute, &pp->second, &dsec, a, &month, &day,
+ &pp->year) != 8) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * If AM or PM is received, assume the clock is displaying local
+ * time. First, convert to 24-hour format, then add the local
+ * time correction (in hours east of Greenwich) from
+ * fudgetime2.
+ */
+ switch (a[1]) {
+ case 'P':
+ if (pp->hour < 12)
+ pp->hour += 12;
+ break;
+
+ case 'A':
+ if (pp->hour == 12)
+ pp->hour -= 12;
+ break;
+ }
+ i = (int)pp->hour - (int)pp->fudgetime2.l_ui;
+ if (i < 0)
+ i += 24;
+ pp->hour = i % 24;
+
+ /*
+ * We determine the day of the year from the DIPswitches. This
+ * should be fixed, since somebody might forget to set them.
+ * Someday this hazard will be fixed by a fiendish scheme that
+ * looks at the timecode and year the radio shows, then computes
+ * the residue of the seconds mod the seconds in a leap cycle.
+ * If in the third year of that cycle and the third and later
+ * months of that year, add one to the day. Then, correct the
+ * timecode accordingly. Icky pooh. This bit of nonsense could
+ * be avoided if the engineers had been required to write a
+ * device driver before finalizing the timecode format.
+ *
+ * Yes, I know this code incorrectly thinks that 2000 is a leap
+ * year; but, the latest year that can be set by the DIPswitches
+ * is 1997 anyay. Life is short.
+ */
+ if (month < 1 || month > 12 || day < 1) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ if (pp->year % 4) {
+ if (day > day1tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day1tab[i];
+ } else {
+ if (day > day2tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day2tab[i];
+ }
+ pp->day = day;
+
+ /*
+ * Determine synchronization and last update
+ */
+ if (!isdigit(dsec)) {
+ pp->leap = LEAP_NOTINSYNC;
+ } else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
+ pp->msec = (dsec - '0') * 100;
+ }
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time, in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
+}
+
+
+/*
+ * heath_poll - called by the transmit procedure
+ */
+static void
+heath_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct heathunit *up;
+ struct refclockproc *pp;
+ int bits = TIOCM_RTS;
+
+ /*
+ * At each poll we check for timeout and toggle the RTS modem
+ * control line, then take a timestamp. Presumably, this is the
+ * event the radio captures to generate the timecode.
+ */
+ pp = peer->procptr;
+ up = (struct heathunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ pp->polls++;
+
+ /*
+ * We toggle the RTS modem control lead to kick a timecode loose
+ * from the radio. This code works only for POSIX and SYSV
+ * interfaces. With bsd you are on your own. We take a timestamp
+ * between the up and down edges to lengthen the pulse, which
+ * should be about 50 usec on a Sun IPC. With hotshot CPUs, the
+ * pulse might get too short. Later.
+ */
+ if (ioctl(pp->io.fd, TIOCMBIC, (char *)&bits) < 0)
+ refclock_report(peer, CEVNT_FAULT);
+ gettstamp(&up->tstamp);
+ ioctl(pp->io.fd, TIOCMBIS, (char *)&bits);
+
+}
+
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_irig.c b/usr.sbin/xntpd/xntpd/refclock_irig.c
index 6167af2784ee..bc93fd74a918 100644
--- a/usr.sbin/xntpd/xntpd/refclock_irig.c
+++ b/usr.sbin/xntpd/xntpd/refclock_irig.c
@@ -1,8 +1,8 @@
/*
* refclock_irig - clock driver for the IRIG audio decoder
*/
+#if defined(REFCLOCK) && defined(IRIG) && defined(sun)
-#if defined(REFCLOCK) && defined(IRIG)
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
@@ -19,72 +19,72 @@
* This driver supports the IRIG audio decoder. This clever gadget uses
* a modified BSD audio driver for the Sun SPARCstation which provides
* a timestamp, raw binary timecode, status byte and decoded ASCII
- * timecode. The data are represented in the structure:
+ * timecode. The data are represented in the structure in the
+ * sys/bsd_audioirig.h header file:
*
* struct irig_time {
- * struct timeval stamp; timestamp
- * u_char bits[13]; 100 irig data bits
- * u_char status; status byte
- * char time[14]; time string (null terminated)
+ * struct timeval stamp; timestamp
+ * u_char bits[13]; 100 IRIG data bits
+ * u_char status; status byte
+ * char time[14]; time string (null terminated)
*
* where stamp represents a timestamp at the zero crossing of the index
* marker at the second's epoch, bits is a 13-octet, zero-padded binary-
* coded string representing code elements 1 through 100 in the IRIG-B
- * code format and status is a status bute, The decoded timestamp is a
+ * code format, and status is a status bute, The decoded timestamp is a
* 13-octet, null-terminated ASCII string "ddd hh:mm:ss*", where ddd is
- * the day of year, hh:mm:ss the time of day and * is a status indicator,
- * with " " indicating valid time and "?" indicating invalid time. The
- * timestamp is in unix timeval format, consisting of two 32-bit
- * longwords, the first of which is the seconds since 1970 and the second
- * is the fraction of the second in microseconds. The status byte is zero
+ * the day of year, hh:mm:ss the time of day and * is a status
+ * indicator, with " " indicating valid time and "?" indicating
+ * something wrong.
+ *
+ * The timestamp is in Unix timeval format, consisting of two 32-bit
+ * words, the first of which is the seconds since 1970 and the second is
+ * the fraction of the second in microseconds. The status byte is zero
* if (a) the input signal is within amplitude tolerances, (b) the raw
* binary timecode contains only valid code elements, (c) 11 position
- * identifiers have been found at the expected element positions, (d) the
- * clock status byte contained in the timecode is valid, and (e) a time
- * determination has been made since the last read() system call.
+ * identifiers have been found at the expected element positions, (d)
+ * the clock status byte contained in the timecode is valid, and (e) a
+ * time determination has been made since the last read() system call.
*
* The 100 elements of the IRIG-B timecode are numbered from 0 through
* 99. Position identifiers occur at elements 0, 9, 19 and every ten
- * thereafter to 99. The control function elements begin at element 50,
- * which is control-field element 1, and extend to element 78, which is
- * control-field element 27. The control functions have different
- * interpretations in various devices. The straight-binary-seconds(SBS)
- * field begins at element 80 and is 17 bits long.
+ * thereafter to 99. The control function (CF) elements begin at element
+ * 50 (CF 1) and extend to element 78 (CF 27). The straight-binary-
+ * seconds (SBS) field, which encodes the seconds of the UTC day, begins
+ * at element 80 (CF 28) and extends to element 97 (CF 44). The encoding
+ * of elements 50 (CF 1) through 78 (CF 27) is device dependent. This
+ * driver presently does not use the CF elements.
+ *
+ * Where feasible, the interface should be operated with signature
+ * control, so that, if the IRIG signal is lost or malformed, the
+ * interface produces an unmodulated signal, rather than possibly random
+ * digits. The driver will declare "unsynchronized" in this case.
*
* Spectracom Netclock/2 WWVB Synchronized Clock
- * 6 time sync status
- * 10-13 bcd year units
- * 15-18 bcd year tens
*
- * Austron 2201A GPS Receiver (speculative)
+ * Element CF Function
+ * -------------------------------------
+ * 55 6 time sync status
+ * 60-63 10-13 bcd year units
+ * 65-68 15-18 bcd year tens
+ *
*/
/*
- * Definitions
+ * IRIG interface definitions
*/
-#define MAXUNITS 1 /* max number of irig units */
-#define IRIGFD "/dev/irig" /* name of driver device */
+#define DEVICE "/dev/irig%d" /* device name and unit */
+#define PRECISION (-13) /* precision assumed (100 us) */
+#define REFID "IRIG" /* reference ID */
+#define DESCRIPTION "IRIG Audio Decoder" /* WRU */
-/*
- * IRIG interface parameters.
- */
-#define IRIGPRECISION (-20) /* precision assumed (1 us) */
-#define IRIGREFID "IRIG" /* reference id */
-#define IRIGDESCRIPTION "IRIG audio decoder" /* who we are */
-#define IRIGHSREFID 0x7f7f0c0a /* 127.127.6.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
+#define NSAMPLES 3 /* stages of median filter */
#define IRIG_FORMAT 1 /* IRIG timestamp format */
-#define BMAX 40 /* length of decoded timecode */
-
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
- */
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
/*
* Imported from ntp_timer module
*/
-extern U_LONG current_time; /* current time (s) */
+extern u_long current_time; /* current time (s) */
/*
* Imported from ntpd module
@@ -92,282 +92,115 @@ extern U_LONG current_time; /* current time (s) */
extern int debug; /* global debug flag */
/*
- * irig unit control structure.
- */
-struct irigunit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp lastrec; /* last local time */
- l_fp lastref; /* last timecode time */
- char lastcode[BMAX]; /* decoded timecode */
- char bincode[BMAX]; /* raw irig message */
- int lencode; /* lengthof last timecode */
- U_LONG lasttime; /* last time clock heard from */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- U_LONG yearstart; /* start of current year */
- u_char leap; /* leap indicators */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
-};
-
-/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct irigunit *irigunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-/*
* Function prototypes
*/
-static void irig_init P(());
-static int irig_start P((u_int, struct peer *));
-static void irig_shutdown P((int));
-static void irig_report_event P((struct irigunit *, int));
-static void irig_poll P((int, struct peer *));
-static void irig_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void irig_buginfo P((int, struct refclockbug *));
+static int irig_start P((int, struct peer *));
+static void irig_shutdown P((int, struct peer *));
+static void irig_poll P((int, struct peer *));
/*
* Transfer vector
*/
-struct refclock refclock_irig = {
- irig_start, irig_shutdown, irig_poll,
- irig_control, irig_init, irig_buginfo, NOFLAGS
+struct refclock refclock_irig = {
+ irig_start, /* start up driver */
+ irig_shutdown, /* shut down driver */
+ irig_poll, /* transmit poll message */
+ noentry, /* not used (old irig_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old irig_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * irig_init - initialize internal irig driver data
- */
-static void
-irig_init()
-{
- register int i;
-
- /*
- * Just zero the data arrays
- */
- memset((char *) irigunits, 0, sizeof irigunits);
- memset((char *) unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = 0;
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
/*
- * irig_start - open the irig device and initialize data for processing
+ * irig_start - open the device and initialize data for processing
*/
static int
irig_start(unit, peer)
- u_int unit;
-struct peer *peer;
+ int unit;
+ struct peer *peer;
{
- register struct irigunit *irig;
- register int i;
- int fd_irig;
- int format = IRIG_FORMAT;
+ register struct refclockproc *pp;
+ char device[20];
+ int fd;
+ int format = IRIG_FORMAT;
/*
- * Check configuration info.
- */
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "irig_start: unit %d invalid", unit);
- return (0);
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "irig_start: unit %d in use", unit);
- return (0);
- }
- /*
- * Open IRIG device and set format
+ * Open audio device and set format
*/
- fd_irig = open(IRIGFD, O_RDONLY | O_NDELAY, 0777);
- if (fd_irig == -1) {
- syslog(LOG_ERR, "irig_start: open of %s: %m", IRIGFD);
+ (void)sprintf(device, DEVICE, unit);
+ fd = open(device, O_RDONLY | O_NDELAY, 0777);
+ if (fd == -1) {
+ syslog(LOG_ERR, "irig_start: open of %s: %m", device);
return (0);
}
- if (ioctl(fd_irig, AUDIO_IRIG_OPEN, 0) < 0) {
- syslog(LOG_ERR,
- "irig_start: ioctl(%s, AUDIO_IRIG_OPEN): %m", IRIGFD);
- close(fd_irig);
+ if (ioctl(fd, AUDIO_IRIG_OPEN, 0) < 0) {
+ syslog(LOG_ERR, "irig_start: AUDIO_IRIG_OPEN %m");
+ close(fd);
return (0);
}
- if (ioctl(fd_irig, AUDIO_IRIG_SETFORMAT, (char *) &format) < 0) {
- syslog(LOG_ERR,
- "irig_start: ioctl(%s, AUDIO_IRIG_SETFORMAT): %m", IRIGFD);
- close(fd_irig);
+ if (ioctl(fd, AUDIO_IRIG_SETFORMAT, (char *)&format) < 0) {
+ syslog(LOG_ERR, "irig_start: AUDIO_IRIG_SETFORMAT %m",
+ DEVICE);
+ close(fd);
return (0);
}
+ pp = peer->procptr;
+ pp->io.clock_recv = noentry;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
/*
- * Allocate unit structure
- */
- if (irigunits[unit] != 0) {
- irig = irigunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && irigunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- irig = irigunits[i];
- irigunits[i] = 0;
- } else {
- irig = (struct irigunit *)
- emalloc(sizeof(struct irigunit));
- }
- }
- memset((char *) irig, 0, sizeof(struct irigunit));
-
- irigunits[unit] = irig;
-
- /*
- * Set up the structures
- */
- irig->peer = peer;
- irig->unit = (u_char) unit;
- irig->timestarted = current_time;
-
- irig->io.clock_recv = noentry;
- irig->io.srcclock = (caddr_t) irig;
- irig->io.datalen = 0;
- irig->io.fd = fd_irig;
-
- /*
- * All done. Initialize a few random peer variables, then
- * return success. Note that root delay and root dispersion are
- * always zero for this clock.
- */
- peer->precision = IRIGPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *) &peer->refid, IRIGREFID, 4);
- else
- peer->refid = htonl(IRIGHSREFID);
- unitinuse[unit] = 1;
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
return (1);
}
-/*
- * irig_shutdown - shut down a irig clock
- */
-static void
-irig_shutdown(unit)
- int unit;
-{
- register struct irigunit *irig;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "irig_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "irig_shutdown: unit %d not in use", unit);
- return;
- }
- /*
- * Tell the I/O module to turn us off. We're history.
- */
- irig = irigunits[unit];
- io_closeclock(&irig->io);
- unitinuse[unit] = 0;
-}
-
/*
- * irig_report_event - note the occurance of an event
- *
- * This routine presently just remembers the report and logs it, but
- * does nothing heroic for the trap handler.
+ * irig_shutdown - shut down the clock
*/
static void
-irig_report_event(irig, code)
- struct irigunit *irig;
-int code;
-{
+irig_shutdown(unit, peer)
+ int unit;
struct peer *peer;
+{
+ struct refclockproc *pp;
- peer = irig->peer;
- if (irig->status != (u_char) code) {
- irig->status = (u_char) code;
- if (code != CEVNT_NOMINAL)
- irig->lastevent = (u_char) code;
- syslog(LOG_INFO,
- "clock %s event %x", ntoa(&peer->srcadr), code);
- }
+ pp = peer->procptr;
+ io_closeclock(&pp->io);
}
+
/*
* irig_poll - called by the transmit procedure
*/
static void
irig_poll(unit, peer)
- int unit;
-struct peer *peer;
+ int unit;
+ struct peer *peer;
{
- struct irigunit *irig;
+ struct refclockproc *pp;
struct irig_time buf;
- register u_char *dpt;
- register char *cp, *dp;
- l_fp tstmp;
- int i;
+ char *cp, *dp;
+ u_char *dpt;
+ int i;
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "irig_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "irig_poll: unit %d not in use", unit);
- return;
- }
- irig = irigunits[unit];
- irig->polls++;
-
- if (read(irig->io.fd, (char *) &buf, sizeof(buf)) != sizeof(buf)) {
- syslog(LOG_ERR, "irig_poll: unit %d: %m", irig->unit);
- irig_report_event(irig, CEVNT_FAULT);
+ pp = peer->procptr;
+ if (read(pp->io.fd, (char *) &buf, sizeof(buf)) != sizeof(buf)) {
+ refclock_report(peer, CEVNT_FAULT);
return;
}
+ pp->polls++;
#ifdef DEBUG
if (debug) {
- dpt = (u_char *) & buf;
+ dpt = (u_char *)&buf;
printf("irig: ");
for (i = 0; i < sizeof(buf); i++)
printf("%02x", *dpt++);
@@ -375,194 +208,52 @@ struct peer *peer;
}
#endif
- buf.stamp.tv_sec += (U_LONG) JAN_1970;
- TVTOTS(&buf.stamp, &irig->lastrec);
- dpt = buf.bits;
- dp = irig->bincode;
- for (i = 0; i < sizeof(buf.bits); i++) {
- *dp++ = *dpt++;
- }
+ buf.stamp.tv_sec += JAN_1970;
+ TVTOTS(&buf.stamp, &pp->lastrec);
cp = buf.time;
- dp = irig->lastcode;
+ dp = pp->lastcode;
for (i = 0; i < sizeof(buf.time); i++)
*dp++ = *cp++;
- dp--;
- *dp = '\0';
- cp = irig->lastcode;
- irig->lencode = dp - cp;
+ *--dp = '\0';
+ pp->lencode = dp - pp->lastcode;
#ifdef DEBUG
if (debug)
- printf("irig: timecode %d %s %s\n",
- irig->lencode, ulfptoa(&irig->lastrec, 6), irig->lastcode);
+ printf("irig: time %s timecode %d %s\n",
+ ulfptoa(&pp->lastrec, 6), pp->lencode,
+ pp->lastcode);
#endif
-
- irig->lasttime = current_time;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
/*
- * Get irig time and convert to timestamp format.
+ * Get IRIG time and convert to timestamp format
*/
- if (irig->lencode < 13 || !isdigit(cp[0]) || !isdigit(cp[1]) ||
- !isdigit(cp[2]) ||
- cp[3] != ' ' || !isdigit(cp[4]) || !isdigit(cp[5]) ||
- cp[6] != ':' || !isdigit(cp[7]) || !isdigit(cp[8]) ||
- cp[9] != ':' || !isdigit(cp[10]) || !isdigit(cp[11])) {
- irig->badformat++;
- irig_report_event(irig, CEVNT_BADREPLY);
- return;
- }
- record_clock_stats(&(irig->peer->srcadr), irig->lastcode);
- irig->day = cp[0] - '0';
- irig->day = MULBY10(irig->day) + cp[1] - '0';
- irig->day = MULBY10(irig->day) + cp[2] - '0';
- irig->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
- irig->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
- irig->second = MULBY10(cp[10] - '0') + cp[11] - '0';
- if (cp[12] = ' ')
- irig->leap = 0;
- else
- irig->leap = LEAP_NOTINSYNC;
- if (irig->day < 1 || irig->day > 366) {
- irig->baddata++;
- irig_report_event(irig, CEVNT_BADDATE);
+ if (sscanf(pp->lastcode, "%3d %2d:%2d:%2d",
+ &pp->day, &pp->hour, &pp->minute, &pp->second) != 4) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
- if (irig->hour > 23 || irig->minute > 59 || irig->second > 59) {
- irig->baddata++;
- irig_report_event(irig, CEVNT_BADTIME);
- return;
+ if (pp->lastcode[12] != ' ') {
+ pp->leap = LEAP_NOTINSYNC;
+ } else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
}
/*
- * Now, compute the reference time value. Use the heavy
- * machinery for the seconds and the millisecond field for the
- * fraction when present. If an error in conversion to internal
- * format is found, the program declares bad data and exits.
- * Note that this code does not yet know how to do the years and
- * relies on the clock-calendar chip for sanity.
- */
- if (!clocktime(irig->day, irig->hour, irig->minute,
- irig->second, GMT, irig->lastrec.l_ui,
- &irig->yearstart, &irig->lastref.l_ui)) {
- irig->baddata++;
- irig_report_event(irig, CEVNT_BADTIME);
- return;
- }
- tstmp = irig->lastref;
- L_SUB(&tstmp, &irig->lastrec);
- irig->coderecv++;
- L_ADD(&tstmp, &(fudgefactor[irig->unit]));
- refclock_receive(irig->peer, &tstmp, GMT, 0,
- &irig->lastrec, &irig->lastrec, irig->leap);
-}
-
-/*
- * irig_control - set fudge factors, return statistics
- */
-static void
-irig_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct irigunit *irig;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "irig_control: unit %d invalid", unit);
- return;
- }
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char) (in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- irig = irigunits[unit];
- peer = irig->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *) &peer->refid,
- IRIGREFID, 4);
- else
- peer->refid = htonl(IRIGHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG1;
- }
- }
- if (out != 0) {
- out->type = REFCLK_IRIG_AUDIO;
- out->haveflags
- = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 | CLK_HAVEFLAG1;
- out->clockdesc = IRIGDESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgeval1 = (LONG) stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- irig = irigunits[unit];
- out->lencode = irig->lencode;
- out->lastcode = irig->lastcode;
- out->timereset = current_time - irig->timestarted;
- out->polls = irig->polls;
- out->noresponse = irig->noreply;
- out->badformat = irig->badformat;
- out->baddata = irig->baddata;
- out->lastevent = irig->lastevent;
- out->currentstatus = irig->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
-}
-
-/*
- * irig_buginfo - return clock dependent debugging info
- */
-static void
-irig_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct irigunit *irig;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "irig_buginfo: unit %d invalid", unit);
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
- if (!unitinuse[unit])
- return;
- irig = irigunits[unit];
-
- bug->nvalues = 8;
- bug->ntimes = 2;
- if (irig->lasttime != 0)
- bug->values[0] = current_time - irig->lasttime;
- else
- bug->values[0] = 0;
- bug->values[2] = (U_LONG) irig->year;
- bug->values[3] = (U_LONG) irig->day;
- bug->values[4] = (U_LONG) irig->hour;
- bug->values[5] = (U_LONG) irig->minute;
- bug->values[6] = (U_LONG) irig->second;
- bug->values[7] = irig->yearstart;
- bug->stimes = 0x1c;
- bug->times[0] = irig->lastref;
- bug->times[1] = irig->lastrec;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_leitch.c b/usr.sbin/xntpd/xntpd/refclock_leitch.c
index 330712997eba..753ad7673908 100644
--- a/usr.sbin/xntpd/xntpd/refclock_leitch.c
+++ b/usr.sbin/xntpd/xntpd/refclock_leitch.c
@@ -54,6 +54,7 @@
* P (last phone update failed)
*/
#define MAXUNITS 1 /* max number of LEITCH units */
+#define LEITCHREFID "ATOM" /* reference id */
#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
#define LEITCH232 "/dev/leitch%d" /* name of radio device */
#define SPEED232 B300 /* uart speed (300 baud) */
@@ -106,17 +107,17 @@ struct leitchunit {
l_fp codetime1;
l_fp codetime2;
l_fp codetime3;
- U_LONG yearstart;
+ u_long yearstart;
};
/*
* Function prototypes
*/
static void leitch_init P((void));
-static int leitch_start P((u_int, struct peer *));
-static void leitch_shutdown P((int));
+static int leitch_start P((int, struct peer *));
+static void leitch_shutdown P((int, struct peer *));
static void leitch_poll P((int, struct peer *));
-static void leitch_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void leitch_control P((int, struct refclockstat *, struct refclockstat *));
#define leitch_buginfo noentry
static void leitch_receive P((struct recvbuf *));
static void leitch_process P((struct leitchunit *));
@@ -127,6 +128,8 @@ static int dysize P((int));
static struct leitchunit leitchunits[MAXUNITS];
static u_char unitinuse[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static U_LONG refid[MAXUNITS];
static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
@@ -144,16 +147,21 @@ struct refclock refclock_leitch = {
static void
leitch_init()
{
+ int i;
+
memset((char*)leitchunits, 0, sizeof(leitchunits));
memset((char*)unitinuse, 0, sizeof(unitinuse));
+ for (i = 0; i < MAXUNITS; i++)
+ memcpy((char *)&refid[i], LEITCHREFID, 4);
}
/*
* leitch_shutdown - shut down a LEITCH clock
*/
static void
-leitch_shutdown(unit)
-int unit;
+leitch_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
{
#ifdef DEBUG
if (debug)
@@ -196,40 +204,38 @@ leitch_poll(unit, peer)
static void
leitch_control(unit, in, out)
- u_int unit;
+ int unit;
struct refclockstat *in;
struct refclockstat *out;
{
-#if debug
- if (debug)
- fprintf(stderr, "leitch_control()\n");
-#endif
if (unit >= MAXUNITS) {
syslog(LOG_ERR,
"leitch_control: unit %d invalid", unit);
return;
}
+
if (in) {
- /* WE DONT SET ANY THING */
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = (&leitchunits[unit])->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
}
+
if (out) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
out->type = REFCLK_ATOM_LEITCH;
- out->flags = 0;
- out->haveflags = 0;
- out->lencode = 0;
+ out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
out->lastcode = "";
- out->polls = 0;
- out->noresponse = 0;
- out->badformat = 0;
- out->baddata = 0;
- out->timereset = 0;
out->clockdesc = LEITCH_DESCRIPTION;
- out->fudgetime1.l_uf = 0;
- out->fudgetime1.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgetime2.l_ui = 0;
- out->currentstatus = 0;
- out->lastevent = 0;
}
}
@@ -238,7 +244,7 @@ leitch_control(unit, in, out)
*/
static int
leitch_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
struct leitchunit *leitch;
@@ -413,8 +419,8 @@ leitch_start(unit, peer)
peer->precision = 0;
peer->rootdelay = 0;
peer->rootdispersion = 0;
- peer->stratum = 0;
- peer->refid = htonl(0x41544f4d); /* ATOM */
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
unitinuse[unit] = 1;
return(1);
diff --git a/usr.sbin/xntpd/xntpd/refclock_local.c b/usr.sbin/xntpd/xntpd/refclock_local.c
index 1323ca91ed62..552e71272ab3 100644
--- a/usr.sbin/xntpd/xntpd/refclock_local.c
+++ b/usr.sbin/xntpd/xntpd/refclock_local.c
@@ -1,7 +1,8 @@
/*
* refclock_local - local pseudo-clock driver
*/
-#if defined(REFCLOCK) && defined(LOCAL_CLOCK)
+#if defined(REFCLOCK) && defined(LOCAL_CLOCK)
+
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
@@ -10,190 +11,129 @@
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
-static void local_init P((void));
-static int local_start P((u_int, struct peer *));
-static void local_shutdown P((int));
-static void local_poll P((int, struct peer *));
-static void local_control P((u_int, struct refclockstat *, struct refclockstat *));
-#define local_buginfo noentry
-
-struct refclock refclock_local = {
- local_start, local_shutdown, local_poll,
- local_control, local_init, local_buginfo, NOFLAGS
-};
-
/*
- * This is a hack to allow a machine to use its own system clock as
- * a "reference clock", i.e. to free run against its own clock at
- * a non-infinity stratum. This is certainly useful if you want to
- * use NTP in an isolated environment with no radio clock (not that
- * this is a good idea) to synchronize the machines together. Pick
- * a machine that you figure has a good clock and configure it with
- * a local reference clock running at stratum 0 (i.e. 127.127.1.0).
- * Then point all the other machines at the one you're using as the
- * reference.
+ * This is a hack to allow a machine to use its own system clock as a
+ * reference clock, i.e., to free-run using no outside clock discipline
+ * source. This is useful if you want to use NTP in an isolated
+ * environment with no radio clock or NIST modem available. Pick a
+ * machine that you figure has a good clock oscillator and configure it
+ * with this driver. Set the clock using the best means available, like
+ * eyeball-and-wristwatch. Then, point all the other machines at this
+ * one or use broadcast (not multicast) mode to distribute time.
*
- * The other thing this is good for is if you want to use a particular
- * server's clock as the last resort, when all radio time has gone
- * away. This is especially good if that server has an ovenized
- * oscillator or something which will keep the time stable for extended
- * periods, since then all the other machines can benefit from this.
- * For this you would configure a local clock at a higher stratum (say
- * 3 or 4) to prevent the server's stratum from falling below here.
- */
-
-/*
- * Definitions
+ * Another application for this driver is if you want to use a
+ * particular server's clock as the clock of last resort when all other
+ * normal synchronization sources have gone away. This is especially
+ * useful if that server has an ovenized oscillator. For this you would
+ * configure this driver at a higher stratum (say 3 or 4) to prevent the
+ * server's stratum from falling below that.
+ *
+ * A third application for this driver is when an external discipline
+ * source is available, such as the NIST "lockclock" program, which
+ * synchronizes the local clock via a telephone modem and the NIST
+ * Automated Computer Time Service (ACTS), or the Digital Time
+ * Synchronization Service (DTSS), which runs on DCE machines. In this
+ * case the stratum should be set at zero, indicating a bona fide
+ * stratum-1 source. Exercise some caution with this, since there is no
+ * easy way to telegraph via NTP that something might be wrong in the
+ * discipline source itself. In the case of DTSS, the local clock can
+ * have a rather large jitter, depending on the interval between
+ * corrections and the intrinsic frequency error of the clock
+ * oscillator. In extreme cases, this can cause clients to exceed the
+ * 128-ms slew window and drop off the NTP subnet.
+ *
+ * In the default mode the behavior of the clock selection algorithm is
+ * modified when this driver is in use. The algorithm is designed so
+ * that this driver will never be selected unless no other discipline
+ * source is available. This can be overriden with the prefer keyword of
+ * the server configuration command, in which case only this driver will
+ * be selected for synchronization and all other discipline sources will
+ * be ignored. This behavior is intended for use when an external
+ * discipline source controls the system clock.
+ *
+ * Fudge Factors
+ *
+ * The stratum for this driver LCLSTRATUM is set at 3 by default, but
+ * can be changed by the fudge command and/or the xntpdc utility. The
+ * reference ID is "LCL" by default, but can be changed using the same
+ * mechanisms. *NEVER* configure this driver to operate at a stratum
+ * which might possibly disrupt a client with access to a bona fide
+ * primary server, unless athe local clock oscillator is reliably
+ * disciplined by another source. *NEVER NEVER* configure a server which
+ * might devolve to an undisciplined local clock to use multicast mode.
+ *
+ * This driver provides a mechanism to trim the local clock in both time
+ * and frequency, as well as a way to manipulate the leap bits. The
+ * fudge time1 parameter adjusts the time, in seconds, and the fudge
+ * time2 parameter adjusts the frequency, in ppm. Both parameters are
+ * additive; that is, they add increments in time or frequency to the
+ * present values. The fudge flag1 and fudge flag2 bits set the
+ * corresponding leap bits; for example, setting flag1 causes a leap
+ * second to be added at the end of the UTC day. These bits are not
+ * reset automatically when the leap takes place; they must be turned
+ * off manually after the leap event.
*/
-#define NUMUNITS 16 /* 127.127.1.[0-15] */
/*
- * Some constant values we stick in the peer structure
+ * Local interface definitions
*/
-#define LCLDISPERSION (FP_SECOND/5) /* 200 ms dispersion */
-#define LCLROOTDISPERSION (FP_SECOND/5) /* 200 ms root dispersion */
-#define LCLPRECISION (-5) /* what the heck */
-#define LCLREFID "LCL\0"
-#define LCLREFOFFSET 20 /* reftime is 20s behind */
-#define LCLHSREFID 0x7f7f0101 /* 127.127.1.1 refid for hi stratum */
+#define PRECISION (-7) /* about 10 ms precision */
+#define REFID "LCL\0" /* reference ID */
+#define DESCRIPTION "Undisciplined local clock" /* WRU */
-/*
- * Description of clock
- */
-#define LCLDESCRIPTION "Free running against local system clock"
+#define STRATUM 3 /* default stratum */
+#define DISPERSION (FP_SECOND / 100) /* default dispersion (10 ms) */
/*
- * Local clock unit control structure.
+ * Imported from the timer module
*/
-struct lclunit {
- struct peer *peer; /* associated peer structure */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char unit; /* unit number */
- u_char unused;
- U_LONG lastupdate; /* last time data received */
- U_LONG polls; /* number of polls */
- U_LONG timestarted; /* time we started this */
-};
-
+extern u_long current_time;
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
+ * Imported from ntp_proto
*/
-static struct lclunit *lclunits[NUMUNITS];
-static u_char unitinuse[NUMUNITS];
+extern s_char sys_precision;
/*
- * Imported from the timer module
+ * Function prototypes
*/
-extern U_LONG current_time;
-
-extern l_fp sys_clock_offset;
+static int local_start P((int, struct peer *));
+static void local_poll P((int, struct peer *));
/*
- * local_init - initialize internal local clock driver data
+ * Transfer vector
*/
-static void
-local_init()
-{
- /*
- * Just zero the data arrays
- */
- memset((char *)lclunits, 0, sizeof lclunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-}
+struct refclock refclock_local = {
+ local_start, /* start up driver */
+ noentry, /* shut down driver (not used) */
+ local_poll, /* transmit poll message */
+ noentry, /* not used (old lcl_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old lcl_buginfo) */
+ NOFLAGS /* not used */
+};
/*
- * local_start - start up a local reference clock
+ * local_start - start up the clock
*/
static int
local_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register int i;
- register struct lclunit *lcl;
+ register struct refclockproc *pp;
- if (unit >= NUMUNITS) {
- syslog(LOG_ERR, "local clock: unit number %d invalid (max 15)",
- unit);
- return 0;
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "local clock: unit number %d in use", unit);
- return 0;
- }
+ pp = peer->procptr;
/*
- * Looks like this might succeed. Find memory for the structure.
- * Look to see if there are any unused ones, if not we malloc()
- * one.
+ * Initialize miscellaneous variables
*/
- if (lclunits[unit] != 0) {
- lcl = lclunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < NUMUNITS; i++) {
- if (!unitinuse[i] && lclunits[i] != 0)
- break;
- }
- if (i < NUMUNITS) {
- /*
- * Reclaim this one
- */
- lcl = lclunits[i];
- lclunits[i] = 0;
- } else {
- lcl = (struct lclunit *)emalloc(sizeof(struct lclunit));
- }
- }
- memset((char *)lcl, 0, sizeof(struct lclunit));
- lclunits[unit] = lcl;
-
- /*
- * Set up the structure
- */
- lcl->peer = peer;
- lcl->unit = (u_char)unit;
- lcl->timestarted = lcl->lastupdate = current_time;
-
- /*
- * That was easy. Diddle the peer variables and return success.
- */
- peer->precision = LCLPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = LCLROOTDISPERSION;
- peer->stratum = (u_char)unit;
- if (unit <= 1)
- memmove((char *)&peer->refid, LCLREFID, 4);
- else
- peer->refid = htonl(LCLHSREFID);
- unitinuse[unit] = 1;
- return 1;
-}
-
-
-/*
- * local_shutdown - shut down a local clock
- */
-static void
-local_shutdown(unit)
- int unit;
-{
- if (unit >= NUMUNITS) {
- syslog(LOG_ERR,
- "local clock: INTERNAL ERROR, unit number %d invalid (max 15)",
- unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR,
- "local clock: INTERNAL ERROR, unit number %d not in use", unit);
- return;
- }
-
- unitinuse[unit] = 0;
+ peer->precision = sys_precision;
+ pp->clockdesc = DESCRIPTION;
+ peer->stratum = STRATUM;
+ memcpy((char *)&pp->refid, REFID, 4);
+ return (1);
}
@@ -205,103 +145,26 @@ local_poll(unit, peer)
int unit;
struct peer *peer;
{
- l_fp off;
- l_fp ts;
+ struct refclockproc *pp;
- if (unit >= NUMUNITS) {
- syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d invalid",
- unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "local clock poll: INTERNAL: unit %d unused",
- unit);
- return;
- }
- if (peer != lclunits[unit]->peer) {
- syslog(LOG_ERR,
- "local clock poll: INTERNAL: peer incorrect for unit %d",
- unit);
- return;
- }
+ pp = peer->procptr;
+ pp->polls++;
+ pp->lasttime = current_time;
/*
- * Update clock stat counters
+ * Ramble through the usual filtering and grooming code, which
+ * is essentially a no-op and included mostly for pretty
+ * billboards. We fudge flags as the leap indicators and allow a
+ * one-time adjustment in time using fudge time1 (s) and
+ * frequency using fudge time 2 (ppm).
*/
- lclunits[unit]->polls++;
- lclunits[unit]->lastupdate = current_time;
-
- /*
- * This is pretty easy. Give the reference clock support
- * a zero offset and our fixed dispersion. Use peer->xmt for
- * our receive time. Use peer->xmt - 20 seconds for our
- * reference time.
- */
- off.l_ui = off.l_uf = 0;
- ts = peer->xmt;
- ts.l_ui -= LCLREFOFFSET;
- refclock_receive(peer, &off, 0, LCLDISPERSION,
- &ts, &peer->xmt, 0);
+ pp->dispersion = DISPERSION;
+ gettstamp(&pp->lastrec);
+ refclock_receive(peer, &pp->fudgetime1, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->sloppyclockflag);
+ adj_frequency(LFPTOFP(&pp->fudgetime2));
+ L_CLR(&pp->fudgetime1);
+ L_CLR(&pp->fudgetime2);
}
-
-
-/*
- * local_control - set fudge factors, return statistics
- */
-static void
-local_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- extern s_fp drift_comp;
-
- if (unit >= NUMUNITS) {
- syslog(LOG_ERR, "local clock: unit %d invalid (max %d)",
- unit, NUMUNITS-1);
- return;
- }
-
- /*
- * The time1 fudge factor is the drift compensation register.
- * The time2 fudge factor is the offset of the system clock from
- * what the protocol has set it to be. Most useful when SLEWALWAYS
- * is defined.
- */
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- drift_comp = LFPTOFP(&in->fudgetime1);
- if (in->haveflags & CLK_HAVETIME2) {
- sys_clock_offset.l_ui = in->fudgetime2.l_ui;
- sys_clock_offset.l_uf = in->fudgetime2.l_uf;
- }
- }
- if (out != 0) {
- out->type = REFCLK_LOCALCLOCK;
- out->flags = 0;
- out->haveflags = CLK_HAVETIME1;
- out->clockdesc = LCLDESCRIPTION;
- FPTOLFP(drift_comp, &out->fudgetime1);
- out->fudgetime2.l_ui = sys_clock_offset.l_ui;
- out->fudgetime2.l_uf = sys_clock_offset.l_uf;
- out->fudgeval1 = out->fudgeval2 = 0;
- out->lencode = 0;
- out->lastcode = "";
- out->badformat = 0;
- out->baddata = 0;
- out->noresponse = 0;
- if (unitinuse[unit]) {
- out->polls = lclunits[unit]->polls;
- out->timereset =
- current_time - lclunits[unit]->timestarted;
- out->lastevent = lclunits[unit]->lastevent;
- out->currentstatus = lclunits[unit]->status;
- } else {
- out->polls = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
-}
#endif /* REFCLOCK */
diff --git a/usr.sbin/xntpd/xntpd/refclock_moto.c b/usr.sbin/xntpd/xntpd/refclock_moto.c
new file mode 100644
index 000000000000..2e888bc40913
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_moto.c
@@ -0,0 +1,2 @@
+#if defined(REFCLOCK) && defined(NMEA)
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_msfees.c b/usr.sbin/xntpd/xntpd/refclock_msfees.c
index c2a882abb919..17e42351d472 100644
--- a/usr.sbin/xntpd/xntpd/refclock_msfees.c
+++ b/usr.sbin/xntpd/xntpd/refclock_msfees.c
@@ -87,7 +87,7 @@
* or 9.5uS/S then 3990.5uS at a 7min re-sync,
* at which point it may loose the "00" second time stamp.
* I assume that the most accurate time is just AFTER the re-sync.
- * Hence remember the last cycle interval,
+ * Hence remember the last cycle interval,
*
* Can run in any one of:
*
@@ -308,6 +308,8 @@ static l_fp onesec; /* = { 1, 0 }; */
/* Imported from the timer module */
extern u_long current_time;
+extern s_char sys_precision;
+
#ifdef DEBUG
static int debug;
#endif
@@ -328,33 +330,6 @@ static int debug;
#define USECS 1000000
#define MINSTEP 5 /* some systems increment uS on each call */
#define MAXLOOPS (USECS/9)
-static int ees_get_precision()
-{
- struct timeval tp;
- struct timezone tzp;
- long last;
- int i;
- long diff;
- long val;
- gettimeofday(&tp, &tzp);
-
- last = tp.tv_usec;
- for (i=0; i< 100000; i++) {
- gettimeofday(&tp, &tzp);
- diff = tp.tv_usec - last;
- if (diff < 0) diff += USECS;
- if (diff > MINSTEP) break;
- last = tp.tv_usec;
- }
- syslog(LOG_INFO,
- "I: ees: precision calculation given %duS after %d loop%s",
- diff, i, (i==1) ? "" : "s");
-
- if (i == 0) return -20 /* assume 1uS */;
- if (i >= MAXLOOPS) return EESPRECISION /* Lies ! */;
- for (i=0, val=USECS; val > 0; i--, val /= 2) if (diff > val) return i;
- return EESPRECISION /* Lies ! */;
-}
static void dump_buf(coffs, from, to, text)
l_fp *coffs;
@@ -407,18 +382,20 @@ static void msfees_init()
/* msfees_start - open the EES devices and initialize data for processing */
static int msfees_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
register struct eesunit *ees;
register int i;
int fd232 = -1;
char eesdev[20];
- struct termios ttyb, *ttyp;
+ struct termios ttyb, *ttyp;
static void ees_receive();
extern int io_addclock();
extern void io_closeclock();
extern char *emalloc();
+ struct refclockproc *pp;
+ pp = peer->procptr;
if (unit >= MAXUNITS) {
syslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
@@ -462,24 +439,24 @@ static int msfees_start(unit, peer)
ttyp = &ttyb;
if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
- goto screwed;
- }
-
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_oflag = 0;
- ttyp->c_lflag = ICANON;
+ syslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_oflag = 0;
+ ttyp->c_lflag = ICANON;
ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
- goto screwed;
- }
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
+ goto screwed;
+ }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
- goto screwed;
- }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
+ goto screwed;
+ }
inherent_delay[unit].l_uf = INH_DELAY_PPS;
@@ -524,7 +501,7 @@ static int msfees_start(unit, peer)
* receiving stuff.
*/
- {
+ {
int rc1;
/* Pop any existing onews first ... */
while (ioctl(fd232, I_POP, 0 ) >= 0) ;
@@ -554,18 +531,21 @@ static int msfees_start(unit, peer)
/* All done. Initialize a few random peer variables, then
* return success. */
- peer->precision = ees_get_precision();
+ peer->precision = sys_precision;
peer->stratum = stratumtouse[unit];
peer->rootdelay = 0; /* ++++ */
peer->rootdispersion = 0; /* ++++ */
if (stratumtouse[unit] <= 1) {
- memmove((char *)&peer->refid, EESREFID, 4);
+ memcpy((char *)&pp->refid, EESREFID, 4);
if (unit > 0 && unit < 10)
- ((char *)&peer->refid)[3] = '0' + unit;
+ ((char *)&pp->refid)[3] = '0' + unit;
} else {
peer->refid = htonl(EESHSREFID);
}
unitinuse[unit] = 1;
+ pp->unitptr = (caddr_t) &eesunits[unit];
+ pp->clockdesc = EESDESCRIPTION;
+ pp->nstages = MAXSTAGE;
syslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
return (1);
@@ -577,8 +557,9 @@ screwed:
/* msfees_shutdown - shut down a EES clock */
-static void msfees_shutdown(unit)
+static void msfees_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
register struct eesunit *ees;
extern void io_closeclock();
@@ -709,7 +690,7 @@ static void ees_receive(rbufp)
* continue on. */
cp = ees->lastcode;
break;
-
+
default:
syslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
ees->unit, ees->codestate);
@@ -818,7 +799,7 @@ static void ees_receive(rbufp)
ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
if (ees->day > 366 || ees->day < 1 ||
- ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
+ ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
ees->baddata++;
ees->reason = CODEREASON + 12;
ees_event(ees, CEVNT_BADDATE);
@@ -861,11 +842,11 @@ static void ees_receive(rbufp)
/* Number of seconds since the last step */
sincelast = this_uisec - ees->last_step;
- memset(&ppsclockev, 0, sizeof ppsclockev);
+ memset((char *) &ppsclockev, 0, sizeof ppsclockev);
rc = ioctl(ees->io.fd, CIOGETEV, (char *) &ppsclockev);
if (debug & DB_PRINT_EV) fprintf(stderr,
- "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08x %08x %d\n",
+ "[%x] CIOGETEV u%d %d (%lx %d) gave %d (%d): %08lx %08lx %ld\n",
DB_PRINT_EV, ees->unit, ees->io.fd, CIOGETEV, is_pps(ees),
rc, errno, ptr[0], ptr[1], ptr[2]);
@@ -881,7 +862,7 @@ static void ees_receive(rbufp)
/* allow for single loss of PPS only */
if (pps_step != 1 && pps_step != 2)
- fprintf(stderr, "PPS step: %d too far off %d (%d)\n",
+ fprintf(stderr, "PPS step: %d too far off %ld (%d)\n",
ppsclockev.serial, ees->last_pps_no, pps_step);
else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
fprintf(stderr, "buftvtots failed\n");
@@ -892,7 +873,7 @@ static void ees_receive(rbufp)
diff = pps_arrvstamp;
conv = 0;
L_SUB(&diff, &ees->arrvtime);
-if (debug & DB_PRINT_CDT) printf("[%x] Have %x.%08x and %x.%08x -> %x.%08x @ %s",
+if (debug & DB_PRINT_CDT) printf("[%x] Have %lx.%08lx and %lx.%08lx -> %lx.%08lx @ %s",
DB_PRINT_CDT, ees->arrvtime.l_ui, ees->arrvtime.l_uf,
pps_arrvstamp.l_ui, pps_arrvstamp.l_uf,
diff.l_ui, diff.l_uf,
@@ -929,7 +910,7 @@ syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
}
ees->last_pps_no = ppsclockev.serial;
if (debug & DB_PRINT_CDTC) printf(
- "[%x] %08x %08x %d u%d (%d %d)\n",
+ "[%x] %08lx %08lx %d u%d (%d %d)\n",
DB_PRINT_CDTC, pps_arrvstamp.l_ui,
pps_arrvstamp.l_uf, conv, ees->unit,
call_pps_sample, pps_step);
@@ -951,7 +932,7 @@ syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
/* Dump the deltas each minute */
if (debug & DB_DUMP_DELTAS)
- { if (0 <= ees->second &&
+ { if (/*0 <= ees->second && */
ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
/* Dump on second 1, as second 0 sometimes missed */
if (ees->second == 1) {
@@ -964,8 +945,8 @@ syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
while (*ptr) ptr++;
}
syslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
- msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
- msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
+ msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
+ msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
text+1);
for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
}
@@ -1056,7 +1037,7 @@ printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
sum = 4 * 60;
}
ees->last_step = this_uisec;
-printf("MSF%d: d=%3d.%04d@%d :%d:%d:$%d:%d:%d\n",
+printf("MSF%d: d=%3ld.%04ld@%d :%d:%d:$%d:%d:%d\n",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
syslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
@@ -1065,7 +1046,7 @@ ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ee
/* OK, so not a 4ms step at a minute boundry */
else {
if (suspect_4ms_step) syslog(LOG_ERR,
- "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
+ "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
msec(EES_STEP_F - EES_STEP_F_GRACE),
subms(EES_STEP_F - EES_STEP_F_GRACE),
@@ -1079,7 +1060,7 @@ ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ee
static ees_step_notes = EES_STEP_NOTES;
if (ees_step_notes > 0) {
ees_step_notes--;
-printf("MSF%d: D=%3d.%04d@%02d :%d%s\n",
+printf("MSF%d: D=%3ld.%04ld@%02d :%d%s\n",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
syslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
@@ -1114,7 +1095,7 @@ ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step)
ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
if (debug & DB_PRINT_DELTAS) printf(
- "MSF%d: %3d/%03d -> d=%11d (%d|%d)\n",
+ "MSF%d: %3ld/%03d -> d=%11ld (%ld|%ld)\n",
ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
@@ -1150,7 +1131,7 @@ ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step)
L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
- if (call_pps_sample && !(debug & DB_NO_PPS)) {
+ if (call_pps_sample && !(debug & DB_NO_PPS)) {
/* Sigh -- it expects its args negated */
L_NEG(&pps_arrvstamp);
(void) pps_sample(&pps_arrvstamp);
@@ -1202,7 +1183,7 @@ static void ees_process(ees)
u_fp dispersion; /* ++++ */
int lostsync, isinsync;
int samples = ees->nsamples;
- int samplelog;
+ int samplelog = 0; /* keep "gcc -Wall" happy ! */
int samplereduce = (samples + 1) / 2;
/* Reset things to zero so we don't have to worry later */
@@ -1238,7 +1219,7 @@ static void ees_process(ees)
* from the median. We work this out by doubling
* the median, subtracting off the end samples, and
* looking at the sign of the answer, using the
- * identity (c-b)-(b-a) == 2*b-a-c
+ * identity (c-b)-(b-a) == 2*b-a-c
*/
tmp = coffs[(noff + i)/2];
L_ADD(&tmp, &tmp);
@@ -1262,7 +1243,7 @@ static void ees_process(ees)
L_RSHIFTU(&offset);
}
else offset = coffs[i+BESTSAMPLE];
-
+
/* Compute the dispersion as the difference between the
* lowest and highest offsets that remain in the
* consideration list.
@@ -1416,7 +1397,7 @@ static void msfees_leap()
/* msfees_control - set fudge factors, return statistics */
static void msfees_control(unit, in, out)
- u_int unit;
+ int unit;
struct refclockstat *in;
struct refclockstat *out;
{
@@ -1443,19 +1424,20 @@ static void msfees_control(unit, in, out)
* will wait for the next timecode
*/
struct peer *peer = ees->peer;
+ struct refclockproc *pp = peer->procptr;
peer->stratum = stratumtouse[unit];
if (stratumtouse[unit] <= 1) {
- memmove((char *)&peer->refid,
+ memmove((char *)&pp->refid,
EESREFID, 4);
if (unit>0 && unit<10)
- ((char *)&peer->refid)[3] =
+ ((char *)&pp->refid)[3] =
'0' + unit;
}
else peer->refid = htonl(EESHSREFID);
}
}
if (in->haveflags & CLK_HAVEVAL2) {
- printf("Debug: %x -> %x\n", debug, in->fudgeval2);
+ printf("Debug: %x -> %lx\n", debug, in->fudgeval2);
syslog(LOG_ERR, "MSF%d: debug %x -> %x",
unit, debug, in->fudgeval2);
debug = in->fudgeval2;
@@ -1478,14 +1460,17 @@ static void msfees_control(unit, in, out)
}
if (out != 0) {
+ struct peer *peer = ees->peer;
+ struct refclockproc *pp = peer->procptr;
out->type = REFCLK_MSF_EES;
out->haveflags
= CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4;
- out->clockdesc = EESDESCRIPTION;
+ out->clockdesc = pp->clockdesc;
out->fudgetime1 = fudgefactor[unit];
out->fudgetime2 = os_delay[unit];
out->fudgeval1 = (long)stratumtouse[unit];
- out->fudgeval2 = debug;
+ /*out->fudgeval2= debug*/;
+ memmove((char *)&out->fudgeval2, (char *)&pp->refid, 4);
out->flags = sloppyclockflag[unit];
if (unitinuse[unit]) {
out->flags |= ees->dump_vals | ees->usealldata;
diff --git a/usr.sbin/xntpd/xntpd/refclock_mx4200.c b/usr.sbin/xntpd/xntpd/refclock_mx4200.c
index 3c0d097a8d9e..2cfee5293c3e 100644
--- a/usr.sbin/xntpd/xntpd/refclock_mx4200.c
+++ b/usr.sbin/xntpd/xntpd/refclock_mx4200.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*/
-#if defined(REFCLOCK) && (defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS))
+#if defined(REFCLOCK) && defined(PPS) && (defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS))
#if !defined(lint) && !defined(__GNUC__)
static char rcsid[] =
@@ -102,7 +102,6 @@ static char rcsid[] =
#define MX4200PRECISION (-18) /* precision assumed (about 4 us) */
#define MX4200REFID "GPS" /* reference id */
#define MX4200DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */
-#define MX4200HSREFID 0x7f7f0a0a /* 127.127.10.10 refid for hi strata */
#define DEFFUDGETIME 0 /* default fudge time (ms) */
/* Leap stuff */
@@ -216,6 +215,7 @@ static u_char unitinuse[MAXUNITS];
static l_fp fudgefactor[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char sloppyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
static const char pmvxg[] = "PMVXG";
@@ -223,13 +223,13 @@ static const char pmvxg[] = "PMVXG";
* Function prototypes
*/
static void mx4200_init P((void));
-static int mx4200_start P((u_int, struct peer *));
-static void mx4200_shutdown P((int));
+static int mx4200_start P((int, struct peer *));
+static void mx4200_shutdown P((int, struct peer *));
static void mx4200_receive P((struct recvbuf *));
static void mx4200_process P((struct mx4200unit *));
static void mx4200_report_event P((struct mx4200unit *, int));
static void mx4200_poll P((int, struct peer *));
-static void mx4200_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void mx4200_control P((int, struct refclockstat *, struct refclockstat *));
static void mx4200_buginfo P((int, struct refclockbug *));
static char * mx4200_parse P((char *, struct calendar *, int *, int *));
@@ -273,6 +273,7 @@ mx4200_init()
fudgefactor[i].l_uf = DEFFUDGETIME;
stratumtouse[i] = 0;
sloppyclockflag[i] = 0;
+ memcpy((char *)&refid[i], MX4200REFID, 4);
}
}
@@ -316,7 +317,7 @@ checkdfile()
*/
static int
mx4200_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
register struct mx4200unit *mx4200;
@@ -511,10 +512,7 @@ mx4200_start(unit, peer)
peer->rootdelay = 0;
peer->rootdispersion = 0;
peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, MX4200REFID, 4);
- else
- peer->refid = htonl(MX4200HSREFID);
+ peer->refid = refid[unit];
unitinuse[unit] = 1;
/* Insure the receiver is properly configured */
@@ -537,8 +535,9 @@ screwed:
* mx4200_shutdown - shut down a MX4200 clock
*/
static void
-mx4200_shutdown(unit)
+mx4200_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
register struct mx4200unit *mx4200;
@@ -830,7 +829,7 @@ mx4200_receive(rbufp)
fprintf(df, "%s\t%s",
umfptoa(tmp_ui, tmp_uf, 6), mfptoa(t.l_ui, t.l_uf, 6));
if (debug > 3)
- fprintf(df, "\t(gps: %lu)", gpstime);
+ fprintf(df, "\t(gps: %lu)", (u_long)gpstime);
if (leapsec != 0)
fprintf(df, "\t(leap sec %+d)", leapsec);
if (!valid)
@@ -1024,7 +1023,7 @@ mx4200_process(mx4200)
*/
static void
mx4200_control(unit, in, out)
- u_int unit;
+ int unit;
struct refclockstat *in;
struct refclockstat *out;
{
@@ -1038,40 +1037,30 @@ mx4200_control(unit, in, out)
if (in != 0) {
if (in->haveflags & CLK_HAVETIME1)
fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- mx4200 = mx4200units[unit];
- peer = mx4200->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- MX4200REFID, 4);
- else
- peer->refid = htonl(MX4200HSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = mx4200units[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
}
}
if (out != 0) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
out->type = REFCLK_GPS_MX4200;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 |
+ CLK_HAVEFLAG1;
out->clockdesc = MX4200DESCRIPTION;
out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
+ out->fudgeval2 = refid[unit];;
out->flags = sloppyclockflag[unit];
if (unitinuse[unit]) {
mx4200 = mx4200units[unit];
@@ -1085,13 +1074,6 @@ mx4200_control(unit, in, out)
out->badformat = mx4200->badformat;
out->baddata = mx4200->baddata;
out->timereset = current_time - mx4200->timestarted;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
}
}
}
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_datum.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_datum.c
new file mode 100644
index 000000000000..2ce53a7d2c43
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_datum.c
@@ -0,0 +1,593 @@
+/*
+ * refclock_datum.c - clock driver for the Datum/Bancomm
+ * bc635VME Time and Frequency Processor.
+ * R. Schmidt, Time Service, US Naval Obs. May 94
+ * modelled after the TPRO NTP driver.
+ *
+ * This requires the Datum HP-UX V9.01 kernel driver and the HP-UX vme2
+ * driver subsystem. It has been tested on an HP9000/747i at HP-UX 9.03.
+ * There are no restrictions on release and use of the following code.
+ * The refclock type has been defined as 16.
+ */
+#if defined(REFCLOCK) && defined(DATUM)
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "/etc/conf/machine/vme2.h"
+#include "/etc/conf/h/io.h"
+#include "ntp_datum.h"
+#include "ntp_stdlib.h"
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 1 /* max number of VME units */
+#define BMAX 50 /* timecode buffer length */
+
+/*
+ * VME interface parameters. The "IRIG" can be changed to "GPS" for the
+ * VME-GPS.
+ */
+#define VMEPRECISION (-21) /* precision assumed (1 us) */
+#define VMEREFID "IRIG" /* reference id */
+#define VMEDESCRIPTION "Datum/ VME IRIG-B Reader" /* who we are */
+#define VMEHSREFID 0x7f7f1000 /* 127.127.16.00 refid hi strata */
+#define GMT 0 /* hour offset from Greenwich */
+
+/*
+ * Imported from ntp_timer module
+ */
+extern u_long current_time; /* current time (s) */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * VME unit control structure.
+ */
+struct vmeunit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ struct vmedate vmedata; /* data returned from vme read */
+ l_fp lastrec; /* last local time */
+ l_fp lastref; /* last timecode time */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short lencode; /* length of last timecode */
+ u_long lasttime; /* last time clock heard from */
+ u_short unit; /* unit number for this guy */
+ u_short status; /* clock status */
+ u_short lastevent; /* last clock event */
+ u_short year; /* year of eternity */
+ u_short day; /* day of year */
+ u_short hour; /* hour of day */
+ u_short minute; /* minute of hour */
+ u_short second; /* seconds of minute */
+ u_long usec; /* microsecond of second */
+ u_long yearstart; /* start of current year */
+ u_short leap; /* leap indicators */
+ /*
+ * Status tallies
+ */
+ u_long polls; /* polls sent */
+ u_long noreply; /* no replies to polls */
+ u_long coderecv; /* timecodes received */
+ u_long badformat; /* bad format */
+ u_long baddata; /* bad data */
+ u_long timestarted; /* time we started this */
+};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct vmeunit *vmeunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void vme_init P(());
+static int vme_start P((u_int, struct peer *));
+static void vme_shutdown P((int));
+static void vme_report_event P((struct vmeunit *, int));
+static void vme_receive P((struct recvbuf *));
+static void vme_poll P((int unit, struct peer *));
+static void vme_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void vme_buginfo P((int, struct refclockbug *));
+struct vmedate *get_datumtime();
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_vme = {
+ vme_start, vme_shutdown, vme_poll,
+ vme_control, vme_init, vme_buginfo, NOFLAGS
+};
+
+int fd_vme; /* file descriptor for ioctls */
+int regvalue;
+
+/*
+ * vme_init - initialize internal vme driver data
+ */
+static void
+vme_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ /*
+ bzero((char *)vmeunits, sizeof vmeunits);
+ bzero((char *)unitinuse, sizeof unitinuse);
+ */
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
+/*
+ * vme_start - open the VME device and initialize data for processing
+ */
+static int
+vme_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct vmeunit *vme;
+ register int i;
+ int dummy;
+ char vmedev[20];
+
+ /*
+ * Check configuration info.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "vme_start: unit %d invalid", unit);
+ return (0);
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "vme_start: unit %d in use", unit);
+ return (0);
+ }
+
+ /*
+ * Open VME device
+ */
+
+ if ( (fd_vme = open(VMEFD, O_RDWR)) < 0) {
+ syslog(LOG_ERR, "vme_start: failed open of %s: %m", vmedev);
+ return (0);
+ }
+ else { /* Release capture lockout in case it was set from before. */
+ if( ioctl( fd_vme, RUNLOCK, &dummy ) )
+ syslog(LOG_ERR, "vme_start: RUNLOCK failed %m");
+
+ regvalue = 0; /* More esoteric stuff to do... */
+ if( ioctl( fd_vme, WCR0, &regvalue ) )
+ syslog(LOG_ERR, "vme_start: WCR0 failed %m");
+ }
+
+ /*
+ * Allocate unit structure
+ */
+ if (vmeunits[unit] != 0) {
+ vme = vmeunits[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && vmeunits[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ vme = vmeunits[i];
+ vmeunits[i] = 0;
+ } else {
+ vme = (struct vmeunit *)
+ emalloc(sizeof(struct vmeunit));
+ }
+ }
+ bzero((char *)vme, sizeof(struct vmeunit));
+ vmeunits[unit] = vme;
+
+ /*
+ * Set up the structures
+ */
+ vme->peer = peer;
+ vme->unit = (u_short)unit;
+ vme->timestarted = current_time;
+
+ vme->io.clock_recv = vme_receive;
+ vme->io.srcclock = (caddr_t)vme;
+ vme->io.datalen = 0;
+ vme->io.fd = fd_vme;
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
+ */
+ peer->precision = VMEPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(VMEREFID, (char *)&peer->refid, 4);
+ else
+ peer->refid = htonl(VMEHSREFID);
+ unitinuse[unit] = 1;
+ return (1);
+}
+
+
+/*
+ * vme_shutdown - shut down a VME clock
+ */
+static void
+vme_shutdown(unit)
+ int unit;
+{
+ register struct vmeunit *vme;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "vme_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "vme_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ vme = vmeunits[unit];
+ io_closeclock(&vme->io);
+ unitinuse[unit] = 0;
+}
+
+/*
+ * vme_report_event - note the occurance of an event
+ *
+ * This routine presently just remembers the report and logs it, but
+ * does nothing heroic for the trap handler.
+ */
+static void
+vme_report_event(vme, code)
+ struct vmeunit *vme;
+ int code;
+{
+ struct peer *peer;
+
+ peer = vme->peer;
+ if (vme->status != (u_short)code) {
+ vme->status = (u_short)code;
+ if (code != CEVNT_NOMINAL)
+ vme->lastevent = (u_short)code;
+ syslog(LOG_INFO,
+ "clock %s event %x", ntoa(&peer->srcadr), code);
+ }
+}
+
+
+/*
+ * vme_receive - receive data from the VME device.
+ *
+ * Note: This interface would be interrupt-driven. We don't use that
+ * now, but include a dummy routine for possible future adventures.
+ */
+static void
+vme_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+}
+
+/*
+ * vme_poll - called by the transmit procedure
+ */
+static void
+vme_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct vmedate *tptr;
+ struct vmeunit *vme;
+ l_fp tstmp;
+ time_t tloc;
+ struct tm *tadr;
+
+
+ vme = (struct vmeunit *)emalloc(sizeof(struct vmeunit *));
+ tptr = (struct vmedate *)emalloc(sizeof(struct vmedate *));
+
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "vme_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "vme_poll: unit %d not in use", unit);
+ return;
+ }
+ vme = vmeunits[unit]; /* Here is the structure */
+ vme->polls++;
+
+ tptr = &vme->vmedata;
+ if ((tptr = get_datumtime()) == NULL ) {
+ vme_report_event(vme, CEVNT_BADREPLY);
+ return;
+ }
+
+ gettstamp(&vme->lastrec);
+ vme->lasttime = current_time;
+
+ /*
+ * Get VME time and convert to timestamp format.
+ * The year must come from the system clock.
+ */
+
+ time(&tloc);
+ tadr = gmtime(&tloc);
+ tptr->year = (unsigned short)(tadr->tm_year + 1900);
+
+ sprintf(vme->lastcode,
+ "%3.3d %2.2d:%2.2d:%2.2d.%.6d %1d\0",
+ tptr->doy, tptr->hr, tptr->mn,
+ tptr->sec, tptr->frac, tptr->status);
+
+ record_clock_stats(&(vme->peer->srcadr), vme->lastcode);
+ vme->lencode = (u_short) strlen(vme->lastcode);
+
+ vme->day = tptr->doy;
+ vme->hour = tptr->hr;
+ vme->minute = tptr->mn;
+ vme->second = tptr->sec;
+ vme->usec = tptr->frac;
+
+#ifdef DEBUG
+ if (debug)
+ printf("vme: %3d %02d:%02d:%02d.%06ld %1x\n",
+ vme->day, vme->hour, vme->minute, vme->second,
+ vme->usec, tptr->status);
+#endif
+ if (tptr->status ) { /* Status 0 is locked to ref., 1 is not */
+ vme_report_event(vme, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the seconds and the millisecond field for the
+ * fraction when present. If an error in conversion to internal
+ * format is found, the program declares bad data and exits.
+ * Note that this code does not yet know how to do the years and
+ * relies on the clock-calendar chip for sanity.
+ */
+ if (!clocktime(vme->day, vme->hour, vme->minute,
+ vme->second, GMT, vme->lastrec.l_ui,
+ &vme->yearstart, &vme->lastref.l_ui)) {
+ vme->baddata++;
+ vme_report_event(vme, CEVNT_BADTIME);
+ syslog(LOG_ERR, "refclock_datum: bad data!!");
+ return;
+ }
+ TVUTOTSF(vme->usec, vme->lastref.l_uf);
+ tstmp = vme->lastref;
+
+ L_SUB(&tstmp, &vme->lastrec);
+ vme->coderecv++;
+
+ L_ADD(&tstmp, &(fudgefactor[vme->unit]));
+
+ refclock_receive(vme->peer, &tstmp, GMT, 0,
+ &vme->lastrec, &vme->lastrec, vme->leap);
+}
+
+/*
+ * vme_control - set fudge factors, return statistics
+ */
+static void
+vme_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct vmeunit *vme;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "vme_control: unit %d invalid)", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ /*
+ * Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ vme = vmeunits[unit];
+ peer = vme->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(VMEREFID, (char *)&peer->refid,
+ 4);
+ else
+ peer->refid = htonl(VMEHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ }
+
+ if (out != 0) {
+/* out->type = REFCLK_IRIG_VME; */
+ out->type = 16; /* made up by RES */
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
+ out->clockdesc = VMEDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ vme = vmeunits[unit];
+ out->lencode = vme->lencode;
+ out->lastcode = vme->lastcode;
+ out->timereset = current_time - vme->timestarted;
+ out->polls = vme->polls;
+ out->noresponse = vme->noreply;
+ out->badformat = vme->badformat;
+ out->baddata = vme->baddata;
+ out->lastevent = vme->lastevent;
+ out->currentstatus = vme->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+/*
+ * vme_buginfo - return clock dependent debugging info
+ */
+static void
+vme_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct vmeunit *vme;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "vme_buginfo: unit %d invalid)", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ vme = vmeunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (vme->lasttime != 0)
+ bug->values[0] = current_time - vme->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[2] = (u_long)vme->year;
+ bug->values[3] = (u_long)vme->day;
+ bug->values[4] = (u_long)vme->hour;
+ bug->values[5] = (u_long)vme->minute;
+ bug->values[6] = (u_long)vme->second;
+ bug->values[7] = (u_long)vme->usec;
+ bug->values[9] = vme->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = vme->lastref;
+ bug->times[1] = vme->lastrec;
+}
+
+struct vmedate *get_datumtime()
+{
+ unsigned short status;
+ char cbuf[7];
+ struct vmedate *time_vme;
+ struct btfp_time vts;
+ time_vme = (struct vmedate *)malloc(sizeof(struct vmedate ));
+
+ if( ioctl(fd_vme, READTIME, &vts))
+ syslog(LOG_ERR, "get_datumtime error: %m");
+
+/* sprintf converts BCD to ASCII */
+/* Get doy */
+ sprintf(cbuf,"%3.3x\0", ((vts.btfp_time[ 0 ] & 0x000f) <<8) +
+ ((vts.btfp_time[ 1 ] & 0xff00) >> 8));
+
+ if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2]) )
+ time_vme->doy = (unsigned short)atoi(cbuf);
+ else
+ time_vme->doy = (unsigned short) 0;
+
+/* Get hour */
+ sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 1 ] & 0x00ff);
+
+ if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
+ time_vme->hr = (unsigned short)atoi(cbuf);
+ else
+ time_vme->hr = (unsigned short) 0;
+
+/* Get minutes */
+ sprintf(cbuf,"%2.2x\0", (vts.btfp_time[ 2 ] & 0xff00) >>8);
+ if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
+ time_vme->mn = (unsigned short)atoi(cbuf);
+ else
+ time_vme->mn = (unsigned short) 0;
+
+/* Get seconds */
+ sprintf(cbuf,"%2.2x\0", vts.btfp_time[ 2 ] & 0x00ff);
+
+ if (isdigit(cbuf[0]) && isdigit(cbuf[1]))
+ time_vme->sec = (unsigned short)atoi(cbuf);
+ else
+ time_vme->sec = (unsigned short) 0;
+
+/* Get microseconds. Yes, we ignore the 0.1 microsecond digit so we can
+use the TVTOTSF function later on...*/
+
+ sprintf(cbuf,"%4.4x%2.2x\0", vts.btfp_time[ 3 ],
+ vts.btfp_time[ 4 ]>>8);
+
+ if (isdigit(cbuf[0]) && isdigit(cbuf[1]) && isdigit(cbuf[2])
+ && isdigit(cbuf[3]) && isdigit(cbuf[4]) && isdigit(cbuf[5]))
+ time_vme->frac = (u_long) atoi(cbuf);
+ else
+ time_vme->frac = (u_long) 0;
+
+/* Get status bit */
+ status = (vts.btfp_time[0] & 0x0010) >>4;
+ time_vme->status = status; /* Status=0 if locked to ref. */
+ /* Status=1 if flywheeling */
+ if (status) { /* lost lock ? */
+ return ((void *)NULL);
+ }
+ else
+ return (time_vme);
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_gpstm.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_gpstm.c
new file mode 100644
index 000000000000..deab7f46ef6b
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_gpstm.c
@@ -0,0 +1,999 @@
+/*
+ * refclock_gpstm - clock driver for the Kinimetrics Truetime GPSTM/TMD rcvr
+ * Version 1.0 (from Version 2.0 of the GOES driver, as of 03Jan94)
+ */
+
+#if defined(REFCLOCK) && (defined(GPSTM) || defined(GPSTMCLK) \
+ || defined(GPSTMPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#ifdef SYS_BSDI
+#undef HAVE_BSD_TTYS
+#include <sys/ioctl.h>
+#endif
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(GPSTMCLK)
+#include <clkdefs.h>
+#endif /* GPSTMCLK */
+#endif /* STREAM */
+
+#if defined(GPSTMPPS)
+#include <sys/ppsclock.h>
+#endif /* GPSTMPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Support for Kinemetrics Truetime GPS-TM/TMD Receiver
+ *
+ * Most of this code is copied from refclock_goes.c with thanks.
+ *
+ * the time code looks like follows:
+ *
+ * ADDD:HH:MM:SSQCL
+ * A - control A
+ * Q Quality indication: indicates possible error of
+ * ? +/- 500 milliseconds # +/- 50 milliseconds
+ * * +/- 5 milliseconds . +/- 1 millisecond
+ * space less than 1 millisecond
+ * C - Carriage return
+ * L - Line feed
+ * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ *
+ * Flag1 set to 1 will silence the clock side of xntpd, just reading the
+ * clock without trying to write to it. This is usefull if several
+ * xntpds listen to the same clock. This has not been tested yet...
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* max number of GPSTM units */
+#define GPSTM232 "/dev/gpstm%d"
+#define SPEED232 B9600 /* 9600 baud */
+
+/*
+ * Radio interface parameters
+ */
+#define MAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
+#define PRECISION (-20) /* precision assumed (about 1 ms) */
+#define REFID "GPS\0" /* reference id */
+#define DESCRIPTION "Kinemetrics GPS-TM/TMD Receiver" /* who we are */
+#define GMT 0 /* hour offset from Greenwich */
+#define NCODES 3 /* stages of median filter */
+#define BMAX 99 /* timecode buffer length */
+#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define TIMEOUT 180 /* ping the clock if it's silent this long */
+
+/*
+ * used by the state machine
+ */
+enum gpstm_event {e_Init, e_F18, e_F50, e_F51, e_TS};
+static enum {Base, Start, F18, F50, F51, F08} State[MAXUNITS];
+static void gpstm_doevent P((int, enum gpstm_event));
+static void gpstm_initstate P((int));
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+
+/*
+ * Imported from the timer module
+ */
+extern u_long current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * GPSTM unit control structure
+ */
+struct gpstm_unit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NCODES]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short polled; /* Hand in a time sample? */
+ u_char lencode; /* length of last timecode */
+ u_long lasttime; /* last time clock heard from */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ u_short msec; /* millisecond of second */
+ u_char quality; /* quality character */
+ u_long yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ u_long polls; /* polls sent */
+ u_long noreply; /* no replies to polls */
+ u_long coderecv; /* timecodes received */
+ u_long badformat; /* bad format */
+ u_long baddata; /* bad data */
+ u_long timestarted; /* time we started this */
+};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct gpstm_unit *gpstm_units[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor1[MAXUNITS];
+static l_fp fudgefactor2[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char readonlyclockflag[MAXUNITS];
+static u_long refid[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void gpstm_init P((void));
+static int gpstm_start P((u_int, struct peer *));
+static void gpstm_shutdown P((int));
+static void gpstm_rep_event P((struct gpstm_unit *, int));
+static void gpstm_receive P((struct recvbuf *));
+static char gpstm_process P((struct gpstm_unit *, l_fp *, u_fp *));
+static void gpstm_poll P((int, struct peer *));
+static void gpstm_control P((u_int, struct refclockstat *,
+ struct refclockstat *));
+static void gpstm_buginfo P((int, struct refclockbug *));
+static void gpstm_send P((struct gpstm_unit *, char *));
+
+struct refclock refclock_gpstm = {
+ gpstm_start, gpstm_shutdown, gpstm_poll,
+ gpstm_control, gpstm_init, gpstm_buginfo, NOFLAGS
+};
+
+/*
+ * gpstm_init - initialize internal driver data
+ */
+static void
+gpstm_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)gpstm_units, 0, sizeof gpstm_units);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor1[i].l_ui = 0;
+ fudgefactor1[i].l_uf = 0;
+ fudgefactor2[i].l_ui = 0;
+ fudgefactor2[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], REFID, 4);
+ }
+}
+
+
+/*
+ * gpstm_start - open the device and initialize data for processing
+ */
+static int
+gpstm_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct gpstm_unit *gpstm;
+ register int i;
+ int fd232;
+ char dev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_start: unit %d invalid", unit);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_start: unit %d in use", unit);
+ return 0;
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(dev, GPSTM232, unit);
+ fd232 = open(dev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "gpstm_start: open of %s: %m", dev);
+ return 0;
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TCGETA): %m", dev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TCSETA): %m", dev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The GPSTMPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+ ttyp = &ttyb;
+
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcgetattr(%s): %m", dev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcsetattr(%s): %m", dev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcflush(%s): %m", dev);
+ goto screwed;
+ }
+#if defined(STREAM)
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, clk): %m", dev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, CLK_SETSTR): %m", dev);
+#endif /* GPSTMCLK */
+#if defined(GPSTMPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, ppsclock): %m", dev);
+ else
+ fdpps = fd232;
+#endif /* GPSTMPPS */
+#endif /* STREAM */
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(GPSTMCLK)
+ int ldisc = CLKLDISC;
+#endif /* GPSTMCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCGETP): %m", dev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(GPSTMCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* GPSTMCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETP): %m", dev);
+ goto screwed;
+ }
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETD): %m", dev);
+ goto screwed;
+ }
+#endif /* GPSTMCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (gpstm_units[unit] != 0) {
+ gpstm = gpstm_units[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && gpstm_units[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ gpstm = gpstm_units[i];
+ gpstm_units[i] = 0;
+ } else {
+ gpstm = (struct gpstm_unit *)
+ emalloc(sizeof(struct gpstm_unit));
+ }
+ }
+ memset((char *)gpstm, 0, sizeof(struct gpstm_unit));
+ gpstm_units[unit] = gpstm;
+
+ /*
+ * Set up the structures
+ */
+ gpstm->peer = peer;
+ gpstm->unit = (u_char)unit;
+ gpstm->timestarted = current_time;
+
+ gpstm->io.clock_recv = gpstm_receive;
+ gpstm->io.srcclock = (caddr_t)gpstm;
+ gpstm->io.datalen = 0;
+ gpstm->io.fd = fd232;
+ if (!io_addclock(&gpstm->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = PRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ gpstm_initstate(unit);
+ return 1;
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return 0;
+}
+
+/*
+ * gpstm_shutdown - shut down a clock
+ */
+static void
+gpstm_shutdown(unit)
+ int unit;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ gpstm = gpstm_units[unit];
+ io_closeclock(&gpstm->io);
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * gpstm_rep_event - note the occurance of an event
+ */
+static void
+gpstm_rep_event(gpstm, code)
+ struct gpstm_unit *gpstm;
+ int code;
+{
+ struct peer *peer;
+
+ peer = gpstm->peer;
+ if (gpstm->status != (u_char)code) {
+ gpstm->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ gpstm->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "clock %s event %x\n", ntoa(&peer->srcadr), code);
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_rep_event(gpstm%d, code %d)\n",
+ gpstm->unit, code);
+ }
+#endif
+ }
+ if (code == CEVNT_BADREPLY)
+ gpstm_initstate(gpstm->unit);
+}
+
+
+/*
+ * gpstm_receive - receive data from the serial interface on a clock
+ */
+static void
+gpstm_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i;
+ register struct gpstm_unit *gpstm;
+ register u_char *dpt;
+ register char *cp;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion;
+
+ /*
+ * Get the clock this applies to and a pointers to the data
+ */
+ gpstm = (struct gpstm_unit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+
+ /*
+ * Edit timecode to remove control chars
+ */
+ dpend = dpt + rbufp->recv_length;
+ cp = gpstm->lastcode;
+ while (dpt < dpend) {
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#ifdef GPSTMCLK
+ else if (*cp == '\r') {
+ if (dpend - dpt < 8) {
+ /* short timestamp */
+ return;
+ }
+ if (!buftvtots(dpt,&gpstm->lastrec)) {
+ /* screwy timestamp */
+ return;
+ }
+ dpt += 8;
+ }
+#endif
+ }
+ *cp = '\0';
+ gpstm->lencode = cp - gpstm->lastcode;
+ if (gpstm->lencode == 0)
+ return;
+#ifndef GPSTMCLK
+ gpstm->lastrec = rbufp->recv_time;
+#endif /* GPSTMCLK */
+#if !defined(GPSTMCLK) && !defined(GPSTMPPS) && defined(TIOCMODT)
+ do {
+ auto struct timeval cur, now;
+ register long usec;
+
+ if (ioctl(gpstm->io.fd, TIOCMODT, &cur) < 0) {
+ syslog(LOG_ERR, "TIOCMODT: %m");
+#ifdef DEBUG
+ if (debug) perror("TIOCMODT");
+ break;
+#endif
+ }
+ if (cur.tv_sec == 0) {
+ /* no timestamps yet */
+ if (debug) printf("MODT tv_sec == 0\n");
+ break;
+ }
+
+ gettimeofday(&now, NULL);
+ usec = 1000000 * (now.tv_sec - cur.tv_sec)
+ + (now.tv_usec - cur.tv_usec);
+#ifdef DEBUG
+ if (debug) printf("lastmodem: delay=%d us\n", usec);
+#endif
+ if (usec < 0 || usec > 10000) {
+ /* time warp or stale timestamp */
+ break;
+ }
+ if (!buftvtots((char *)&cur, &gpstm->lastrec)) {
+ /* screwy timestamp */
+ break;
+ }
+ } while (0);
+#endif /*TIOCMODT*/
+
+#ifdef DEBUG
+ if (debug)
+ printf("gpstm: timecode %d %s\n",
+ gpstm->lencode, gpstm->lastcode);
+#endif
+
+ cp = gpstm->lastcode;
+ gpstm->leap = 0;
+ if ((cp[0] == 'F' && isdigit(cp[1]) && isdigit(cp[2]))
+ || (cp[0] == ' ' && cp[1] == 'T' && cp[2] == 'R')) {
+ enum gpstm_event event;
+
+ syslog(LOG_NOTICE, "gpstm%d: \"%s\"", gpstm->unit, cp);
+ if (cp[1] == '5' && cp[2] == '0')
+ event = e_F50;
+ else if (cp[1] == '5' && cp[2] == '1')
+ event = e_F51;
+ else if (!strncmp(" TRUETIME Mk III", cp, 16))
+ event = e_F18;
+ else {
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, event);
+ return;
+ } else if (gpstm->lencode == 13) {
+ /*
+ * Check timecode format 0
+ */
+ if (!isdigit(cp[0]) /* day of year */
+ || !isdigit(cp[1])
+ || !isdigit(cp[2])
+ || cp[3] != ':' /* : separator */
+ || !isdigit(cp[4]) /* hours */
+ || !isdigit(cp[5])
+ || cp[6] != ':' /* : separator */
+ || !isdigit(cp[7]) /* minutes */
+ || !isdigit(cp[8])
+ || cp[9] != ':' /* : separator */
+ || !isdigit(cp[10]) /* seconds */
+ || !isdigit(cp[11]))
+ {
+ gpstm->badformat++;
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Convert format 0 and check values
+ */
+ gpstm->year = 0; /* fake */
+ gpstm->day = cp[0] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[1] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[2] - '0';
+ gpstm->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ gpstm->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ gpstm->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ gpstm->msec = 0;
+
+ if (cp[12] != ' ' && cp[12] != '.' && cp[12] != '*')
+ gpstm->leap = LEAP_NOTINSYNC;
+ else
+ gpstm->lasttime = current_time;
+
+ if (gpstm->day < 1 || gpstm->day > 366) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADDATE);
+ return;
+ }
+ if (gpstm->hour > 23 || gpstm->minute > 59
+ || gpstm->second > 59) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, e_TS);
+ } else {
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * The clock will blurt a timecode every second but we only
+ * want one when polled. If we havn't been polled, bail out.
+ */
+ if (!gpstm->polled)
+ return;
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the seconds and the millisecond field for the
+ * fraction when present.
+ *
+ * this code does not yet know how to do the years
+ */
+ tstmp = gpstm->lastrec;
+ if (!clocktime(gpstm->day, gpstm->hour, gpstm->minute,
+ gpstm->second, GMT, tstmp.l_ui,
+ &gpstm->yearstart, &gpstm->lastref.l_ui))
+ {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(gpstm->msec, gpstm->lastref.l_uf);
+
+ i = ((int)(gpstm->coderecv)) % NCODES;
+ gpstm->offset[i] = gpstm->lastref;
+ L_SUB(&gpstm->offset[i], &tstmp);
+ if (gpstm->coderecv == 0)
+ for (i = 1; i < NCODES; i++)
+ gpstm->offset[i] = gpstm->offset[0];
+
+ gpstm->coderecv++;
+
+ /*
+ * Process the median filter, and pass the
+ * offset and dispersion along. We use lastrec as both the
+ * reference time and receive time in order to avoid being cute,
+ * like setting the reference time later than the receive time,
+ * which may cause a paranoid protocol module to chuck out the
+ * data.
+ */
+ if (!gpstm_process(gpstm, &tstmp, &dispersion)) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(gpstm->peer, &tstmp, GMT, dispersion,
+ &gpstm->lastrec, &gpstm->lastrec, gpstm->leap);
+
+ /*
+ * We have succedded in answering the poll. Turn off the flag
+ */
+ gpstm->polled = 0;
+}
+
+/*
+ * gpstm_send - time to send the clock a signal to cough up a time sample
+ */
+static void
+gpstm_send(gpstm, cmd)
+ struct gpstm_unit *gpstm;
+ char *cmd;
+{
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_send(gpstm%d): %s\n", gpstm->unit, cmd);
+ }
+#endif
+ if (!readonlyclockflag[gpstm->unit]) {
+ register int len = strlen(cmd);
+
+ if (write(gpstm->io.fd, cmd, len) != len) {
+ syslog(LOG_ERR, "gpstm_send: unit %d: %m",
+ gpstm->unit);
+ gpstm_rep_event(gpstm, CEVNT_FAULT);
+ }
+ }
+}
+
+/*
+ * state machine for initializing the clock
+ */
+
+static void
+gpstm_doevent(unit, event)
+ int unit;
+ enum gpstm_event event;
+{
+ struct gpstm_unit *gpstm = gpstm_units[unit];
+
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_doevent(gpstm%d, %d)\n", unit, (int)event);
+ }
+#endif
+ if (event == e_TS && State[unit] != F51 && State[unit] != F08) {
+ gpstm_send(gpstm, "\03\r");
+ }
+
+ switch (event) {
+ case e_Init:
+ gpstm_send(gpstm, "F18\r");
+ State[unit] = Start;
+ break;
+ case e_F18:
+ gpstm_send(gpstm, "F50\r");
+ State[unit] = F18;
+ break;
+ case e_F50:
+ gpstm_send(gpstm, "F51\r");
+ State[unit] = F50;
+ break;
+ case e_F51:
+ gpstm_send(gpstm, "F08\r");
+ State[unit] = F51;
+ break;
+ case e_TS:
+ /* nothing to send - we like this mode */
+ State[unit] = F08;
+ break;
+ }
+}
+
+static void
+gpstm_initstate(unit)
+ int unit;
+{
+ State[unit] = Base; /* just in case */
+ gpstm_doevent(unit, e_Init);
+}
+
+/*
+ * gpstm_process - process a pile of samples from the clock
+ */
+static char
+gpstm_process(gpstm, offset, dispersion)
+ struct gpstm_unit *gpstm;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, j;
+ register u_long tmp_ui, tmp_uf;
+ int not_median1 = -1; /* XXX correct? */
+ int not_median2 = -1; /* XXX correct? */
+ int median;
+ u_fp disp_tmp, disp_tmp2;
+
+ /*
+ * This code implements a three-stage median filter. First, we
+ * check if the samples are within 125 ms of each other. If not,
+ * dump the sample set. We take the median of the three offsets
+ * and use that as the sample offset. We take the maximum
+ * difference and use that as the sample dispersion. There
+ * probably is not much to be gained by a longer filter, since
+ * the clock filter in ntp_proto should do its thing.
+ */
+ disp_tmp2 = 0;
+ for (i = 0; i < NCODES-1; i++) {
+ for (j = i+1; j < NCODES; j++) {
+ tmp_ui = gpstm->offset[i].l_ui;
+ tmp_uf = gpstm->offset[i].l_uf;
+ M_SUB(tmp_ui, tmp_uf, gpstm->offset[j].l_ui,
+ gpstm->offset[j].l_uf);
+ if (M_ISNEG(tmp_ui, tmp_uf)) {
+ M_NEG(tmp_ui, tmp_uf);
+ }
+ if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
+ return 0;
+ }
+ disp_tmp = MFPTOFP(0, tmp_uf);
+ if (disp_tmp > disp_tmp2) {
+ disp_tmp2 = disp_tmp;
+ not_median1 = i;
+ not_median2 = j;
+ }
+ }
+ }
+
+ /*
+ * It seems as if all are within 125 ms of each other.
+ * Now to determine the median of the three. Whlie the
+ * 125 ms check was going on, we also subtly catch the
+ * dispersion and set-up for a very easy median calculation.
+ * The largest difference between any two samples constitutes
+ * the dispersion. The sample not involve in the dispersion is
+ * the median sample. EASY!
+ */
+ if (gpstm->lasttime == 0 || disp_tmp2 > MAXDISPERSE)
+ disp_tmp2 = MAXDISPERSE;
+ if (not_median1 == 0) {
+ if (not_median2 == 1)
+ median = 2;
+ else
+ median = 1;
+ } else {
+ median = 0;
+ }
+ *offset = gpstm->offset[median];
+ *dispersion = disp_tmp2;
+ return 1;
+}
+
+/*
+ * gpstm_poll - called by the transmit procedure
+ */
+static void
+gpstm_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct gpstm_unit *gpstm;
+
+ /*
+ * You don't need to poll this clock. It puts out timecodes
+ * once per second. If asked for a timestamp, take note.
+ * The next time a timecode comes in, it will be fed back.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_poll: unit %d not in use", unit);
+ return;
+ }
+ gpstm = gpstm_units[unit];
+ if ((current_time - gpstm->lasttime) > 150) {
+ gpstm->noreply++;
+ gpstm_rep_event(gpstm_units[unit], CEVNT_TIMEOUT);
+ gpstm_initstate(gpstm->unit);
+ }
+
+ /*
+ * polled every 64 seconds. Ask our receiver to hand in a timestamp.
+ */
+ gpstm->polled = 1;
+ gpstm->polls++;
+}
+
+/*
+ * gpstm_control - set fudge factors, return statistics
+ */
+static void
+gpstm_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor1[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ fudgefactor2[unit] = in->fudgetime2;
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = gpstm_units[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out != 0) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
+ out->type = REFCLK_GPSTM_TRUETIME;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2 | CLK_HAVEFLAG1;
+ out->clockdesc = DESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ gpstm = gpstm_units[unit];
+ out->lencode = gpstm->lencode;
+ out->lastcode = gpstm->lastcode;
+ out->timereset = current_time - gpstm->timestarted;
+ out->polls = gpstm->polls;
+ out->noresponse = gpstm->noreply;
+ out->badformat = gpstm->badformat;
+ out->baddata = gpstm->baddata;
+ out->lastevent = gpstm->lastevent;
+ out->currentstatus = gpstm->status;
+ }
+ }
+}
+
+/*
+ * gpstm_buginfo - return clock dependent debugging info
+ */
+static void
+gpstm_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gpstm = gpstm_units[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (gpstm->lasttime != 0)
+ bug->values[0] = current_time - gpstm->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = gpstm->reason;
+ bug->values[2] = gpstm->year;
+ bug->values[3] = gpstm->day;
+ bug->values[4] = gpstm->hour;
+ bug->values[5] = gpstm->minute;
+ bug->values[6] = gpstm->second;
+ bug->values[7] = gpstm->msec;
+ bug->values[8] = gpstm->noreply;
+ bug->values[9] = gpstm->yearstart;
+ bug->values[10] = gpstm->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = gpstm->lastref;
+ bug->times[1] = gpstm->lastrec;
+ bug->times[2] = gpstm->offset[0];
+ bug->times[3] = gpstm->offset[1];
+ bug->times[4] = gpstm->offset[2];
+}
+
+#endif /*GPSTM et al*/
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_leitch.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_leitch.c
new file mode 100644
index 000000000000..b2a0e7fa76bf
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_leitch.c
@@ -0,0 +1,718 @@
+/*
+ * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock
+ */
+#if defined(REFCLOCK) && (defined(LEITCH) || defined(LEITCHCLK) || defined(LEITCHPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#ifdef STREAM
+#include <stropts.h>
+#if defined(LEITCHCLK)
+#include <sys/clkdefs.h>
+#endif /* LEITCHCLK */
+#endif /* STREAM */
+
+#if defined (LEITCHPPS)
+#include <sys/ppsclock.h>
+#endif /* LEITCHPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Driver for Leitch CSD-5300 Master Clock System
+ *
+ * COMMANDS:
+ * DATE: D <CR>
+ * TIME: T <CR>
+ * STATUS: S <CR>
+ * LOOP: L <CR>
+ *
+ * FORMAT:
+ * DATE: YYMMDD<CR>
+ * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/
+ * second bondaried on the stop bit of the <CR>
+ * second boundaries at '/' above.
+ * STATUS: G (good), D (diag fail), T (time not provided) or
+ * P (last phone update failed)
+ */
+#define MAXUNITS 1 /* max number of LEITCH units */
+#define LEITCHREFID "ATOM" /* reference id */
+#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
+#define LEITCH232 "/dev/leitch%d" /* name of radio device */
+#define SPEED232 B300 /* uart speed (300 baud) */
+#define leitch_send(A,M) \
+ if (debug) fprintf(stderr,"write leitch %s\n",M); \
+ if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
+ if (debug) \
+ fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \
+ else \
+ syslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
+
+#define STATE_IDLE 0
+#define STATE_DATE 1
+#define STATE_TIME1 2
+#define STATE_TIME2 3
+#define STATE_TIME3 4
+
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * LEITCH unit control structure
+ */
+struct leitchunit {
+ struct peer *peer;
+ struct event leitchtimer;
+ struct refclockio leitchio;
+ u_char unit;
+ short year;
+ short yearday;
+ short month;
+ short day;
+ short hour;
+ short second;
+ short minute;
+ short state;
+ u_short fudge1;
+ l_fp reftime1;
+ l_fp reftime2;
+ l_fp reftime3;
+ l_fp codetime1;
+ l_fp codetime2;
+ l_fp codetime3;
+ u_long yearstart;
+};
+
+/*
+ * Function prototypes
+ */
+static void leitch_init P((void));
+static int leitch_start P((u_int, struct peer *));
+static void leitch_shutdown P((int));
+static void leitch_poll P((int, struct peer *));
+static void leitch_control P((u_int, struct refclockstat *, struct refclockstat *));
+#define leitch_buginfo noentry
+static void leitch_receive P((struct recvbuf *));
+static void leitch_process P((struct leitchunit *));
+static void leitch_timeout P((struct peer *));
+static int leitch_get_date P((struct recvbuf *, struct leitchunit *));
+static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int));
+static int dysize P((int));
+
+static struct leitchunit leitchunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_long refid[MAXUNITS];
+
+static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_leitch = {
+ leitch_start, leitch_shutdown, leitch_poll,
+ leitch_control, leitch_init, leitch_buginfo, NOFLAGS
+};
+
+/*
+ * leitch_init - initialize internal leitch driver data
+ */
+static void
+leitch_init()
+{
+ int i;
+
+ memset((char*)leitchunits, 0, sizeof(leitchunits));
+ memset((char*)unitinuse, 0, sizeof(unitinuse));
+ for (i = 0; i < MAXUNITS; i++)
+ memcpy((char *)&refid[i], LEITCHREFID, 4);
+}
+
+/*
+ * leitch_shutdown - shut down a LEITCH clock
+ */
+static void
+leitch_shutdown(unit)
+int unit;
+{
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_shutdown()\n");
+#endif
+}
+
+/*
+ * leitch_poll - called by the transmit procedure
+ */
+static void
+leitch_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct leitchunit *leitch;
+
+ /* start the state machine rolling */
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_poll()\n");
+#endif
+ if (unit > MAXUNITS) {
+ /* XXXX syslog it */
+ return;
+ }
+
+ leitch = &leitchunits[unit];
+
+ if (leitch->state != STATE_IDLE) {
+ /* reset and wait for next poll */
+ /* XXXX syslog it */
+ leitch->state = STATE_IDLE;
+ } else {
+ leitch_send(leitch,"D\r");
+ leitch->state = STATE_DATE;
+ }
+}
+
+static void
+leitch_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "leitch_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in) {
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = (&leitchunits[unit])->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
+ out->type = REFCLK_ATOM_LEITCH;
+ out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
+ out->fudgeval1 = stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->lastcode = "";
+ out->clockdesc = LEITCH_DESCRIPTION;
+ }
+}
+
+/*
+ * leitch_start - open the LEITCH devices and initialize data for processing
+ */
+static int
+leitch_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ struct leitchunit *leitch;
+ int fd232;
+ char leitchdev[20];
+
+ /*
+ * Check configuration info.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "leitch_start: unit %d invalid", unit);
+ return (0);
+ }
+
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "leitch_start: unit %d in use", unit);
+ return (0);
+ }
+
+ /*
+ * Open serial port.
+ */
+ (void) sprintf(leitchdev, LEITCH232, unit);
+ fd232 = open(leitchdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR,
+ "leitch_start: open of %s: %m", leitchdev);
+ return (0);
+ }
+
+ leitch = &leitchunits[unit];
+ memset((char*)leitch, 0, sizeof(*leitch));
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TCGETA): %m", leitchdev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TCSETA): %m", leitchdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The LEITCHCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The LEITCHPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcgetattr(%s): %m", leitchdev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcsetattr(%s): %m", leitchdev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcflush(%s): %m", leitchdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);
+#endif /* LEITCHCLK */
+#if defined(LEITCHPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, ppsclock): %m", leitchdev);
+ else
+ fdpps = fd232;
+#endif /* LEITCHPPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The LEITCHCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(LEITCHCLK)
+ int ldisc = CLKLDISC;
+#endif /* LEITCHCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(LEITCHCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* LEITCHCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
+ goto screwed;
+ }
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);
+ goto screwed;
+ }
+#endif /* LEITCHCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Set up the structures
+ */
+ leitch->peer = peer;
+ leitch->unit = unit;
+ leitch->state = STATE_IDLE;
+ leitch->fudge1 = 15; /* 15ms */
+
+ leitch->leitchio.clock_recv = leitch_receive;
+ leitch->leitchio.srcclock = (caddr_t) leitch;
+ leitch->leitchio.datalen = 0;
+ leitch->leitchio.fd = fd232;
+ if (!io_addclock(&leitch->leitchio)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
+ */
+ peer->precision = 0;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ return(1);
+
+ /*
+ * Something broke; abandon ship.
+ */
+screwed:
+ close(fd232);
+ return(0);
+}
+
+/*
+ * leitch_receive - receive data from the serial interface on a leitch
+ * clock
+ */
+static void
+leitch_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_recieve(%*.*s)\n",
+ rbufp->recv_length, rbufp->recv_length,
+ rbufp->recv_buffer);
+#endif
+ if (rbufp->recv_length != 7)
+ return; /* The date is return with a trailing newline,
+ discard it. */
+
+ switch (leitch->state) {
+ case STATE_IDLE: /* unexpected, discard and resync */
+ return;
+ case STATE_DATE:
+ if (!leitch_get_date(rbufp,leitch)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+ leitch_send(leitch,"T\r");
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n",leitch->yearday);
+#endif
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ if (!leitch_get_time(rbufp,leitch,1)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime1.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%lu\n", (u_long)leitch->reftime1.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);
+ leitch->codetime1 = rbufp->recv_time;
+ leitch->state = STATE_TIME2;
+ break;
+ case STATE_TIME2:
+ if (!leitch_get_time(rbufp,leitch,2)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime2.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%lu\n", (u_long)leitch->reftime2.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);
+ leitch->codetime2 = rbufp->recv_time;
+ leitch->state = STATE_TIME3;
+ break;
+ case STATE_TIME3:
+ if (!leitch_get_time(rbufp,leitch,3)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime3.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%lu\n", (u_long)leitch->reftime3.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);
+ leitch->codetime3 = rbufp->recv_time;
+ leitch_process(leitch);
+ leitch->state = STATE_IDLE;
+ break;
+ default:
+ syslog(LOG_ERR,
+ "leitech_receive: invalid state %d unit %d",
+ leitch->state, leitch->unit);
+ }
+}
+
+/*
+ * leitch_process - process a pile of samples from the clock
+ *
+ * This routine uses a three-stage median filter to calculate offset and
+ * dispersion. reduce jitter. The dispersion is calculated as the span
+ * of the filter (max - min), unless the quality character (format 2) is
+ * non-blank, in which case the dispersion is calculated on the basis of
+ * the inherent tolerance of the internal radio oscillator, which is
+ * +-2e-5 according to the radio specifications.
+ */
+static void
+leitch_process(leitch)
+ struct leitchunit *leitch;
+{
+ l_fp off;
+ s_fp delay;
+ l_fp codetime;
+ l_fp tmp_fp;
+ int isinsync = 1;
+ u_fp dispersion = 10;
+
+ delay = 20;
+
+ codetime = leitch->codetime3;
+
+ off = leitch->reftime1;
+ L_SUB(&off,&leitch->codetime1);
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%lu %lu %lu %lu %ld %ld\n",
+ (u_long)leitch->codetime1.l_ui,
+ (u_long)leitch->codetime1.l_uf,
+ (u_long)leitch->reftime1.l_ui,
+ (u_long)leitch->reftime1.l_uf,
+ (u_long)off.l_i,
+ (u_long)off.l_f);
+#endif
+ tmp_fp = leitch->reftime2;
+ L_SUB(&tmp_fp,&leitch->codetime2);
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%lu %lu %lu %lu %ld %ld\n",
+ (u_long)leitch->codetime2.l_ui,
+ (u_long)leitch->codetime2.l_uf,
+ (u_long)leitch->reftime2.l_ui,
+ (u_long)leitch->reftime2.l_uf,
+ (u_long)off.l_i,
+ (u_long)off.l_f);
+#endif
+ tmp_fp = leitch->reftime3;
+ L_SUB(&tmp_fp,&leitch->codetime3);
+
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%lu %lu %lu %lu %ld %ld\n",
+ (u_long)leitch->codetime3.l_ui,
+ (u_long)leitch->codetime3.l_uf,
+ (u_long)leitch->reftime3.l_ui,
+ (u_long)leitch->reftime3.l_uf,
+ (u_long)off.l_i,
+ (u_long)off.l_f);
+#endif
+ refclock_receive(leitch->peer, &off, 0, dispersion, &codetime,
+ &codetime, isinsync);
+}
+
+/*
+ * leitch_timeout
+ */
+static void
+leitch_timeout(fp)
+ struct peer *fp;
+{
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_timeout()\n");
+#endif
+
+#ifdef NOTYET
+ { struct leitchunit *leitch = (struct leitchunit *)fp;
+
+ switch(leitch->state) {
+ case STATE_IDLE:
+ leitch_send(leitch,"D\r");
+ leitch->state = STATE_DATE;
+ break;
+ case STATE_DATE:
+ leitch_send(leitch,"T\r");
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ case STATE_TIME2:
+ case STATE_TIME3:
+ default:
+ break;
+ }
+
+ leitch->leitchtimer.event_time += 30;
+ TIMER_ENQUEUE(timerqueue, &leitch->leitchtimer);
+ }
+#endif /* NOTYET */
+}
+
+/*
+ * dysize
+ */
+static int
+dysize(year)
+int year;
+{
+ if (year%4) { /* not a potential leap year */
+ return (365);
+ } else {
+ if (year % 100) { /* is a leap year */
+ return (366);
+ } else {
+ if (year % 400) {
+ return (365);
+ } else {
+ return (366);
+ }
+ }
+ }
+}
+
+static int
+leitch_get_date(rbufp,leitch)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+{
+ int i;
+
+ if (rbufp->recv_length < 6)
+ return(0);
+#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+#define ATOB(A) ((rbufp->recv_buffer[A])-'0')
+ leitch->year = ATOB(0)*10 + ATOB(1);
+ leitch->month = ATOB(2)*10 + ATOB(3);
+ leitch->day = ATOB(4)*10 + ATOB(5);
+
+ /* sanity checks */
+ if (leitch->month > 12)
+ return(0);
+ if (leitch->day > days_in_month[leitch->month-1])
+ return(0);
+
+ /* calculate yearday */
+ i = 0;
+ leitch->yearday = leitch->day;
+
+ while ( i < (leitch->month-1) )
+ leitch->yearday += days_in_month[i++];
+
+ if ((dysize((leitch->year>90?1900:2000)+leitch->year)==365) &&
+ leitch->month > 2)
+ leitch->yearday--;
+
+ return(1);
+}
+
+/*
+ * leitch_get_time
+ */
+static int
+leitch_get_time(rbufp,leitch,which)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+ int which;
+{
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+ leitch->hour = ATOB(0)*10 +ATOB(1);
+ leitch->minute = ATOB(2)*10 +ATOB(3);
+ leitch->second = ATOB(4)*10 +ATOB(5);
+
+ if ((leitch->hour > 23) || (leitch->minute > 60) ||
+ (leitch->second > 60))
+ return(0);
+ return(1);
+}
+
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c
new file mode 100644
index 000000000000..5a6307c3b6f6
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c
@@ -0,0 +1,1575 @@
+/* refclock_ees - clock driver for the EES M201 receiver */
+
+#if defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM)
+
+/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
+ * were removed as the code was overly hairy, they weren't in use
+ * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk
+ */
+
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+#include <termios.h>
+#include <stropts.h>
+#include <sys/ppsclock.h>
+#include "ntp_stdlib.h"
+
+ /*
+ fudgefactor = fudgetime1;
+ os_delay = fudgetime2;
+ offset_fudge = os_delay + fudgefactor + inherent_delay;
+ stratumtouse = fudgeval1 & 0xf
+ debug = fudgeval2;
+ sloppyclockflag = flags & CLK_FLAG1;
+ 1 log smoothing summary when processing sample
+ 4 dump the buffer from the clock
+ 8 EIOGETKD the last n uS time stamps
+ if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
+ ees->dump_vals = flags & CLK_FLAG3;
+ ees->usealldata = flags & CLK_FLAG4;
+
+
+ bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
+ bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
+ bug->values[2] = ees->status;
+ bug->values[3] = ees->lastevent;
+ bug->values[4] = ees->reason;
+ bug->values[5] = ees->nsamples;
+ bug->values[6] = ees->codestate;
+ bug->values[7] = ees->day;
+ bug->values[8] = ees->hour;
+ bug->values[9] = ees->minute;
+ bug->values[10] = ees->second;
+ bug->values[11] = ees->tz;
+ bug->values[12] = ees->yearstart;
+ bug->values[13] = (ees->leaphold > current_time) ?
+ ees->leaphold - current_time : 0;
+ bug->values[14] = inherent_delay[unit].l_uf;
+ bug->values[15] = offset_fudge[unit].l_uf;
+
+ bug->times[0] = ees->reftime;
+ bug->times[1] = ees->arrvtime;
+ bug->times[2] = ees->lastsampletime;
+ bug->times[3] = ees->offset;
+ bug->times[4] = ees->lowoffset;
+ bug->times[5] = ees->highoffset;
+ bug->times[6] = inherent_delay[unit];
+ bug->times[8] = os_delay[unit];
+ bug->times[7] = fudgefactor[unit];
+ bug->times[9] = offset_fudge[unit];
+ bug->times[10]= ees->yearstart, 0;
+ */
+
+/* This should support the use of an EES M201 receiver with RS232
+ * output (modified to transmit time once per second).
+ *
+ * For the format of the message sent by the clock, see the EESM_
+ * definitions below.
+ *
+ * It appears to run free for an integral number of minutes, until the error
+ * reaches 4mS, at which point it steps at second = 01.
+ * It appears that sometimes it steps 4mS (say at 7 min interval),
+ * then the next minute it decides that it was an error, so steps back.
+ * On the next minute it steps forward again :-(
+ * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
+ * or 9.5uS/S then 3990.5uS at a 7min re-sync,
+ * at which point it may loose the "00" second time stamp.
+ * I assume that the most accurate time is just AFTER the re-sync.
+ * Hence remember the last cycle interval,
+ *
+ * Can run in any one of:
+ *
+ * PPSCD PPS signal sets CD which interupts, and grabs the current TOD
+ * (sun) *in the interupt code*, so as to avoid problems with
+ * the STREAMS scheduling.
+ *
+ * It appears that it goes 16.5 uS slow each second, then every 4 mins it
+ * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
+ */
+
+/* Definitions */
+#ifndef MAXUNITS
+#define MAXUNITS 4 /* maximum number of EES units permitted */
+#endif
+
+#ifndef EES232
+#define EES232 "/dev/ees%d" /* Device to open to read the data */
+#endif
+
+/* Other constant stuff */
+#ifndef EESPRECISION
+#define EESPRECISION (-10) /* what the heck - 2**-10 = 1ms */
+#endif
+#ifndef EESREFID
+#define EESREFID "MSF\0" /* String to identify the clock */
+#endif
+#ifndef EESHSREFID
+#define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
+#endif
+
+/* Description of clock */
+#define EESDESCRIPTION "EES M201 MSF Receiver"
+
+/* Speed we run the clock port at. If this is changed the UARTDELAY
+ * value should be recomputed to suit.
+ */
+#ifndef SPEED232
+#define SPEED232 B9600 /* 9600 baud */
+#endif
+
+/* What is the inherent delay for this mode of working, i.e. when is the
+ * data time stamped.
+ */
+#define SAFETY_SHIFT 10 /* Split the shift to avoid overflow */
+#define BITS_TO_L_FP(bits, baud) \
+ (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
+#define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600)
+#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
+
+#ifndef STREAM_PP1
+#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
+#endif
+#ifndef STREAM_PP2
+#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
+#endif
+
+/* Offsets of the bytes of the serial line code. The clock gives
+ * local time with a GMT/BST indication. The EESM_ definitions
+ * give offsets into ees->lastcode.
+ */
+#define EESM_CSEC 0 /* centiseconds - always zero in our clock */
+#define EESM_SEC 1 /* seconds in BCD */
+#define EESM_MIN 2 /* minutes in BCD */
+#define EESM_HOUR 3 /* hours in BCD */
+#define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */
+#define EESM_DAY 5 /* day of month in BCD */
+#define EESM_MON 6 /* month in BCD */
+#define EESM_YEAR 7 /* year MOD 100 in BCD */
+#define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */
+#define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */
+#define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */
+ /* followed by a frame alignment byte (0xff) /
+ / which is not put into the lastcode buffer*/
+
+/* Length of the serial time code, in characters. The first length
+ * is less the frame alignment byte.
+ */
+#define LENEESPRT (EESM_MSFOK+1)
+#define LENEESCODE (LENEESPRT+1)
+
+/* Code state. */
+#define EESCS_WAIT 0 /* waiting for start of timecode */
+#define EESCS_GOTSOME 1 /* have an incomplete time code buffered */
+
+/* Default fudge factor and character to receive */
+#define DEFFUDGETIME 0 /* Default user supplied fudge factor */
+#ifndef DEFOSTIME
+#define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */
+#endif
+#define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/
+
+/* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median
+ * elimination. If we're running with an accurate clock, chose the BESTSAMPLE
+ * as the estimated offset, otherwise average the remainder.
+ */
+#define FULLSHIFT 6 /* NCODES root 2 */
+#define NCODES (1<< FULLSHIFT) /* 64 */
+#define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */
+
+/* Towards the high ( Why ?) end of half */
+#define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */
+
+/* Leap hold time. After a leap second the clock will no longer be
+ * reliable until it resynchronizes. Hope 40 minutes is enough. */
+#define EESLEAPHOLD (40 * 60)
+
+#define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */
+#define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
+#define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */
+#define EES_STEP_NOTES 50 /* Only do a limited number */
+#define MAX_STEP 16 /* Max number of steps to remember */
+
+/* debug is a bit mask of debugging that is wanted */
+#define DB_SYSLOG_SMPLI 0x0001
+#define DB_SYSLOG_SMPLE 0x0002
+#define DB_SYSLOG_SMTHI 0x0004
+#define DB_SYSLOG_NSMTHE 0x0008
+#define DB_SYSLOG_NSMTHI 0x0010
+#define DB_SYSLOG_SMTHE 0x0020
+#define DB_PRINT_EV 0x0040
+#define DB_PRINT_CDT 0x0080
+#define DB_PRINT_CDTC 0x0100
+#define DB_SYSLOG_KEEPD 0x0800
+#define DB_SYSLOG_KEEPE 0x1000
+#define DB_LOG_DELTAS 0x2000
+#define DB_PRINT_DELTAS 0x4000
+#define DB_LOG_AWAITMORE 0x8000
+#define DB_LOG_SAMPLES 0x10000
+#define DB_NO_PPS 0x20000
+#define DB_INC_PPS 0x40000
+#define DB_DUMP_DELTAS 0x80000
+
+struct eesunit { /* EES unit control structure. */
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp reftime; /* reference time */
+ l_fp lastsampletime; /* time as in txt from last EES msg */
+ l_fp arrvtime; /* Time at which pkt arrived */
+ l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */
+ l_fp offset; /* chosen offset (for clkbug) */
+ l_fp lowoffset; /* lowest sample offset (for clkbug) */
+ l_fp highoffset; /* highest " " (for clkbug) */
+ char lastcode[LENEESCODE+6]; /* last time code we received */
+ u_long lasttime; /* last time clock heard from */
+ u_long clocklastgood; /* last time good radio seen */
+ u_char lencode; /* length of code in buffer */
+ u_char nsamples; /* number of samples we've collected */
+ u_char codestate; /* state of 232 code reception */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ char tz; /* timezone from clock */
+ u_char ttytype; /* method used */
+ u_char dump_vals; /* Should clock values be dumped */
+ u_char usealldata; /* Use ALL samples */
+ u_short day; /* day of year from last code */
+ u_long yearstart; /* start of current year */
+ u_long leaphold; /* time of leap hold expiry */
+ u_long badformat; /* number of bad format codes */
+ u_long baddata; /* number of invalid time codes */
+ u_long timestarted; /* time we started this */
+ long last_pps_no; /* The serial # of the last PPS */
+ char fix_pending; /* Is a "sync to time" pending ? */
+ /* Fine tuning - compensate for 4 mS ramping .... */
+ l_fp last_l; /* last time stamp */
+ u_char last_steps[MAX_STEP]; /* Most recent n steps */
+ int best_av_step; /* Best guess at average step */
+ char best_av_step_count; /* # of steps over used above */
+ char this_step; /* Current pos in buffer */
+ int last_step_late; /* How late the last step was (0-59) */
+ long jump_fsecs; /* # of fractions of a sec last jump */
+ u_long last_step; /* time of last step */
+ int last_step_secs; /* Number of seconds in last step */
+ int using_ramp; /* 1 -> noemal, -1 -> over stepped */
+};
+#define last_sec last_l.l_ui
+#define last_sfsec last_l.l_f
+#define this_uisec ((ees->arrvtime).l_ui)
+#define this_sfsec ((ees->arrvtime).l_f)
+#define msec(x) ((x) / (1<<22))
+#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0])
+#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
+
+/* Bitmask for what methods to try to use -- currently only PPS enabled */
+#define T_CBREAK 1
+#define T_PPS 8
+/* macros to test above */
+#define is_cbreak(x) ((x)->ttytype & T_CBREAK)
+#define is_pps(x) ((x)->ttytype & T_PPS)
+#define is_any(x) ((x)->ttytype)
+
+#define CODEREASON 20 /* reason codes */
+
+/* Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back. */
+static struct eesunit *eesunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/* Keep the fudge factors separately so they can be set even
+ * when no clock is configured. */
+static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */
+static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */
+static l_fp os_delay[MAXUNITS]; /* fudgetime2 */
+static l_fp offset_fudge[MAXUNITS]; /* Sum of above */
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+
+static int deltas[60];
+
+static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
+static l_fp onesec; /* = { 1, 0 }; */
+
+/* Imported from the timer module */
+extern u_long current_time;
+
+#ifdef DEBUG
+static int debug;
+#endif
+
+#ifndef DUMP_BUF_SIZE /* Size of buffer to be used by dump_buf */
+#define DUMP_BUF_SIZE 10112
+#endif
+
+/* ees_reset - reset the count back to zero */
+#define ees_reset(ees) (ees)->nsamples = 0; \
+ (ees)->codestate = EESCS_WAIT
+
+/* ees_event - record and report an event */
+#define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
+ ees_report_event((ees), (evcode))
+
+/* Find the precision of the system clock by reading it */
+#define USECS 1000000
+#define MINSTEP 5 /* some systems increment uS on each call */
+#define MAXLOOPS (USECS/9)
+static int ees_get_precision()
+{
+ struct timeval tp;
+ struct timezone tzp;
+ long last;
+ int i;
+ long diff;
+ long val;
+ gettimeofday(&tp, &tzp);
+
+ last = tp.tv_usec;
+ for (i=0; i< 100000; i++) {
+ gettimeofday(&tp, &tzp);
+ diff = tp.tv_usec - last;
+ if (diff < 0) diff += USECS;
+ if (diff > MINSTEP) break;
+ last = tp.tv_usec;
+ }
+ syslog(LOG_INFO,
+ "I: ees: precision calculation given %duS after %d loop%s",
+ diff, i, (i==1) ? "" : "s");
+
+ if (i == 0) return -20 /* assume 1uS */;
+ if (i >= MAXLOOPS) return EESPRECISION /* Lies ! */;
+ for (i=0, val=USECS; val > 0; i--, val /= 2) if (diff > val) return i;
+ return EESPRECISION /* Lies ! */;
+}
+
+static void dump_buf(coffs, from, to, text)
+l_fp *coffs;
+int from;
+int to;
+char *text;
+{
+ char buff[DUMP_BUF_SIZE + 80];
+ int i;
+ register char *ptr = buff;
+ sprintf(ptr, text);
+ for (i=from; i<to; i++)
+ { while (*ptr) ptr++;
+ if ((ptr-buff) > DUMP_BUF_SIZE) syslog(LOG_DEBUG, "D: %s", ptr=buff);
+ sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
+ }
+ syslog(LOG_DEBUG, "D: %s", buff);
+}
+
+/* msfees_init - initialize internal ees driver data */
+static void msfees_init()
+{
+ register int i;
+ /* Just zero the data arrays */
+ memset((char *)eesunits, 0, sizeof eesunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ acceptable_slop.l_ui = 0;
+ acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
+
+ onesec.l_ui = 1;
+ onesec.l_uf = 0;
+
+ /* Initialize fudge factors to default. */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = DEFFUDGETIME;
+ os_delay[i].l_ui = 0;
+ os_delay[i].l_uf = DEFOSTIME;
+ inherent_delay[i].l_ui = 0;
+ inherent_delay[i].l_uf = DEFINHTIME;
+ offset_fudge[i] = os_delay[i];
+ L_ADD(&offset_fudge[i], &fudgefactor[i]);
+ L_ADD(&offset_fudge[i], &inherent_delay[i]);
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
+
+/* msfees_start - open the EES devices and initialize data for processing */
+static int msfees_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct eesunit *ees;
+ register int i;
+ int fd232 = -1;
+ char eesdev[20];
+ struct termios ttyb, *ttyp;
+ static void ees_receive();
+ extern int io_addclock();
+ extern void io_closeclock();
+ extern char *emalloc();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "ees clock: unit number %d in use", unit);
+ return 0;
+ }
+
+ /* Unit okay, attempt to open the devices. We do them both at
+ * once to make sure we can */
+ (void) sprintf(eesdev, EES232, unit);
+
+ fd232 = open(eesdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
+ return 0;
+ }
+
+#ifdef TIOCEXCL
+ /* Set for exclusive use */
+ if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
+ goto screwed;
+ }
+#endif
+
+ /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
+
+ /* Set port characteristics. If we don't have a STREAMS module or
+ * a clock line discipline, cooked mode is just usable, even though it
+ * strips the top bit. The only EES byte which uses the top
+ * bit is the year, and we don't use that anyway. If we do
+ * have the line discipline, we choose raw mode, and the
+ * line discipline code will block up the messages.
+ */
+
+ /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_oflag = 0;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ inherent_delay[unit].l_uf = INH_DELAY_PPS;
+
+ /* offset fudge (how *late* the timestamp is) = fudge + os delays */
+ offset_fudge[unit] = os_delay[unit];
+ L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
+ L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
+
+ /* Looks like this might succeed. Find memory for the structure.
+ * Look to see if there are any unused ones, if not we malloc() one.
+ */
+ if (eesunits[unit] != 0) /* The one we want is okay */
+ ees = eesunits[unit];
+ else {
+ /* Look for an unused, but allocated struct */
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && eesunits[i] != 0)
+ break;
+ }
+
+ if (i < MAXUNITS) { /* Reclaim this one */
+ ees = eesunits[i];
+ eesunits[i] = 0;
+ } /* no spare -- make a new one */
+ else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
+ }
+ memset((char *)ees, 0, sizeof(struct eesunit));
+ eesunits[unit] = ees;
+
+ /* Set up the structures */
+ ees->peer = peer;
+ ees->unit = (u_char)unit;
+ ees->timestarted= current_time;
+ ees->ttytype = 0;
+ ees->io.clock_recv= ees_receive;
+ ees->io.srcclock= (caddr_t)ees;
+ ees->io.datalen = 0;
+ ees->io.fd = fd232;
+
+ /* Okay. Push one of the two (linked into the kernel, or dynamically
+ * loaded) STREAMS module, and give it to the I/O code to start
+ * receiving stuff.
+ */
+
+ {
+ int rc1;
+ /* Pop any existing onews first ... */
+ while (ioctl(fd232, I_POP, 0 ) >= 0) ;
+
+ /* Now try pushing either of the possible modules */
+ if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
+ ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
+ syslog(LOG_ERR,
+ "ees clock: Push of `%s' and `%s' to %s failed %m",
+ STREAM_PP1, STREAM_PP2, eesdev);
+ goto screwed;
+ }
+ else {
+ syslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
+ (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
+ ees->ttytype |= T_PPS;
+ }
+ }
+
+ /* Add the clock */
+ if (!io_addclock(&ees->io)) {
+ /* Oh shit. Just close and return. */
+ syslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
+ goto screwed;
+ }
+
+
+ /* All done. Initialize a few random peer variables, then
+ * return success. */
+ peer->precision = ees_get_precision();
+ peer->stratum = stratumtouse[unit];
+ peer->rootdelay = 0; /* ++++ */
+ peer->rootdispersion = 0; /* ++++ */
+ if (stratumtouse[unit] <= 1) {
+ memmove((char *)&peer->refid, EESREFID, 4);
+ if (unit > 0 && unit < 10)
+ ((char *)&peer->refid)[3] = '0' + unit;
+ } else {
+ peer->refid = htonl(EESHSREFID);
+ }
+ unitinuse[unit] = 1;
+ syslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
+ return (1);
+
+screwed:
+ if (fd232 != -1)
+ (void) close(fd232);
+ return (0);
+}
+
+
+/* msfees_shutdown - shut down a EES clock */
+static void msfees_shutdown(unit)
+ int unit;
+{
+ register struct eesunit *ees;
+ extern void io_closeclock();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
+ unit, MAXUNITS);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR,
+ "ees clock: INTERNAL ERROR, unit number %d not in use", unit);
+ return;
+ }
+
+ /* Tell the I/O module to turn us off. We're history. */
+ ees = eesunits[unit];
+ io_closeclock(&ees->io);
+ unitinuse[unit] = 0;
+}
+
+
+/* ees_report_event - note the occurance of an event */
+static void ees_report_event(ees, code)
+ struct eesunit *ees;
+ int code;
+{
+ if (ees->status != (u_char)code) {
+ ees->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ ees->lastevent = (u_char)code;
+ /* Should report event to trap handler in here.
+ * Soon...
+ */
+ }
+}
+
+
+/* ees_receive - receive data from the serial interface on an EES clock */
+static void ees_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int n_sample;
+ register int day;
+ register struct eesunit *ees;
+ register u_char *dpt; /* Data PoinTeR: move along ... */
+ register u_char *dpend; /* Points just *after* last data char */
+ register char *cp;
+ l_fp tmp;
+ static void ees_process();
+ int call_pps_sample = 0;
+ l_fp pps_arrvstamp;
+ int sincelast;
+ int pps_step = 0;
+ int suspect_4ms_step = 0;
+ struct ppsclockev ppsclockev;
+ long *ptr = (long *) &ppsclockev;
+ extern errno;
+ int rc;
+
+ /* Get the clock this applies to and a pointer to the data */
+ ees = (struct eesunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = dpt + rbufp->recv_length;
+ if ((debug & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
+ printf("[%d] ", rbufp->recv_length);
+
+ /* Check out our state and process appropriately */
+ switch (ees->codestate) {
+ case EESCS_WAIT:
+ /* Set an initial guess at the timestamp as the recv time.
+ * If just running in CBREAK mode, we can't improve this.
+ * If we have the CLOCK Line Discipline, PPSCD, or sime such,
+ * then we will do better later ....
+ */
+ ees->arrvtime = rbufp->recv_time;
+ ees->codestate = EESCS_GOTSOME;
+ ees->lencode = 0;
+ /*FALLSTHROUGH*/
+
+ case EESCS_GOTSOME:
+ cp = &(ees->lastcode[ees->lencode]);
+
+ /* Gobble the bytes until the final (possibly stripped) 0xff */
+ while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
+ *cp++ = (char)*dpt++;
+ ees->lencode++;
+ /* Oh dear -- too many bytes .. */
+ if (ees->lencode > LENEESPRT) {
+ syslog(LOG_INFO,
+"I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
+ ees->lencode, dpend - dpt, LENEESPRT,
+#define D(x) (ees->lastcode[x])
+ D(0), D(1), D(2), D(3), D(4), D(5), D(6),
+ D(7), D(8), D(9), D(10), D(11), D(12));
+#undef D
+ ees->badformat++;
+ ees->reason = CODEREASON + 1;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+ }
+ /* Gave up because it was end of the buffer, rather than ff */
+ if (dpt == dpend) {
+ /* Incomplete. Wait for more. */
+ if (debug & DB_LOG_AWAITMORE) syslog(LOG_INFO,
+ "I: ees clock %d: %d == %d: await more",
+ ees->unit, dpt, dpend);
+ return;
+ }
+
+ /* This shouldn't happen ... ! */
+ if ((*dpt & 0x7f) != 0x7f) {
+ syslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
+ ees->badformat++;
+ ees->reason = CODEREASON + 2;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Skip the 0xff */
+ dpt++;
+
+ /* Finally, got a complete buffer. Mainline code will
+ * continue on. */
+ cp = ees->lastcode;
+ break;
+
+ default:
+ syslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
+ ees->unit, ees->codestate);
+ ees->reason = CODEREASON + 5;
+ ees_event(ees, CEVNT_FAULT);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Boy! After all that crap, the lastcode buffer now contains
+ * something we hope will be a valid time code. Do length
+ * checks and sanity checks on constant data.
+ */
+ ees->codestate = EESCS_WAIT;
+ ees->lasttime = current_time;
+ if (ees->lencode != LENEESPRT) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 6;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ cp = ees->lastcode;
+
+ /* Check that centisecond is zero */
+ if (cp[EESM_CSEC] != 0) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 7;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Check flag formats */
+ if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 8;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 9;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 10;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* So far, so good. Compute day, hours, minutes, seconds,
+ * time zone. Do range checks on these.
+ */
+
+#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
+#define istrue(x) ((x)?1:0)
+
+ ees->second = bcdunpack(cp[EESM_SEC]); /* second */
+ ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */
+ ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */
+
+ day = bcdunpack(cp[EESM_DAY]); /* day of month */
+
+ switch (bcdunpack(cp[EESM_MON])) { /* month */
+
+ /* Add in lengths of all previous months. Add one more
+ if it is a leap year and after February.
+ */
+ case 12: day += NOV; /*FALLSTHROUGH*/
+ case 11: day += OCT; /*FALLSTHROUGH*/
+ case 10: day += SEP; /*FALLSTHROUGH*/
+ case 9: day += AUG; /*FALLSTHROUGH*/
+ case 8: day += JUL; /*FALLSTHROUGH*/
+ case 7: day += JUN; /*FALLSTHROUGH*/
+ case 6: day += MAY; /*FALLSTHROUGH*/
+ case 5: day += APR; /*FALLSTHROUGH*/
+ case 4: day += MAR; /*FALLSTHROUGH*/
+ case 3: day += FEB;
+ if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
+ case 2: day += JAN; /*FALLSTHROUGH*/
+ case 1: break;
+ default: ees->baddata++;
+ ees->reason = CODEREASON + 11;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+
+ ees->day = day;
+
+ /* Get timezone. The clocktime routine wants the number
+ * of hours to add to the delivered time to get UT.
+ * Currently -1 if BST flag set, 0 otherwise. This
+ * is the place to tweak things if double summer time
+ * ever happens.
+ */
+ ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
+
+ if (ees->day > 366 || ees->day < 1 ||
+ ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 12;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+
+ n_sample = ees->nsamples;
+
+ /* Now, compute the reference time value: text -> tmp.l_ui */
+ if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
+ ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
+ &tmp.l_ui)) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 13;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+ tmp.l_uf = 0;
+
+ /* DON'T use ees->arrvtime -- it may be < reftime */
+ ees->lastsampletime = tmp;
+
+ /* If we are synchronised to the radio, update the reference time.
+ * Also keep a note of when clock was last good.
+ */
+ if (istrue(cp[EESM_MSFOK])) {
+ ees->reftime = tmp;
+ ees->clocklastgood = current_time;
+ }
+
+
+ /* Compute the offset. For the fractional part of the
+ * offset we use the expected delay for the message.
+ */
+ ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
+ ees->codeoffsets[n_sample].l_uf = 0;
+
+ /* Number of seconds since the last step */
+ sincelast = this_uisec - ees->last_step;
+
+ memset(&ppsclockev, 0, sizeof ppsclockev);
+
+ rc = ioctl(ees->io.fd, CIOGETEV, (char *) &ppsclockev);
+ if (debug & DB_PRINT_EV) fprintf(stderr,
+ "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08x %08x %d\n",
+ DB_PRINT_EV, ees->unit, ees->io.fd, CIOGETEV, is_pps(ees),
+ rc, errno, ptr[0], ptr[1], ptr[2]);
+
+ /* If we managed to get the time of arrival, process the info */
+ if (rc >= 0) {
+ int conv = -1;
+ pps_step = ppsclockev.serial - ees->last_pps_no;
+
+ /* Possible that PPS triggered, but text message didn't */
+ if (pps_step == 2) syslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
+ if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
+ if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
+
+ /* allow for single loss of PPS only */
+ if (pps_step != 1 && pps_step != 2)
+ fprintf(stderr, "PPS step: %d too far off %d (%d)\n",
+ ppsclockev.serial, ees->last_pps_no, pps_step);
+ else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
+ fprintf(stderr, "buftvtots failed\n");
+ else { /* if ((ABS(time difference) - 0.25) < 0)
+ * then believe it ...
+ */
+ l_fp diff;
+ diff = pps_arrvstamp;
+ conv = 0;
+ L_SUB(&diff, &ees->arrvtime);
+if (debug & DB_PRINT_CDT) printf("[%x] Have %x.%08x and %x.%08x -> %x.%08x @ %s",
+ DB_PRINT_CDT, ees->arrvtime.l_ui, ees->arrvtime.l_uf,
+ pps_arrvstamp.l_ui, pps_arrvstamp.l_uf,
+ diff.l_ui, diff.l_uf,
+ ctime(&(ppsclockev.tv.tv_sec)));
+ if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
+ L_SUB(&diff, &acceptable_slop);
+ if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
+ ees->arrvtime = pps_arrvstamp;
+ conv++;
+ call_pps_sample++;
+ }
+ /* Some loss of some signals around sec = 1 */
+ else if (ees->second == 1) {
+ diff = pps_arrvstamp;
+ L_ADD(&diff, &onesec);
+ L_SUB(&diff, &ees->arrvtime);
+ if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
+ L_SUB(&diff, &acceptable_slop);
+syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
+ pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
+ pps_arrvstamp.l_uf,
+ ees->arrvtime.l_uf,
+ diff.l_ui, diff.l_uf,
+ ppsclockev.tv.tv_usec,
+ ctime(&(ppsclockev.tv.tv_sec)));
+ if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
+ suspect_4ms_step |= 2;
+ ees->arrvtime = pps_arrvstamp;
+ L_ADD(&ees->arrvtime, &onesec);
+ conv++;
+ call_pps_sample++;
+ }
+ }
+ }
+ ees->last_pps_no = ppsclockev.serial;
+ if (debug & DB_PRINT_CDTC) printf(
+ "[%x] %08x %08x %d u%d (%d %d)\n",
+ DB_PRINT_CDTC, pps_arrvstamp.l_ui,
+ pps_arrvstamp.l_uf, conv, ees->unit,
+ call_pps_sample, pps_step);
+ }
+
+ /* See if there has been a 4ms jump at a minute boundry */
+ { l_fp delta;
+#define delta_isec delta.l_ui
+#define delta_ssec delta.l_i
+#define delta_sfsec delta.l_f
+ long delta_f_abs;
+
+ delta.l_i = ees->arrvtime.l_i;
+ delta.l_f = ees->arrvtime.l_f;
+
+ L_SUB(&delta, &ees->last_l);
+ delta_f_abs = delta_sfsec;
+ if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
+
+ /* Dump the deltas each minute */
+ if (debug & DB_DUMP_DELTAS)
+ { if (0 <= ees->second &&
+ ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
+ /* Dump on second 1, as second 0 sometimes missed */
+ if (ees->second == 1) {
+ char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
+ char *ptr=text;
+ int i;
+ for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
+ sprintf(ptr, " %d.%04d",
+ msec(deltas[i]), subms(deltas[i]));
+ while (*ptr) ptr++;
+ }
+ syslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
+ msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
+ msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
+ text+1);
+ for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
+ }
+ }
+
+ /* Lets see if we have a 4 mS step at a minute boundaary */
+ if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
+ (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
+ (ees->second == 0 || ees->second == 1 || ees->second == 2) &&
+ (sincelast < 0 || sincelast > 122)
+ ) { /* 4ms jump at min boundry */
+ int old_sincelast;
+ int count=0;
+ int sum = 0;
+ /* Yes -- so compute the ramp time */
+ if (ees->last_step == 0) sincelast = 0;
+ old_sincelast = sincelast;
+
+ /* First time in, just set "ees->last_step" */
+ if(ees->last_step) {
+ int other_step = 0;
+ int third_step = 0;
+ int this_step = (sincelast + (60 /2)) / 60;
+ int p_step = ees->this_step;
+ int p;
+ ees->last_steps[p_step] = this_step;
+ p= p_step;
+ p_step++;
+ if (p_step >= LAST_STEPS) p_step = 0;
+ ees->this_step = p_step;
+ /* Find the "average" interval */
+ while (p != p_step) {
+ int this = ees->last_steps[p];
+ if (this == 0) break;
+ if (this != this_step) {
+ if (other_step == 0 && (
+ this== (this_step +2) ||
+ this== (this_step -2) ||
+ this== (this_step +1) ||
+ this== (this_step -1)))
+ other_step = this;
+ if (other_step != this) {
+ int delta = (this_step - other_step);
+ if (delta < 0) delta = - delta;
+ if (third_step == 0 && (
+ (delta == 1) ? (
+ this == (other_step +1) ||
+ this == (other_step -1) ||
+ this == (this_step +1) ||
+ this == (this_step -1))
+ :
+ (
+ this == (this_step + other_step)/2
+ )
+ )) third_step = this;
+ if (third_step != this) break;
+ }
+ }
+ sum += this;
+ p--;
+ if (p < 0) p += LAST_STEPS;
+ count++;
+ }
+syslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step);
+ if (count != 0) sum = ((sum * 60) + (count /2)) / count;
+#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
+syslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
+ SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
+printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
+ SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
+#undef SV
+ ees->jump_fsecs = delta_sfsec;
+ ees->using_ramp = 1;
+ if (sincelast > 170)
+ ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
+ else ees->last_step_late = 30;
+ if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
+ if (ees->last_step_late < 0) ees->last_step_late = 0;
+ if (ees->last_step_late >= 60) ees->last_step_late = 59;
+ sincelast = 0;
+ }
+ else { /* First time in -- just save info */
+ ees->last_step_late = 30;
+ ees->jump_fsecs = delta_sfsec;
+ ees->using_ramp = 1;
+ sum = 4 * 60;
+ }
+ ees->last_step = this_uisec;
+printf("MSF%d: d=%3d.%04d@%d :%d:%d:$%d:%d:%d\n",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
+syslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
+ if (sum) ees->last_step_secs = sum;
+ }
+ /* OK, so not a 4ms step at a minute boundry */
+ else {
+ if (suspect_4ms_step) syslog(LOG_ERR,
+ "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
+ ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
+ msec(EES_STEP_F - EES_STEP_F_GRACE),
+ subms(EES_STEP_F - EES_STEP_F_GRACE),
+ msec(delta_f_abs),
+ subms(delta_f_abs),
+ msec(EES_STEP_F + EES_STEP_F_GRACE),
+ subms(EES_STEP_F + EES_STEP_F_GRACE),
+ ees->second,
+ sincelast);
+ if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
+ static ees_step_notes = EES_STEP_NOTES;
+ if (ees_step_notes > 0) {
+ ees_step_notes--;
+printf("MSF%d: D=%3d.%04d@%02d :%d%s\n",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
+syslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
+ }
+ }
+ }
+ }
+ ees->last_l = ees->arrvtime;
+
+ /* IF we have found that it's ramping
+ * && it's within twice the expected ramp period
+ * && there is a non zero step size (avoid /0 !)
+ * THEN we twiddle things
+ */
+ if (ees->using_ramp &&
+ sincelast < (ees->last_step_secs)*2 &&
+ ees->last_step_secs)
+ { long sec_of_ramp = sincelast + ees->last_step_late;
+ long fsecs;
+ l_fp inc;
+
+ /* Ramp time may vary, so may ramp for longer than last time */
+ if (sec_of_ramp > (ees->last_step_secs + 120))
+ sec_of_ramp = ees->last_step_secs;
+
+ /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
+ fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs);
+
+ if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
+ "[%x] MSF%d: %3d/%03d -> d=%11d (%d|%d)",
+ DB_LOG_DELTAS,
+ ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
+ pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
+ if (debug & DB_PRINT_DELTAS) printf(
+ "MSF%d: %3d/%03d -> d=%11d (%d|%d)\n",
+ ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
+ pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
+
+ /* Must sign extend the result */
+ inc.l_i = (fsecs < 0) ? -1 : 0;
+ inc.l_f = fsecs;
+ if (debug & DB_INC_PPS)
+ { L_SUB(&pps_arrvstamp, &inc);
+ L_SUB(&ees->arrvtime, &inc);
+ }
+ else
+ { L_ADD(&pps_arrvstamp, &inc);
+ L_ADD(&ees->arrvtime, &inc);
+ }
+ }
+ else {
+ if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
+ "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
+ DB_LOG_DELTAS,
+ ees->unit, ees->using_ramp,
+ sincelast,
+ (ees->last_step_secs)*2,
+ ees->last_step_secs);
+ if (debug & DB_PRINT_DELTAS) printf(
+ "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
+ DB_LOG_DELTAS,
+ ees->unit, ees->using_ramp,
+ sincelast,
+ (ees->last_step_secs)*2,
+ ees->last_step_secs);
+ }
+
+ L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
+ L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
+
+ if (call_pps_sample && !(debug & DB_NO_PPS)) {
+ /* Sigh -- it expects its args negated */
+ L_NEG(&pps_arrvstamp);
+ (void) pps_sample(&pps_arrvstamp);
+ }
+
+ /* Subtract off the local clock time stamp */
+ L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
+ if (debug & DB_LOG_SAMPLES) syslog(LOG_ERR,
+ "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
+ ees->unit, DB_LOG_DELTAS, n_sample,
+ ees->codeoffsets[n_sample].l_f,
+ ees->codeoffsets[n_sample].l_f / 4295,
+ pps_arrvstamp.l_f,
+ pps_arrvstamp.l_f /4295,
+ (debug & DB_NO_PPS) ? " [no PPS]" : "");
+
+ if (ees->nsamples++ == NCODES-1) ees_process(ees);
+
+ /* Done! */
+}
+
+
+static void set_x(fp_offset)
+l_fp *fp_offset;
+{
+ step_systime_real(fp_offset);
+}
+
+
+/* offcompare - auxiliary comparison routine for offset sort */
+
+static int
+offcompare(a, b)
+l_fp *a, *b;
+{
+ return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
+}
+
+
+/* ees_process - process a pile of samples from the clock */
+static void ees_process(ees)
+ struct eesunit *ees;
+{
+ static last_samples = -1;
+ register int i, j;
+ register int noff;
+ register l_fp *coffs = ees->codeoffsets;
+ l_fp offset, tmp;
+ u_fp dispersion; /* ++++ */
+ int lostsync, isinsync;
+ int samples = ees->nsamples;
+ int samplelog;
+ int samplereduce = (samples + 1) / 2;
+
+ /* Reset things to zero so we don't have to worry later */
+ ees_reset(ees);
+
+ if (sloppyclockflag[ees->unit]) {
+ samplelog = (samples < 2) ? 0 :
+ (samples < 5) ? 1 :
+ (samples < 9) ? 2 :
+ (samples < 17) ? 3 :
+ (samples < 33) ? 4 : 5;
+ samplereduce = (1 << samplelog);
+ }
+
+ if (samples != last_samples &&
+ ((samples != (last_samples-1)) || samples < 3)) {
+ syslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
+ samples, last_samples, samplereduce);
+ last_samples = samples;
+ }
+ if (samples < 1) return;
+
+ /* If requested, dump the raw data we have in the buffer */
+ if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
+
+ /* Sort the offsets, trim off the extremes, then choose one. */
+ qsort((char *) coffs, samples, sizeof(l_fp), offcompare);
+
+ noff = samples;
+ i = 0;
+ while ((noff - i) > samplereduce) {
+ /* Trim off the sample which is further away
+ * from the median. We work this out by doubling
+ * the median, subtracting off the end samples, and
+ * looking at the sign of the answer, using the
+ * identity (c-b)-(b-a) == 2*b-a-c
+ */
+ tmp = coffs[(noff + i)/2];
+ L_ADD(&tmp, &tmp);
+ L_SUB(&tmp, &coffs[i]);
+ L_SUB(&tmp, &coffs[noff-1]);
+ if (L_ISNEG(&tmp)) noff--; else i++;
+ }
+
+ /* If requested, dump the reduce data we have in the buffer */
+ if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:");
+
+ /* What we do next depends on the setting of the sloppy clock flag.
+ * If it is on, average the remainder to derive our estimate.
+ * Otherwise, just pick a representative value from the remaining stuff
+ */
+ if (sloppyclockflag[ees->unit]) {
+ offset.l_ui = offset.l_uf = 0;
+ for (j = i; j < noff; j++)
+ L_ADD(&offset, &coffs[j]);
+ for (j = samplelog; j > 0; j--)
+ L_RSHIFTU(&offset);
+ }
+ else offset = coffs[i+BESTSAMPLE];
+
+ /* Compute the dispersion as the difference between the
+ * lowest and highest offsets that remain in the
+ * consideration list.
+ *
+ * It looks like MOST clocks have MOD (max error), so halve it !
+ */
+ tmp = coffs[noff-1];
+ L_SUB(&tmp, &coffs[i]);
+#define FRACT_SEC(n) ((1 << 30) / (n/2))
+ dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
+ if (debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) syslog(
+ (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] Offset=%06d (%d), disp=%06d%s [%d], %d %d=%d %d:%d %d=%d %d",
+ debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
+ offset.l_f / 4295, offset.l_f,
+ (dispersion * 1526) / 100,
+ (sloppyclockflag[ees->unit]) ? " by averaging" : "",
+ FRACT_SEC(10) / 4295,
+ (coffs[0].l_f) / 4295,
+ i,
+ (coffs[i].l_f) / 4295,
+ (coffs[samples/2].l_f) / 4295,
+ (coffs[i+BESTSAMPLE].l_f) / 4295,
+ noff-1,
+ (coffs[noff-1].l_f) / 4295,
+ (coffs[samples-1].l_f) / 4295);
+
+ /* Are we playing silly wotsits ?
+ * If we are using all data, see if there is a "small" delta,
+ * and if so, blurr this with 3/4 of the delta from the last value
+ */
+ if (ees->usealldata && ees->offset.l_uf) {
+ long diff = (long) (ees->offset.l_uf - offset.l_uf);
+
+ /* is the delta small enough ? */
+ if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
+ int samd = (64 * 4) / samples;
+ long new;
+ if (samd < 2) samd = 2;
+ new = offset.l_uf + ((diff * (samd -1)) / samd);
+
+ /* Sign change -> need to fix up int part */
+ if ((new & (1 << 31)) !=
+ (((long) offset.l_uf) & ( 1 << 31)))
+ { syslog(LOG_INFO, "I: %x != %x (%x %x), so add %d",
+ new & (1 << 31),
+ ((long) offset.l_uf) & ( 1 << 31),
+ new, (long) offset.l_uf,
+ (new < 0) ? -1 : 1);
+ offset.l_ui += (new < 0) ? -1 : 1;
+ }
+ dispersion /= 4;
+ if (debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) syslog(
+ (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] Smooth data: %d -> %d, dispersion now %d",
+ debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
+ ((long) offset.l_uf) / 4295, new / 4295,
+ (dispersion * 1526) / 100);
+ offset.l_uf = new;
+ }
+ else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
+ (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
+ "[%x] No smooth as delta not %d < %d < %d",
+ debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
+ - FRACT_SEC(100), diff, FRACT_SEC(100));
+ }
+ else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
+ (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
+ debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
+ ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
+ offset.l_f, ees->offset.l_f - offset.l_f);
+
+ /* Collect offset info for debugging info */
+ ees->offset = offset;
+ ees->lowoffset = coffs[i];
+ ees->highoffset = coffs[noff-1];
+
+ /* Determine synchronization status. Can be unsync'd either
+ * by a report from the clock or by a leap hold.
+ *
+ * Loss of the radio signal for a short time does not cause
+ * us to go unsynchronised, since the receiver keeps quite
+ * good time on its own. The spec says 20ms in 4 hours; the
+ * observed drift in our clock (Cambridge) is about a second
+ * a day, but even that keeps us within the inherent tolerance
+ * of the clock for about 15 minutes. Observation shows that
+ * the typical "short" outage is 3 minutes, so to allow us
+ * to ride out those, we will give it 5 minutes.
+ */
+ lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
+ isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
+
+ /* Done. Use time of last good, synchronised code as the
+ * reference time, and lastsampletime as the receive time.
+ */
+ if (ees->fix_pending) {
+ syslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
+ ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
+ ees->fix_pending = 0;
+ set_x(&offset);
+ L_CLR(&offset);
+ }
+ refclock_receive(ees->peer,
+ &offset,
+ 0, /* delay */
+ dispersion,
+ &ees->reftime,
+ &ees->lastsampletime, /* receive time */
+ (isinsync) ? 0 : LEAP_NOTINSYNC);
+ ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
+}
+
+/* msfees_poll - called by the transmit procedure */
+static void msfees_poll(unit, peer)
+ int unit;
+ char *peer;
+{
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
+ unit);
+ return;
+ }
+
+ ees_process(eesunits[unit]);
+
+ if ((current_time - eesunits[unit]->lasttime) > 150)
+ ees_event(eesunits[unit], CEVNT_FAULT);
+}
+
+/* msfees_leap - called when a leap second occurs */
+static void msfees_leap()
+{
+ register int i;
+
+ /* This routine should be entered a few seconds after
+ * midnight UTC when a leap second occurs. To ensure we
+ * don't believe foolish time from the clock(s) we set a
+ * 40 minute hold on them. It shouldn't take anywhere
+ * near this amount of time to adjust if the clock is getTING
+ * data, but doing anything else is complicated.
+ */
+ for (i = 0; i < MAXUNITS; i++) if (unitinuse[i])
+ eesunits[i]->leaphold = current_time + EESLEAPHOLD;
+}
+
+/* msfees_control - set fudge factors, return statistics */
+static void msfees_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct eesunit *ees = eesunits[unit];
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ os_delay[unit] = in->fudgetime2;
+ offset_fudge[unit] = os_delay[unit];
+ L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
+ L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ if (unitinuse[unit]) {
+ /* Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ struct peer *peer = ees->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1) {
+ memmove((char *)&peer->refid,
+ EESREFID, 4);
+ if (unit>0 && unit<10)
+ ((char *)&peer->refid)[3] =
+ '0' + unit;
+ }
+ else peer->refid = htonl(EESHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEVAL2) {
+ printf("Debug: %x -> %x\n", debug, in->fudgeval2);
+ syslog(LOG_ERR, "MSF%d: debug %x -> %x",
+ unit, debug, in->fudgeval2);
+ debug = in->fudgeval2;
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ if (in->haveflags & CLK_HAVEFLAG2) {
+ ees->fix_pending++;
+ /* if (in->flags & CLK_FLAG2 && unitinuse[unit])
+ ees->leaphold = 0; */
+ }
+ if (in->haveflags & CLK_HAVEFLAG3 && unitinuse[unit]) {
+ printf("dump_vals: %x -> %x\n", ees->dump_vals, in->flags & CLK_FLAG3);
+ ees->dump_vals = in->flags & CLK_FLAG3;
+ }
+ if (in->haveflags & CLK_HAVEFLAG4 && unitinuse[unit]) {
+ ees->usealldata = in->flags & CLK_FLAG4;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_MSF_EES;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4;
+ out->clockdesc = EESDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2 = os_delay[unit];
+ out->fudgeval1 = stratumtouse[unit];
+ /*out->fudgeval2= debug*/;
+ memmove((char *)&out->fudgeval2, EESREFID, 4);
+ if (unit > 0 && unit < 10)
+ ((char *)&out->fudgeval2)[3] = '0' + unit;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ out->flags |= ees->dump_vals | ees->usealldata;
+ out->lencode = ees->lencode;
+ out->lastcode = ees->lastcode;
+ out->timereset = current_time - ees->timestarted;
+ out->polls = 0; /* we don't poll */
+ out->noresponse = 0; /* ditto */
+ out->badformat = ees->badformat;
+ out->baddata = ees->baddata;
+ out->lastevent = ees->lastevent;
+ out->currentstatus = ees->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+
+/* msfees_buginfo - return clock dependent debugging info */
+static void msfees_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct eesunit *ees;
+
+ bug->nvalues = bug->ntimes = 0;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ ees = eesunits[unit];
+
+ bug->nvalues = 16;
+ bug->svalues = 0x0800;
+ bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
+ bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
+ bug->values[2] = ees->status;
+ bug->values[3] = ees->lastevent;
+ bug->values[4] = ees->reason;
+ bug->values[5] = ees->nsamples;
+ bug->values[6] = ees->codestate;
+ bug->values[7] = ees->day;
+ bug->values[8] = ees->hour;
+ bug->values[9] = ees->minute;
+ bug->values[10] = ees->second;
+ bug->values[11] = ees->tz;
+ bug->values[12] = ees->yearstart;
+ bug->values[13] = (ees->leaphold > current_time) ?
+ ees->leaphold - current_time : 0;
+ bug->values[14] = inherent_delay[unit].l_uf;
+ bug->values[15] = offset_fudge[unit].l_uf;
+
+ bug->ntimes = 11;
+ bug->stimes = 0x3f8;
+ bug->times[0] = ees->reftime;
+ bug->times[1] = ees->arrvtime;
+ bug->times[2] = ees->lastsampletime;
+ bug->times[3] = ees->offset;
+ bug->times[4] = ees->lowoffset;
+ bug->times[5] = ees->highoffset;
+ bug->times[6] = inherent_delay[unit];
+ bug->times[8] = os_delay[unit];
+ bug->times[7] = fudgefactor[unit];
+ bug->times[9] = offset_fudge[unit];
+ bug->times[10].l_ui = ees->yearstart;
+ bug->times[10].l_uf = 0;
+}
+
+struct refclock refclock_msfees = {
+ msfees_start, msfees_shutdown, msfees_poll,
+ msfees_control, msfees_init, msfees_buginfo, NOFLAGS
+};
+#endif /* defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) */
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_mx4200.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_mx4200.c
new file mode 100644
index 000000000000..caf5951c55ed
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_mx4200.c
@@ -0,0 +1,977 @@
+/*
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66.
+ *
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ * 4. The name of the University may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(REFCLOCK) && defined(MX4200)
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_calendar.h"
+#include "ntp_unixtime.h"
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <sys/ppsclock.h>
+
+#include "mx4200.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the Magnavox Model MX4200 GPS Receiver.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 2 /* max number of mx4200 units */
+#define MX4200FD "/dev/gps%d"
+#define SPEED232 B4800 /* baud */
+
+/*
+ * The number of raw samples which we acquire to derive a single estimate.
+ */
+#define NSTMPS 64
+
+/*
+ * Radio interface parameters
+ */
+#define MX4200PRECISION (-18) /* precision assumed (about 4 us) */
+#define MX4200REFID "GPS" /* reference id */
+#define MX4200DESCRIPTION "Magnavox MX4200 GPS Receiver" /* WRU */
+#define DEFFUDGETIME 0 /* default fudge time (ms) */
+
+/* Leap stuff */
+extern u_long leap_hoursfromleap;
+extern u_long leap_happened;
+static int leap_debug;
+
+/*
+ * mx4200_reset - reset the count back to zero
+ */
+#define mx4200_reset(up) \
+ do { \
+ (up)->nsamples = 0; \
+ } while (0)
+
+/*
+ * Imported from the timer module
+ */
+extern u_long current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * MX4200 unit control structure.
+ */
+struct mx4200unit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ u_long gpssamples[NSTMPS]; /* the GPS time samples */
+ l_fp unixsamples[NSTMPS]; /* the UNIX time samples */
+
+
+ l_fp lastsampletime; /* time of last estimate */
+ u_int lastserial; /* last pps serial number */
+#ifdef notdef
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+#endif
+ char lastcode[RX_BUFF_SIZE]; /* last timecode received */
+ u_long lasttime; /* last time clock heard from */
+ u_char nsamples; /* number of samples we've collected */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char lencode; /* length of last timecode */
+ u_char year; /* year of eternity */
+ u_short monthday; /* day of month */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ /*
+ * Status tallies
+ */
+#ifdef notdef
+ u_long polls; /* polls sent */
+ u_long noresponse; /* number of nonresponses */
+#endif
+ u_long badformat; /* bad format */
+ u_long baddata; /* bad data */
+ u_long timestarted; /* time we started this */
+};
+
+/*
+ * We demand that consecutive PPS samples are more than 0.995 seconds
+ * and less than 1.005 seconds apart.
+ */
+#define PPSLODIFF_UI 0 /* 0.900 as an l_fp */
+#define PPSLODIFF_UF 0xe6666610
+
+#define PPSHIDIFF_UI 1 /* 1.100 as an l_fp */
+#define PPSHIDIFF_UF 0x19999990
+
+/*
+ * reason codes
+ */
+#define PPSREASON 20
+#define CODEREASON 40
+#define PROCREASON 60
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct mx4200unit *mx4200units[MAXUNITS];
+
+static const char pmvxg[] = "PMVXG";
+
+/*
+ * Function prototypes
+ */
+static int mx4200_start P((int, struct peer *));
+static void mx4200_shutdown P((int, struct peer *));
+static void mx4200_receive P((struct recvbuf *));
+static void mx4200_process P((struct mx4200unit *));
+static void mx4200_poll P((int, struct peer *));
+
+static char * mx4200_parse P((char *, struct calendar *, int *, int *));
+static int mx4200_needconf P((char *));
+static void mx4200_config P((struct mx4200unit *));
+static void mx4200_send P((int, const char *, ...));
+static int mx4200_cmpl_fp P((void *, void *));
+static u_char cksum P((char *, u_int));
+
+#ifdef DEBUG
+static void opendfile P((int));
+static void checkdfile P((void));
+#endif /* DEBUG */
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_mx4200 = {
+ mx4200_start, /* start up driver */
+ mx4200_shutdown, /* shut down driver */
+ mx4200_poll, /* transmit poll message */
+ noentry, /* not used (old mx4200_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old mx4200_buginfo) */
+ NOFLAGS /* not used */
+};
+
+#ifdef DEBUG
+static char dfile[] = "/var/tmp/MX4200.debug";
+static FILE *df = NULL;
+
+static void
+opendfile(create)
+ int create;
+{
+ if (!create && access(dfile, F_OK) < 0) {
+ syslog(LOG_ERR, "mx4200: open %s: %m", dfile);
+ return;
+ }
+ df = fopen(dfile, "a");
+ if (df == NULL)
+ syslog(LOG_ERR, "mx4200: open %s: %m", dfile);
+ else if (setvbuf(df, NULL, _IOLBF, 0) < 0)
+ syslog(LOG_ERR, "mx4200: setvbuf %s: %m", dfile);
+}
+
+static void
+checkdfile()
+{
+
+ if (df == NULL)
+ return;
+
+ if (access(dfile, F_OK) < 0) {
+ fclose(df);
+ opendfile(1);
+ }
+}
+
+#endif
+
+
+/*
+ * mx4200_start - open the devices and initialize data for processing
+ */
+static int
+mx4200_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct mx4200unit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
+
+ /*
+ * Open serial port
+ */
+ (void)sprintf(device, MX4200FD, unit);
+ if (!(fd = refclock_open(device, SPEED232, 0)))
+ return (0);
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct mx4200unit *)
+ emalloc(sizeof(struct mx4200unit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct mx4200unit));
+ up->io.clock_recv = mx4200_receive;
+ up->io.srcclock = (caddr_t)up;
+ up->io.datalen = 0;
+ up->io.fd = fd;
+ if (!io_addclock(&up->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+ up->peer = peer;
+ pp = peer->procptr;
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = MX4200PRECISION;
+ pp->clockdesc = MX4200DESCRIPTION;
+ memcpy((char *)&pp->refid, MX4200REFID, 4);
+
+ /* Insure the receiver is properly configured */
+ mx4200_config(up);
+
+#ifdef DEBUG
+ opendfile(0);
+#endif
+ return (1);
+}
+
+
+/*
+ * mx4200_shutdown - shut down the clock
+ */
+static void
+mx4200_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct mx4200unit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct mx4200unit *)pp->unitptr;
+ io_closeclock(&up->io);
+ free(up);
+}
+
+
+static void
+mx4200_config(up)
+ register struct mx4200unit *up;
+{
+ register int fd = up->io.fd;
+
+syslog(LOG_DEBUG, "mx4200_config");
+
+ /* Zero the output list (do it twice to flush possible junk) */
+ mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1);
+ mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1);
+
+ /* Switch to 2d mode */
+ mx4200_send(fd, "%s,%03d,%d,,%.1f,%.1f,,%d,%d,%c,%d",
+ pmvxg, PMVXG_S_INITMODEB,
+ 2, /* 2d mode */
+ 0.1, /* hor accel fact as per Steve */
+ 0.1, /* ver accel fact as per Steve */
+ 10, /* hdop limit as per Steve */
+ 5, /* elevation limit as per Steve */
+ 'U', /* time output mode */
+ 0); /* local time offset from gmt */
+
+ /* Configure time recovery */
+ mx4200_send(fd, "%s,%03d,%c,%c,%c,%d,%d,%d,",
+ pmvxg, PMVXG_S_TRECOVCONF,
+#ifdef notdef
+ 'K', /* known position */
+ 'D', /* dynamic position */
+#else
+ 'S', /* static position */
+#endif
+ 'U', /* steer clock to gps time */
+ 'A', /* always output time pulse */
+ 500, /* max time error in ns */
+ 0, /* user bias in ns */
+ 1); /* output to control port */
+}
+
+
+/*
+ * mx4200_poll - mx4200 watchdog routine
+ */
+static void
+mx4200_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct mx4200unit *up;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_poll: unit %d invalid", unit);
+ return;
+ }
+
+ up = mx4200units[unit];
+ if ((current_time - up->lasttime) > 150) {
+ refclock_report(peer, CEVNT_FAULT);
+
+ /* Request a status message which should trigger a reconfig */
+ mx4200_send(up->io.fd, "%s,%03d", "CDGPQ", PMVXG_D_STATUS);
+ syslog(LOG_DEBUG, "mx4200_poll: request status");
+ }
+}
+
+static const char char2hex[] = "0123456789ABCDEF";
+
+
+/*
+ * mx4200_receive - receive gps data
+ */
+static void
+mx4200_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct mx4200unit *up;
+ struct peer *peer;
+ register char *dpt, *cp;
+ register u_long tmp_ui;
+ register u_long tmp_uf;
+ register u_long gpstime;
+ struct ppsclockev ev;
+ register struct calendar *jt;
+ struct calendar sjt;
+ register int n;
+ int valid, leapsec;
+ register u_char ck;
+
+ up = (struct mx4200unit *)rbufp->recv_srcclock;
+ peer = up->peer;
+#ifdef DEBUG
+ if (debug > 3)
+ printf("mx4200_receive: nsamples = %d\n", up->nsamples);
+#endif
+
+ /* Record the time of this event */
+ up->lasttime = current_time;
+
+ /* Get the pps value */
+ if (ioctl(up->io.fd, CIOGETEV, (char *)&ev) < 0) {
+ /* XXX Actually, if this fails, we're pretty much screwed */
+#ifdef DEBUG
+ if (debug) {
+ fprintf(stderr, "mx4200_receive: ");
+ perror("CIOGETEV");
+ }
+#endif
+ refclock_report(peer, CEVNT_FAULT);
+ mx4200_reset(up);
+ return;
+ }
+ tmp_ui = ev.tv.tv_sec + JAN_1970;
+ TVUTOTSF(ev.tv.tv_usec, tmp_uf);
+
+ /* Get buffer and length; sock away last timecode */
+ n = rbufp->recv_length;
+ dpt = rbufp->recv_buffer;
+ if (n <= 1)
+ return;
+ up->lencode = n;
+ memmove(up->lastcode, dpt, n);
+
+ /*
+ * We expect to see something like:
+ *
+ * $PMVXG,830,T,1992,07,09,04:18:34,U,S,-02154,00019,000000,00*1D\n
+ *
+ * Reject if any important landmarks are missing.
+ */
+ cp = dpt + n - 4;
+ if (cp < dpt || *dpt != '$' || cp[0] != '*' || cp[3] != '\n') {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad format\n");
+#endif
+ refclock_report(peer, CEVNT_BADREPLY);
+ mx4200_reset(up);
+ return;
+ }
+
+ /* Check checksum */
+ ck = cksum(&dpt[1], n - 5);
+ if (char2hex[ck >> 4] != cp[1] || char2hex[ck & 0xf] != cp[2]) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad checksum\n");
+#endif
+ refclock_report(peer, CEVNT_BADREPLY);
+ mx4200_reset(up);
+ return;
+ }
+
+ /* Truncate checksum (and the buffer for that matter) */
+ *cp = '\0';
+
+ /* Leap second debugging stuff */
+ if ((leap_hoursfromleap && !leap_happened) || leap_debug > 0) {
+ /* generate reports for awhile after leap */
+ if (leap_hoursfromleap && !leap_happened)
+ leap_debug = 3600;
+ else
+ --leap_debug;
+ syslog(LOG_INFO, "mx4200 leap: %s \"%s\"",
+ umfptoa(tmp_ui, tmp_uf, 6), dpt);
+ }
+
+ /* Parse time recovery message */
+ jt = &sjt;
+ if ((cp = mx4200_parse(dpt, jt, &valid, &leapsec)) != NULL) {
+ /* Configure the receiver if necessary */
+ if (mx4200_needconf(dpt))
+ mx4200_config(up);
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: mx4200_parse: %s\n", cp);
+#endif
+ refclock_report(peer, CEVNT_BADREPLY);
+ mx4200_reset(up);
+ return;
+ }
+
+ /* Setup leap second indicator */
+ if (leapsec == 0)
+ up->leap = LEAP_NOWARNING;
+ else if (leapsec == 1)
+ up->leap = LEAP_ADDSECOND;
+ else if (leapsec == -1)
+ up->leap = LEAP_DELSECOND;
+ else
+ up->leap = LEAP_NOTINSYNC; /* shouldn't happen */
+
+ /* Check parsed time (allow for possible leap seconds) */
+ if (jt->second >= 61 || jt->minute >= 60 || jt->hour >= 24) {
+#ifdef DEBUG
+ if (debug) {
+ printf("mx4200_receive: bad time %d:%02d:%02d",
+ jt->hour, jt->minute, jt->second);
+ if (leapsec != 0)
+ printf(" (leap %+d)", leapsec);
+ putchar('\n');
+ }
+#endif
+ refclock_report(peer, CEVNT_BADTIME);
+ mx4200_reset(up);
+ /* Eat the next pulse which the clock claims will be bad */
+ up->nsamples = -1;
+ return;
+ }
+
+ /* Check parsed date */
+ if (jt->monthday > 31 || jt->month > 12 || jt->year < 1900) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad date (%d/%d/%d)\n",
+ jt->monthday, jt->month, jt->year);
+#endif
+ refclock_report(peer, CEVNT_BADDATE);
+ mx4200_reset(up);
+ return;
+ }
+
+ /* Convert to ntp time */
+ gpstime = caltontp(jt);
+
+ /* The gps message describes the *next* pulse; pretend it's this one */
+ --gpstime;
+
+ /* Debugging */
+#ifdef DEBUG
+ checkdfile();
+ if (df != NULL) {
+ l_fp t;
+
+ t.l_ui = gpstime;
+ t.l_uf = 0;
+ M_SUB(t.l_ui, t.l_uf, tmp_ui, tmp_uf);
+ fprintf(df, "%s\t%s",
+ umfptoa(tmp_ui, tmp_uf, 6), mfptoa(t.l_ui, t.l_uf, 6));
+ if (debug > 3)
+ fprintf(df, "\t(gps: %lu)", gpstime);
+ if (leapsec != 0)
+ fprintf(df, "\t(leap sec %+d)", leapsec);
+ if (!valid)
+ fprintf(df, "\t(pulse not valid)");
+ fputc('\n', df);
+ }
+#endif
+
+ /* Check pps serial number against last one */
+ if (up->lastserial + 1 != ev.serial && up->lastserial != 0) {
+#ifdef DEBUG
+ if (debug) {
+ if (ev.serial == up->lastserial)
+ printf("mx4200_receive: no new pps event\n");
+ else
+ printf("mx4200_receive: missed %d pps events\n",
+ ev.serial - up->lastserial - 1);
+ }
+#endif
+ refclock_report(peer, CEVNT_FAULT);
+ mx4200_reset(up);
+ /* fall through and this one collect as first sample */
+ }
+ up->lastserial = ev.serial;
+
+/*
+ * XXX
+ * Since this message is for the next pulse, it's really the next pulse
+ * that the clock might be telling us will be invalid.
+ */
+ /* Toss if not designated "valid" by the gps */
+ if (!valid) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: pps not valid\n");
+#endif
+ refclock_report(peer, CEVNT_BADTIME);
+ mx4200_reset(up);
+ return;
+ }
+
+ /* Copy time into mx4200unit struct */
+ /* XXX (why?) */
+ up->year = jt->year;
+ up->monthday = jt->monthday;
+ up->hour = jt->hour;
+ up->minute = jt->minute;
+ up->second = jt->second;
+
+ /* Sock away the GPS and UNIX timesamples */
+ n = up->nsamples++;
+ if (n < 0)
+ return; /* oops, this pulse is bad */
+ up->gpssamples[n] = gpstime;
+ up->unixsamples[n].l_ui = up->lastsampletime.l_ui = tmp_ui;
+ up->unixsamples[n].l_uf = up->lastsampletime.l_uf = tmp_uf;
+ if (up->nsamples >= NSTMPS) {
+ /*
+ * Here we've managed to complete an entire NSTMPS
+ * second cycle without major mishap. Process what has
+ * been received.
+ */
+ mx4200_process(up);
+ mx4200_reset(up);
+ }
+}
+
+/*
+ * Compare two l_fp's, used with qsort()
+ */
+static int
+mx4200_cmpl_fp(p1, p2)
+ register void *p1, *p2;
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+/*
+ * mx4200_process - process a pile of samples from the clock
+ */
+static void
+mx4200_process(up)
+ struct mx4200unit *up;
+{
+ struct peer *peer;
+ struct refclockproc *pp;
+ register int i, n;
+ register l_fp *fp, *op;
+ register u_long *lp;
+ l_fp off[NSTMPS];
+ register u_long tmp_ui, tmp_uf;
+ register u_long date_ui, date_uf;
+ u_fp dispersion;
+
+ /* Compute offsets from the raw data. */
+ peer = up->peer;
+ pp = peer->procptr;
+ fp = up->unixsamples;
+ op = off;
+ lp = up->gpssamples;
+ for (i = 0; i < NSTMPS; ++i, ++lp, ++op, ++fp) {
+ op->l_ui = *lp;
+ op->l_uf = 0;
+ L_SUB(op, fp);
+ }
+
+ /* Sort offsets into ascending order. */
+ qsort((char *)off, NSTMPS, sizeof(l_fp), mx4200_cmpl_fp);
+
+ /*
+ * Reject the furthest from the median until 8 samples left
+ */
+ i = 0;
+ n = NSTMPS;
+ while ((n - i) > 8) {
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ date_ui = off[(n+i)/2].l_ui;
+ date_uf = off[(n+i)/2].l_uf;
+ M_SUB(tmp_ui, tmp_uf, date_ui, date_uf);
+ M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf);
+ if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) {
+ /*
+ * reject low end
+ */
+ i++;
+ } else {
+ /*
+ * reject high end
+ */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets.
+ */
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ dispersion = MFPTOFP(tmp_ui, tmp_uf);
+
+ /*
+ * Now compute the offset estimate. If the sloppy clock
+ * flag is set, average the remainder, otherwise pick the
+ * median.
+ */
+ if (pp->sloppyclockflag) {
+ tmp_ui = tmp_uf = 0;
+ while (i < n) {
+ M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ i++;
+ }
+ M_RSHIFT(tmp_ui, tmp_uf);
+ M_RSHIFT(tmp_ui, tmp_uf);
+ M_RSHIFT(tmp_ui, tmp_uf);
+ i = 0;
+ off[0].l_ui = tmp_ui;
+ off[0].l_uf = tmp_uf;
+ } else {
+ i = (n + i) / 2;
+ }
+
+ /*
+ * Add the default MX4200 QT delay into this.
+ */
+#ifdef notdef
+ L_ADDUF(&off[i], MX4200QTFUDGE);
+#endif
+
+ /*
+ * Done. Use lastref as the reference time and lastrec
+ * as the receive time. ** note this can result in tossing
+ * out the peer in the protocol module if lastref > lastrec,
+ * so last rec is used for both values - dlm ***
+ */
+ refclock_receive(up->peer, &off[i],
+ (s_fp)0, /* delay */
+ dispersion,
+ &up->unixsamples[NSTMPS-1], /* reftime */
+ &up->unixsamples[NSTMPS-1], /* rectime */
+ up->leap);
+
+ refclock_report(peer, CEVNT_NOMINAL);
+}
+
+
+/*
+ * Returns true if the this is a status message. We use this as
+ * an indication that the receiver needs to be initialized.
+ */
+static int
+mx4200_needconf(buf)
+ char *buf;
+{
+ register long v;
+ char *cp;
+
+ cp = buf;
+
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Record type */
+ v = strtol(cp, &cp, 10);
+ if (v != PMVXG_D_STATUS)
+ return (0);
+ /*
+ * XXX
+ * Since we configure the receiver to not give us status
+ * messages and since the receiver outputs status messages by
+ * default after being reset to factory defaults when sent the
+ * "$PMVXG,018,C\r\n" message, any status message we get
+ * indicates the reciever needs to be initialized; thus, it is
+ * not necessary to decode the status message.
+ */
+#ifdef notdef
+ ++cp;
+
+ /* Receiver status */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Number of satellites which should be visible */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Number of satellites being tracked */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Time since last NAV */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Initialization status */
+ v = strtol(cp, &cp, 10);
+ if (v == 0)
+#endif
+ return (1);
+}
+
+/* Parse a mx4200 time recovery message. Returns a string if error */
+static char *
+mx4200_parse(buf, jt, validp, leapsecp)
+ register char *buf;
+ register struct calendar *jt;
+ register int *validp, *leapsecp;
+{
+ register long v;
+ char *cp;
+
+ cp = buf;
+ memset((char *)jt, 0, sizeof(*jt));
+
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no rec-type");
+ ++cp;
+
+ /* Record type */
+ v = strtol(cp, &cp, 10);
+ if (v != PMVXG_D_TRECOVOUT)
+ return ("wrong rec-type");
+
+ /* Pulse valid indicator */
+ if (*cp++ != ',')
+ return ("no pulse-valid");
+ if (*cp == 'T')
+ *validp = 1;
+ else if (*cp == 'F')
+ *validp = 0;
+ else
+ return ("bad pulse-valid");
+ ++cp;
+
+ /* Year */
+ if (*cp++ != ',')
+ return ("no year");
+ jt->year = strtol(cp, &cp, 10);
+
+ /* Month of year */
+ if (*cp++ != ',')
+ return ("no month");
+ jt->month = strtol(cp, &cp, 10);
+
+ /* Day of month */
+ if (*cp++ != ',')
+ return ("no month day");
+ jt->monthday = strtol(cp, &cp, 10);
+
+ /* Hour */
+ if (*cp++ != ',')
+ return ("no hour");
+ jt->hour = strtol(cp, &cp, 10);
+
+ /* Minute */
+ if (*cp++ != ':')
+ return ("no minute");
+ jt->minute = strtol(cp, &cp, 10);
+
+ /* Second */
+ if (*cp++ != ':')
+ return ("no second");
+ jt->second = strtol(cp, &cp, 10);
+
+ /* Time indicator */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time indicator");
+
+ /* Time recovery mode */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time mode");
+
+ /* Oscillator offset */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no osc off");
+ ++cp;
+
+ /* Time mark error */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no time mark err");
+ ++cp;
+
+ /* User time bias */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no user bias");
+ ++cp;
+
+ /* Leap second flag */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no leap");
+ ++cp;
+ *leapsecp = strtol(cp, &cp, 10);
+
+ return (NULL);
+}
+
+/* Calculate the checksum */
+static u_char
+cksum(cp, n)
+ register char *cp;
+ register u_int n;
+{
+ register u_char ck;
+
+ for (ck = 0; n-- > 0; ++cp)
+ ck ^= *cp;
+ return (ck);
+}
+
+static void
+#if __STDC__
+mx4200_send(register int fd, const char *fmt, ...)
+#else
+mx4200_send(fd, fmt, va_alist)
+ register int fd;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ register char *cp;
+ register int n, m;
+ va_list ap;
+ char buf[1024];
+ u_char ck;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ cp = buf;
+ *cp++ = '$';
+#ifdef notdef
+ /* BSD is rational */
+ n = vsnprintf(cp, sizeof(buf) - 1, fmt, ap);
+#else
+ /* SunOS sucks */
+ (void)vsprintf(cp, fmt, ap);
+ n = strlen(cp);
+#endif
+ ck = cksum(cp, n);
+ cp += n;
+ ++n;
+#ifdef notdef
+ /* BSD is rational */
+ n += snprintf(cp, sizeof(buf) - n - 5, "*%02X\r\n", ck);
+#else
+ /* SunOS sucks */
+ sprintf(cp, "*%02X\r\n", ck);
+ n += strlen(cp);
+#endif
+
+ m = write(fd, buf, n);
+ if (m < 0)
+ syslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf);
+ else if (m != n)
+ syslog(LOG_ERR, "mx4200_send: write: %d != %d (%s)", m, n, buf);
+ va_end(ap);
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_omega.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_omega.c
new file mode 100644
index 000000000000..e62b668956f3
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_omega.c
@@ -0,0 +1,999 @@
+/*
+ * refclock_omega - clock driver for the Kinemetrics Truetime OM-DC OMEGA
+ * receiver.
+ *
+ * Version 1.0 11-Dec-92 Steve Clift (clift@ml.csiro.au)
+ * Initial version, mostly lifted from refclock_goes.c.
+ *
+ * 1.1 03-May-93 Steve Clift
+ * Tarted up the sample filtering mechanism to give improved
+ * one-off measurements. Improved measurement dispersion code
+ * to account for accumulated drift when the clock loses lock.
+ *
+ */
+
+#if defined(REFCLOCK) && (defined(OMEGA) || defined(OMEGACLK) || defined(OMEGAPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(OMEGACLK)
+#include <sys/clkdefs.h>
+#endif /* OMEGACLK */
+#endif /* STREAM */
+
+#if defined (OMEGAPPS)
+#include <sys/ppsclock.h>
+#endif /* OMEGAPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Support for Kinemetrics Truetime OM-DC OMEGA Receiver
+ *
+ * Most of this code is copied from refclock_goes.c with thanks.
+ *
+ * the time code looks like follows; Send the clock a R or C and once per
+ * second a timestamp will appear that looks like this:
+ * ADDD:HH:MM:SSQCL
+ * A - control A
+ * Q Quality indication: indicates possible error of
+ * > >+- 5 seconds
+ * ? >+/- 500 milliseconds # >+/- 50 milliseconds
+ * * >+/- 5 milliseconds . >+/- 1 millisecond
+ * A-H less than 1 millisecond. Character indicates which station
+ * is being received as follows:
+ * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
+ * E = La Reunion, F = Argentina, G = Australia, H = Japan.
+ * C - Carriage return
+ * L - Line feed
+ * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* max number of OMEGA units */
+#define OMEGA232 "/dev/omega%d"
+#define SPEED232 B9600 /* 9600 baud */
+
+/*
+ * Radio interface parameters
+ */
+#define OMEGADESCRIPTION "Kinemetrics OM-DC OMEGA Receiver" /* who we are */
+#define OMEGAMAXDISPERSE (FP_SECOND/32) /* max allowed sample dispersion */
+#define OMEGAPRECISION (-10) /* precision assumed (about 1 ms) */
+#define OMEGAREFID "VLF\0" /* reference id */
+#define LENOMEGA 13 /* length of standard response */
+#define GMT 0 /* hour offset from Greenwich */
+#define NSTAMPS 9 /* samples collected when polled */
+#define NSKEEP 5 /* samples to keep after discards */
+#define BMAX 50 /* timecode buffer length */
+
+/*
+ * The OM-DC puts out the start bit of the <CR> on the second, but
+ * we see the result after the <LF> is received, about 2ms later at
+ * 9600 baud. Use this as the default fudge time, and let the user
+ * fiddle it to account for driver latency etc.
+ */
+#define DEFFUDGETIME 0x00830000 /* default fudge time (~2ms) */
+
+/*
+ * Clock drift errors as u_fp values.
+ */
+#define U_FP5000MS (5*FP_SECOND) /* 5 seconds */
+#define U_FP500MS (FP_SECOND/2) /* 500 msec */
+#define U_FP50MS (FP_SECOND/20) /* 50 msec */
+#define U_FP5MS (FP_SECOND/200) /* 5 msec */
+
+/*
+ * Station codes
+ */
+#define STATION_NONE 0
+#define STATION_NORWAY 1
+#define STATION_LIBERIA 2
+#define STATION_HAWAII 3
+#define STATION_N_DAKOTA 4
+#define STATION_LA_REUNION 5
+#define STATION_ARGENTINA 6
+#define STATION_AUSTRALIA 7
+#define STATION_JAPAN 8
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+
+/*
+ * Imported from the timer module
+ */
+extern u_long current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * OMEGA unit control structure
+ */
+struct omegaunit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NSTAMPS]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short station; /* which station we're locked to */
+ u_short polled; /* Hand in a time sample? */
+ u_long coderecv; /* timecodes received */
+ u_char lencode; /* length of last timecode */
+ u_long lasttime; /* last time clock heard from */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last failure */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ u_short msec; /* millisecond of second */
+ u_char quality; /* quality char from last timecode */
+ u_long yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ u_long polls; /* polls sent */
+ u_long noreply; /* no replies to polls */
+ u_long badformat; /* bad format */
+ u_long baddata; /* bad data */
+ u_long timestarted; /* time we started this */
+};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct omegaunit *omegaunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor1[MAXUNITS];
+static l_fp fudgefactor2[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char readonlyclockflag[MAXUNITS];
+static u_long refid[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void omega_init P((void));
+static int omega_start P((u_int, struct peer *));
+static void omega_shutdown P((int));
+static void omega_report_event P((struct omegaunit *, int));
+static void omega_receive P((struct recvbuf *));
+static char omega_process P((struct omegaunit *, l_fp *, u_fp *));
+static void omega_poll P((int, struct peer *));
+static void omega_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void omega_buginfo P((int, struct refclockbug *));
+static void omega_send P((struct omegaunit *, char *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_omega = {
+ omega_start, omega_shutdown, omega_poll,
+ omega_control, omega_init, omega_buginfo, NOFLAGS
+};
+
+/*
+ * omega_init - initialize internal omega driver data
+ */
+static void
+omega_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)omegaunits, 0, sizeof omegaunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor1[i].l_ui = 0;
+ fudgefactor1[i].l_uf = DEFFUDGETIME;
+ fudgefactor2[i].l_ui = 0;
+ fudgefactor2[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], OMEGAREFID, 4);
+ }
+}
+
+
+/*
+ * omega_start - open the OMEGA devices and initialize data for processing
+ */
+static int
+omega_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct omegaunit *omega;
+ register int i;
+ int fd232;
+ char omegadev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,"omega_start: unit %d invalid", unit);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_start: unit %d in use", unit);
+ return 0;
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(omegadev, OMEGA232, unit);
+ fd232 = open(omegadev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "omega_start: open of %s: %m", omegadev);
+ return 0;
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TCGETA): %m", omegadev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TCSETA): %m", omegadev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The OMEGACLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The OMEGAPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcgetattr(%s): %m", omegadev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcsetattr(%s): %m", omegadev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcflush(%s): %m", omegadev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(OMEGACLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, I_PUSH, clk): %m", omegadev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, CLK_SETSTR): %m", omegadev);
+#endif /* OMEGACLK */
+#if defined(OMEGAPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, I_PUSH, ppsclock): %m", omegadev);
+ else
+ fdpps = fd232;
+#endif /* OMEGAPPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The OMEGACLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(OMEGACLK)
+ int ldisc = CLKLDISC;
+#endif /* OMEGACLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCGETP): %m", omegadev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(OMEGACLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* OMEGACLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCSETP): %m", omegadev);
+ goto screwed;
+ }
+#if defined(OMEGACLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCSETD): %m",omegadev);
+ goto screwed;
+ }
+#endif /* OMEGACLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (omegaunits[unit] != 0) {
+ omega = omegaunits[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && omegaunits[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ omega = omegaunits[i];
+ omegaunits[i] = 0;
+ } else {
+ omega = (struct omegaunit *)
+ emalloc(sizeof(struct omegaunit));
+ }
+ }
+ memset((char *)omega, 0, sizeof(struct omegaunit));
+ omegaunits[unit] = omega;
+
+ /*
+ * Set up the structures
+ */
+ omega->peer = peer;
+ omega->unit = (u_char)unit;
+ omega->timestarted = current_time;
+ omega->station = STATION_NONE;
+
+ omega->io.clock_recv = omega_receive;
+ omega->io.srcclock = (caddr_t)omega;
+ omega->io.datalen = 0;
+ omega->io.fd = fd232;
+ if (!io_addclock(&omega->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = OMEGAPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ return 1;
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return 0;
+}
+
+
+/*
+ * omega_shutdown - shut down a OMEGA clock
+ */
+static void
+omega_shutdown(unit)
+ int unit;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_shutdown: unit %d invalid",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ omega = omegaunits[unit];
+ io_closeclock(&omega->io);
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * omega_report_event - note the occurance of an event
+ */
+static void
+omega_report_event(omega, code)
+ struct omegaunit *omega;
+ int code;
+{
+ struct peer *peer;
+
+ peer = omega->peer;
+ if (omega->status != (u_char)code) {
+ omega->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ omega->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "omega clock %s event %x\n", ntoa(&peer->srcadr), code);
+ }
+}
+
+
+/*
+ * omega_receive - receive data from the serial interface on a
+ * Kinemetrics OM-DC OMEGA clock.
+ */
+static void
+omega_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i;
+ register struct omegaunit *omega;
+ register u_char *dpt;
+ register char *cp, *cpend;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion, drift;
+
+ /*
+ * Get the clock this applies to and a pointers to the data
+ */
+ omega = (struct omegaunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+
+#ifndef PEDANTIC
+ /*
+ * The OM-DC outputs a timecode every second, but we only want
+ * a set of NSTAMPS timecodes when polled (every 64 seconds).
+ * Setting PEDANTIC causes a sanity check on every timecode.
+ */
+ if (!omega->polled)
+ return;
+#endif
+
+ /*
+ * Edit timecode to remove control chars
+ */
+ dpend = dpt + rbufp->recv_length;
+ cp = omega->lastcode;
+ cpend = omega->lastcode + BMAX - 1;
+ while (dpt < dpend && cp < cpend) {
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#ifdef OMEGACLK
+ else if (*cp == '\r') {
+ if (dpend - dpt < 8) {
+ /* short timestamp */
+ return;
+ }
+ if (!buftvtots(dpt,&omega->lastrec)) {
+ /* screwy timestamp */
+ return;
+ }
+ dpt += 8;
+ }
+#endif
+ }
+ *cp = '\0';
+ omega->lencode = cp - omega->lastcode;
+
+ if (omega->lencode == 0)
+ return;
+ else if (omega->lencode != LENOMEGA) {
+ omega->badformat++;
+ /* Sometimes get a lot of these, filling the log with noise */
+ /* omega_report_event(omega, CEVNT_BADREPLY); */
+ return;
+ }
+
+#ifndef OMEGACLK
+ omega->lastrec = rbufp->recv_time;
+#endif
+
+#ifdef DEBUG
+ if (debug)
+ printf("omega: timecode %d %s\n",
+ omega->lencode, omega->lastcode);
+#endif
+
+ /*
+ * We get down to business, check the timecode format
+ * and decode its contents.
+ */
+ cp = omega->lastcode;
+ omega->leap = 0;
+ /*
+ * Check timecode format.
+ */
+ if (!isdigit(cp[0]) || /* day of year */
+ !isdigit(cp[1]) ||
+ !isdigit(cp[2]) ||
+ cp[3] != ':' || /* <sp> */
+ !isdigit(cp[4]) || /* hours */
+ !isdigit(cp[5]) ||
+ cp[6] != ':' || /* : separator */
+ !isdigit(cp[7]) || /* minutes */
+ !isdigit(cp[8]) ||
+ cp[9] != ':' || /* : separator */
+ !isdigit(cp[10]) || /* seconds */
+ !isdigit(cp[11])) {
+ omega->badformat++;
+ omega_report_event(omega, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Convert and check values.
+ */
+ omega->year = 0; /* fake */
+ omega->day = cp[0] - '0';
+ omega->day = MULBY10(omega->day) + cp[1] - '0';
+ omega->day = MULBY10(omega->day) + cp[2] - '0';
+ omega->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ omega->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ omega->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ omega->msec = 0;
+
+ if (omega->day < 1 || omega->day > 366) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADDATE);
+ return;
+ }
+ if (omega->hour > 23 || omega->minute > 59 || omega->second > 59) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+
+ /*
+ * Check quality/station-id flag. The OM-DC should normally stay
+ * permanently locked to a station, and its time error should be less
+ * than 1 msec. If it loses lock for any reason, it makes a worst
+ * case drift estimate based on the internally stored stability figure
+ * for its reference oscillator. The stability figure can be adjusted
+ * by the user based on experience. The default value is 1E05, which
+ * is pretty bad - 2E07 is about right for the unit I have.
+ *
+ * The following is arbitrary, change it if you're offended:
+ * For errors less than 50 msec, just clear the station indicator.
+ * For errors greater than 50 msec, flag loss of sync and report a
+ * propagation problem. If the error is greater than 500 msec,
+ * something is dreadfully wrong - report a clock fault.
+ *
+ * In each case, we set a drift estimate which is used below as an
+ * estimate of measurement accuracy.
+ */
+ omega->quality = cp[12];
+ if (cp[12] == '>' || cp[12] == '?') {
+ /* Error 500 to 5000 msec */
+ omega_report_event(omega, CEVNT_FAULT);
+ omega->leap = LEAP_NOTINSYNC;
+ omega->station = STATION_NONE;
+ drift = U_FP5000MS;
+ } else if (cp[12] == '#') {
+ /* Error 50 to 500 msec */
+ omega_report_event(omega, CEVNT_PROP);
+ omega->leap = LEAP_NOTINSYNC;
+ omega->station = STATION_NONE;
+ drift = U_FP500MS;
+ } else if (cp[12] == '*') {
+ /* Error 5 to 50 msec */
+ omega->lasttime = current_time;
+ omega->station = STATION_NONE;
+ drift = U_FP50MS;
+ } else if (cp[12] == '.') {
+ /* Error 1 to 5 msec */
+ omega->lasttime = current_time;
+ omega->station = STATION_NONE;
+ drift = U_FP5MS;
+ } else if ('A' <= cp[12] && cp[12] <= 'H') {
+ /* Error less than 1 msec */
+ omega->lasttime = current_time;
+ omega->station = cp[12] - 'A' + 1;
+ drift = 0;
+ } else {
+ omega->badformat++;
+ omega_report_event(omega, CEVNT_BADREPLY);
+ return;
+ }
+
+#ifdef PEDANTIC
+ /* If we haven't been polled, bail out. */
+ if (!omega->polled)
+ return;
+#endif
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the seconds and the millisecond field for the
+ * fraction when present.
+ *
+ * this code does not yet know how to do the years
+ */
+ tstmp = omega->lastrec;
+ if (!clocktime(omega->day, omega->hour, omega->minute,
+ omega->second, GMT, tstmp.l_ui,
+ &omega->yearstart, &omega->lastref.l_ui)) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(omega->msec, omega->lastref.l_uf);
+
+ /*
+ * Adjust the read value by fudgefactor1 to correct RS232 delays.
+ */
+ L_ADD(&omega->lastref, &fudgefactor1[omega->unit]);
+
+ /* Carousel of NSTAMPS offsets. */
+ i = omega->coderecv % NSTAMPS;
+ omega->offset[i] = omega->lastref;
+ L_SUB(&omega->offset[i], &tstmp);
+ omega->coderecv++;
+
+ /* If we don't yet have a full set, return. */
+ if (omega->coderecv < NSTAMPS)
+ return;
+
+ /*
+ * Filter the samples, add the fudge factor and pass the
+ * offset and dispersion along. We use lastrec as both the
+ * reference time and receive time in order to avoid being cute,
+ * like setting the reference time later than the receive time,
+ * which may cause a paranoid protocol module to chuck out the
+ * data. If the sample filter chokes because of excessive
+ * dispersion or whatever, get a new sample (omega->coderecv
+ * is still >= NSTAMPS) and try again.
+ */
+ if (!omega_process(omega, &tstmp, &dispersion)) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+
+ /*
+ * Add accumulated clock drift to the dispersion to get
+ * a (hopefully) meaningful measurement accuracy estimate.
+ */
+ dispersion += drift;
+ refclock_receive(omega->peer, &tstmp, GMT, dispersion,
+ &omega->lastrec, &omega->lastrec, omega->leap);
+
+ /*
+ * We have succeeded in answering the poll. If the clock
+ * is locked, we're nominal.
+ */
+ omega->polled = 0;
+ omega->coderecv = 0;
+ if (omega->leap != LEAP_NOTINSYNC)
+ omega_report_event(omega, CEVNT_NOMINAL);
+}
+
+
+/*
+ * omega_send - time to send the clock a signal to cough up a time sample
+ */
+static void
+omega_send(omega,cmd)
+ struct omegaunit *omega;
+ char *cmd;
+{
+ if (!readonlyclockflag[omega->unit]) {
+ /*
+ * Send a command to the clock.
+ */
+ if (write(omega->io.fd, cmd, 1) != 1) {
+ syslog(LOG_ERR, "omega_send: unit %d: %m", omega->unit);
+ omega_report_event(omega, CEVNT_FAULT);
+ }
+ }
+}
+
+
+/*
+ * Compare two l_fp's, used with qsort()
+ */
+static int
+omega_cmpl_fp(p1, p2)
+ register void *p1, *p2;
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+
+/*
+ * omega_process - process a pile of samples from the clock
+ */
+static char
+omega_process(omega, offset, dispersion)
+ struct omegaunit *omega;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, n;
+ register u_long med_ui, med_uf, tmp_ui, tmp_uf;
+ l_fp off[NSTAMPS];
+ u_fp disp;
+
+ /* Copy in offsets and sort into ascending order */
+ for (i = 0; i < NSTAMPS; i++)
+ off[i] = omega->offset[i];
+ qsort((char *)off, NSTAMPS, sizeof(l_fp), omega_cmpl_fp);
+ /*
+ * Reject the furthest from the median until NSKEEP samples remain
+ */
+ i = 0;
+ n = NSTAMPS;
+ while ((n - i) > NSKEEP) {
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ med_ui = off[(n+i)/2].l_ui;
+ med_uf = off[(n+i)/2].l_uf;
+ M_SUB(tmp_ui, tmp_uf, med_ui, med_uf);
+ M_SUB(med_ui, med_uf, off[i].l_ui, off[i].l_uf);
+ if (M_ISHIS(med_ui, med_uf, tmp_ui, tmp_uf)) {
+ /* reject low end */
+ i++;
+ } else {
+ /* reject high end */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets. If this is greater than
+ * the allowed sample set dispersion, bail out. Otherwise,
+ * return the median offset and the dispersion.
+ */
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ disp = MFPTOFP(tmp_ui, tmp_uf);
+ if (disp > OMEGAMAXDISPERSE)
+ return 0;
+ *offset = off[(n+1)/2];
+ *dispersion = disp;
+ return 1;
+}
+
+
+/*
+ * omega_poll - called by the transmit procedure
+ */
+static void
+omega_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct omegaunit *omega;
+
+ /*
+ * You don't need to poll this clock. It puts out timecodes
+ * once per second. If asked for a timestamp, take note.
+ * The next time a timecode comes in, it will be fed back.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_poll: unit %d not in use", unit);
+ return;
+ }
+ omega = omegaunits[unit];
+ if ((current_time - omega->lasttime) > 150) {
+ omega->noreply++;
+ omega_report_event(omegaunits[unit], CEVNT_TIMEOUT);
+ }
+
+ /*
+ * polled every 64 seconds. Ask OMEGA_RECEIVE to hand in a timestamp.
+ */
+ omega->polled = 1;
+ omega->polls++;
+ /*
+ * Ensure the clock is running in the correct mode - on-second
+ * timestamps.
+ */
+ omega_send(omega,"C");
+}
+
+
+/*
+ * omega_control - set fudge factors, return statistics
+ */
+static void
+omega_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor1[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ fudgefactor2[unit] = in->fudgetime2;
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = omegaunits[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_OMEGA_TRUETIME;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2| CLK_HAVEFLAG1;
+ out->clockdesc = OMEGADESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ omega = omegaunits[unit];
+ out->flags |= omega->station << 1;
+ out->lencode = omega->lencode;
+ out->lastcode = omega->lastcode;
+ out->timereset = current_time - omega->timestarted;
+ out->polls = omega->polls;
+ out->noresponse = omega->noreply;
+ out->badformat = omega->badformat;
+ out->baddata = omega->baddata;
+ out->lastevent = omega->lastevent;
+ out->currentstatus = omega->status;
+ }
+ }
+}
+
+
+/*
+ * omega_buginfo - return clock dependent debugging info
+ */
+static void
+omega_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ omega = omegaunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (omega->lasttime != 0)
+ bug->values[0] = current_time - omega->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = omega->reason;
+ bug->values[2] = omega->year;
+ bug->values[3] = omega->day;
+ bug->values[4] = omega->hour;
+ bug->values[5] = omega->minute;
+ bug->values[6] = omega->second;
+ bug->values[7] = omega->msec;
+ bug->values[8] = omega->noreply;
+ bug->values[9] = omega->yearstart;
+ bug->values[10] = omega->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = omega->lastref;
+ bug->times[1] = omega->lastrec;
+ bug->times[2] = omega->offset[0];
+ bug->times[3] = omega->offset[1];
+ bug->times[4] = omega->offset[2];
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_parse.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_parse.c
new file mode 100644
index 000000000000..1b950a9b8e6f
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_new/refclock_parse.c
@@ -0,0 +1,3617 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
+/*
+ * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.59 1994/05/23 16:29:27 kardel Exp
+ *
+ * refclock_parse.c,v 3.59 1994/05/23 16:29:27 kardel Exp
+ *
+ * generic reference clock driver for receivers
+ *
+ * make use of a STREAMS module for input processing where
+ * available and configured. Currently the STREAMS module
+ * is only available for Suns running SunOS 4.x and SunOS5.x (new - careful!)
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * Defines:
+ * REFCLOCK && (PARSE||PARSEPPS)
+ * - enable this mess
+ * STREAM - allow for STREAMS modules
+ * ("parse", "ppsclocd", "ppsclock")
+ * PARSEPPS - provide PPS information to loopfilter (for
+ * backward compatibilty only)
+ * PPS - supply loopfilter with PPS samples (if configured)
+ * PPSPPS - notify loopfilter of PPS file descriptor
+ *
+ * TTY defines:
+ * HAVE_BSD_TTYS - currently unsupported
+ * HAVE_SYSV_TTYS - will use termio.h
+ * HAVE_TERMIOS - will use termios.h
+ * STREAM - will use streams and implies HAVE_TERMIOS
+ */
+
+/*
+ * This driver currently provides the support for
+ * - Meinberg DCF77 receiver DCF77 PZF 535 (TCXO version) (DCF)
+ * - Meinberg DCF77 receiver DCF77 PZF 535 (OCXO version) (DCF)
+ * - Meinberg DCF77 receiver U/A 31 (DCF)
+ * - IGEL CLOCK (DCF)
+ * - ELV DCF7000 (DCF)
+ * - Schmid clock (DCF)
+ * - Conrad DCF77 receiver module (DCF)
+ * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
+ * - Meinberg GPS166 (GPS)
+ * - Trimble SV6 (GPS)
+ *
+ */
+
+/*
+ * Meinberg receivers are connected via a 9600 baud serial line
+ *
+ * Receivers that do NOT support:
+ * - leap second indication
+ * DCF U/A 31
+ * DCF PZF535 (stock version)
+ *
+ * so...
+ * - for PZF535 please ask for revision PZFUERL4.6 or higher
+ * (support for leap second and alternate antenna)
+ *
+ * The Meinberg GPS receiver also has a special NTP time stamp
+ * format. The firmware release is Uni-Erlangen. Only this
+ * firmware release is supported by xntp3.
+ *
+ * Meinberg generic receiver setup:
+ * output time code every second
+ * Baud rate 9600 7E2S
+ */
+
+#include "ntpd.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_control.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <sys/errno.h>
+extern int errno;
+
+#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
+/* #error NEED TO DEFINE ONE OF "STREAM" or "HAVE_SYSV_TTYS" */
+NEED TO DEFINE ONE OF "STREAM", "HAVE_SYSV_TTYS" or "HAVE_TERMIOS"
+#endif
+
+#ifdef STREAM
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#ifndef HAVE_TERMIOS
+#define HAVE_TERMIOS
+#endif
+#endif
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
+#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
+#undef HAVE_SYSV_TTYS
+#endif
+
+#ifdef HAVE_SYSV_TTYS
+#include <termio.h>
+#define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
+#define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
+#endif
+
+#ifdef HAVE_BSD_TTYS
+/* #error CURRENTLY NO BSD TTY SUPPORT */
+CURRENTLY NO BSD TTY SUPPORT
+#endif
+
+#if !defined(O_RDWR) /* XXX SOLARIS */
+#include <fcntl.h>
+#endif /* !def(O_RDWR) */
+
+#ifdef PPSPPS
+#include <sys/ppsclock.h>
+#endif
+
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+
+#include "parse.h"
+
+#if !defined(NO_SCCSID) && !defined(lint) && !defined(__GNUC__)
+static char rcsid[]="refclock_parse.c,v 3.59 1994/05/23 16:29:27 kardel Exp";
+#endif
+
+/**===========================================================================
+ ** external interface to xntp mechanism
+ **/
+
+static void parse_init P((void));
+static int parse_start P((u_int, struct peer *));
+static void parse_shutdown P((int));
+static void parse_poll P((int, struct peer *));
+static void parse_control P((u_int, struct refclockstat *, struct refclockstat *));
+
+#define parse_buginfo noentry
+
+struct refclock refclock_parse = {
+ parse_start,
+ parse_shutdown,
+ parse_poll,
+ parse_control,
+ parse_init,
+ parse_buginfo,
+ NOFLAGS
+};
+
+/*
+ * the unit field selects for one the prototype to be used (lower 4 bits)
+ * and for the other the clock type in case of different but similar
+ * receivers (bits 4-6)
+ * the most significant bit encodes PPS support
+ * when the most significant bit is set the pps telegrams will be used
+ * for controlling the local clock (ntp_loopfilter.c)
+ * receiver specific configration data is kept in the clockinfo field.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
+#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
+
+/**===========================================================================
+ ** function vector for dynamically binding io handling mechanism
+ **/
+
+typedef struct bind
+{
+ char *bd_description; /* name of type of binding */
+ int (*bd_init)(); /* initialize */
+ void (*bd_end)(); /* end */
+ int (*bd_setcs)(); /* set character size */
+ int (*bd_disable)(); /* disable */
+ int (*bd_enable)(); /* enable */
+ int (*bd_getfmt)(); /* get format */
+ int (*bd_setfmt)(); /* setfmt */
+ int (*bd_getstat)(); /* getstat */
+ int (*bd_setstat)(); /* setstat */
+ int (*bd_timecode)(); /* get time code */
+ void (*bd_receive)(); /* receive operation */
+ void (*bd_poll)(); /* poll operation */
+} bind_t;
+
+#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
+#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
+#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
+#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
+#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
+#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
+#define PARSE_GETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_getstat)(_X_, _DCT_)
+#define PARSE_SETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_setstat)(_X_, _DCT_)
+#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
+#define PARSE_POLL(_X_) (*(_X_)->binding->bd_poll)(_X_)
+
+/*
+ * io modes
+ */
+#define PARSE_F_NOPOLLONLY 0x0001 /* always do async io (possible PPS support via PARSE) */
+#define PARSE_F_POLLONLY 0x0002 /* never do async io (no PPS support via PARSE) */
+#define PARSE_F_PPSPPS 0x0004 /* use loopfilter PPS code (CIOGETEV) */
+#define PARSE_F_PPSONSECOND 0x0008 /* PPS pulses are on second */
+
+/**===========================================================================
+ ** refclock instance data
+ **/
+
+struct parseunit
+{
+ /*
+ * XNTP management
+ */
+ struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
+ int fd; /* device file descriptor */
+ u_char unit; /* encoded unit/type/PPS */
+
+ /*
+ * XNTP io
+ */
+ struct refclockio io; /* io system structure (used in PPS mode) */
+ bind_t *binding; /* io handling binding */
+
+ /*
+ * parse state
+ */
+ parse_t parseio; /* io handling structure (user level parsing) */
+
+ /*
+ * type specific parameters
+ */
+ struct clockinfo *parse_type; /* link to clock description */
+
+ /*
+ * clock specific configuration
+ */
+ l_fp basedelay; /* clock local phase offset */
+ l_fp ppsdelay; /* clock local pps phase offset */
+
+ /*
+ * clock state handling/reporting
+ */
+ u_char flags; /* flags (leap_control) */
+ u_char status; /* current status */
+ u_char lastevent; /* last not NORMAL status */
+ u_long lastchange; /* time (xntp) when last state change accured */
+ u_long statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
+ struct event stattimer; /* statistics timer */
+ u_long polls; /* polls from NTP protocol machine */
+ u_long noresponse; /* number of expected but not seen datagrams */
+ u_long badformat; /* bad format (failed format conversions) */
+ u_long baddata; /* usually bad receive length, bad format */
+
+ u_char pollonly; /* 1 for polling only (no PPS mode) */
+ u_char pollneeddata; /* 1 for receive sample expected in PPS mode */
+ u_long laststatus; /* last packet status (error indication) */
+ u_short lastformat; /* last format used */
+ u_long lastsync; /* time (xntp) when clock was last seen fully synchronized */
+ u_long timestarted; /* time (xntp) when peer clock was instantiated */
+ u_long nosynctime; /* time (xntp) when last nosync message was posted */
+ u_long lastmissed; /* time (xntp) when poll didn't get data (powerup heuristic) */
+ u_long ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
+ parsetime_t time; /* last (parse module) data */
+ void *localdata; /* optional local data */
+};
+
+
+/**===========================================================================
+ ** Clockinfo section all parameter for specific clock types
+ ** includes NTP paramaters, TTY parameters and IO handling parameters
+ **/
+
+static void poll_dpoll P((struct parseunit *));
+static void poll_poll P((struct parseunit *));
+static int poll_init P((struct parseunit *));
+static void poll_end P((struct parseunit *));
+
+typedef struct poll_info
+{
+ u_long rate; /* poll rate - once every "rate" seconds - 0 off */
+ char * string; /* string to send for polling */
+ u_long count; /* number of charcters in string */
+} poll_info_t;
+
+#define NO_FLAGS 0
+#define NO_POLL (void (*)())0
+#define NO_INIT (int (*)())0
+#define NO_END (void (*)())0
+#define NO_DATA (void *)0
+#define NO_FORMAT ""
+#define NO_PPSDELAY 0
+
+#define DCF_ID "DCF" /* generic DCF */
+#define DCF_A_ID "DCFa" /* AM demodulation */
+#define DCF_P_ID "DCFp" /* psuedo random phase shift */
+#define GPS_ID "GPS" /* GPS receiver */
+
+#define NOCLOCK_ROOTDELAY 0x00000000
+#define NOCLOCK_BASEDELAY 0x00000000
+#define NOCLOCK_DESCRIPTION ((char *)0)
+#define NOCLOCK_MAXUNSYNC 0
+#define NOCLOCK_CFLAG 0
+#define NOCLOCK_IFLAG 0
+#define NOCLOCK_OFLAG 0
+#define NOCLOCK_LFLAG 0
+#define NOCLOCK_ID "TILT"
+#define NOCLOCK_POLL NO_POLL
+#define NOCLOCK_INIT NO_INIT
+#define NOCLOCK_END NO_END
+#define NOCLOCK_DATA NO_DATA
+#define NOCLOCK_FORMAT NO_FORMAT
+#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
+
+#define DCF_TYPE CTL_SST_TS_LF
+#define GPS_TYPE CTL_SST_TS_UHF
+
+/*
+ * receiver specific constants
+ */
+#define MBG_CFLAG19200 (B19200|CS7|PARENB|CREAD|HUPCL)
+#define MBG_CFLAG (B9600|CS7|PARENB|CREAD|HUPCL)
+#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
+#define MBG_OFLAG 0
+#define MBG_LFLAG 0
+/*
+ * Meinberg DCF U/A 31 (AM) receiver
+ */
+#define DCFUA31_ROOTDELAY 0x00000D00 /* 50.78125ms */
+#define DCFUA31_BASEDELAY 0x02C00000 /* 10.7421875ms: 10 ms (+/- 3 ms) */
+#define DCFUA31_DESCRIPTION "Meinberg DCF U/A 31"
+#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
+#define DCFUA31_CFLAG MBG_CFLAG
+#define DCFUA31_IFLAG MBG_IFLAG
+#define DCFUA31_OFLAG MBG_OFLAG
+#define DCFUA31_LFLAG MBG_LFLAG
+
+/*
+ * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
+ */
+#define DCFPZF535_ROOTDELAY 0x00000034 /* 800us */
+#define DCFPZF535_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/TCXO"
+#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
+ * @ 5e-8df/f we have accumulated
+ * at most 2.16 ms (thus we move to
+ * NTP synchronisation */
+#define DCFPZF535_CFLAG MBG_CFLAG
+#define DCFPZF535_IFLAG MBG_IFLAG
+#define DCFPZF535_OFLAG MBG_OFLAG
+#define DCFPZF535_LFLAG MBG_LFLAG
+
+
+/*
+ * Meinberg DCF PZF535/OCXO receiver
+ */
+#define DCFPZF535OCXO_ROOTDELAY 0x00000034 /* 800us (max error * 10) */
+#define DCFPZF535OCXO_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/OCXO"
+#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
+ * @ 5e-9df/f we have accumulated
+ * at most an error of 1.73 ms
+ * (thus we move to NTP synchronisation) */
+#define DCFPZF535OCXO_CFLAG MBG_CFLAG
+#define DCFPZF535OCXO_IFLAG MBG_IFLAG
+#define DCFPZF535OCXO_OFLAG MBG_OFLAG
+#define DCFPZF535OCXO_LFLAG MBG_LFLAG
+
+/*
+ * Meinberg GPS166 receiver
+ */
+#define GPS166_ROOTDELAY 0x00000000 /* nothing here */
+#define GPS166_BASEDELAY 0x00800000 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define GPS166_DESCRIPTION "Meinberg GPS166 receiver"
+#define GPS166_MAXUNSYNC 0 /* this clock is immediately lost */
+#define GPS166_CFLAG MBG_CFLAG
+#define GPS166_IFLAG MBG_IFLAG
+#define GPS166_OFLAG MBG_OFLAG
+#define GPS166_LFLAG MBG_LFLAG
+#define GPS166_POLL NO_POLL
+#define GPS166_INIT NO_INIT
+#define GPS166_END NO_END
+#define GPS166_DATA NO_DATA
+#define GPS166_ID GPS_ID
+#define GPS166_FORMAT NO_FORMAT
+
+/*
+ * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
+ *
+ * This is really not the hottest clock - but before you have nothing ...
+ */
+#define DCF7000_ROOTDELAY 0x00000364 /* 13 ms */
+#define DCF7000_BASEDELAY 0x67AE0000 /* 405 ms - slow blow */
+#define DCF7000_DESCRIPTION "ELV DCF7000"
+#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
+#define DCF7000_CFLAG (B9600|CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
+#define DCF7000_IFLAG (IGNBRK)
+#define DCF7000_OFLAG 0
+#define DCF7000_LFLAG 0
+
+/*
+ * Schmid DCF Receiver Kit
+ *
+ * When the WSDCF clock is operating optimally we want the primary clock
+ * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
+ * structure is set to 290 ms and we compute delays which are at least
+ * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
+ */
+#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
+#define WS_POLLCMD "\163"
+#define WS_CMDSIZE 1
+
+static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
+
+#define WSDCF_INIT poll_init
+#define WSDCF_POLL poll_dpoll
+#define WSDCF_END poll_end
+#define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
+#define WSDCF_ROOTDELAY 0X00004A3D /* ~ 290ms */
+#define WSDCF_BASEDELAY 0x028F5C29 /* ~ 10ms */
+#define WSDCF_DESCRIPTION "WS/DCF Receiver"
+#define WSDCF_FORMAT "Schmid"
+#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
+#define WSDCF_CFLAG (B1200|CS8|CREAD|CLOCAL)
+#define WSDCF_IFLAG 0
+#define WSDCF_OFLAG 0
+#define WSDCF_LFLAG 0
+
+/*
+ * RAW DCF77 - input of DCF marks via RS232 - many variants
+ */
+#define RAWDCF_FLAGS PARSE_F_NOPOLLONLY
+#define RAWDCF_ROOTDELAY 0x00000364 /* 13 ms */
+#define RAWDCF_FORMAT "RAW DCF77 Timecode"
+#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
+#define RAWDCF_CFLAG (B50|CS8|CREAD|CLOCAL|PARENB)
+#define RAWDCF_IFLAG (IGNPAR)
+#define RAWDCF_OFLAG 0
+#define RAWDCF_LFLAG 0
+
+/*
+ * RAW DCF variants
+ */
+/*
+ * Conrad receiver
+ *
+ * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
+ * (~40DM - roughly $30 ) followed by a level converter for RS232
+ */
+#define CONRAD_BASEDELAY 0x420C49B0 /* ~258 ms - Conrad receiver @ 50 Baud on a Sun */
+#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
+
+/*
+ * TimeBrick receiver
+ */
+#define TIMEBRICK_BASEDELAY 0x35C29000 /* ~210 ms - TimeBrick @ 50 Baud on a Sun */
+#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
+
+/*
+ * IGEL:clock receiver
+ */
+#define IGELCLOCK_BASEDELAY 0x420C49B0 /* ~258 ms - IGEL:clock receiver */
+#define IGELCLOCK_DESCRIPTION "RAW DCF77 CODE (IGEL:clock)"
+#define IGELCLOCK_CFLAG (B1200|CS8|CREAD|HUPCL|CLOCAL)
+
+/*
+ * Trimble SV6 GPS receiver
+ */
+#ifndef TRIM_POLLRATE
+#define TRIM_POLLRATE 0 /* only true direct polling */
+#endif
+#define TRIM_POLLCMD ">SRM;FR_FLAG=F<>QTM<"
+#define TRIM_CMDSIZE 20
+
+static poll_info_t trimble_pollinfo = { TRIM_POLLRATE, TRIM_POLLCMD, TRIM_CMDSIZE };
+static int trimble_init P((struct parseunit *));
+
+#define TRIMBLESV6_CFLAG (B4800|CS8|CREAD)
+#define TRIMBLESV6_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
+#define TRIMBLESV6_OFLAG (OPOST|ONLCR)
+#define TRIMBLESV6_LFLAG (ICANON|ECHOK)
+#define TRIMBLESV6_FLAGS (PARSE_F_PPSPPS|PARSE_F_PPSONSECOND)
+#define TRIMBLESV6_POLL poll_dpoll
+#define TRIMBLESV6_INIT trimble_init
+#define TRIMBLESV6_END poll_end
+#define TRIMBLESV6_DATA ((void *)(&trimble_pollinfo))
+#define TRIMBLESV6_ID GPS_ID
+#define TRIMBLESV6_FORMAT NO_FORMAT
+#define TRIMBLESV6_ROOTDELAY 0x0
+#define TRIMBLESV6_BASEDELAY 0x0
+#define TRIMBLESV6_DESCRIPTION "Trimble SV6 GPS receiver"
+#define TRIMBLESV6_MAXUNSYNC 0
+#define TRIMBLESV6_EOL '<'
+
+static struct clockinfo
+{
+ u_long cl_flags; /* operation flags (io modes) */
+ void (*cl_poll)(); /* active poll routine */
+ int (*cl_init)(); /* active poll init routine */
+ void (*cl_end)(); /* active poll end routine */
+ void *cl_data; /* local data area for "poll" mechanism */
+ u_fp cl_rootdelay; /* rootdelay */
+ u_long cl_basedelay; /* current offset - unsigned l_fp fractional part */
+ u_long cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional part */
+ char *cl_id; /* ID code (usually "DCF") */
+ char *cl_description; /* device name */
+ char *cl_format; /* fixed format */
+ u_char cl_type; /* clock type (ntp control) */
+ u_long cl_maxunsync; /* time to trust oscillator after loosing synch */
+ u_long cl_cflag; /* terminal io flags */
+ u_long cl_iflag; /* terminal io flags */
+ u_long cl_oflag; /* terminal io flags */
+ u_long cl_lflag; /* terminal io flags */
+} clockinfo[] =
+{ /* 0. 0.0.128 - base offset for PPS support */
+ { /* 127.127.8.<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFPZF535_ROOTDELAY,
+ DCFPZF535_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_P_ID,
+ DCFPZF535_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFPZF535_MAXUNSYNC,
+ DCFPZF535_CFLAG,
+ DCFPZF535_IFLAG,
+ DCFPZF535_OFLAG,
+ DCFPZF535_LFLAG
+ },
+ { /* 127.127.8.4+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFPZF535OCXO_ROOTDELAY,
+ DCFPZF535OCXO_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_P_ID,
+ DCFPZF535OCXO_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFPZF535OCXO_MAXUNSYNC,
+ DCFPZF535OCXO_CFLAG,
+ DCFPZF535OCXO_IFLAG,
+ DCFPZF535OCXO_OFLAG,
+ DCFPZF535OCXO_LFLAG
+ },
+ { /* 127.127.8.8+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFUA31_ROOTDELAY,
+ DCFUA31_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ DCFUA31_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFUA31_MAXUNSYNC,
+ DCFUA31_CFLAG,
+ DCFUA31_IFLAG,
+ DCFUA31_OFLAG,
+ DCFUA31_LFLAG
+ },
+ { /* 127.127.8.12+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCF7000_ROOTDELAY,
+ DCF7000_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ DCF7000_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCF7000_MAXUNSYNC,
+ DCF7000_CFLAG,
+ DCF7000_IFLAG,
+ DCF7000_OFLAG,
+ DCF7000_LFLAG
+ },
+ { /* 127.127.8.16+<device> */
+ NO_FLAGS,
+ WSDCF_POLL,
+ WSDCF_INIT,
+ WSDCF_END,
+ WSDCF_DATA,
+ WSDCF_ROOTDELAY,
+ WSDCF_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ WSDCF_DESCRIPTION,
+ WSDCF_FORMAT,
+ DCF_TYPE,
+ WSDCF_MAXUNSYNC,
+ WSDCF_CFLAG,
+ WSDCF_IFLAG,
+ WSDCF_OFLAG,
+ WSDCF_LFLAG
+ },
+ { /* 127.127.8.20+<device> */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ RAWDCF_ROOTDELAY,
+ CONRAD_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ CONRAD_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG
+ },
+ { /* 127.127.8.24+<device> */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ RAWDCF_ROOTDELAY,
+ TIMEBRICK_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ TIMEBRICK_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG
+ },
+ { /* 127.127.8.28+<device> */
+ NO_FLAGS,
+ GPS166_POLL,
+ GPS166_INIT,
+ GPS166_END,
+ GPS166_DATA,
+ GPS166_ROOTDELAY,
+ GPS166_BASEDELAY,
+ NO_PPSDELAY,
+ GPS166_ID,
+ GPS166_DESCRIPTION,
+ GPS166_FORMAT,
+ GPS_TYPE,
+ GPS166_MAXUNSYNC,
+ GPS166_CFLAG,
+ GPS166_IFLAG,
+ GPS166_OFLAG,
+ GPS166_LFLAG
+ },
+ { /* 127.127.8.32+<device> */
+ TRIMBLESV6_FLAGS,
+#if TRIM_POLLRATE /* DHD940515: Allow user config */
+ NO_POLL,
+#else
+ TRIMBLESV6_POLL,
+#endif
+ TRIMBLESV6_INIT,
+ TRIMBLESV6_END,
+ TRIMBLESV6_DATA,
+ TRIMBLESV6_ROOTDELAY,
+ TRIMBLESV6_BASEDELAY,
+ NO_PPSDELAY,
+ TRIMBLESV6_ID,
+ TRIMBLESV6_DESCRIPTION,
+ TRIMBLESV6_FORMAT,
+ GPS_TYPE,
+ TRIMBLESV6_MAXUNSYNC,
+ TRIMBLESV6_CFLAG,
+ TRIMBLESV6_IFLAG,
+ TRIMBLESV6_OFLAG,
+ TRIMBLESV6_LFLAG
+ },
+ { /* 127.127.8.36+<device> */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ RAWDCF_ROOTDELAY,
+ IGELCLOCK_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ IGELCLOCK_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ IGELCLOCK_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG
+ }
+};
+
+static int ncltypes = sizeof(clockinfo) / sizeof(struct clockinfo);
+
+#define CL_REALTYPE(x) (((x) >> 2) & 0x1F)
+#define CL_TYPE(x) ((CL_REALTYPE(x) >= ncltypes) ? ~0 : CL_REALTYPE(x))
+#define CL_PPS(x) ((x) & 0x80)
+#define CL_UNIT(x) ((x) & 0x3)
+
+/*
+ * Other constant stuff
+ */
+#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
+
+#define PARSENOSYNCREPEAT (10*60) /* mention uninitialized clocks all 10 minutes */
+#define PARSESTATISTICS (60*60) /* output state statistics every hour */
+
+static struct parseunit *parseunits[MAXUNITS];
+
+extern u_long current_time;
+extern s_char sys_precision;
+extern struct event timerqueue[];
+#ifdef PPSPPS
+extern int fdpps;
+#endif
+
+static int notice = 0;
+
+#define PARSE_STATETIME(parse, i) ((parse->status == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
+
+static void parse_event P((struct parseunit *, int));
+static void parse_process P((struct parseunit *, parsetime_t *));
+
+/**===========================================================================
+ ** implementation of i/o handling methods
+ ** (all STREAM, partial STREAM, user level)
+ **/
+
+/*
+ * define possible io handling methods
+ */
+#ifdef STREAM
+static int ppsclock_init P((struct parseunit *));
+static int stream_init P((struct parseunit *));
+static void stream_nop P((struct parseunit *));
+static int stream_enable P((struct parseunit *));
+static int stream_disable P((struct parseunit *));
+static int stream_setcs P((struct parseunit *, parsectl_t *));
+static int stream_getfmt P((struct parseunit *, parsectl_t *));
+static int stream_setfmt P((struct parseunit *, parsectl_t *));
+static int stream_getstat P((struct parseunit *, parsectl_t *));
+static int stream_setstat P((struct parseunit *, parsectl_t *));
+static int stream_timecode P((struct parseunit *, parsectl_t *));
+static void stream_receive P((struct recvbuf *));
+static void stream_poll P((struct parseunit *));
+#endif
+
+static int local_init P((struct parseunit *));
+static void local_end P((struct parseunit *));
+static int local_nop P((struct parseunit *));
+static int local_setcs P((struct parseunit *, parsectl_t *));
+static int local_getfmt P((struct parseunit *, parsectl_t *));
+static int local_setfmt P((struct parseunit *, parsectl_t *));
+static int local_getstat P((struct parseunit *, parsectl_t *));
+static int local_setstat P((struct parseunit *, parsectl_t *));
+static int local_timecode P((struct parseunit *, parsectl_t *));
+static void local_receive P((struct recvbuf *));
+static void local_poll P((struct parseunit *));
+
+static bind_t io_bindings[] =
+{
+#ifdef STREAM
+ {
+ "parse STREAM",
+ stream_init,
+ stream_nop,
+ stream_setcs,
+ stream_disable,
+ stream_enable,
+ stream_getfmt,
+ stream_setfmt,
+ stream_getstat,
+ stream_setstat,
+ stream_timecode,
+ stream_receive,
+ stream_poll
+ },
+ {
+ "ppsclock STREAM",
+ ppsclock_init,
+ local_end,
+ local_setcs,
+ local_nop,
+ local_nop,
+ local_getfmt,
+ local_setfmt,
+ local_getstat,
+ local_setstat,
+ local_timecode,
+ local_receive,
+ local_poll
+ },
+#endif
+ {
+ "normal",
+ local_init,
+ local_end,
+ local_setcs,
+ local_nop,
+ local_nop,
+ local_getfmt,
+ local_setfmt,
+ local_getstat,
+ local_setstat,
+ local_timecode,
+ local_receive,
+ local_poll
+ },
+ {
+ (char *)0,
+ }
+};
+
+#ifdef STREAM
+/*--------------------------------------------------
+ * ppsclock STREAM init
+ */
+static int
+ppsclock_init(parse)
+ struct parseunit *parse;
+{
+ /*
+ * now push the parse streams module
+ * it will ensure exclusive access to the device
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclocd") == -1 &&
+ ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclock") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
+ CL_UNIT(parse->unit));
+ return 0;
+ }
+ if (!local_init(parse))
+ {
+ (void)ioctl(parse->fd, I_POP, (caddr_t)0);
+ return 0;
+ }
+
+ parse->flags |= PARSE_PPSCLOCK;
+ return 1;
+}
+
+/*--------------------------------------------------
+ * parse STREAM init
+ */
+static int
+stream_init(parse)
+ struct parseunit *parse;
+{
+ /*
+ * now push the parse streams module
+ * to test whether it is there (Oh boy - neat kernel interface)
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"parse") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ while(ioctl(parse->fd, I_POP, (caddr_t)0) == 0)
+ /* empty loop */;
+
+ /*
+ * now push it a second time after we have removed all
+ * module garbage
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"parse") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+}
+
+ /*--------------------------------------------------
+ * STREAM setcs
+ */
+static int
+stream_setcs(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETCS;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM nop
+ */
+static void
+stream_nop(parse)
+ struct parseunit *parse;
+{
+}
+
+/*--------------------------------------------------
+ * STREAM enable
+ */
+static int
+stream_enable(parse)
+ struct parseunit *parse;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_ENABLE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)0;
+ strioc.ic_len = 0;
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ parse->io.clock_recv = stream_receive; /* ok - parse input in kernel */
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM disable
+ */
+static int
+stream_disable(parse)
+ struct parseunit *parse;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_DISABLE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)0;
+ strioc.ic_len = 0;
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ parse->io.clock_recv = local_receive; /* ok - parse input in daemon */
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM getfmt
+ */
+static int
+stream_getfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_GETFMT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM setfmt
+ */
+static int
+stream_setfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETFMT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM getstat
+ */
+static int
+stream_getstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_GETSTAT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_getstat: ioctl(fd, I_STR, PARSEIOC_GETSTAT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM setstat
+ */
+static int
+stream_setstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETSTAT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setstat: ioctl(fd, I_STR, PARSEIOC_SETSTAT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM timecode
+ */
+static int
+stream_timecode(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_TIMECODE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_process: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CL_UNIT(parse->unit), parse->fd);
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM receive
+ */
+static void
+stream_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock;
+ parsetime_t parsetime;
+
+ if (rbufp->recv_length != sizeof(parsetime_t))
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: parse_receive: bad size (got %d expected %d)",
+ CL_UNIT(parse->unit), rbufp->recv_length, sizeof(parsetime_t));
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+ return;
+ }
+ memmove((caddr_t)&parsetime,
+ (caddr_t)&rbufp->recv_space,
+ sizeof(parsetime_t));
+
+ /*
+ * switch time stamp world - be sure to normalize small usec field
+ * errors.
+ */
+
+#define fix_ts(_X_) \
+ if ((&(_X_))->tv.tv_usec >= 1000000) \
+ { \
+ (&(_X_))->tv.tv_usec -= 1000000; \
+ (&(_X_))->tv.tv_sec += 1; \
+ }
+
+#define cvt_ts(_X_, _Y_) \
+ { \
+ l_fp ts; \
+ \
+ fix_ts((_X_)); \
+ if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
+ { \
+ syslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%d.%06d) ", (_Y_), (&(_X_))->tv.tv_sec, (&(_X_))->tv.tv_usec);\
+ return; \
+ } \
+ else \
+ { \
+ (&(_X_))->fp = ts; \
+ } \
+ }
+
+ if (PARSE_TIMECODE(parsetime.parse_state))
+ {
+ cvt_ts(parsetime.parse_time, "parse_time");
+ cvt_ts(parsetime.parse_stime, "parse_stime");
+ }
+
+ if (PARSE_PPS(parsetime.parse_state))
+ cvt_ts(parsetime.parse_ptime, "parse_ptime");
+
+ parse_process(parse, &parsetime);
+}
+
+/*--------------------------------------------------
+ * STREAM poll
+ */
+static void
+stream_poll(parse)
+ struct parseunit *parse;
+{
+ register int fd, i, rtc;
+ fd_set fdmask;
+ struct timeval timeout, starttime, curtime, selecttime;
+ parsetime_t parsetime;
+
+ /*
+ * now we do the following:
+ * - read the first packet from the parse module (OLD !!!)
+ * - read the second packet from the parse module (fresh)
+ * - compute values for xntp
+ */
+
+ FD_ZERO(&fdmask);
+ fd = parse->fd;
+ FD_SET(fd, &fdmask);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500000; /* 0.5 sec */
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * elapsed real time passed timeout value - consider it timed out
+ */
+ break;
+ }
+
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device", CL_UNIT(parse->unit));
+ }
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ return;
+ }
+
+ while (((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime)))
+ {
+ /* bad packet */
+ if ( i == -1)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+
+ return;
+ }
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 500000; /* 1.500 sec */
+ FD_ZERO(&fdmask);
+ FD_SET(fd, &fdmask);
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * elapsed real time passed timeout value - consider it timed out
+ */
+ break;
+ }
+
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device", CL_UNIT(parse->unit));
+ }
+
+ /*
+ * we will return here iff we got a good old sample as this would
+ * be misinterpreted. bad samples are passed on to be logged into the
+ * state statistics
+ */
+ if ((parsetime.parse_status & CVT_MASK) == CVT_OK)
+ {
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+ return;
+ }
+ }
+
+ /*
+ * we get here either by a possible read() (rtc == 1 - while assertion)
+ * or by a timeout or a system call error. when a read() is possible we
+ * get the new data, otherwise we stick with the old
+ */
+ if ((rtc == 1) && ((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime)))
+ {
+ /* bad packet */
+ if ( i== -1)
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+
+ return;
+ }
+
+ /*
+ * process what we got
+ */
+ parse_process(parse, &parsetime);
+}
+#endif
+
+/*--------------------------------------------------
+ * local init
+ */
+static int
+local_init(parse)
+ struct parseunit *parse;
+{
+ return parse_ioinit(&parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local end
+ */
+static void
+local_end(parse)
+ struct parseunit *parse;
+{
+ parse_ioend(&parse->parseio);
+}
+
+
+/*--------------------------------------------------
+ * local nop
+ */
+static int
+local_nop(parse)
+ struct parseunit *parse;
+{
+ return 1;
+}
+
+/*--------------------------------------------------
+ * local setcs
+ */
+static int
+local_setcs(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setcs(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local getfmt
+ */
+static int
+local_getfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_getfmt(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local setfmt
+ */
+static int
+local_setfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setfmt(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local getstat
+ */
+static int
+local_getstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_getstat(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local setstat
+ */
+static int
+local_setstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setstat(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local timecode
+ */
+static int
+local_timecode(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_timecode(tcl, &parse->parseio);
+}
+
+
+/*--------------------------------------------------
+ * local receive
+ */
+static void
+local_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock;
+ register int count;
+ register char *s;
+ /*
+ * eat all characters, parsing then and feeding complete samples
+ */
+ count = rbufp->recv_length;
+ s = rbufp->recv_buffer;
+
+ while (count--)
+ {
+ if (parse_ioread(&parse->parseio, *s++, &rbufp->recv_time))
+ {
+ /*
+ * got something good to eat
+ */
+#ifdef PPSPPS
+ if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state) &&
+ (parse->flags & PARSE_PPSCLOCK))
+ {
+ l_fp ts;
+ struct ppsclockev ev;
+
+ if (ioctl(parse->fd, CIOGETEV, (caddr_t)&ev) == 0)
+ {
+ if (ev.serial != parse->ppsserial)
+ {
+ /*
+ * add PPS time stamp if available via ppsclock module
+ * and not supplied already.
+ */
+ if (!buftvtots((const char *)&ev.tv, &ts))
+ {
+ syslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
+ }
+ else
+ {
+ parse->parseio.parse_dtime.parse_ptime.fp = ts;
+ parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
+ }
+ }
+ parse->ppsserial = ev.serial;
+ }
+ }
+#endif
+ parse_process(parse, &parse->parseio.parse_dtime);
+ parse_iodone(&parse->parseio);
+ }
+ }
+}
+
+/*--------------------------------------------------
+ * local poll
+ */
+static void
+local_poll(parse)
+ struct parseunit *parse;
+{
+ register int fd, i, rtc;
+ fd_set fdmask;
+ struct timeval timeout, starttime, curtime, selecttime;
+ static struct timeval null_time = { 0, 0};
+ timestamp_t ts;
+
+ FD_ZERO(&fdmask);
+ fd = parse->fd;
+ FD_SET(fd, &fdmask);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 500000; /* 1.5 sec */
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ do
+ {
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (!timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device", CL_UNIT(parse->unit));
+ }
+
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ return;
+ }
+
+ /*
+ * at least 1 character is available - gobble everthing up that is available
+ */
+ do
+ {
+ char inbuf[256];
+
+ register char *s = inbuf;
+
+ rtc = i = read(fd, inbuf, sizeof(inbuf));
+
+ get_systime(&ts.fp);
+
+ while (i-- > 0)
+ {
+ if (parse_ioread(&parse->parseio, *s++, &ts))
+ {
+ /*
+ * got something good to eat
+ */
+ parse_process(parse, &parse->parseio.parse_dtime);
+ parse_iodone(&parse->parseio);
+ /*
+ * done if no more characters are available
+ */
+ FD_SET(fd, &fdmask);
+ if ((i == 0) &&
+ (select(fd + 1, &fdmask, 0, 0, &null_time) == 0))
+ return;
+ }
+ }
+ FD_SET(fd, &fdmask);
+ } while ((rtc = select(fd + 1, &fdmask, 0, 0, &null_time)) == 1);
+ FD_SET(fd, &fdmask);
+ } while (1);
+}
+
+/*--------------------------------------------------
+ * init_iobinding - find and initialize lower layers
+ */
+static bind_t *
+init_iobinding(parse)
+ struct parseunit *parse;
+{
+ register bind_t *b = io_bindings;
+
+ while (b->bd_description != (char *)0)
+ {
+ if ((*b->bd_init)(parse))
+ {
+ return b;
+ }
+ b++;
+ }
+ return (bind_t *)0;
+}
+
+/**===========================================================================
+ ** support routines
+ **/
+
+/*--------------------------------------------------
+ * convert a flag field to a string
+ */
+static char *
+parsestate(state, buffer)
+ u_long state;
+ char *buffer;
+{
+ static struct bits
+ {
+ u_long bit;
+ char *name;
+ } flagstrings[] =
+ {
+ { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
+ { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
+ { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
+ { PARSEB_DST, "DST" },
+ { PARSEB_UTC, "UTC DISPLAY" },
+ { PARSEB_LEAPADD, "LEAP ADD WARNING" },
+ { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
+ { PARSEB_LEAPSECOND, "LEAP SECOND" },
+ { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" },
+ { PARSEB_TIMECODE, "TIME CODE" },
+ { PARSEB_PPS, "PPS" },
+ { PARSEB_POSITION, "POSITION" },
+ { 0 }
+ };
+
+ static struct sbits
+ {
+ u_long bit;
+ char *name;
+ } sflagstrings[] =
+ {
+ { PARSEB_S_LEAP, "LEAP INDICATION" },
+ { PARSEB_S_PPS, "PPS SIGNAL" },
+ { PARSEB_S_ANTENNA, "ANTENNA" },
+ { PARSEB_S_POSITION, "POSITION" },
+ { 0 }
+ };
+ int i;
+
+ *buffer = '\0';
+
+ i = 0;
+ while (flagstrings[i].bit)
+ {
+ if (flagstrings[i].bit & state)
+ {
+ if (buffer[0])
+ strcat(buffer, "; ");
+ strcat(buffer, flagstrings[i].name);
+ }
+ i++;
+ }
+
+ if (state & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
+ {
+ register char *s, *t;
+
+ if (buffer[0])
+ strcat(buffer, "; ");
+
+ strcat(buffer, "(");
+
+ t = s = buffer + strlen(buffer);
+
+ i = 0;
+ while (sflagstrings[i].bit)
+ {
+ if (sflagstrings[i].bit & state)
+ {
+ if (t != s)
+ {
+ strcpy(t, "; ");
+ t += 2;
+ }
+
+ strcpy(t, sflagstrings[i].name);
+ t += strlen(t);
+ }
+ i++;
+ }
+ strcpy(t, ")");
+ }
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * convert a status flag field to a string
+ */
+static char *
+parsestatus(state, buffer)
+ u_long state;
+ char *buffer;
+{
+ static struct bits
+ {
+ u_long bit;
+ char *name;
+ } flagstrings[] =
+ {
+ { CVT_OK, "CONVERSION SUCCESSFUL" },
+ { CVT_NONE, "NO CONVERSION" },
+ { CVT_FAIL, "CONVERSION FAILED" },
+ { CVT_BADFMT, "ILLEGAL FORMAT" },
+ { CVT_BADDATE, "DATE ILLEGAL" },
+ { CVT_BADTIME, "TIME ILLEGAL" },
+ { 0 }
+ };
+ int i;
+
+ *buffer = '\0';
+
+ i = 0;
+ while (flagstrings[i].bit)
+ {
+ if (flagstrings[i].bit & state)
+ {
+ if (buffer[0])
+ strcat(buffer, "; ");
+ strcat(buffer, flagstrings[i].name);
+ }
+ i++;
+ }
+
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * convert a clock status flag field to a string
+ */
+static char *
+clockstatus(state)
+ u_long state;
+{
+ static char buffer[20];
+ static struct status
+ {
+ u_long value;
+ char *name;
+ } flagstrings[] =
+ {
+ { CEVNT_NOMINAL, "NOMINAL" },
+ { CEVNT_TIMEOUT, "NO RESPONSE" },
+ { CEVNT_BADREPLY,"BAD FORMAT" },
+ { CEVNT_FAULT, "FAULT" },
+ { CEVNT_PROP, "PROPAGATION DELAY" },
+ { CEVNT_BADDATE, "ILLEGAL DATE" },
+ { CEVNT_BADTIME, "ILLEGAL TIME" },
+ { ~0 }
+ };
+ int i;
+
+ i = 0;
+ while (flagstrings[i].value != ~0)
+ {
+ if (flagstrings[i].value == state)
+ {
+ return flagstrings[i].name;
+ }
+ i++;
+ }
+
+ sprintf(buffer, "unknown #%ld", (u_long)state);
+
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * mkascii - make a printable ascii string
+ * assumes (unless defined better) 7-bit ASCII
+ */
+#ifndef isprint
+#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
+#endif
+
+static char *
+mkascii(buffer, blen, src, srclen)
+ register char *buffer;
+ register long blen;
+ register char *src;
+ register long srclen;
+{
+ register char *b = buffer;
+ register char *endb = (char *)0;
+
+ if (blen < 4)
+ return (char *)0; /* don't bother with mini buffers */
+
+ endb = buffer + blen - 4;
+
+ blen--; /* account for '\0' */
+
+ while (blen && srclen--)
+ {
+ if ((*src != '\\') && isprint(*src))
+ { /* printables are easy... */
+ *buffer++ = *src++;
+ blen--;
+ }
+ else
+ {
+ if (blen < 4)
+ {
+ while (blen--)
+ {
+ *buffer++ = '.';
+ }
+ *buffer = '\0';
+ return b;
+ }
+ else
+ {
+ if (*src == '\\')
+ {
+ strcpy(buffer,"\\\\");
+ buffer += 2;
+ blen -= 2;
+ }
+ else
+ {
+ sprintf(buffer, "\\x%02x", *src++);
+ blen -= 4;
+ buffer += 4;
+ }
+ }
+ }
+ if (srclen && !blen && endb) /* overflow - set last chars to ... */
+ strcpy(endb, "...");
+ }
+
+ *buffer = '\0';
+ return b;
+}
+
+
+/*--------------------------------------------------
+ * l_mktime - make representation of a relative time
+ */
+static char *
+l_mktime(delta)
+ u_long delta;
+{
+ u_long tmp, m, s;
+ static char buffer[40];
+
+ buffer[0] = '\0';
+
+ if ((tmp = delta / (60*60*24)) != 0)
+ {
+ sprintf(buffer, "%ldd+", (u_long)tmp);
+ delta -= tmp * 60*60*24;
+ }
+
+ s = delta % 60;
+ delta /= 60;
+ m = delta % 60;
+ delta /= 60;
+
+ sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
+ (int)delta, (int)m, (int)s);
+
+ return buffer;
+}
+
+
+/*--------------------------------------------------
+ * parse_statistics - list summary of clock states
+ */
+static void
+parse_statistics(parse)
+ register struct parseunit *parse;
+{
+ register int i;
+
+ syslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
+ CL_UNIT(parse->unit),
+ l_mktime(current_time - parse->timestarted));
+
+ syslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
+ CL_UNIT(parse->unit),
+ clockstatus(parse->status));
+
+ for (i = 0; i <= CEVNT_MAX; i++)
+ {
+ register u_long stime;
+ register u_long percent, div = current_time - parse->timestarted;
+
+ percent = stime = PARSE_STATETIME(parse, i);
+
+ while (((u_long)(~0) / 10000) < percent)
+ {
+ percent /= 10;
+ div /= 10;
+ }
+
+ if (div)
+ percent = (percent * 10000) / div;
+ else
+ percent = 10000;
+
+ if (stime)
+ syslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3d.%02d%%)",
+ CL_UNIT(parse->unit),
+ clockstatus(i),
+ l_mktime(stime),
+ percent / 100, percent % 100);
+ }
+}
+
+/*--------------------------------------------------
+ * cparse_statistics - wrapper for statistics call
+ */
+static void
+cparse_statistics(peer)
+ register struct peer *peer;
+{
+ register struct parseunit *parse = (struct parseunit *)peer;
+
+ parse_statistics(parse);
+ parse->stattimer.event_time = current_time + PARSESTATISTICS;
+ TIMER_ENQUEUE(timerqueue, &parse->stattimer);
+}
+
+/**===========================================================================
+ ** xntp interface routines
+ **/
+
+/*--------------------------------------------------
+ * parse_init - initialize internal parse driver data
+ */
+static void
+parse_init()
+{
+ memset((caddr_t)parseunits, 0, sizeof parseunits);
+}
+
+
+/*--------------------------------------------------
+ * parse_shutdown - shut down a PARSE clock
+ */
+static void
+parse_shutdown(unit)
+ int unit;
+{
+ register struct parseunit *parse;
+
+ unit = CL_UNIT(unit);
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit invalid (max %d)",
+ unit,MAXUNITS);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (parse && !parse->peer) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
+ return;
+ }
+
+ /*
+ * print statistics a last time and
+ * stop statistics machine
+ */
+ parse_statistics(parse);
+ TIMER_DEQUEUE(&parse->stattimer);
+
+#if PPSPPS
+ {
+ /*
+ * kill possible PPS association
+ */
+ if (fdpps == parse->fd)
+ fdpps = -1;
+ }
+#endif
+
+ if (parse->parse_type->cl_end)
+ {
+ parse->parse_type->cl_end(parse);
+ }
+
+ if (parse->binding)
+ PARSE_END(parse);
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ if (!parse->pollonly)
+ io_closeclock(&parse->io);
+ else
+ (void) close(parse->fd);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
+ CL_UNIT(parse->unit), parse->parse_type->cl_description);
+
+ parse->peer = (struct peer *)0; /* unused now */
+}
+
+/*--------------------------------------------------
+ * parse_start - open the PARSE devices and initialize data for processing
+ */
+static int
+parse_start(sysunit, peer)
+ u_int sysunit;
+ struct peer *peer;
+{
+ u_int unit;
+ int fd232, i;
+#ifdef HAVE_TERMIOS
+ struct termios tm; /* NEEDED FOR A LONG TIME ! */
+#endif
+#ifdef HAVE_SYSV_TTYS
+ struct termio tm; /* NEEDED FOR A LONG TIME ! */
+#endif
+ struct parseunit * parse;
+ char parsedev[sizeof(PARSEDEVICE)+20];
+ parsectl_t tmp_ctl;
+ u_int type;
+
+ type = CL_TYPE(sysunit);
+ unit = CL_UNIT(sysunit);
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit number invalid (max %d)",
+ unit, MAXUNITS-1);
+ return 0;
+ }
+
+ if ((type == ~0) || (clockinfo[type].cl_description == (char *)0))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
+ unit, CL_REALTYPE(sysunit), ncltypes-1);
+ return 0;
+ }
+
+ if (parseunits[unit] && parseunits[unit]->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit in use", unit);
+ return 0;
+ }
+
+ /*
+ * Unit okay, attempt to open the device.
+ */
+ (void) sprintf(parsedev, PARSEDEVICE, unit);
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+ fd232 = open(parsedev, O_RDWR|O_NOCTTY, 0777);
+ if (fd232 == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
+ return 0;
+ }
+
+ /*
+ * Looks like this might succeed. Find memory for the structure.
+ * Look to see if there are any unused ones, if not we malloc()
+ * one.
+ */
+ if (parseunits[unit])
+ {
+ parse = parseunits[unit]; /* The one we want is okay - and free */
+ }
+ else
+ {
+ for (i = 0; i < MAXUNITS; i++)
+ {
+ if (parseunits[i] && !parseunits[i]->peer)
+ break;
+ }
+ if (i < MAXUNITS)
+ {
+ /*
+ * Reclaim this one
+ */
+ parse = parseunits[i];
+ parseunits[i] = (struct parseunit *)0;
+ }
+ else
+ {
+ parse = (struct parseunit *)
+ emalloc(sizeof(struct parseunit));
+ }
+ }
+
+ memset((char *)parse, 0, sizeof(struct parseunit));
+ parseunits[unit] = parse;
+
+ /*
+ * Set up the structures
+ */
+ parse->unit = (u_char)sysunit;
+ parse->timestarted = current_time;
+ parse->lastchange = current_time;
+ /*
+ * we want to filter input for the sake of
+ * getting an impression on dispersion
+ * also we like to average the median range
+ */
+ parse->flags = PARSE_STAT_FILTER|PARSE_STAT_AVG;
+ parse->pollneeddata = 0;
+ parse->pollonly = 1; /* go for default polling mode */
+ parse->lastformat = ~0; /* assume no format known */
+ parse->status = CEVNT_TIMEOUT; /* expect the worst */
+ parse->laststatus = ~0; /* be sure to mark initial status change */
+ parse->nosynctime = 0; /* assume clock reasonable */
+ parse->lastmissed = 0; /* assume got everything */
+ parse->ppsserial = 0;
+ parse->localdata = (void *)0;
+
+ parse->parse_type = &clockinfo[type];
+
+ parse->basedelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */
+ parse->basedelay.l_uf = parse->parse_type->cl_basedelay;
+
+ parse->ppsdelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */
+ parse->ppsdelay.l_uf = parse->parse_type->cl_ppsdelay;
+
+ peer->rootdelay = parse->parse_type->cl_rootdelay;
+ peer->sstclktype = parse->parse_type->cl_type;
+ peer->precision = sys_precision;
+ peer->stratum = STRATUM_REFCLOCK;
+ if (peer->stratum <= 1)
+ memmove((char *)&peer->refid, parse->parse_type->cl_id, 4);
+ else
+ peer->refid = htonl(PARSEHSREFID);
+
+ parse->fd = fd232;
+
+ parse->peer = peer; /* marks it also as busy */
+
+ parse->binding = init_iobinding(parse);
+
+ if (parse->binding == (bind_t *)0)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.");
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+ /*
+ * configure terminal line
+ */
+ if (TTY_GETATTR(fd232, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tm): %m", unit, fd232);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ else
+ {
+#ifndef _PC_VDISABLE
+ memset((char *)tm.c_cc, 0, sizeof(tm.c_cc));
+#else
+ int disablec;
+ errno = 0; /* pathconf can deliver -1 without changing errno ! */
+
+ disablec = fpathconf(parse->fd, _PC_VDISABLE);
+ if (disablec == -1 && errno)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CL_UNIT(parse->unit));
+ memset((char *)tm.c_cc, 0, sizeof(tm.c_cc)); /* best guess */
+ }
+ else
+ if (disablec != -1)
+ memset((char *)tm.c_cc, disablec, sizeof(tm.c_cc));
+#endif
+
+ tm.c_cflag = clockinfo[type].cl_cflag;
+ tm.c_iflag = clockinfo[type].cl_iflag;
+ tm.c_oflag = clockinfo[type].cl_oflag;
+ tm.c_lflag = clockinfo[type].cl_lflag;
+
+ if (TTY_SETATTR(fd232, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tm): %m", unit, fd232);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ }
+
+ /*
+ * as we always(?) get 8 bit chars we want to be
+ * sure, that the upper bits are zero for less
+ * than 8 bit I/O - so we pass that information on.
+ * note that there can be only one bit count format
+ * per file descriptor
+ */
+
+ switch (tm.c_cflag & CSIZE)
+ {
+ case CS5:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
+ break;
+
+ case CS6:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
+ break;
+
+ case CS7:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
+ break;
+
+ case CS8:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
+ break;
+ }
+
+ if (!PARSE_SETCS(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+ strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
+ tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
+
+ if (!PARSE_SETFMT(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+#ifdef TCFLSH
+ /*
+ * get rid of all IO accumulated so far
+ */
+ {
+#ifndef TCIOFLUSH
+#define TCIOFLUSH 2
+#endif
+ int flshcmd = TCIOFLUSH;
+
+ (void) ioctl(parse->fd, TCFLSH, (caddr_t)&flshcmd);
+ }
+#endif
+
+ tmp_ctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS;
+
+ if (!PARSE_SETSTAT(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setstat() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+ /*
+ * try to do any special initializations
+ */
+ if (parse->parse_type->cl_init)
+ {
+ if (parse->parse_type->cl_init(parse))
+ {
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+ }
+
+ if (!(parse->parse_type->cl_flags & PARSE_F_POLLONLY) &&
+ (CL_PPS(parse->unit) || (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY)))
+ {
+ /*
+ * Insert in async io device list.
+ */
+ parse->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
+ parse->io.srcclock = (caddr_t)parse;
+ parse->io.datalen = 0;
+ parse->io.fd = parse->fd; /* replicated, but what the heck */
+ if (!io_addclock(&parse->io))
+ {
+ if (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY)
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CL_UNIT(parse->unit), parsedev);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ else
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_start: addclock %s fails (switching to polling mode)", CL_UNIT(parse->unit), parsedev);
+ }
+ }
+ else
+ {
+ parse->pollonly = 0; /*
+ * update at receipt of time_stamp - also
+ * supports PPS processing
+ */
+ }
+ }
+
+#ifdef PPSPPS
+ if (parse->pollonly && (parse->parse_type->cl_flags & PARSE_F_PPSPPS))
+ {
+ if (fdpps == -1)
+ {
+ fdpps = parse->fd;
+ if (!PARSE_DISABLE(parse))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_disable() FAILED", CL_UNIT(parse->unit));
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ }
+ else
+ {
+ syslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: loopfilter PPS already active - no PPS via CIOGETEV", CL_UNIT(parse->unit));
+ }
+ }
+#endif
+
+ /*
+ * wind up statistics timer
+ */
+ parse->stattimer.peer = (struct peer *)parse; /* we know better, but what the heck */
+ parse->stattimer.event_handler = cparse_statistics;
+ parse->stattimer.event_time = current_time + PARSESTATISTICS;
+ TIMER_ENQUEUE(timerqueue, &parse->stattimer);
+
+ /*
+ * get out Copyright information once
+ */
+ if (!notice)
+ {
+ syslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1993, Frank Kardel");
+ notice = 1;
+ }
+
+ /*
+ * print out configuration
+ */
+ syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
+ CL_UNIT(parse->unit),
+ parse->parse_type->cl_description, parsedev);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d",
+ CL_UNIT(parse->unit),
+ parse->peer->stratum, (parse->pollonly || !CL_PPS(parse->unit)) ? "no " : "",
+ l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: rootdelay %s s, phaseadjust %s s, %s IO handling",
+ CL_UNIT(parse->unit),
+ ufptoa(parse->parse_type->cl_rootdelay, 6),
+ lfptoa(&parse->basedelay, 8),
+ parse->binding->bd_description);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CL_UNIT(parse->unit),
+ !(*parse->parse_type->cl_format) ? "<AUTOMATIC>" : parse->parse_type->cl_format);
+
+#ifdef PPSPPS
+ syslog(LOG_INFO, "PARSE receiver #%d: %sCD PPS support",
+ CL_UNIT(parse->unit),
+ (fdpps == parse->fd) ? "" : "NO ");
+#endif
+
+ return 1;
+}
+
+/*--------------------------------------------------
+ * parse_poll - called by the transmit procedure
+ */
+static void
+parse_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct parseunit *parse;
+
+ unit = CL_UNIT(unit);
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit invalid",
+ unit);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (!parse->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit unused",
+ unit);
+ return;
+ }
+
+ if (peer != parse->peer)
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
+ unit);
+ return;
+ }
+
+ /*
+ * Update clock stat counters
+ */
+ parse->polls++;
+
+ /*
+ * in PPS mode we just mark that we want the next sample
+ * for the clock filter
+ */
+ if (!parse->pollonly)
+ {
+ if (parse->pollneeddata)
+ {
+ /*
+ * bad news - didn't get a response last time
+ */
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval", CL_UNIT(parse->unit));
+ }
+ parse->pollneeddata = 1;
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+ return;
+ }
+
+ /*
+ * the following code is only executed only when polling is used
+ */
+
+ PARSE_POLL(parse);
+}
+
+/*--------------------------------------------------
+ * parse_leap - called when a leap second occurs
+ */
+
+static void
+parse_leap()
+{
+ /*
+ * PARSE encodes the LEAP correction direction.
+ * For timecodes that do not pass on the leap correction direction
+ * the default PARSEB_LEAPADD must be used. It may then be modified
+ * with a fudge flag (flag2).
+ */
+}
+
+
+/*--------------------------------------------------
+ * parse_control - set fudge factors, return statistics
+ */
+static void
+parse_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct parseunit *parse;
+ parsectl_t tmpctl;
+ u_long type;
+ static char outstatus[400]; /* status output buffer */
+
+ type = CL_TYPE(unit);
+ unit = CL_UNIT(unit);
+
+ if (out)
+ {
+ out->lencode = 0;
+ out->lastcode = 0;
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ out->kv_list = (struct ctl_var *)0;
+ }
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (!parse || !parse->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
+ unit);
+ return;
+ }
+
+ if (in)
+ {
+ if (in->haveflags & CLK_HAVETIME1)
+ parse->basedelay = in->fudgetime1;
+
+ if (in->haveflags & CLK_HAVETIME2)
+ {
+ parse->ppsdelay = in->fudgetime2;
+ }
+
+ if (in->haveflags & CLK_HAVEVAL1)
+ {
+ parse->peer->stratum = (u_char)(in->fudgeval1 & 0xf);
+ if (parse->peer->stratum <= 1)
+ memmove((char *)&parse->peer->refid,
+ parse->parse_type->cl_id,
+ 4);
+ else
+ parse->peer->refid = htonl(PARSEHSREFID);
+ }
+
+ if (in->haveflags & CLK_HAVEVAL2)
+ {
+ parse->peer->refid = in->fudgeval2;
+ }
+
+ if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
+ {
+ parse->flags = (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
+ (parse->flags & ~PARSE_STAT_FLAGS);
+ }
+
+ if (in->haveflags & (CLK_HAVEVAL2|CLK_HAVETIME2|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
+ {
+ parsectl_t tmpctl;
+ tmpctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS;
+
+ if (!PARSE_SETSTAT(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_setstat() FAILED", unit);
+ }
+ }
+ }
+
+ if (out)
+ {
+ register u_long sum = 0;
+ register char *t, *tt;
+ register struct tm *tm;
+ register short utcoff;
+ register char sign;
+ register int i;
+ time_t tim;
+
+ outstatus[0] = '\0';
+
+ out->haveflags = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3;
+ out->clockdesc = parse->parse_type->cl_description;
+
+ out->fudgetime1 = parse->basedelay;
+
+ out->fudgetime2 = parse->ppsdelay;
+
+ out->fudgeval1 = parse->peer->stratum;
+
+ out->fudgeval2 = parse->peer->refid;
+
+ out->flags = parse->flags & PARSE_STAT_FLAGS;
+
+ out->type = REFCLK_PARSE;
+
+ /*
+ * figure out skew between PPS and RS232 - just for informational
+ * purposes - returned in time2 value
+ */
+ if (PARSE_SYNC(parse->time.parse_state))
+ {
+ if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state))
+ {
+ l_fp off;
+
+ /*
+ * we have a PPS and RS232 signal - calculate the skew
+ * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
+ */
+ off = parse->time.parse_stime.fp;
+ L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */
+ tt = add_var(&out->kv_list, 40, RO);
+ sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6));
+ }
+ }
+
+ if (PARSE_PPS(parse->time.parse_state))
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_ppstime=\"%s\"", prettydate(&parse->time.parse_ptime.fp));
+ }
+
+ /*
+ * all this for just finding out the +-xxxx part (there are always
+ * new and changing fields in the standards 8-().
+ *
+ * but we do it for the human user...
+ */
+ tim = parse->time.parse_time.fp.l_ui - JAN_1970;
+ tm = gmtime(&tim);
+ utcoff = tm->tm_hour * 60 + tm->tm_min;
+ tm = localtime(&tim);
+ utcoff = tm->tm_hour * 60 + tm->tm_min - utcoff + 12 * 60;
+ utcoff += 24 * 60;
+ utcoff %= 24 * 60;
+ utcoff -= 12 * 60;
+ if (utcoff < 0)
+ {
+ utcoff = -utcoff;
+ sign = '-';
+ }
+ else
+ {
+ sign = '+';
+ }
+
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_time=\"");
+ tt += strlen(tt);
+
+ if (parse->time.parse_time.fp.l_ui == 0)
+ {
+ strcpy(tt, "<UNDEFINED>\"");
+ }
+ else
+ {
+ strcpy(tt, prettydate(&parse->time.parse_time.fp));
+ t = tt + strlen(tt);
+
+ sprintf(t, " (%c%02d%02d)\"", sign, utcoff / 60, utcoff % 60);
+ }
+
+ if (!PARSE_GETTIMECODE(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
+ }
+ else
+ {
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_status=\"");
+ tt += strlen(tt);
+
+ /*
+ * copy PPS flags from last read transaction (informational only)
+ */
+ tmpctl.parsegettc.parse_state |= parse->time.parse_state &
+ (PARSEB_PPS|PARSEB_S_PPS);
+
+ (void) parsestate(tmpctl.parsegettc.parse_state, tt);
+
+ strcat(tt, "\"");
+
+ if (tmpctl.parsegettc.parse_count)
+ mkascii(outstatus+strlen(outstatus), sizeof(outstatus)- strlen(outstatus) - 1,
+ tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1);
+
+ parse->badformat += tmpctl.parsegettc.parse_badformat;
+ }
+
+ tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
+
+ if (!PARSE_GETFMT(parse, &tmpctl))
+ {
+ syslog (LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
+ }
+ else
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_format=\"");
+
+ strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
+ strcat(tt,"\"");
+ }
+
+ /*
+ * gather state statistics
+ */
+
+ tt = add_var(&out->kv_list, 200, RO|DEF);
+ strcpy(tt, "refclock_states=\"");
+ tt += strlen(tt);
+
+ for (i = 0; i <= CEVNT_MAX; i++)
+ {
+ register u_long stime;
+ register u_long div = current_time - parse->timestarted;
+ register u_long percent;
+
+ percent = stime = PARSE_STATETIME(parse, i);
+
+ while (((u_long)(~0) / 10000) < percent)
+ {
+ percent /= 10;
+ div /= 10;
+ }
+
+ if (div)
+ percent = (percent * 10000) / div;
+ else
+ percent = 10000;
+
+ if (stime)
+ {
+ sprintf(tt, "%s%s%s: %s (%d.%02d%%)",
+ sum ? "; " : "",
+ (parse->status == i) ? "*" : "",
+ clockstatus(i),
+ l_mktime(stime),
+ (int)(percent / 100), (int)(percent % 100));
+ sum += stime;
+ tt += strlen(tt);
+ }
+ }
+
+ sprintf(tt, "; running time: %s\"", l_mktime(sum));
+
+ tt = add_var(&out->kv_list, 32, RO);
+ sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id);
+
+ tt = add_var(&out->kv_list, 80, RO);
+ sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
+
+ tt = add_var(&out->kv_list, 128, RO);
+ sprintf(tt, "refclock_driver_version=\"refclock_parse.c,v 3.59 1994/05/23 16:29:27 kardel Exp\"");
+
+ out->lencode = strlen(outstatus);
+ out->lastcode = outstatus;
+ out->timereset = parse->timestarted;
+ out->polls = parse->polls;
+ out->noresponse = parse->noresponse;
+ out->badformat = parse->badformat;
+ out->baddata = parse->baddata;
+ out->lastevent = parse->lastevent;
+ out->currentstatus = parse->status;
+ }
+}
+
+/**===========================================================================
+ ** processing routines
+ **/
+
+/*--------------------------------------------------
+ * event handling - note that nominal events will also be posted
+ */
+static void
+parse_event(parse, event)
+ struct parseunit *parse;
+ int event;
+{
+ if (parse->status != (u_char) event)
+ {
+ parse->statetime[parse->status] += current_time - parse->lastchange;
+ parse->lastchange = current_time;
+
+ parse->status = (u_char)event;
+ if (event != CEVNT_NOMINAL)
+ parse->lastevent = parse->status;
+
+ report_event(EVNT_PEERCLOCK, parse->peer);
+ }
+}
+
+/*--------------------------------------------------
+ * process a PARSE time sample
+ */
+static void
+parse_process(parse, parsetime)
+ struct parseunit *parse;
+ parsetime_t *parsetime;
+{
+ unsigned char leap;
+ struct timeval usecdisp;
+ l_fp off, rectime, reftime, dispersion;
+
+ /*
+ * check for changes in conversion status
+ * (only one for each new status !)
+ */
+ if (parse->laststatus != parsetime->parse_status)
+ {
+ char buffer[200];
+
+ syslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
+ CL_UNIT(parse->unit), parsestatus(parsetime->parse_status, buffer));
+
+ if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
+ {
+ /*
+ * tell more about the story - list time code
+ * there is a slight change for a race condition and
+ * the time code might be overwritten by the next packet
+ */
+ parsectl_t tmpctl;
+
+ if (!PARSE_GETTIMECODE(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CL_UNIT(parse->unit));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\"",
+ CL_UNIT(parse->unit), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1));
+ parse->badformat += tmpctl.parsegettc.parse_badformat;
+ }
+ }
+
+ parse->laststatus = parsetime->parse_status;
+ }
+
+ /*
+ * examine status and post appropriate events
+ */
+ if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
+ {
+ /*
+ * got bad data - tell the rest of the system
+ */
+ switch (parsetime->parse_status & CVT_MASK)
+ {
+ case CVT_NONE:
+ break; /* well, still waiting - timeout is handled at higher levels */
+
+ case CVT_FAIL:
+ parse->badformat++;
+ if (parsetime->parse_status & CVT_BADFMT)
+ {
+ parse_event(parse, CEVNT_BADREPLY);
+ }
+ else
+ if (parsetime->parse_status & CVT_BADDATE)
+ {
+ parse_event(parse, CEVNT_BADDATE);
+ }
+ else
+ if (parsetime->parse_status & CVT_BADTIME)
+ {
+ parse_event(parse, CEVNT_BADTIME);
+ }
+ else
+ {
+ parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
+ }
+ }
+ return; /* skip the rest - useless */
+ }
+
+ /*
+ * check for format changes
+ * (in case somebody has swapped clocks 8-)
+ */
+ if (parse->lastformat != parsetime->parse_format)
+ {
+ parsectl_t tmpctl;
+
+ tmpctl.parseformat.parse_format = parsetime->parse_format;
+
+ if (!PARSE_GETFMT(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CL_UNIT(parse->unit));
+ }
+ else
+ {
+ syslog(LOG_INFO, "PARSE receiver #%d: new packet format \"%s\"",
+ CL_UNIT(parse->unit), tmpctl.parseformat.parse_buffer);
+ }
+ parse->lastformat = parsetime->parse_format;
+ }
+
+ /*
+ * now, any changes ?
+ */
+ if (parse->time.parse_state != parsetime->parse_state)
+ {
+ char tmp1[200];
+ char tmp2[200];
+ /*
+ * something happend
+ */
+
+ (void) parsestate(parsetime->parse_state, tmp1);
+ (void) parsestate(parse->time.parse_state, tmp2);
+
+ syslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
+ CL_UNIT(parse->unit), tmp2, tmp1);
+ }
+
+ /*
+ * remember for future
+ */
+ parse->time = *parsetime;
+
+ /*
+ * check to see, whether the clock did a complete powerup or lost PZF signal
+ * and post correct events for current condition
+ */
+ if (PARSE_POWERUP(parsetime->parse_state))
+ {
+ /*
+ * this is bad, as we have completely lost synchronisation
+ * well this is a problem with the receiver here
+ * for PARSE U/A 31 the lost synchronisation ist true
+ * as it is the powerup state and the time is taken
+ * from a crude real time clock chip
+ * for the PZF series this is only partly true, as
+ * PARSE_POWERUP only means that the pseudo random
+ * phase shift sequence cannot be found. this is only
+ * bad, if we have never seen the clock in the SYNC
+ * state, where the PHASE and EPOCH are correct.
+ * for reporting events the above business does not
+ * really matter, but we can use the time code
+ * even in the POWERUP state after having seen
+ * the clock in the synchronized state (PZF class
+ * receivers) unless we have had a telegram disruption
+ * after having seen the clock in the SYNC state. we
+ * thus require having seen the clock in SYNC state
+ * *after* having missed telegrams (noresponse) from
+ * the clock. one problem remains: we might use erroneously
+ * POWERUP data if the disruption is shorter than 1 polling
+ * interval. fortunately powerdowns last usually longer than 64
+ * seconds and the receiver is at least 2 minutes in the
+ * POWERUP or NOSYNC state before switching to SYNC
+ */
+ parse_event(parse, CEVNT_FAULT);
+ if (parse->nosynctime)
+ {
+ /*
+ * repeated POWERUP/NOSYNC state - look whether
+ * the message should be repeated
+ */
+ if (current_time - parse->nosynctime > PARSENOSYNCREPEAT)
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: *STILL* NOT SYNCHRONIZED (POWERUP or no PZF signal)",
+ CL_UNIT(parse->unit));
+ parse->nosynctime = current_time;
+ }
+ }
+ else
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
+ CL_UNIT(parse->unit));
+ parse->nosynctime = current_time;
+ }
+ }
+ else
+ {
+ /*
+ * we have two states left
+ *
+ * SYNC:
+ * this state means that the EPOCH (timecode) and PHASE
+ * information has be read correctly (at least two
+ * successive PARSE timecodes were received correctly)
+ * this is the best possible state - full trust
+ *
+ * NOSYNC:
+ * The clock should be on phase with respect to the second
+ * signal, but the timecode has not been received correctly within
+ * at least the last two minutes. this is a sort of half baked state
+ * for PARSE U/A 31 this is bad news (clock running without timecode
+ * confirmation)
+ * PZF 535 has also no time confirmation, but the phase should be
+ * very precise as the PZF signal can be decoded
+ */
+ parse->nosynctime = 0; /* current state is better than worst state */
+
+ if (PARSE_SYNC(parsetime->parse_state))
+ {
+ /*
+ * currently completely synchronized - best possible state
+ */
+ parse->lastsync = current_time;
+ /*
+ * log OK status
+ */
+ parse_event(parse, CEVNT_NOMINAL);
+ }
+ else
+ {
+ /*
+ * we have had some problems receiving the time code
+ */
+ parse_event(parse, CEVNT_PROP);
+ }
+ }
+
+ if (PARSE_TIMECODE(parsetime->parse_state))
+ {
+ l_fp offset;
+
+ /*
+ * calculate time offset including systematic delays
+ * off = PARSE-timestamp + propagation delay - kernel time stamp
+ */
+ offset = parse->basedelay;
+
+ off = parsetime->parse_time.fp;
+
+ reftime = off;
+
+ L_ADD(&off, &offset);
+ rectime = off; /* this makes org time and xmt time somewhat artificial */
+
+ L_SUB(&off, &parsetime->parse_stime.fp);
+
+ if ((parse->flags & PARSE_STAT_FILTER) &&
+ (off.l_i > -60) &&
+ (off.l_i < 60)) /* take usec error only if within +- 60 secs */
+ {
+ struct timeval usecerror;
+ /*
+ * offset is already calculated
+ */
+ usecerror.tv_sec = parsetime->parse_usecerror / 1000000;
+ usecerror.tv_usec = parsetime->parse_usecerror % 1000000;
+
+ sTVTOTS(&usecerror, &off);
+ L_ADD(&off, &offset);
+ }
+ }
+
+ if (PARSE_PPS(parsetime->parse_state) && CL_PPS(parse->unit))
+ {
+ l_fp offset;
+
+ /*
+ * we have a PPS signal - much better than the RS232 stuff (we hope)
+ */
+ offset = parsetime->parse_ptime.fp;
+
+ L_ADD(&offset, &parse->ppsdelay);
+
+ if (PARSE_TIMECODE(parsetime->parse_state))
+ {
+ if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
+ M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
+ {
+ /*
+ * RS232 offsets within [-0.5..0.5[ - take PPS offsets
+ */
+
+ if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
+ {
+ reftime = off = offset;
+ rectime = offset;
+ /*
+ * implied on second offset
+ */
+ off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
+ off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ }
+ else
+ {
+ /*
+ * time code describes pulse
+ */
+ off = parsetime->parse_time.fp;
+
+ rectime = reftime = off; /* take reference time - fake rectime */
+
+ L_SUB(&off, &offset); /* true offset */
+ }
+ }
+ /*
+ * take RS232 offset when PPS when out of bounds
+ */
+ }
+ else
+ {
+ /*
+ * Well, no time code to guide us - assume on second pulse
+ * and pray, that we are within [-0.5..0.5[
+ */
+ reftime = off = offset;
+ rectime = offset;
+ /*
+ * implied on second offset
+ */
+ off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
+ off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ }
+ }
+ else
+ {
+ if (!PARSE_TIMECODE(parsetime->parse_state))
+ {
+ /*
+ * Well, no PPS, no TIMECODE, no more work ...
+ */
+ return;
+ }
+ }
+
+
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) || defined(PARSEPPS)
+ if (CL_PPS(parse->unit) && !parse->pollonly && PARSE_SYNC(parsetime->parse_state))
+ {
+ /*
+ * only provide PPS information when clock
+ * is in sync
+ * thus PHASE and EPOCH are correct and PPS is not
+ * done via the CIOGETEV loopfilter mechanism
+ */
+#ifdef PPSPPS
+ if (fdpps != parse->fd)
+#endif
+ (void) pps_sample(&off);
+ }
+#endif /* PPS || PPSCLK || PPSPPS || PARSEPPS */
+
+ /*
+ * ready, unless the machine wants a sample
+ */
+ if (!parse->pollonly && !parse->pollneeddata)
+ return;
+
+ parse->pollneeddata = 0;
+
+ if (PARSE_PPS(parsetime->parse_state))
+ {
+ L_CLR(&dispersion);
+ }
+ else
+ {
+ /*
+ * convert usec dispersion into NTP TS world
+ */
+
+ usecdisp.tv_sec = parsetime->parse_usecdisp / 1000000;
+ usecdisp.tv_usec = parsetime->parse_usecdisp % 1000000;
+
+ TVTOTS(&usecdisp, &dispersion);
+ }
+
+ /*
+ * and now stick it into the clock machine
+ * samples are only valid iff lastsync is not too old and
+ * we have seen the clock in sync at least once
+ * after the last time we didn't see an expected data telegram
+ * see the clock states section above for more reasoning
+ */
+ if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) ||
+ (parse->lastsync <= parse->lastmissed))
+ {
+ leap = LEAP_NOTINSYNC;
+ }
+ else
+ {
+ if (PARSE_LEAPADD(parsetime->parse_state))
+ {
+ /*
+ * we pick this state also for time code that pass leap warnings
+ * without direction information (as earth is currently slowing
+ * down).
+ */
+ leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
+ }
+ else
+ if (PARSE_LEAPDEL(parsetime->parse_state))
+ {
+ leap = LEAP_DELSECOND;
+ }
+ else
+ {
+ leap = LEAP_NOWARNING;
+ }
+ }
+
+ refclock_receive(parse->peer, &off, 0, LFPTOFP(&dispersion), &reftime, &rectime, leap);
+}
+
+/**===========================================================================
+ ** clock polling support
+ **/
+
+struct poll_timer
+{
+ struct event timer; /* we'd like to poll a a higher rate than 1/64s */
+};
+
+typedef struct poll_timer poll_timer_t;
+
+/*--------------------------------------------------
+ * direct poll routine
+ */
+static void
+poll_dpoll(parse)
+ struct parseunit *parse;
+{
+ register int rtc;
+ register char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
+ register int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
+
+ rtc = write(parse->fd, ps, ct);
+ if (rtc < 0)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CL_UNIT(parse->unit));
+ }
+ else
+ if (rtc != ct)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CL_UNIT(parse->unit), rtc, ct);
+ }
+}
+
+/*--------------------------------------------------
+ * periodic poll routine
+ */
+static void
+poll_poll(parse)
+ struct parseunit *parse;
+{
+ register poll_timer_t *pt = (poll_timer_t *)parse->localdata;
+
+ poll_dpoll(parse);
+
+ if (pt != (poll_timer_t *)0)
+ {
+ pt->timer.event_time = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
+ TIMER_ENQUEUE(timerqueue, &pt->timer);
+ }
+}
+
+/*--------------------------------------------------
+ * init routine - setup timer
+ */
+static int
+poll_init(parse)
+ struct parseunit *parse;
+{
+ register poll_timer_t *pt;
+
+ if (((poll_info_t *)parse->parse_type->cl_data)->rate)
+ {
+ parse->localdata = (void *)malloc(sizeof(poll_timer_t));
+ memset((char *)parse->localdata, 0, sizeof(poll_timer_t));
+
+ pt = (poll_timer_t *)parse->localdata;
+
+ pt->timer.peer = (struct peer *)parse; /* well, only we know what it is */
+ pt->timer.event_handler = poll_poll;
+ poll_poll(parse);
+ }
+ else
+ {
+ parse->localdata = (void *)0;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------
+ * end routine - clean up timer
+ */
+static void
+poll_end(parse)
+ struct parseunit *parse;
+{
+ if (parse->localdata != (void *)0)
+ {
+ TIMER_DEQUEUE(&((poll_timer_t *)parse->localdata)->timer);
+ free((char *)parse->localdata);
+ parse->localdata = (void *)0;
+ }
+}
+
+/**===========================================================================
+ ** special code for special clocks
+ **/
+
+/*--------------------------------------------------
+ * trimble init routine - setup EOL and then do poll_init.
+ */
+static int
+trimble_init(parse)
+ struct parseunit *parse;
+{
+#ifdef HAVE_TERMIOS
+ struct termios tm;
+#endif
+#ifdef HAVE_SYSV_TTYS
+ struct termio tm;
+#endif
+ /*
+ * configure terminal line for trimble receiver
+ */
+ if (TTY_GETATTR(parse->fd, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcgetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ tm.c_cc[VEOL] = TRIMBLESV6_EOL;
+
+ if (TTY_SETATTR(parse->fd, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcsetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ }
+ return poll_init(parse);
+}
+#endif /* defined(REFCLOCK) && defined(PARSE) */
+
+/*
+ * History:
+ *
+ * refclock_parse.c,v
+ * Revision 3.59 1994/05/23 16:29:27 kardel
+ * IGEL clock - Trimble update
+ *
+ * Revision 3.58 1994/05/12 21:03:39 kardel
+ * adhere to new standard that fudgeval2 is refid
+ *
+ * Revision 3.57 1994/05/12 12:50:47 kardel
+ * printf fmt/arg cleanup
+ *
+ * Revision 3.56 1994/05/10 21:15:51 kardel
+ * var reference level bug, kernel disable fix
+ *
+ * Revision 3.55 1994/05/02 00:37:01 kardel
+ * 3.3t reconcilation + bug fixes (PPS simulation - old kpll)
+ *
+ * Revision 3.54 1994/04/11 19:34:42 kardel
+ * longer input characters for DCF77 raw input (8Bit+parity ignored)
+ *
+ * Revision 3.53 1994/03/25 13:07:39 kardel
+ * fixed offset calculation for large (>4 Min) offsets
+ *
+ * Revision 3.52 1994/03/03 09:58:00 kardel
+ * stick -kv in cvs is no fun
+ *
+ * Revision 3.49 1994/02/20 13:26:00 kardel
+ * rcs id cleanup
+ *
+ * Revision 3.48 1994/02/20 13:04:56 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.47 1994/02/02 17:44:30 kardel
+ * rcs ids fixed
+ *
+ * Revision 3.45 1994/01/25 19:06:27 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.44 1994/01/25 17:32:23 kardel
+ * settable extended variables
+ *
+ * Revision 3.43 1994/01/23 16:28:39 kardel
+ * HAVE_TERMIOS introduced
+ *
+ * Revision 3.42 1994/01/22 11:35:04 kardel
+ * added HAVE_TERMIOS
+ *
+ * Revision 3.41 1993/11/27 18:44:37 kardel
+ * can't trust GPS166 on unsync
+ *
+ * Revision 3.40 1993/11/21 18:03:36 kardel
+ * useless declaration deleted
+ *
+ * Revision 3.39 1993/11/21 15:30:15 kardel
+ * static funcitions may be declared only at outer level
+ *
+ * Revision 3.38 1993/11/15 21:26:49 kardel
+ * conditional define comments fixed
+ *
+ * Revision 3.37 1993/11/11 11:20:49 kardel
+ * declaration fixes
+ *
+ * Revision 3.36 1993/11/10 12:17:14 kardel
+ * #ifdef glitch
+ *
+ * Revision 3.35 1993/11/01 21:15:06 kardel
+ * comments updated
+ *
+ * Revision 3.34 1993/11/01 20:01:08 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.33 1993/10/30 09:44:58 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.32 1993/10/22 14:28:43 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.31 1993/10/10 21:19:10 kardel
+ * compilation cleanup - (minimal porting tests)
+ *
+ * Revision 3.30 1993/10/09 21:44:35 kardel
+ * syslog strings fixed
+ *
+ * Revision 3.29 1993/10/09 14:40:15 kardel
+ * default precision setting fixed
+ *
+ * Revision 3.28 1993/10/08 14:48:22 kardel
+ * Changed offset determination logic:
+ * Take the PPS offset if it is available and the time
+ * code offset is within [-0.5..0.5[, otherwise stick
+ * to the time code offset
+ *
+ * Revision 3.27 1993/10/08 00:53:17 kardel
+ * announce also simulated PPS via CIOGETEV in ntpq cl
+ *
+ * Revision 3.26 1993/10/07 23:29:35 kardel
+ * trimble fixes
+ *
+ * Revision 3.25 1993/10/06 21:13:35 kardel
+ * test reversed (CIOGETEV support)
+ *
+ * Revision 3.24 1993/10/03 20:18:26 kardel
+ * Well, values > 999999 in the usec field from uniqtime() timestamps
+ * can prove harmful.
+ *
+ * Revision 3.23 1993/10/03 19:49:54 kardel
+ * buftvtots where failing on uninitialized time stamps
+ *
+ * Revision 3.22 1993/10/03 19:11:09 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.21 1993/09/29 11:30:18 kardel
+ * special init for trimble to set EOL
+ *
+ * Revision 3.20 1993/09/27 22:46:28 kardel
+ * preserve module stack if I_PUSH parse fails
+ *
+ * Revision 3.19 1993/09/27 21:10:11 kardel
+ * wrong structure member
+ *
+ * Revision 3.18 1993/09/27 13:05:06 kardel
+ * Trimble is true polling only
+ *
+ * Revision 3.17 1993/09/27 12:47:10 kardel
+ * poll string support generalized
+ *
+ * Revision 3.16 1993/09/26 23:40:56 kardel
+ * new parse driver logic
+ *
+ * Revision 3.15 1993/09/24 15:00:51 kardel
+ * Sep 23rd distribution...
+ *
+ * Revision 3.14 1993/09/22 18:21:15 kardel
+ * support ppsclock streams module (-DSTREAM -DPPSPPS -DPARSEPPS -UPARSESTREAM)
+ *
+ * Revision 3.13 1993/09/05 15:38:33 kardel
+ * not every cpp understands #error...
+ *
+ * Revision 3.12 1993/09/02 20:04:19 kardel
+ * TTY cleanup
+ *
+ * Revision 3.11 1993/09/01 21:48:47 kardel
+ * conditional cleanup
+ *
+ * Revision 3.10 1993/09/01 11:32:45 kardel
+ * assuming HAVE_POSIX_TTYS when STREAM defined
+ *
+ * Revision 3.9 1993/08/31 22:31:46 kardel
+ * SINIX-M SysVR4 integration
+ *
+ * Revision 3.8 1993/08/27 00:29:50 kardel
+ * compilation cleanup
+ *
+ * Revision 3.7 1993/08/24 22:27:30 kardel
+ * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad
+ *
+ * Revision 3.6 1993/08/24 21:36:23 kardel
+ * casting and ifdefs
+ *
+ * Revision 3.5 1993/07/09 23:36:59 kardel
+ * HAVE_POSIX_TTYS used to produce errors 8-( - BSD driver support still lacking
+ *
+ * Revision 3.4 1993/07/09 12:42:29 kardel
+ * RAW DCF now officially released
+ *
+ * Revision 3.3 1993/07/09 11:50:37 kardel
+ * running GPS also on 960 to be able to switch GPS/DCF77
+ *
+ * Revision 3.2 1993/07/09 11:37:34 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:01:07 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/usr.sbin/xntpd/xntpd/refclock_nmea.c b/usr.sbin/xntpd/xntpd/refclock_nmea.c
new file mode 100644
index 000000000000..3058956df516
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_nmea.c
@@ -0,0 +1,391 @@
+/*
+ * refclock_nmea.c - clock driver for an NMEA GPS CLOCK
+ * Michael Petry Jun 20, 1994
+ * based on refclock_heath.c
+ */
+#if defined(REFCLOCK) && defined(NMEA)
+
+#define DEBUG 1
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the NMEA GPS Receiver with
+ *
+ * Protype was refclock_trak.c, Thanks a lot.
+ *
+ * The reciever used spits out the NMEA sentences for boat navigation.
+ * And you thought it was an information superhighway. Try a raging river
+ * filled with rapids and whirlpools that rip away your data and warp time.
+ */
+
+/*
+ * Definitions
+ */
+#define DEVICE "/dev/gps%d" /* name of radio device */
+#define SPEED232 B4800 /* uart speed (4800 bps) */
+#define PRECISION (-9) /* precision assumed (about 2 ms) */
+#define REFID "GPS\0" /* reference id */
+#define DESCRIPTION "NMEA GPS Clock" /* who we are */
+
+#define NSAMPLES 3 /* stages of median filter */
+#define LENNMEA 75 /* min timecode length */
+
+/*
+ * Imported from ntp_timer module
+ */
+extern u_long current_time; /* current time (s) */
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * Tables to compute the ddd of year form icky dd/mm timecode. Viva la
+ * leap.
+ */
+static day1tab[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static day2tab[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ * Unit control structure
+ */
+struct nmeaunit {
+ int pollcnt; /* poll message counter */
+ l_fp tstamp; /* timestamp of last poll */
+};
+
+/*
+ * Function prototypes
+ */
+static int nmea_start P((int, struct peer *));
+static void nmea_shutdown P((int, struct peer *));
+static void nmea_receive P((struct recvbuf *));
+static void nmea_poll P((int, struct peer *));
+static void gps_send P((int, char *, struct peer *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_nmea = {
+ nmea_start, /* start up driver */
+ nmea_shutdown, /* shut down driver */
+ nmea_poll, /* transmit poll message */
+ noentry, /* handle control */
+ noentry, /* initialize driver */
+ noentry, /* buginfo */
+ NOFLAGS /* not used */
+};
+
+/*
+ * nmea_start - open the GPS devices and initialize data for processing
+ */
+static int
+nmea_start(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct nmeaunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
+
+ /*
+ * Open serial port. Use CLK line discipline, if available.
+ */
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ return (0);
+
+ /*
+ * Allocate and initialize unit structure
+ */
+ if (!(up = (struct nmeaunit *)
+ emalloc(sizeof(struct nmeaunit)))) {
+ (void) close(fd);
+ return (0);
+ }
+ memset((char *)up, 0, sizeof(struct nmeaunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = nmea_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
+ }
+ pp->unitptr = (caddr_t)up;
+
+ /*
+ * Initialize miscellaneous variables
+ */
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
+ gps_send(pp->io.fd,"$PMOTG,RMC,0000\n", peer);
+ return (1);
+}
+
+/*
+ * nmea_shutdown - shut down a GPS clock
+ */
+static void
+nmea_shutdown(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct nmeaunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct nmeaunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
+}
+
+/*
+ * nmea_receive - receive data from the serial interface
+ */
+static void
+nmea_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct nmeaunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp trtmp;
+ int month, day;
+ int i;
+ char *cp, *dp;
+ int cmdtype;
+ char *field_parse();
+
+ /*
+ * Initialize pointers and read the timecode and timestamp
+ */
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct nmeaunit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX, &trtmp);
+
+ /*
+ * There is a case that a <CR><LF> gives back a "blank" line
+ */
+ if (pp->lencode == 0)
+ return;
+
+ /*
+ * We get a buffer and timestamp for each <cr>; however, we use
+ * the timestamp of "now" since this may be a broadcast instead
+ * of a poll. This needs to be checked empeerically
+ */
+ gettstamp(&up->tstamp); /* HACK */
+ pp->lastrec = up->tstamp;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+#ifdef DEBUG
+ if (debug)
+ printf("nmea: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
+#endif
+
+ /*
+ * We check the timecode format and decode its contents. The
+ * we only care about a few of them. The most important being
+ * the $GPRMC format
+ * $GPRMC,hhmmss,a,fddmm.xx,n,dddmmm.xx,w,zz.z,yyy.,ddmmyy,dd,v*CC
+ */
+#define GPRMC 0
+#define GPXXX 1
+ cp = pp->lastcode;
+ pp->leap = 0;
+ cmdtype=0;
+ if(strncmp(cp,"$GPRMC",6)==0) {
+ cmdtype=GPRMC;
+ }
+ else if(strncmp(cp,"$GPXXX",6)==0) {
+ cmdtype=GPXXX;
+ }
+ else
+ return;
+
+ switch( cmdtype ) {
+ case GPRMC:
+ /*
+ * Check time code format of NMEA
+ */
+
+ dp = field_parse(cp,1);
+ if( !isdigit(dp[0]) ||
+ !isdigit(dp[1]) ||
+ !isdigit(dp[2]) ||
+ !isdigit(dp[3]) ||
+ !isdigit(dp[4]) ||
+ !isdigit(dp[5])
+ ) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
+ break;
+ case GPXXX:
+ return;
+ default:
+ return;
+
+ }
+
+ dp = field_parse(cp,9);
+ /*
+ * Convert date and check values.
+ */
+ day = dp[0] - '0';
+ day = (day * 10) + dp[1] - '0';
+ month = dp[2] - '0';
+ month = (month * 10) + dp[3] - '0';
+ pp->year = dp[4] - '0';
+ pp->year = (pp->year * 10) + dp[5] - '0';
+
+ if (month < 1 || month > 12 || day < 1) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+
+ if (pp->year % 4) {
+ if (day > day1tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day1tab[i];
+ } else {
+ if (day > day2tab[month - 1]) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ for (i = 0; i < month - 1; i++)
+ day += day2tab[i];
+ }
+ pp->day = day;
+
+ dp = field_parse(cp,1);
+ /*
+ * Convert time and check values.
+ */
+ pp->hour = ((dp[0] - '0') * 10) + dp[1] - '0';
+ pp->minute = ((dp[2] - '0') * 10) + dp[3] - '0';
+ pp->second = ((dp[4] - '0') * 10) + dp[5] - '0';
+ pp->msec = 0;
+
+ if (pp->hour > 23 || pp->minute > 59 || pp->second > 59) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+
+ /*
+ * Test for synchronization Check for quality byte. (soon)
+ */
+ pp->leap = 0;
+ pp->lasttime = current_time;
+
+ /*
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time, in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
+}
+
+/*
+ * nmea_poll - called by the transmit procedure
+ *
+ * We go to great pains to avoid changing state here, since there may be
+ * more than one eavesdropper receiving the same timecode.
+ */
+static void
+nmea_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct nmeaunit *up;
+ struct refclockproc *pp;
+
+ pp = peer->procptr;
+ up = (struct nmeaunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ pp->polls++;
+
+ /*
+ * usually nmea_receive can get a timestamp every second
+ */
+
+ gps_send(pp->io.fd,"$PMOTG,RMC,0\n", peer);
+}
+
+/*
+ *
+ * gps_send(fd,cmd, peer) Sends a command to the GPS receiver.
+ * as gps_send(fd,"rqts,u\r", peer);
+ *
+ * We don't currently send any data, but would like to send
+ * RTCM SC104 messages for differential positioning. It should
+ * also give us better time. Without a PPS output, we're
+ * Just fooling ourselves because of the serial code paths
+ *
+ */
+static void
+gps_send(fd, cmd, peer)
+ int fd;
+ char *cmd;
+ struct peer *peer;
+{
+
+ if (write(fd, cmd, strlen(cmd)) == -1) {
+ refclock_report(peer, CEVNT_FAULT);
+ }
+}
+
+char *
+field_parse(cp, fn)
+ char *cp;
+ int fn;
+{
+ char *tp;
+ int i = fn;
+
+ for (tp = cp; *tp != '\0'; tp++) {
+ if (*tp == ',')
+ i--;
+ if (i == 0)
+ break;
+ }
+ return (++tp);
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_datum.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_datum.c
new file mode 100644
index 000000000000..680f104568bf
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_datum.c
@@ -0,0 +1,645 @@
+/*
+ * refclock_datum - clock driver for the Datum watchayamacallit
+ */
+#if defined(REFCLOCK) && (defined(DATUM) || defined(DATUMCLK) || defined(DATUMPPS))
+/* */
+/*...... Include Files .................................................*/
+/* */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(WWVBCLK)
+#include <sys/clkdefs.h>
+#endif /* WWVBCLK */
+#endif /* STREAM */
+
+#if defined (WWVBPPS)
+#include <sys/ppsclock.h>
+#endif /* WWVBPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+#include "temp.c"
+void set_logfile();
+*/
+
+
+#define DEBUG_DATUM_PTC
+
+
+/* */
+/*...... #defines ......................................................*/
+/* */
+
+/*
+#define refclock_datum_pts refclock_wwvb
+*/
+
+#define MAXUNITS 4
+#define PTSPRECISION (-13) /* precision assumed (about 100 us) */
+#define GMT 7
+#define DATUM_MAX_ERROR 0.100
+#define DATUM_MAX_ERROR2 DATUM_MAX_ERROR*DATUM_MAX_ERROR
+
+/* */
+/*...... externals .....................................................*/
+/* */
+
+extern U_LONG current_time; /* current time (s) */
+extern int debug; /* global debug flag */
+
+
+/* */
+/*...... My structure ..................................................*/
+/* */
+
+struct datum_pts_unit {
+ struct peer *peer; /* peer used by xntp */
+ struct refclockio io; /* io structure used by xntp */
+ int PTS_fd; /* file descriptor for PTS */
+ int PTS_START; /* ? */
+ u_int unit; /* id for unit */
+ U_LONG timestarted; /* time started */
+ int inuse; /* in use flag */
+ l_fp lastrec;
+ l_fp lastref;
+ int yearstart;
+ int coderecv;
+ int day; /* day */
+ int hour; /* hour */
+ int minute; /* minutes */
+ int second; /* seconds */
+ int msec; /* miliseconds */
+ int usec; /* miliseconds */
+ u_char leap;
+ char retbuf[8]; /* returned time from the datum pts */
+ char nbytes; /* number of bytes received from datum pts */
+ double sigma2; /* average squared error (roughly) */
+};
+
+
+/* */
+/*...... pts static constant variables for internal use ................*/
+/* */
+
+static char STOP_GENERATOR[6];
+static char START_GENERATOR[6];
+static char TIME_REQUEST[6];
+
+static int nunits;
+static struct datum_pts_unit **datum_pts_unit;
+static u_char stratumtouse[MAXUNITS];
+static l_fp fudgefactor[MAXUNITS];
+
+static FILE *logfile;
+
+/* */
+/*...... callback functions that xntp knows about ......................*/
+/* */
+
+static int datum_pts_start P((u_int, struct peer *));
+static void datum_pts_shutdown P((int));
+static void datum_pts_poll P((int, struct peer *));
+static void datum_pts_control P((u_int, struct refclockstat *,
+ struct refclockstat *));
+static void datum_pts_init P((void));
+static void datum_pts_buginfo P((int, struct refclockbug *));
+
+struct refclock refclock_datum = {
+ datum_pts_start,
+ datum_pts_shutdown,
+ datum_pts_poll,
+ datum_pts_control,
+ datum_pts_init,
+ datum_pts_buginfo,
+ NOFLAGS
+};
+
+/*
+struct refclock refclock_wvvb = {
+ datum_pts_start,
+ datum_pts_shutdown,
+ datum_pts_poll,
+ datum_pts_control,
+ datum_pts_init,
+ datum_pts_buginfo,
+ NOFLAGS
+};
+*/
+
+/* */
+/*...... receive callback functions for xntp ..........................*/
+/* */
+
+static void datum_pts_receive P((struct recvbuf *));
+
+
+/*......................................................................*/
+/* datum_pts_start */
+/*......................................................................*/
+
+static int datum_pts_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ struct datum_pts_unit **temp_datum_pts_unit;
+ struct datum_pts_unit *datum_pts;
+ struct termios arg;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile, "Starting Datum PTS unit %d\n", unit);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... create the memory for the new unit ............................*/
+/* */
+
+ temp_datum_pts_unit = (struct datum_pts_unit **)
+ malloc((nunits+1)*sizeof(struct datum_pts_unit *));
+ if (nunits > 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
+ nunits*sizeof(struct datum_pts_unit *));
+ free(datum_pts_unit);
+ datum_pts_unit = temp_datum_pts_unit;
+ datum_pts_unit[nunits] = (struct datum_pts_unit *)
+ malloc(sizeof(struct datum_pts_unit));
+ datum_pts = datum_pts_unit[nunits];
+
+ datum_pts->unit = unit;
+ datum_pts->yearstart = 0;
+ datum_pts->sigma2 = 0.0;
+
+/* */
+/*...... open the datum pts device .....................................*/
+/* */
+
+ datum_pts->PTS_fd = open("/dev/ttya",O_RDWR);
+
+ fcntl(datum_pts->PTS_fd, F_SETFL, 0);
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Opening RS232 port ttya with file descriptor %d\n",
+ datum_pts->PTS_fd);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... set up the RS232 terminal device information ..................*/
+/* */
+
+ arg.c_iflag = IGNBRK;
+ arg.c_oflag = 0;
+ arg.c_cflag = B9600 | CS8 | CREAD | PARENB | CLOCAL;
+ arg.c_lflag = 0;
+ arg.c_line = 0;
+ arg.c_cc[VMIN] = 0; /* start timeout timer right away */
+ arg.c_cc[VTIME] = 30; /* this is a 3 second timout on reads */
+
+ tcsetattr(datum_pts->PTS_fd, TCSANOW, &arg);
+
+/* */
+/*...... initialize the io structure ...................................*/
+/* */
+
+ datum_pts->peer = peer;
+ datum_pts->timestarted = current_time;
+
+ datum_pts->io.clock_recv = datum_pts_receive;
+ datum_pts->io.srcclock = (caddr_t)datum_pts;
+ datum_pts->io.datalen = 0;
+ datum_pts->io.fd = datum_pts->PTS_fd;
+
+ if (!io_addclock(&(datum_pts->io))) {
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Problem adding clock\n");
+ fflush(logfile);
+#endif
+ syslog(LOG_ERR, "Datum_PTS: Problem adding clock");
+ }
+
+ peer->precision = PTSPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+
+/* */
+/*...... now add one to the number of units ............................*/
+/* */
+
+ nunits++;
+
+/* */
+/*...... return successful code ........................................*/
+/* */
+
+ return 1;
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_shutdown */
+/*......................................................................*/
+
+static void datum_pts_shutdown(unit)
+ int unit;
+{
+ int i,j;
+ struct datum_pts_unit **temp_datum_pts_unit;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Shutdown Datum PTS\n");
+ fflush(logfile);
+#endif
+ syslog(LOG_ERR, "Datum_PTS: Shutdown Datum PTS");
+
+/* */
+/*...... loop until the right unit is found ............................*/
+/* */
+
+ for (i=0; i<nunits; i++) {
+ if (datum_pts_unit[i]->unit == unit) {
+
+/* */
+/*...... found it so close the file descriptor and free up memory .....*/
+/* */
+
+ io_closeclock(&datum_pts_unit[i]->io);
+ close(datum_pts_unit[i]->PTS_fd);
+ free(datum_pts_unit[i]);
+
+/* */
+/*...... clean up the datum_pts_unit array (no holes) ..................*/
+/* */
+
+ if (nunits > 1) {
+
+ temp_datum_pts_unit = (struct datum_pts_unit **)
+ malloc((nunits-1)*sizeof(struct datum_pts_unit *));
+ if (i!= 0) memcpy(temp_datum_pts_unit, datum_pts_unit,
+ i*sizeof(struct datum_pts_unit *));
+
+ for (j=i+1; j<nunits; j++) {
+ temp_datum_pts_unit[j-1] = datum_pts_unit[j];
+ }
+
+ free(datum_pts_unit);
+ datum_pts_unit = temp_datum_pts_unit;
+
+ }else{
+
+ free(datum_pts_unit);
+ datum_pts_unit = NULL;
+
+ }
+
+ return;
+
+ }
+ }
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error, could not shut down unit %d\n",unit);
+ fflush(logfile);
+#endif
+ syslog(LOG_ERR, "Datum_PTS: Could not shut down Datum PTS unit %d",unit);
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_poll */
+/*......................................................................*/
+
+static void datum_pts_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ int i;
+ int index;
+ int error_code;
+ l_fp tstmp;
+ struct datum_pts_unit *datum_pts;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Poll Datum PTS\n");
+ fflush(logfile);
+#endif
+
+/* */
+/*...... find the unit and send out a time request .....................*/
+/* */
+
+ index = -1;
+ for (i=0; i<nunits; i++) {
+ if (datum_pts_unit[i]->unit == unit) {
+ index = i;
+ datum_pts = datum_pts_unit[i];
+ error_code = write(datum_pts->PTS_fd, TIME_REQUEST, 6);
+ if (error_code != 6) perror("TIME_REQUEST");
+ datum_pts->nbytes = 0;
+ break;
+ }
+ }
+
+ if (index == -1) {
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error, could not poll unit %d\n",unit);
+ fflush(logfile);
+#endif
+ syslog(LOG_ERR, "Datum_PTS: Could not poll unit %d",unit);
+ return;
+ }
+
+}
+
+
+/*......................................................................*/
+/* datum_pts_control */
+/*......................................................................*/
+
+static void datum_pts_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Control Datum PTS\n");
+ fflush(logfile);
+#endif
+}
+
+
+/*......................................................................*/
+/* datum_pts_init */
+/*......................................................................*/
+
+static void datum_pts_init()
+{
+
+#ifdef DEBUG_DATUM_PTC
+ logfile = fopen("xntpd.log", "w");
+ fprintf(logfile,"Init Datum PTS\n");
+ fflush(logfile);
+#endif
+
+ memcpy(START_GENERATOR, "//kk01",6);
+ memcpy(STOP_GENERATOR, "//kk00",6);
+ memcpy(TIME_REQUEST, "//k/mn",6);
+
+ datum_pts_unit = NULL;
+ nunits = 0;
+}
+
+
+/*......................................................................*/
+/* datum_pts_buginfo */
+/*......................................................................*/
+
+static void datum_pts_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Buginfo Datum PTS\n");
+ fflush(logfile);
+#endif
+}
+
+
+/*......................................................................*/
+/* datum_pts_receive */
+/*......................................................................*/
+
+static void datum_pts_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ int i;
+ l_fp tstmp, trtmp, tstmp1;
+ struct datum_pts_unit *datum_pts;
+ char *dpt;
+ int dpend;
+ time_t tim;
+ struct tm *loctm;
+ int tzoff;
+ int timerr;
+ double ftimerr, abserr;
+
+ datum_pts = (struct datum_pts_unit *)rbufp->recv_srcclock;
+ dpt = (char *)&rbufp->recv_space;
+ dpend = rbufp->recv_length;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Receive Datum PTS: %d bytes\n", dpend);
+ fflush(logfile);
+#endif
+
+ for (i=0; i<dpend; i++) {
+ datum_pts->retbuf[datum_pts->nbytes+i] = dpt[i];
+ }
+ datum_pts->nbytes += dpend;
+
+ if (datum_pts->nbytes != 7) {
+ return;
+ }
+
+
+/* */
+/*...... save the ntp system time ......................................*/
+/* */
+
+ trtmp = rbufp->recv_time;
+ datum_pts->lastrec = trtmp;
+
+/* */
+/*...... convert the time from the buffer ..............................*/
+/* */
+
+ datum_pts->day = 100*(datum_pts->retbuf[0] & 0x0f) +
+ 10*((datum_pts->retbuf[1] & 0xf0)>>4) +
+ (datum_pts->retbuf[1] & 0x0f);
+
+ datum_pts->hour = 10*((datum_pts->retbuf[2] & 0x30)>>4) +
+ (datum_pts->retbuf[2] & 0x0f);
+
+ datum_pts->minute = 10*((datum_pts->retbuf[3] & 0x70)>>4) +
+ (datum_pts->retbuf[3] & 0x0f);
+
+ datum_pts->second = 10*((datum_pts->retbuf[4] & 0x70)>>4) +
+ (datum_pts->retbuf[4] & 0x0f);
+
+ datum_pts->msec = 100*((datum_pts->retbuf[5] & 0xf0) >> 4) +
+ 10*(datum_pts->retbuf[5] & 0x0f) +
+ ((datum_pts->retbuf[6] & 0xf0)>>4);
+
+ datum_pts->usec = 1000*datum_pts->msec;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"day %d, hour %d, minute %d, second %d, msec %d\n",
+ datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ datum_pts->msec);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... get the GMT time zone offset ..................................*/
+/* */
+
+ tim = trtmp.l_ui - JAN_1970;
+ loctm = localtime(&tim);
+ tzoff = -loctm->tm_gmtoff/3600;
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Time Zone = %d, time (sec) since 1970 = %d\n",tzoff, tim);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... make sure that we have a good time from the Datum PTS .........*/
+/* */
+
+ if (!clocktime( datum_pts->day,
+ datum_pts->hour,
+ datum_pts->minute,
+ datum_pts->second,
+ tzoff,
+ datum_pts->lastrec.l_ui,
+ &datum_pts->yearstart,
+ &datum_pts->lastref.l_ui) ) {
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Error: bad clocktime\n");
+ fprintf(logfile,"GMT %d, lastrec %d, yearstart %d, lastref %d\n",
+ tzoff,
+ datum_pts->lastrec.l_ui,
+ datum_pts->yearstart,
+ datum_pts->lastref.l_ui);
+ fflush(logfile);
+#endif
+ syslog(LOG_ERR, "Datum_PTS: Bad clocktime");
+
+ return;
+
+ }else{
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Good clocktime\n");
+ fflush(logfile);
+#endif
+
+ }
+
+/* */
+/*...... we have datum_pts->lastref.l_ui set, get useconds now .........*/
+/* */
+
+ TVUTOTSF(datum_pts->usec, datum_pts->lastref.l_uf);
+
+/* */
+/*...... pass the new time to xntpd ....................................*/
+/* */
+
+ tstmp = datum_pts->lastref;
+ L_SUB(&tstmp, &datum_pts->lastrec); /* tstmp is the time correction */
+ datum_pts->coderecv++;
+
+/*
+ set_logfile(logfile);
+*/
+
+ refclock_receive( datum_pts->peer,
+ &tstmp,
+ tzoff,
+ 0,
+ &datum_pts->lastrec,
+ &datum_pts->lastrec,
+ datum_pts->leap );
+ timerr = tstmp.l_ui<<20;
+ timerr |= (tstmp.l_uf>>12) & 0x000fffff;
+ ftimerr = timerr;
+ ftimerr /= 1024*1024;
+ abserr = ftimerr;
+ if (ftimerr < 0.0) abserr = -ftimerr;
+
+ if (datum_pts->sigma2 == 0.0) {
+ if (abserr < DATUM_MAX_ERROR) {
+ datum_pts->sigma2 = abserr*abserr;
+ }else{
+ datum_pts->sigma2 = DATUM_MAX_ERROR2;
+ }
+ }else{
+ if (abserr < DATUM_MAX_ERROR) {
+ datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*abserr*abserr;
+ }else{
+ datum_pts->sigma2 = 0.95*datum_pts->sigma2 + 0.05*DATUM_MAX_ERROR2;
+ }
+ }
+
+#ifdef DEBUG_DATUM_PTC
+ fprintf(logfile,"Time error = %f seconds, Sigma Squared = %f\n",
+ ftimerr, datum_pts->sigma2);
+ fflush(logfile);
+#endif
+
+/* */
+/*...... make sure that we understand the format for xntp time .........*/
+/* */
+
+#ifdef DEBUG_DATUM_PTC
+ tstmp.l_ui = 2;
+ TVUTOTSF(123456, tstmp.l_uf);
+
+ timerr = tstmp.l_ui<<20;
+ timerr |= (tstmp.l_uf>>12) & 0x000fffff;
+ ftimerr = timerr;
+ ftimerr /= 1024*1024;
+ fprintf(logfile,"Test1 2.123456 = %f\n",ftimerr);
+ fflush(logfile);
+
+ tstmp1.l_ui = 3;
+ TVUTOTSF(223456, tstmp1.l_uf);
+ timerr = tstmp1.l_ui<<20;
+ timerr |= (tstmp1.l_uf>>12) & 0x000fffff;
+ ftimerr = timerr;
+ ftimerr /= 1024*1024;
+ fprintf(logfile,"Test2 3.223456 = %f\n",ftimerr);
+ fflush(logfile);
+
+ L_SUB(&tstmp, &tstmp1);
+ timerr = tstmp.l_ui<<20;
+ timerr |= (tstmp.l_uf>>12) & 0x000fffff;
+ ftimerr = timerr;
+ ftimerr /= 1024*1024;
+ fprintf(logfile,"Test3 -1.100000 = %f\n",ftimerr);
+ fflush(logfile);
+#endif
+
+
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_gpstm.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_gpstm.c
new file mode 100644
index 000000000000..2e81e52c8dae
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_gpstm.c
@@ -0,0 +1,998 @@
+/*
+ * refclock_gpstm - clock driver for the Kinimetrics Truetime GPSTM/TMD rcvr
+ * Version 1.0 (from Version 2.0 of the GOES driver, as of 03Jan94)
+ */
+
+#if defined(REFCLOCK) && (defined(GPSTM) || defined(GPSTMCLK) \
+ || defined(GPSTMPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#ifdef SYS_BSDI
+#undef HAVE_BSD_TTYS
+#include <sys/ioctl.h>
+#endif
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(GPSTMCLK)
+#include <clkdefs.h>
+#endif /* GPSTMCLK */
+#endif /* STREAM */
+
+#if defined(GPSTMPPS)
+#include <sys/ppsclock.h>
+#endif /* GPSTMPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Support for Kinemetrics Truetime GPS-TM/TMD Receiver
+ *
+ * Most of this code is copied from refclock_goes.c with thanks.
+ *
+ * the time code looks like follows:
+ *
+ * ADDD:HH:MM:SSQCL
+ * A - control A
+ * Q Quality indication: indicates possible error of
+ * ? +/- 500 milliseconds # +/- 50 milliseconds
+ * * +/- 5 milliseconds . +/- 1 millisecond
+ * space less than 1 millisecond
+ * C - Carriage return
+ * L - Line feed
+ * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ *
+ * Flag1 set to 1 will silence the clock side of xntpd, just reading the
+ * clock without trying to write to it. This is usefull if several
+ * xntpds listen to the same clock. This has not been tested yet...
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* max number of GPSTM units */
+#define GPSTM232 "/dev/gpstm%d"
+#define SPEED232 B9600 /* 9600 baud */
+
+/*
+ * Radio interface parameters
+ */
+#define MAXDISPERSE (FP_SECOND>>1) /* max error for synchronized clock (0.5 s as an u_fp) */
+#define PRECISION (-20) /* precision assumed (about 1 ms) */
+#define REFID "GPS\0" /* reference id */
+#define DESCRIPTION "Kinemetrics GPS-TM/TMD Receiver" /* who we are */
+#define GMT 0 /* hour offset from Greenwich */
+#define NCODES 3 /* stages of median filter */
+#define BMAX 99 /* timecode buffer length */
+#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define TIMEOUT 180 /* ping the clock if it's silent this long */
+
+/*
+ * used by the state machine
+ */
+enum gpstm_event {e_Init, e_F18, e_F50, e_F51, e_TS};
+static enum {Base, Start, F18, F50, F51, F08} State[MAXUNITS];
+static time_t Last[MAXUNITS];
+static void gpstm_doevent P((int, enum gpstm_event));
+static void gpstm_initstate P((int));
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+
+/*
+ * Imported from the timer module
+ */
+extern U_LONG current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * GPSTM unit control structure
+ */
+struct gpstm_unit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NCODES]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short polled; /* Hand in a time sample? */
+ u_char lencode; /* length of last timecode */
+ U_LONG lasttime; /* last time clock heard from */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ u_short msec; /* millisecond of second */
+ u_char quality; /* quality character */
+ U_LONG yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ U_LONG polls; /* polls sent */
+ U_LONG noreply; /* no replies to polls */
+ U_LONG coderecv; /* timecodes received */
+ U_LONG badformat; /* bad format */
+ U_LONG baddata; /* bad data */
+ U_LONG timestarted; /* time we started this */
+};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct gpstm_unit *gpstm_units[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor1[MAXUNITS];
+static l_fp fudgefactor2[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char readonlyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void gpstm_init P((void));
+static int gpstm_start P((u_int, struct peer *));
+static void gpstm_shutdown P((int));
+static void gpstm_rep_event P((struct gpstm_unit *, int));
+static void gpstm_receive P((struct recvbuf *));
+static char gpstm_process P((struct gpstm_unit *, l_fp *, u_fp *));
+static void gpstm_poll P((int, struct peer *));
+static void gpstm_control P((u_int, struct refclockstat *,
+ struct refclockstat *));
+static void gpstm_buginfo P((int, struct refclockbug *));
+static void gpstm_send P((struct gpstm_unit *, char *));
+
+struct refclock refclock_gpstm = {
+ gpstm_start, gpstm_shutdown, gpstm_poll,
+ gpstm_control, gpstm_init, gpstm_buginfo, NOFLAGS
+};
+
+/*
+ * gpstm_init - initialize internal driver data
+ */
+static void
+gpstm_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)gpstm_units, 0, sizeof gpstm_units);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor1[i].l_ui = 0;
+ fudgefactor1[i].l_uf = 0;
+ fudgefactor2[i].l_ui = 0;
+ fudgefactor2[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], REFID, 4);
+ }
+}
+
+
+/*
+ * gpstm_start - open the device and initialize data for processing
+ */
+static int
+gpstm_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct gpstm_unit *gpstm;
+ register int i;
+ int fd232;
+ char dev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_start: unit %d invalid", unit);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_start: unit %d in use", unit);
+ return 0;
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(dev, GPSTM232, unit);
+ fd232 = open(dev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "gpstm_start: open of %s: %m", dev);
+ return 0;
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TCGETA): %m", dev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TCSETA): %m", dev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The GPSTMPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+ ttyp = &ttyb;
+
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcgetattr(%s): %m", dev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcsetattr(%s): %m", dev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: tcflush(%s): %m", dev);
+ goto screwed;
+ }
+#if defined(STREAM)
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, clk): %m", dev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, CLK_SETSTR): %m", dev);
+#endif /* GPSTMCLK */
+#if defined(GPSTMPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, I_PUSH, ppsclock): %m", dev);
+ else
+ fdpps = fd232;
+#endif /* GPSTMPPS */
+#endif /* STREAM */
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The GPSTMCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(GPSTMCLK)
+ int ldisc = CLKLDISC;
+#endif /* GPSTMCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCGETP): %m", dev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(GPSTMCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* GPSTMCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETP): %m", dev);
+ goto screwed;
+ }
+#if defined(GPSTMCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "gpstm_start: ioctl(%s, TIOCSETD): %m", dev);
+ goto screwed;
+ }
+#endif /* GPSTMCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (gpstm_units[unit] != 0) {
+ gpstm = gpstm_units[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && gpstm_units[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ gpstm = gpstm_units[i];
+ gpstm_units[i] = 0;
+ } else {
+ gpstm = (struct gpstm_unit *)
+ emalloc(sizeof(struct gpstm_unit));
+ }
+ }
+ memset((char *)gpstm, 0, sizeof(struct gpstm_unit));
+ gpstm_units[unit] = gpstm;
+
+ /*
+ * Set up the structures
+ */
+ gpstm->peer = peer;
+ gpstm->unit = (u_char)unit;
+ gpstm->timestarted = current_time;
+
+ gpstm->io.clock_recv = gpstm_receive;
+ gpstm->io.srcclock = (caddr_t)gpstm;
+ gpstm->io.datalen = 0;
+ gpstm->io.fd = fd232;
+ if (!io_addclock(&gpstm->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = PRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ gpstm_initstate(unit);
+ return 1;
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return 0;
+}
+
+/*
+ * gpstm_shutdown - shut down a clock
+ */
+static void
+gpstm_shutdown(unit)
+ int unit;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ gpstm = gpstm_units[unit];
+ io_closeclock(&gpstm->io);
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * gpstm_rep_event - note the occurance of an event
+ */
+static void
+gpstm_rep_event(gpstm, code)
+ struct gpstm_unit *gpstm;
+ int code;
+{
+ struct peer *peer;
+
+ peer = gpstm->peer;
+ if (gpstm->status != (u_char)code) {
+ gpstm->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ gpstm->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "clock %s event %x\n", ntoa(&peer->srcadr), code);
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_rep_event(gpstm%d, code %d)\n",
+ gpstm->unit, code);
+ }
+#endif
+ }
+ if (code == CEVNT_BADREPLY)
+ gpstm_initstate(gpstm->unit);
+}
+
+
+/*
+ * gpstm_receive - receive data from the serial interface on a clock
+ */
+static void
+gpstm_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i;
+ register struct gpstm_unit *gpstm;
+ register u_char *dpt;
+ register char *cp;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion;
+
+ /*
+ * Get the clock this applies to and a pointers to the data
+ */
+ gpstm = (struct gpstm_unit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+
+ /*
+ * Edit timecode to remove control chars
+ */
+ dpend = dpt + rbufp->recv_length;
+ cp = gpstm->lastcode;
+ while (dpt < dpend) {
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#ifdef GPSTMCLK
+ else if (*cp == '\r') {
+ if (dpend - dpt < 8) {
+ /* short timestamp */
+ return;
+ }
+ if (!buftvtots(dpt,&gpstm->lastrec)) {
+ /* screwy timestamp */
+ return;
+ }
+ dpt += 8;
+ }
+#endif
+ }
+ *cp = '\0';
+ gpstm->lencode = cp - gpstm->lastcode;
+ if (gpstm->lencode == 0)
+ return;
+#ifndef GPSTMCLK
+ gpstm->lastrec = rbufp->recv_time;
+#endif /* GPSTMCLK */
+#if !defined(GPSTMCLK) && !defined(GPSTMPPS) && defined(TIOCMODT)
+ do {
+ auto struct timeval cur, now;
+ register long usec;
+
+ if (ioctl(gpstm->io.fd, TIOCMODT, &cur) < 0) {
+ syslog(LOG_ERR, "TIOCMODT: %m");
+#ifdef DEBUG
+ if (debug) perror("TIOCMODT");
+ break;
+#endif
+ }
+ if (cur.tv_sec == 0) {
+ /* no timestamps yet */
+ if (debug) printf("MODT tv_sec == 0\n");
+ break;
+ }
+
+ gettimeofday(&now, NULL);
+ usec = 1000000 * (now.tv_sec - cur.tv_sec)
+ + (now.tv_usec - cur.tv_usec);
+#ifdef DEBUG
+ if (debug) printf("lastmodem: delay=%d us\n", usec);
+#endif
+ if (usec < 0 || usec > 10000) {
+ /* time warp or stale timestamp */
+ break;
+ }
+ if (!buftvtots((char *)&cur, &gpstm->lastrec)) {
+ /* screwy timestamp */
+ break;
+ }
+ } while (0);
+#endif /*TIOCMODT*/
+
+#ifdef DEBUG
+ if (debug)
+ printf("gpstm: timecode %d %s\n",
+ gpstm->lencode, gpstm->lastcode);
+#endif
+
+ cp = gpstm->lastcode;
+ gpstm->leap = 0;
+ if ((cp[0] == 'F' && isdigit(cp[1]) && isdigit(cp[2]))
+ || (cp[0] == ' ' && cp[1] == 'T' && cp[2] == 'R')) {
+ enum gpstm_event event;
+
+ syslog(LOG_NOTICE, "gpstm%d: \"%s\"", gpstm->unit, cp);
+ if (cp[1] == '5' && cp[2] == '0')
+ event = e_F50;
+ else if (cp[1] == '5' && cp[2] == '1')
+ event = e_F51;
+ else if (!strncmp(" TRUETIME Mk III", cp, 16))
+ event = e_F18;
+ else {
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, event);
+ return;
+ } else if (gpstm->lencode == 13) {
+ /*
+ * Check timecode format 0
+ */
+ if (!isdigit(cp[0]) /* day of year */
+ || !isdigit(cp[1])
+ || !isdigit(cp[2])
+ || cp[3] != ':' /* : separator */
+ || !isdigit(cp[4]) /* hours */
+ || !isdigit(cp[5])
+ || cp[6] != ':' /* : separator */
+ || !isdigit(cp[7]) /* minutes */
+ || !isdigit(cp[8])
+ || cp[9] != ':' /* : separator */
+ || !isdigit(cp[10]) /* seconds */
+ || !isdigit(cp[11]))
+ {
+ gpstm->badformat++;
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Convert format 0 and check values
+ */
+ gpstm->year = 0; /* fake */
+ gpstm->day = cp[0] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[1] - '0';
+ gpstm->day = MULBY10(gpstm->day) + cp[2] - '0';
+ gpstm->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ gpstm->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ gpstm->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ gpstm->msec = 0;
+
+ if (cp[12] != ' ' && cp[12] != '.' && cp[12] != '*')
+ gpstm->leap = LEAP_NOTINSYNC;
+ else
+ gpstm->lasttime = current_time;
+
+ if (gpstm->day < 1 || gpstm->day > 366) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADDATE);
+ return;
+ }
+ if (gpstm->hour > 23 || gpstm->minute > 59
+ || gpstm->second > 59) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ gpstm_doevent(gpstm->unit, e_TS);
+ } else {
+ gpstm_rep_event(gpstm, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * The clock will blurt a timecode every second but we only
+ * want one when polled. If we havn't been polled, bail out.
+ */
+ if (!gpstm->polled)
+ return;
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the seconds and the millisecond field for the
+ * fraction when present.
+ *
+ * this code does not yet know how to do the years
+ */
+ tstmp = gpstm->lastrec;
+ if (!clocktime(gpstm->day, gpstm->hour, gpstm->minute,
+ gpstm->second, GMT, tstmp.l_ui,
+ &gpstm->yearstart, &gpstm->lastref.l_ui))
+ {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(gpstm->msec, gpstm->lastref.l_uf);
+
+ i = ((int)(gpstm->coderecv)) % NCODES;
+ gpstm->offset[i] = gpstm->lastref;
+ L_SUB(&gpstm->offset[i], &tstmp);
+ if (gpstm->coderecv == 0)
+ for (i = 1; i < NCODES; i++)
+ gpstm->offset[i] = gpstm->offset[0];
+
+ gpstm->coderecv++;
+
+ /*
+ * Process the median filter, and pass the
+ * offset and dispersion along. We use lastrec as both the
+ * reference time and receive time in order to avoid being cute,
+ * like setting the reference time later than the receive time,
+ * which may cause a paranoid protocol module to chuck out the
+ * data.
+ */
+ if (!gpstm_process(gpstm, &tstmp, &dispersion)) {
+ gpstm->baddata++;
+ gpstm_rep_event(gpstm, CEVNT_BADTIME);
+ return;
+ }
+ refclock_receive(gpstm->peer, &tstmp, GMT, dispersion,
+ &gpstm->lastrec, &gpstm->lastrec, gpstm->leap);
+
+ /*
+ * We have succedded in answering the poll. Turn off the flag
+ */
+ gpstm->polled = 0;
+}
+
+/*
+ * gpstm_send - time to send the clock a signal to cough up a time sample
+ */
+static void
+gpstm_send(gpstm, cmd)
+ struct gpstm_unit *gpstm;
+ char *cmd;
+{
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_send(gpstm%d): %s\n", gpstm->unit, cmd);
+ }
+#endif
+ if (!readonlyclockflag[gpstm->unit]) {
+ register int len = strlen(cmd);
+
+ if (write(gpstm->io.fd, cmd, len) != len) {
+ syslog(LOG_ERR, "gpstm_send: unit %d: %m",
+ gpstm->unit);
+ gpstm_rep_event(gpstm, CEVNT_FAULT);
+ }
+ }
+}
+
+/*
+ * state machine for initializing the clock
+ */
+
+static void
+gpstm_doevent(unit, event)
+ int unit;
+ enum gpstm_event event;
+{
+ struct gpstm_unit *gpstm = gpstm_units[unit];
+
+#ifdef DEBUG
+ if (debug) {
+ printf("gpstm_doevent(gpstm%d, %d)\n", unit, (int)event);
+ }
+#endif
+ if (event == e_TS && State[unit] != F51 && State[unit] != F08) {
+ gpstm_send(gpstm, "\03\r");
+ }
+
+ switch (event) {
+ case e_Init:
+ gpstm_send(gpstm, "F18\r");
+ State[unit] = Start;
+ break;
+ case e_F18:
+ gpstm_send(gpstm, "F50\r");
+ State[unit] = F18;
+ break;
+ case e_F50:
+ gpstm_send(gpstm, "F51\r");
+ State[unit] = F50;
+ break;
+ case e_F51:
+ gpstm_send(gpstm, "F08\r");
+ State[unit] = F51;
+ break;
+ case e_TS:
+ /* nothing to send - we like this mode */
+ State[unit] = F08;
+ break;
+ }
+}
+
+static void
+gpstm_initstate(unit) {
+ State[unit] = Base; /* just in case */
+ gpstm_doevent(unit, e_Init);
+}
+
+/*
+ * gpstm_process - process a pile of samples from the clock
+ */
+static char
+gpstm_process(gpstm, offset, dispersion)
+ struct gpstm_unit *gpstm;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, j;
+ register U_LONG tmp_ui, tmp_uf;
+ int not_median1 = -1; /* XXX correct? */
+ int not_median2 = -1; /* XXX correct? */
+ int median;
+ u_fp disp_tmp, disp_tmp2;
+
+ /*
+ * This code implements a three-stage median filter. First, we
+ * check if the samples are within 125 ms of each other. If not,
+ * dump the sample set. We take the median of the three offsets
+ * and use that as the sample offset. We take the maximum
+ * difference and use that as the sample dispersion. There
+ * probably is not much to be gained by a longer filter, since
+ * the clock filter in ntp_proto should do its thing.
+ */
+ disp_tmp2 = 0;
+ for (i = 0; i < NCODES-1; i++) {
+ for (j = i+1; j < NCODES; j++) {
+ tmp_ui = gpstm->offset[i].l_ui;
+ tmp_uf = gpstm->offset[i].l_uf;
+ M_SUB(tmp_ui, tmp_uf, gpstm->offset[j].l_ui,
+ gpstm->offset[j].l_uf);
+ if (M_ISNEG(tmp_ui, tmp_uf)) {
+ M_NEG(tmp_ui, tmp_uf);
+ }
+ if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
+ return 0;
+ }
+ disp_tmp = MFPTOFP(0, tmp_uf);
+ if (disp_tmp > disp_tmp2) {
+ disp_tmp2 = disp_tmp;
+ not_median1 = i;
+ not_median2 = j;
+ }
+ }
+ }
+
+ /*
+ * It seems as if all are within 125 ms of each other.
+ * Now to determine the median of the three. Whlie the
+ * 125 ms check was going on, we also subtly catch the
+ * dispersion and set-up for a very easy median calculation.
+ * The largest difference between any two samples constitutes
+ * the dispersion. The sample not involve in the dispersion is
+ * the median sample. EASY!
+ */
+ if (gpstm->lasttime == 0 || disp_tmp2 > MAXDISPERSE)
+ disp_tmp2 = MAXDISPERSE;
+ if (not_median1 == 0) {
+ if (not_median2 == 1)
+ median = 2;
+ else
+ median = 1;
+ } else {
+ median = 0;
+ }
+ *offset = gpstm->offset[median];
+ *dispersion = disp_tmp2;
+ return 1;
+}
+
+/*
+ * gpstm_poll - called by the transmit procedure
+ */
+static void
+gpstm_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct gpstm_unit *gpstm;
+
+ /*
+ * You don't need to poll this clock. It puts out timecodes
+ * once per second. If asked for a timestamp, take note.
+ * The next time a timecode comes in, it will be fed back.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "gpstm_poll: unit %d not in use", unit);
+ return;
+ }
+ gpstm = gpstm_units[unit];
+ if ((current_time - gpstm->lasttime) > 150) {
+ gpstm->noreply++;
+ gpstm_rep_event(gpstm_units[unit], CEVNT_TIMEOUT);
+ gpstm_initstate(gpstm->unit);
+ }
+
+ /*
+ * polled every 64 seconds. Ask our receiver to hand in a timestamp.
+ */
+ gpstm->polled = 1;
+ gpstm->polls++;
+}
+
+/*
+ * gpstm_control - set fudge factors, return statistics
+ */
+static void
+gpstm_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor1[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ fudgefactor2[unit] = in->fudgetime2;
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = gpstm_units[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out != 0) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
+ out->type = REFCLK_GPSTM_TRUETIME;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2 | CLK_HAVEFLAG1;
+ out->clockdesc = DESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ gpstm = gpstm_units[unit];
+ out->lencode = gpstm->lencode;
+ out->lastcode = gpstm->lastcode;
+ out->timereset = current_time - gpstm->timestarted;
+ out->polls = gpstm->polls;
+ out->noresponse = gpstm->noreply;
+ out->badformat = gpstm->badformat;
+ out->baddata = gpstm->baddata;
+ out->lastevent = gpstm->lastevent;
+ out->currentstatus = gpstm->status;
+ }
+ }
+}
+
+/*
+ * gpstm_buginfo - return clock dependent debugging info
+ */
+static void
+gpstm_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpstm_unit *gpstm;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "gpstm_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gpstm = gpstm_units[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (gpstm->lasttime != 0)
+ bug->values[0] = current_time - gpstm->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)gpstm->reason;
+ bug->values[2] = (U_LONG)gpstm->year;
+ bug->values[3] = (U_LONG)gpstm->day;
+ bug->values[4] = (U_LONG)gpstm->hour;
+ bug->values[5] = (U_LONG)gpstm->minute;
+ bug->values[6] = (U_LONG)gpstm->second;
+ bug->values[7] = (U_LONG)gpstm->msec;
+ bug->values[8] = gpstm->noreply;
+ bug->values[9] = gpstm->yearstart;
+ bug->values[10] = gpstm->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = gpstm->lastref;
+ bug->times[1] = gpstm->lastrec;
+ bug->times[2] = gpstm->offset[0];
+ bug->times[3] = gpstm->offset[1];
+ bug->times[4] = gpstm->offset[2];
+}
+
+#endif /*GPSTM et al*/
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_leitch.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_leitch.c
new file mode 100644
index 000000000000..808f65bb4b89
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_leitch.c
@@ -0,0 +1,709 @@
+/*
+ * refclock_leitch - clock driver for the Leitch CSD-5300 Master Clock
+ */
+#if defined(REFCLOCK) && (defined(LEITCH) || defined(LEITCHCLK) || defined(LEITCHPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#ifdef STREAM
+#include <stropts.h>
+#if defined(LEITCHCLK)
+#include <sys/clkdefs.h>
+#endif /* LEITCHCLK */
+#endif /* STREAM */
+
+#if defined (LEITCHPPS)
+#include <sys/ppsclock.h>
+#endif /* LEITCHPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Driver for Leitch CSD-5300 Master Clock System
+ *
+ * COMMANDS:
+ * DATE: D <CR>
+ * TIME: T <CR>
+ * STATUS: S <CR>
+ * LOOP: L <CR>
+ *
+ * FORMAT:
+ * DATE: YYMMDD<CR>
+ * TIME: <CR>/HHMMSS <CR>/HHMMSS <CR>/HHMMSS <CR>/
+ * second bondaried on the stop bit of the <CR>
+ * second boundaries at '/' above.
+ * STATUS: G (good), D (diag fail), T (time not provided) or
+ * P (last phone update failed)
+ */
+#define MAXUNITS 1 /* max number of LEITCH units */
+#define LEITCHREFID "ATOM" /* reference id */
+#define LEITCH_DESCRIPTION "Leitch: CSD 5300 Master Clock System Driver"
+#define LEITCH232 "/dev/leitch%d" /* name of radio device */
+#define SPEED232 B300 /* uart speed (300 baud) */
+#define leitch_send(A,M) \
+ if (debug) fprintf(stderr,"write leitch %s\n",M); \
+ if ((write(A->leitchio.fd,M,sizeof(M)) < 0)) {\
+ if (debug) \
+ fprintf(stderr, "leitch_send: unit %d send failed\n", A->unit); \
+ else \
+ syslog(LOG_ERR, "leitch_send: unit %d send failed %m",A->unit);}
+
+#define STATE_IDLE 0
+#define STATE_DATE 1
+#define STATE_TIME1 2
+#define STATE_TIME2 3
+#define STATE_TIME3 4
+
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * LEITCH unit control structure
+ */
+struct leitchunit {
+ struct peer *peer;
+ struct event leitchtimer;
+ struct refclockio leitchio;
+ u_char unit;
+ short year;
+ short yearday;
+ short month;
+ short day;
+ short hour;
+ short second;
+ short minute;
+ short state;
+ u_short fudge1;
+ l_fp reftime1;
+ l_fp reftime2;
+ l_fp reftime3;
+ l_fp codetime1;
+ l_fp codetime2;
+ l_fp codetime3;
+ U_LONG yearstart;
+};
+
+/*
+ * Function prototypes
+ */
+static void leitch_init P((void));
+static int leitch_start P((u_int, struct peer *));
+static void leitch_shutdown P((int));
+static void leitch_poll P((int, struct peer *));
+static void leitch_control P((u_int, struct refclockstat *, struct refclockstat *));
+#define leitch_buginfo noentry
+static void leitch_receive P((struct recvbuf *));
+static void leitch_process P((struct leitchunit *));
+static void leitch_timeout P((struct peer *));
+static int leitch_get_date P((struct recvbuf *, struct leitchunit *));
+static int leitch_get_time P((struct recvbuf *, struct leitchunit *, int));
+static int dysize P((int));
+
+static struct leitchunit leitchunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static U_LONG refid[MAXUNITS];
+
+static char days_in_month [] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_leitch = {
+ leitch_start, leitch_shutdown, leitch_poll,
+ leitch_control, leitch_init, leitch_buginfo, NOFLAGS
+};
+
+/*
+ * leitch_init - initialize internal leitch driver data
+ */
+static void
+leitch_init()
+{
+ int i;
+
+ memset((char*)leitchunits, 0, sizeof(leitchunits));
+ memset((char*)unitinuse, 0, sizeof(unitinuse));
+ for (i = 0; i < MAXUNITS; i++)
+ memcpy((char *)&refid[i], LEITCHREFID, 4);
+}
+
+/*
+ * leitch_shutdown - shut down a LEITCH clock
+ */
+static void
+leitch_shutdown(unit)
+int unit;
+{
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_shutdown()\n");
+#endif
+}
+
+/*
+ * leitch_poll - called by the transmit procedure
+ */
+static void
+leitch_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct leitchunit *leitch;
+
+ /* start the state machine rolling */
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_poll()\n");
+#endif
+ if (unit > MAXUNITS) {
+ /* XXXX syslog it */
+ return;
+ }
+
+ leitch = &leitchunits[unit];
+
+ if (leitch->state != STATE_IDLE) {
+ /* reset and wait for next poll */
+ /* XXXX syslog it */
+ leitch->state = STATE_IDLE;
+ } else {
+ leitch_send(leitch,"D\r");
+ leitch->state = STATE_DATE;
+ }
+}
+
+static void
+leitch_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "leitch_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in) {
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = (&leitchunits[unit])->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
+ out->type = REFCLK_ATOM_LEITCH;
+ out->haveflags = CLK_HAVEVAL1 | CLK_HAVEVAL2;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->lastcode = "";
+ out->clockdesc = LEITCH_DESCRIPTION;
+ }
+}
+
+/*
+ * leitch_start - open the LEITCH devices and initialize data for processing
+ */
+static int
+leitch_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ struct leitchunit *leitch;
+ int fd232;
+ char leitchdev[20];
+
+ /*
+ * Check configuration info.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "leitch_start: unit %d invalid", unit);
+ return (0);
+ }
+
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "leitch_start: unit %d in use", unit);
+ return (0);
+ }
+
+ /*
+ * Open serial port.
+ */
+ (void) sprintf(leitchdev, LEITCH232, unit);
+ fd232 = open(leitchdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR,
+ "leitch_start: open of %s: %m", leitchdev);
+ return (0);
+ }
+
+ leitch = &leitchunits[unit];
+ memset((char*)leitch, 0, sizeof(*leitch));
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TCGETA): %m", leitchdev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TCSETA): %m", leitchdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The LEITCHCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The LEITCHPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcgetattr(%s): %m", leitchdev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcsetattr(%s): %m", leitchdev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: tcflush(%s): %m", leitchdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, clk): %m", leitchdev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, CLK_SETSTR): %m", leitchdev);
+#endif /* LEITCHCLK */
+#if defined(LEITCHPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, I_PUSH, ppsclock): %m", leitchdev);
+ else
+ fdpps = fd232;
+#endif /* LEITCHPPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The LEITCHCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(LEITCHCLK)
+ int ldisc = CLKLDISC;
+#endif /* LEITCHCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCGETP): %m", leitchdev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(LEITCHCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* LEITCHCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETP): %m", leitchdev);
+ goto screwed;
+ }
+#if defined(LEITCHCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "leitch_start: ioctl(%s, TIOCSETD): %m",leitchdev);
+ goto screwed;
+ }
+#endif /* LEITCHCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Set up the structures
+ */
+ leitch->peer = peer;
+ leitch->unit = unit;
+ leitch->state = STATE_IDLE;
+ leitch->fudge1 = 15; /* 15ms */
+
+ leitch->leitchio.clock_recv = leitch_receive;
+ leitch->leitchio.srcclock = (caddr_t) leitch;
+ leitch->leitchio.datalen = 0;
+ leitch->leitchio.fd = fd232;
+ if (!io_addclock(&leitch->leitchio)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
+ */
+ peer->precision = 0;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ return(1);
+
+ /*
+ * Something broke; abandon ship.
+ */
+screwed:
+ close(fd232);
+ return(0);
+}
+
+/*
+ * leitch_receive - receive data from the serial interface on a leitch
+ * clock
+ */
+static void
+leitch_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct leitchunit *leitch = (struct leitchunit *)rbufp->recv_srcclock;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_recieve(%*.*s)\n",
+ rbufp->recv_length, rbufp->recv_length,
+ rbufp->recv_buffer);
+#endif
+ if (rbufp->recv_length != 7)
+ return; /* The date is return with a trailing newline,
+ discard it. */
+
+ switch (leitch->state) {
+ case STATE_IDLE: /* unexpected, discard and resync */
+ return;
+ case STATE_DATE:
+ if (!leitch_get_date(rbufp,leitch)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+ leitch_send(leitch,"T\r");
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n",leitch->yearday);
+#endif
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ if (!leitch_get_time(rbufp,leitch,1)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime1.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime1.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime1.l_uf);
+ leitch->codetime1 = rbufp->recv_time;
+ leitch->state = STATE_TIME2;
+ break;
+ case STATE_TIME2:
+ if (!leitch_get_time(rbufp,leitch,2)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime2.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime2.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime2.l_uf);
+ leitch->codetime2 = rbufp->recv_time;
+ leitch->state = STATE_TIME3;
+ break;
+ case STATE_TIME3:
+ if (!leitch_get_time(rbufp,leitch,3)) {
+ }
+ if (!clocktime(leitch->yearday,leitch->hour,leitch->minute,
+ leitch->second, 0, rbufp->recv_time.l_ui,
+ &leitch->yearstart, &leitch->reftime3.l_ui)) {
+ leitch->state = STATE_IDLE;
+ break;
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "%u\n", leitch->reftime3.l_ui);
+#endif
+ MSUTOTSF(leitch->fudge1, leitch->reftime3.l_uf);
+ leitch->codetime3 = rbufp->recv_time;
+ leitch_process(leitch);
+ leitch->state = STATE_IDLE;
+ break;
+ default:
+ syslog(LOG_ERR,
+ "leitech_receive: invalid state %d unit %d",
+ leitch->state, leitch->unit);
+ }
+}
+
+/*
+ * leitch_process - process a pile of samples from the clock
+ *
+ * This routine uses a three-stage median filter to calculate offset and
+ * dispersion. reduce jitter. The dispersion is calculated as the span
+ * of the filter (max - min), unless the quality character (format 2) is
+ * non-blank, in which case the dispersion is calculated on the basis of
+ * the inherent tolerance of the internal radio oscillator, which is
+ * +-2e-5 according to the radio specifications.
+ */
+static void
+leitch_process(leitch)
+ struct leitchunit *leitch;
+{
+ l_fp off;
+ s_fp delay;
+ l_fp codetime;
+ l_fp tmp_fp;
+ int isinsync = 1;
+ u_fp dispersion = 10;
+
+ delay = 20;
+
+ codetime = leitch->codetime3;
+
+ off = leitch->reftime1;
+ L_SUB(&off,&leitch->codetime1);
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime1.l_ui, leitch->codetime1.l_uf,
+ leitch->reftime1.l_ui, leitch->reftime1.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ tmp_fp = leitch->reftime2;
+ L_SUB(&tmp_fp,&leitch->codetime2);
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime2.l_ui, leitch->codetime2.l_uf,
+ leitch->reftime2.l_ui, leitch->reftime2.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ tmp_fp = leitch->reftime3;
+ L_SUB(&tmp_fp,&leitch->codetime3);
+
+ if (L_ISGEQ(&off,&tmp_fp))
+ off = tmp_fp;
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr,"%u %u %u %u %d %d\n",
+ leitch->codetime3.l_ui, leitch->codetime3.l_uf,
+ leitch->reftime3.l_ui, leitch->reftime3.l_uf,
+ off.l_ui, off.l_uf);
+#endif
+ refclock_receive(leitch->peer, &off, 0, dispersion, &codetime,
+ &codetime, isinsync);
+}
+
+/*
+ * leitch_timeout
+ */
+static void
+leitch_timeout(fp)
+ struct peer *fp;
+{
+
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "leitch_timeout()\n");
+#endif
+
+#ifdef NOTYET
+ { struct leitchunit *leitch = (struct leitchunit *)fp;
+
+ switch(leitch->state) {
+ case STATE_IDLE:
+ leitch_send(leitch,"D\r");
+ leitch->state = STATE_DATE;
+ break;
+ case STATE_DATE:
+ leitch_send(leitch,"T\r");
+ leitch->state = STATE_TIME1;
+ break;
+ case STATE_TIME1:
+ case STATE_TIME2:
+ case STATE_TIME3:
+ default:
+ break;
+ }
+
+ leitch->leitchtimer.event_time += 30;
+ TIMER_ENQUEUE(timerqueue, &leitch->leitchtimer);
+ }
+#endif /* NOTYET */
+}
+
+/*
+ * dysize
+ */
+static int
+dysize(year)
+int year;
+{
+ if (year%4) { /* not a potential leap year */
+ return (365);
+ } else {
+ if (year % 100) { /* is a leap year */
+ return (366);
+ } else {
+ if (year % 400) {
+ return (365);
+ } else {
+ return (366);
+ }
+ }
+ }
+}
+
+static int
+leitch_get_date(rbufp,leitch)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+{
+ int i;
+
+ if (rbufp->recv_length < 6)
+ return(0);
+#define BAD(A) (rbufp->recv_buffer[A] < '0') || (rbufp->recv_buffer[A] > '9')
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+#define ATOB(A) ((rbufp->recv_buffer[A])-'0')
+ leitch->year = ATOB(0)*10 + ATOB(1);
+ leitch->month = ATOB(2)*10 + ATOB(3);
+ leitch->day = ATOB(4)*10 + ATOB(5);
+
+ /* sanity checks */
+ if (leitch->month > 12)
+ return(0);
+ if (leitch->day > days_in_month[leitch->month-1])
+ return(0);
+
+ /* calculate yearday */
+ i = 0;
+ leitch->yearday = leitch->day;
+
+ while ( i < (leitch->month-1) )
+ leitch->yearday += days_in_month[i++];
+
+ if ((dysize((leitch->year>90?1900:2000)+leitch->year)==365) &&
+ leitch->month > 2)
+ leitch->yearday--;
+
+ return(1);
+}
+
+/*
+ * leitch_get_time
+ */
+static int
+leitch_get_time(rbufp,leitch,which)
+ struct recvbuf *rbufp;
+ struct leitchunit *leitch;
+ int which;
+{
+ if (BAD(0)||BAD(1)||BAD(2)||BAD(3)||BAD(4)||BAD(5))
+ return(0);
+ leitch->hour = ATOB(0)*10 +ATOB(1);
+ leitch->minute = ATOB(2)*10 +ATOB(3);
+ leitch->second = ATOB(4)*10 +ATOB(5);
+
+ if ((leitch->hour > 23) || (leitch->minute > 60) ||
+ (leitch->second > 60))
+ return(0);
+ return(1);
+}
+
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_msfees.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_msfees.c
new file mode 100644
index 000000000000..255d74f285de
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_msfees.c
@@ -0,0 +1,1575 @@
+/* refclock_ees - clock driver for the EES M201 receiver */
+
+#if defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM)
+
+/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
+ * were removed as the code was overly hairy, they weren't in use
+ * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk
+ */
+
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_calendar.h"
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+#include <termios.h>
+#include <stropts.h>
+#include <sys/ppsclock.h>
+#include "ntp_stdlib.h"
+
+ /*
+ fudgefactor = fudgetime1;
+ os_delay = fudgetime2;
+ offset_fudge = os_delay + fudgefactor + inherent_delay;
+ stratumtouse = fudgeval1 & 0xf
+ debug = fudgeval2;
+ sloppyclockflag = flags & CLK_FLAG1;
+ 1 log smoothing summary when processing sample
+ 4 dump the buffer from the clock
+ 8 EIOGETKD the last n uS time stamps
+ if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
+ ees->dump_vals = flags & CLK_FLAG3;
+ ees->usealldata = flags & CLK_FLAG4;
+
+
+ bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
+ bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
+ bug->values[2] = (u_long)ees->status;
+ bug->values[3] = (u_long)ees->lastevent;
+ bug->values[4] = (u_long)ees->reason;
+ bug->values[5] = (u_long)ees->nsamples;
+ bug->values[6] = (u_long)ees->codestate;
+ bug->values[7] = (u_long)ees->day;
+ bug->values[8] = (u_long)ees->hour;
+ bug->values[9] = (u_long)ees->minute;
+ bug->values[10] = (u_long)ees->second;
+ bug->values[11] = (u_long)ees->tz;
+ bug->values[12] = ees->yearstart;
+ bug->values[13] = (ees->leaphold > current_time) ?
+ ees->leaphold - current_time : 0;
+ bug->values[14] = inherent_delay[unit].l_uf;
+ bug->values[15] = offset_fudge[unit].l_uf;
+
+ bug->times[0] = ees->reftime;
+ bug->times[1] = ees->arrvtime;
+ bug->times[2] = ees->lastsampletime;
+ bug->times[3] = ees->offset;
+ bug->times[4] = ees->lowoffset;
+ bug->times[5] = ees->highoffset;
+ bug->times[6] = inherent_delay[unit];
+ bug->times[8] = os_delay[unit];
+ bug->times[7] = fudgefactor[unit];
+ bug->times[9] = offset_fudge[unit];
+ bug->times[10]= ees->yearstart, 0;
+ */
+
+/* This should support the use of an EES M201 receiver with RS232
+ * output (modified to transmit time once per second).
+ *
+ * For the format of the message sent by the clock, see the EESM_
+ * definitions below.
+ *
+ * It appears to run free for an integral number of minutes, until the error
+ * reaches 4mS, at which point it steps at second = 01.
+ * It appears that sometimes it steps 4mS (say at 7 min interval),
+ * then the next minute it decides that it was an error, so steps back.
+ * On the next minute it steps forward again :-(
+ * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
+ * or 9.5uS/S then 3990.5uS at a 7min re-sync,
+ * at which point it may loose the "00" second time stamp.
+ * I assume that the most accurate time is just AFTER the re-sync.
+ * Hence remember the last cycle interval,
+ *
+ * Can run in any one of:
+ *
+ * PPSCD PPS signal sets CD which interupts, and grabs the current TOD
+ * (sun) *in the interupt code*, so as to avoid problems with
+ * the STREAMS scheduling.
+ *
+ * It appears that it goes 16.5 uS slow each second, then every 4 mins it
+ * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
+ */
+
+/* Definitions */
+#ifndef MAXUNITS
+#define MAXUNITS 4 /* maximum number of EES units permitted */
+#endif
+
+#ifndef EES232
+#define EES232 "/dev/ees%d" /* Device to open to read the data */
+#endif
+
+/* Other constant stuff */
+#ifndef EESPRECISION
+#define EESPRECISION (-10) /* what the heck - 2**-10 = 1ms */
+#endif
+#ifndef EESREFID
+#define EESREFID "MSF\0" /* String to identify the clock */
+#endif
+#ifndef EESHSREFID
+#define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
+#endif
+
+/* Description of clock */
+#define EESDESCRIPTION "EES M201 MSF Receiver"
+
+/* Speed we run the clock port at. If this is changed the UARTDELAY
+ * value should be recomputed to suit.
+ */
+#ifndef SPEED232
+#define SPEED232 B9600 /* 9600 baud */
+#endif
+
+/* What is the inherent delay for this mode of working, i.e. when is the
+ * data time stamped.
+ */
+#define SAFETY_SHIFT 10 /* Split the shift to avoid overflow */
+#define BITS_TO_L_FP(bits, baud) \
+ (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
+#define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600)
+#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
+
+#ifndef STREAM_PP1
+#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
+#endif
+#ifndef STREAM_PP2
+#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
+#endif
+
+/* Offsets of the bytes of the serial line code. The clock gives
+ * local time with a GMT/BST indication. The EESM_ definitions
+ * give offsets into ees->lastcode.
+ */
+#define EESM_CSEC 0 /* centiseconds - always zero in our clock */
+#define EESM_SEC 1 /* seconds in BCD */
+#define EESM_MIN 2 /* minutes in BCD */
+#define EESM_HOUR 3 /* hours in BCD */
+#define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */
+#define EESM_DAY 5 /* day of month in BCD */
+#define EESM_MON 6 /* month in BCD */
+#define EESM_YEAR 7 /* year MOD 100 in BCD */
+#define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */
+#define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */
+#define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */
+ /* followed by a frame alignment byte (0xff) /
+ / which is not put into the lastcode buffer*/
+
+/* Length of the serial time code, in characters. The first length
+ * is less the frame alignment byte.
+ */
+#define LENEESPRT (EESM_MSFOK+1)
+#define LENEESCODE (LENEESPRT+1)
+
+/* Code state. */
+#define EESCS_WAIT 0 /* waiting for start of timecode */
+#define EESCS_GOTSOME 1 /* have an incomplete time code buffered */
+
+/* Default fudge factor and character to receive */
+#define DEFFUDGETIME 0 /* Default user supplied fudge factor */
+#ifndef DEFOSTIME
+#define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */
+#endif
+#define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/
+
+/* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median
+ * elimination. If we're running with an accurate clock, chose the BESTSAMPLE
+ * as the estimated offset, otherwise average the remainder.
+ */
+#define FULLSHIFT 6 /* NCODES root 2 */
+#define NCODES (1<< FULLSHIFT) /* 64 */
+#define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */
+
+/* Towards the high ( Why ?) end of half */
+#define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */
+
+/* Leap hold time. After a leap second the clock will no longer be
+ * reliable until it resynchronizes. Hope 40 minutes is enough. */
+#define EESLEAPHOLD (40 * 60)
+
+#define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */
+#define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
+#define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */
+#define EES_STEP_NOTES 50 /* Only do a limited number */
+#define MAX_STEP 16 /* Max number of steps to remember */
+
+/* debug is a bit mask of debugging that is wanted */
+#define DB_SYSLOG_SMPLI 0x0001
+#define DB_SYSLOG_SMPLE 0x0002
+#define DB_SYSLOG_SMTHI 0x0004
+#define DB_SYSLOG_NSMTHE 0x0008
+#define DB_SYSLOG_NSMTHI 0x0010
+#define DB_SYSLOG_SMTHE 0x0020
+#define DB_PRINT_EV 0x0040
+#define DB_PRINT_CDT 0x0080
+#define DB_PRINT_CDTC 0x0100
+#define DB_SYSLOG_KEEPD 0x0800
+#define DB_SYSLOG_KEEPE 0x1000
+#define DB_LOG_DELTAS 0x2000
+#define DB_PRINT_DELTAS 0x4000
+#define DB_LOG_AWAITMORE 0x8000
+#define DB_LOG_SAMPLES 0x10000
+#define DB_NO_PPS 0x20000
+#define DB_INC_PPS 0x40000
+#define DB_DUMP_DELTAS 0x80000
+
+struct eesunit { /* EES unit control structure. */
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp reftime; /* reference time */
+ l_fp lastsampletime; /* time as in txt from last EES msg */
+ l_fp arrvtime; /* Time at which pkt arrived */
+ l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */
+ l_fp offset; /* chosen offset (for clkbug) */
+ l_fp lowoffset; /* lowest sample offset (for clkbug) */
+ l_fp highoffset; /* highest " " (for clkbug) */
+ char lastcode[LENEESCODE+6]; /* last time code we received */
+ u_long lasttime; /* last time clock heard from */
+ u_long clocklastgood; /* last time good radio seen */
+ u_char lencode; /* length of code in buffer */
+ u_char nsamples; /* number of samples we've collected */
+ u_char codestate; /* state of 232 code reception */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ char tz; /* timezone from clock */
+ u_char ttytype; /* method used */
+ u_char dump_vals; /* Should clock values be dumped */
+ u_char usealldata; /* Use ALL samples */
+ u_short day; /* day of year from last code */
+ u_long yearstart; /* start of current year */
+ u_long leaphold; /* time of leap hold expiry */
+ u_long badformat; /* number of bad format codes */
+ u_long baddata; /* number of invalid time codes */
+ u_long timestarted; /* time we started this */
+ long last_pps_no; /* The serial # of the last PPS */
+ char fix_pending; /* Is a "sync to time" pending ? */
+ /* Fine tuning - compensate for 4 mS ramping .... */
+ l_fp last_l; /* last time stamp */
+ u_char last_steps[MAX_STEP]; /* Most recent n steps */
+ int best_av_step; /* Best guess at average step */
+ char best_av_step_count; /* # of steps over used above */
+ char this_step; /* Current pos in buffer */
+ int last_step_late; /* How late the last step was (0-59) */
+ long jump_fsecs; /* # of fractions of a sec last jump */
+ u_long last_step; /* time of last step */
+ int last_step_secs; /* Number of seconds in last step */
+ int using_ramp; /* 1 -> noemal, -1 -> over stepped */
+};
+#define last_sec last_l.l_ui
+#define last_sfsec last_l.l_f
+#define this_uisec ((ees->arrvtime).l_ui)
+#define this_sfsec ((ees->arrvtime).l_f)
+#define msec(x) ((x) / (1<<22))
+#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0])
+#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
+
+/* Bitmask for what methods to try to use -- currently only PPS enabled */
+#define T_CBREAK 1
+#define T_PPS 8
+/* macros to test above */
+#define is_cbreak(x) ((x)->ttytype & T_CBREAK)
+#define is_pps(x) ((x)->ttytype & T_PPS)
+#define is_any(x) ((x)->ttytype)
+
+#define CODEREASON 20 /* reason codes */
+
+/* Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back. */
+static struct eesunit *eesunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/* Keep the fudge factors separately so they can be set even
+ * when no clock is configured. */
+static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */
+static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */
+static l_fp os_delay[MAXUNITS]; /* fudgetime2 */
+static l_fp offset_fudge[MAXUNITS]; /* Sum of above */
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+
+static int deltas[60];
+
+static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
+static l_fp onesec; /* = { 1, 0 }; */
+
+/* Imported from the timer module */
+extern u_long current_time;
+
+#ifdef DEBUG
+static int debug;
+#endif
+
+#ifndef DUMP_BUF_SIZE /* Size of buffer to be used by dump_buf */
+#define DUMP_BUF_SIZE 10112
+#endif
+
+/* ees_reset - reset the count back to zero */
+#define ees_reset(ees) (ees)->nsamples = 0; \
+ (ees)->codestate = EESCS_WAIT
+
+/* ees_event - record and report an event */
+#define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
+ ees_report_event((ees), (evcode))
+
+/* Find the precision of the system clock by reading it */
+#define USECS 1000000
+#define MINSTEP 5 /* some systems increment uS on each call */
+#define MAXLOOPS (USECS/9)
+static int ees_get_precision()
+{
+ struct timeval tp;
+ struct timezone tzp;
+ long last;
+ int i;
+ long diff;
+ long val;
+ gettimeofday(&tp, &tzp);
+
+ last = tp.tv_usec;
+ for (i=0; i< 100000; i++) {
+ gettimeofday(&tp, &tzp);
+ diff = tp.tv_usec - last;
+ if (diff < 0) diff += USECS;
+ if (diff > MINSTEP) break;
+ last = tp.tv_usec;
+ }
+ syslog(LOG_INFO,
+ "I: ees: precision calculation given %duS after %d loop%s",
+ diff, i, (i==1) ? "" : "s");
+
+ if (i == 0) return -20 /* assume 1uS */;
+ if (i >= MAXLOOPS) return EESPRECISION /* Lies ! */;
+ for (i=0, val=USECS; val > 0; i--, val /= 2) if (diff > val) return i;
+ return EESPRECISION /* Lies ! */;
+}
+
+static void dump_buf(coffs, from, to, text)
+l_fp *coffs;
+int from;
+int to;
+char *text;
+{
+ char buff[DUMP_BUF_SIZE + 80];
+ int i;
+ register char *ptr = buff;
+ sprintf(ptr, text);
+ for (i=from; i<to; i++)
+ { while (*ptr) ptr++;
+ if ((ptr-buff) > DUMP_BUF_SIZE) syslog(LOG_DEBUG, "D: %s", ptr=buff);
+ sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
+ }
+ syslog(LOG_DEBUG, "D: %s", buff);
+}
+
+/* msfees_init - initialize internal ees driver data */
+static void msfees_init()
+{
+ register int i;
+ /* Just zero the data arrays */
+ memset((char *)eesunits, 0, sizeof eesunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ acceptable_slop.l_ui = 0;
+ acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
+
+ onesec.l_ui = 1;
+ onesec.l_uf = 0;
+
+ /* Initialize fudge factors to default. */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = DEFFUDGETIME;
+ os_delay[i].l_ui = 0;
+ os_delay[i].l_uf = DEFOSTIME;
+ inherent_delay[i].l_ui = 0;
+ inherent_delay[i].l_uf = DEFINHTIME;
+ offset_fudge[i] = os_delay[i];
+ L_ADD(&offset_fudge[i], &fudgefactor[i]);
+ L_ADD(&offset_fudge[i], &inherent_delay[i]);
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
+
+/* msfees_start - open the EES devices and initialize data for processing */
+static int msfees_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct eesunit *ees;
+ register int i;
+ int fd232 = -1;
+ char eesdev[20];
+ struct termios ttyb, *ttyp;
+ static void ees_receive();
+ extern int io_addclock();
+ extern void io_closeclock();
+ extern char *emalloc();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "ees clock: unit number %d in use", unit);
+ return 0;
+ }
+
+ /* Unit okay, attempt to open the devices. We do them both at
+ * once to make sure we can */
+ (void) sprintf(eesdev, EES232, unit);
+
+ fd232 = open(eesdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
+ return 0;
+ }
+
+#ifdef TIOCEXCL
+ /* Set for exclusive use */
+ if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
+ goto screwed;
+ }
+#endif
+
+ /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
+
+ /* Set port characteristics. If we don't have a STREAMS module or
+ * a clock line discipline, cooked mode is just usable, even though it
+ * strips the top bit. The only EES byte which uses the top
+ * bit is the year, and we don't use that anyway. If we do
+ * have the line discipline, we choose raw mode, and the
+ * line discipline code will block up the messages.
+ */
+
+ /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_oflag = 0;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
+ goto screwed;
+ }
+
+ inherent_delay[unit].l_uf = INH_DELAY_PPS;
+
+ /* offset fudge (how *late* the timestamp is) = fudge + os delays */
+ offset_fudge[unit] = os_delay[unit];
+ L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
+ L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
+
+ /* Looks like this might succeed. Find memory for the structure.
+ * Look to see if there are any unused ones, if not we malloc() one.
+ */
+ if (eesunits[unit] != 0) /* The one we want is okay */
+ ees = eesunits[unit];
+ else {
+ /* Look for an unused, but allocated struct */
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && eesunits[i] != 0)
+ break;
+ }
+
+ if (i < MAXUNITS) { /* Reclaim this one */
+ ees = eesunits[i];
+ eesunits[i] = 0;
+ } /* no spare -- make a new one */
+ else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
+ }
+ memset((char *)ees, 0, sizeof(struct eesunit));
+ eesunits[unit] = ees;
+
+ /* Set up the structures */
+ ees->peer = peer;
+ ees->unit = (u_char)unit;
+ ees->timestarted= current_time;
+ ees->ttytype = 0;
+ ees->io.clock_recv= ees_receive;
+ ees->io.srcclock= (caddr_t)ees;
+ ees->io.datalen = 0;
+ ees->io.fd = fd232;
+
+ /* Okay. Push one of the two (linked into the kernel, or dynamically
+ * loaded) STREAMS module, and give it to the I/O code to start
+ * receiving stuff.
+ */
+
+ {
+ int rc1;
+ /* Pop any existing onews first ... */
+ while (ioctl(fd232, I_POP, 0 ) >= 0) ;
+
+ /* Now try pushing either of the possible modules */
+ if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
+ ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
+ syslog(LOG_ERR,
+ "ees clock: Push of `%s' and `%s' to %s failed %m",
+ STREAM_PP1, STREAM_PP2, eesdev);
+ goto screwed;
+ }
+ else {
+ syslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
+ (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
+ ees->ttytype |= T_PPS;
+ }
+ }
+
+ /* Add the clock */
+ if (!io_addclock(&ees->io)) {
+ /* Oh shit. Just close and return. */
+ syslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
+ goto screwed;
+ }
+
+
+ /* All done. Initialize a few random peer variables, then
+ * return success. */
+ peer->precision = ees_get_precision();
+ peer->stratum = stratumtouse[unit];
+ peer->rootdelay = 0; /* ++++ */
+ peer->rootdispersion = 0; /* ++++ */
+ if (stratumtouse[unit] <= 1) {
+ memmove((char *)&peer->refid, EESREFID, 4);
+ if (unit > 0 && unit < 10)
+ ((char *)&peer->refid)[3] = '0' + unit;
+ } else {
+ peer->refid = htonl(EESHSREFID);
+ }
+ unitinuse[unit] = 1;
+ syslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
+ return (1);
+
+screwed:
+ if (fd232 != -1)
+ (void) close(fd232);
+ return (0);
+}
+
+
+/* msfees_shutdown - shut down a EES clock */
+static void msfees_shutdown(unit)
+ int unit;
+{
+ register struct eesunit *ees;
+ extern void io_closeclock();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
+ unit, MAXUNITS);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR,
+ "ees clock: INTERNAL ERROR, unit number %d not in use", unit);
+ return;
+ }
+
+ /* Tell the I/O module to turn us off. We're history. */
+ ees = eesunits[unit];
+ io_closeclock(&ees->io);
+ unitinuse[unit] = 0;
+}
+
+
+/* ees_report_event - note the occurance of an event */
+static void ees_report_event(ees, code)
+ struct eesunit *ees;
+ int code;
+{
+ if (ees->status != (u_char)code) {
+ ees->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ ees->lastevent = (u_char)code;
+ /* Should report event to trap handler in here.
+ * Soon...
+ */
+ }
+}
+
+
+/* ees_receive - receive data from the serial interface on an EES clock */
+static void ees_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int n_sample;
+ register int day;
+ register struct eesunit *ees;
+ register u_char *dpt; /* Data PoinTeR: move along ... */
+ register u_char *dpend; /* Points just *after* last data char */
+ register char *cp;
+ l_fp tmp;
+ static void ees_process();
+ int call_pps_sample = 0;
+ l_fp pps_arrvstamp;
+ int sincelast;
+ int pps_step = 0;
+ int suspect_4ms_step = 0;
+ struct ppsclockev ppsclockev;
+ long *ptr = (long *) &ppsclockev;
+ extern errno;
+ int rc;
+
+ /* Get the clock this applies to and a pointer to the data */
+ ees = (struct eesunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = dpt + rbufp->recv_length;
+ if ((debug & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
+ printf("[%d] ", rbufp->recv_length);
+
+ /* Check out our state and process appropriately */
+ switch (ees->codestate) {
+ case EESCS_WAIT:
+ /* Set an initial guess at the timestamp as the recv time.
+ * If just running in CBREAK mode, we can't improve this.
+ * If we have the CLOCK Line Discipline, PPSCD, or sime such,
+ * then we will do better later ....
+ */
+ ees->arrvtime = rbufp->recv_time;
+ ees->codestate = EESCS_GOTSOME;
+ ees->lencode = 0;
+ /*FALLSTHROUGH*/
+
+ case EESCS_GOTSOME:
+ cp = &(ees->lastcode[ees->lencode]);
+
+ /* Gobble the bytes until the final (possibly stripped) 0xff */
+ while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
+ *cp++ = (char)*dpt++;
+ ees->lencode++;
+ /* Oh dear -- too many bytes .. */
+ if (ees->lencode > LENEESPRT) {
+ syslog(LOG_INFO,
+"I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
+ ees->lencode, dpend - dpt, LENEESPRT,
+#define D(x) (ees->lastcode[x])
+ D(0), D(1), D(2), D(3), D(4), D(5), D(6),
+ D(7), D(8), D(9), D(10), D(11), D(12));
+#undef D
+ ees->badformat++;
+ ees->reason = CODEREASON + 1;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+ }
+ /* Gave up because it was end of the buffer, rather than ff */
+ if (dpt == dpend) {
+ /* Incomplete. Wait for more. */
+ if (debug & DB_LOG_AWAITMORE) syslog(LOG_INFO,
+ "I: ees clock %d: %d == %d: await more",
+ ees->unit, dpt, dpend);
+ return;
+ }
+
+ /* This shouldn't happen ... ! */
+ if ((*dpt & 0x7f) != 0x7f) {
+ syslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
+ ees->badformat++;
+ ees->reason = CODEREASON + 2;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Skip the 0xff */
+ dpt++;
+
+ /* Finally, got a complete buffer. Mainline code will
+ * continue on. */
+ cp = ees->lastcode;
+ break;
+
+ default:
+ syslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
+ ees->unit, ees->codestate);
+ ees->reason = CODEREASON + 5;
+ ees_event(ees, CEVNT_FAULT);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Boy! After all that crap, the lastcode buffer now contains
+ * something we hope will be a valid time code. Do length
+ * checks and sanity checks on constant data.
+ */
+ ees->codestate = EESCS_WAIT;
+ ees->lasttime = current_time;
+ if (ees->lencode != LENEESPRT) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 6;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ cp = ees->lastcode;
+
+ /* Check that centisecond is zero */
+ if (cp[EESM_CSEC] != 0) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 7;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* Check flag formats */
+ if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 8;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 9;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
+ ees->badformat++;
+ ees->reason = CODEREASON + 10;
+ ees_event(ees, CEVNT_BADREPLY);
+ ees_reset(ees);
+ return;
+ }
+
+ /* So far, so good. Compute day, hours, minutes, seconds,
+ * time zone. Do range checks on these.
+ */
+
+#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
+#define istrue(x) ((x)?1:0)
+
+ ees->second = bcdunpack(cp[EESM_SEC]); /* second */
+ ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */
+ ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */
+
+ day = bcdunpack(cp[EESM_DAY]); /* day of month */
+
+ switch (bcdunpack(cp[EESM_MON])) { /* month */
+
+ /* Add in lengths of all previous months. Add one more
+ if it is a leap year and after February.
+ */
+ case 12: day += NOV; /*FALLSTHROUGH*/
+ case 11: day += OCT; /*FALLSTHROUGH*/
+ case 10: day += SEP; /*FALLSTHROUGH*/
+ case 9: day += AUG; /*FALLSTHROUGH*/
+ case 8: day += JUL; /*FALLSTHROUGH*/
+ case 7: day += JUN; /*FALLSTHROUGH*/
+ case 6: day += MAY; /*FALLSTHROUGH*/
+ case 5: day += APR; /*FALLSTHROUGH*/
+ case 4: day += MAR; /*FALLSTHROUGH*/
+ case 3: day += FEB;
+ if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
+ case 2: day += JAN; /*FALLSTHROUGH*/
+ case 1: break;
+ default: ees->baddata++;
+ ees->reason = CODEREASON + 11;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+
+ ees->day = day;
+
+ /* Get timezone. The clocktime routine wants the number
+ * of hours to add to the delivered time to get UT.
+ * Currently -1 if BST flag set, 0 otherwise. This
+ * is the place to tweak things if double summer time
+ * ever happens.
+ */
+ ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
+
+ if (ees->day > 366 || ees->day < 1 ||
+ ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 12;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+
+ n_sample = ees->nsamples;
+
+ /* Now, compute the reference time value: text -> tmp.l_ui */
+ if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
+ ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
+ &tmp.l_ui)) {
+ ees->baddata++;
+ ees->reason = CODEREASON + 13;
+ ees_event(ees, CEVNT_BADDATE);
+ ees_reset(ees);
+ return;
+ }
+ tmp.l_uf = 0;
+
+ /* DON'T use ees->arrvtime -- it may be < reftime */
+ ees->lastsampletime = tmp;
+
+ /* If we are synchronised to the radio, update the reference time.
+ * Also keep a note of when clock was last good.
+ */
+ if (istrue(cp[EESM_MSFOK])) {
+ ees->reftime = tmp;
+ ees->clocklastgood = current_time;
+ }
+
+
+ /* Compute the offset. For the fractional part of the
+ * offset we use the expected delay for the message.
+ */
+ ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
+ ees->codeoffsets[n_sample].l_uf = 0;
+
+ /* Number of seconds since the last step */
+ sincelast = this_uisec - ees->last_step;
+
+ memset(&ppsclockev, 0, sizeof ppsclockev);
+
+ rc = ioctl(ees->io.fd, CIOGETEV, (char *) &ppsclockev);
+ if (debug & DB_PRINT_EV) fprintf(stderr,
+ "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08x %08x %d\n",
+ DB_PRINT_EV, ees->unit, ees->io.fd, CIOGETEV, is_pps(ees),
+ rc, errno, ptr[0], ptr[1], ptr[2]);
+
+ /* If we managed to get the time of arrival, process the info */
+ if (rc >= 0) {
+ int conv = -1;
+ pps_step = ppsclockev.serial - ees->last_pps_no;
+
+ /* Possible that PPS triggered, but text message didn't */
+ if (pps_step == 2) syslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
+ if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
+ if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
+
+ /* allow for single loss of PPS only */
+ if (pps_step != 1 && pps_step != 2)
+ fprintf(stderr, "PPS step: %d too far off %d (%d)\n",
+ ppsclockev.serial, ees->last_pps_no, pps_step);
+ else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
+ fprintf(stderr, "buftvtots failed\n");
+ else { /* if ((ABS(time difference) - 0.25) < 0)
+ * then believe it ...
+ */
+ l_fp diff;
+ diff = pps_arrvstamp;
+ conv = 0;
+ L_SUB(&diff, &ees->arrvtime);
+if (debug & DB_PRINT_CDT) printf("[%x] Have %x.%08x and %x.%08x -> %x.%08x @ %s",
+ DB_PRINT_CDT, ees->arrvtime.l_ui, ees->arrvtime.l_uf,
+ pps_arrvstamp.l_ui, pps_arrvstamp.l_uf,
+ diff.l_ui, diff.l_uf,
+ ctime(&(ppsclockev.tv.tv_sec)));
+ if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
+ L_SUB(&diff, &acceptable_slop);
+ if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
+ ees->arrvtime = pps_arrvstamp;
+ conv++;
+ call_pps_sample++;
+ }
+ /* Some loss of some signals around sec = 1 */
+ else if (ees->second == 1) {
+ diff = pps_arrvstamp;
+ L_ADD(&diff, &onesec);
+ L_SUB(&diff, &ees->arrvtime);
+ if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
+ L_SUB(&diff, &acceptable_slop);
+syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
+ pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
+ pps_arrvstamp.l_uf,
+ ees->arrvtime.l_uf,
+ diff.l_ui, diff.l_uf,
+ ppsclockev.tv.tv_usec,
+ ctime(&(ppsclockev.tv.tv_sec)));
+ if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
+ suspect_4ms_step |= 2;
+ ees->arrvtime = pps_arrvstamp;
+ L_ADD(&ees->arrvtime, &onesec);
+ conv++;
+ call_pps_sample++;
+ }
+ }
+ }
+ ees->last_pps_no = ppsclockev.serial;
+ if (debug & DB_PRINT_CDTC) printf(
+ "[%x] %08x %08x %d u%d (%d %d)\n",
+ DB_PRINT_CDTC, pps_arrvstamp.l_ui,
+ pps_arrvstamp.l_uf, conv, ees->unit,
+ call_pps_sample, pps_step);
+ }
+
+ /* See if there has been a 4ms jump at a minute boundry */
+ { l_fp delta;
+#define delta_isec delta.l_ui
+#define delta_ssec delta.l_i
+#define delta_sfsec delta.l_f
+ long delta_f_abs;
+
+ delta.l_i = ees->arrvtime.l_i;
+ delta.l_f = ees->arrvtime.l_f;
+
+ L_SUB(&delta, &ees->last_l);
+ delta_f_abs = delta_sfsec;
+ if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
+
+ /* Dump the deltas each minute */
+ if (debug & DB_DUMP_DELTAS)
+ { if (0 <= ees->second &&
+ ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
+ /* Dump on second 1, as second 0 sometimes missed */
+ if (ees->second == 1) {
+ char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
+ char *ptr=text;
+ int i;
+ for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
+ sprintf(ptr, " %d.%04d",
+ msec(deltas[i]), subms(deltas[i]));
+ while (*ptr) ptr++;
+ }
+ syslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
+ msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
+ msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
+ text+1);
+ for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
+ }
+ }
+
+ /* Lets see if we have a 4 mS step at a minute boundaary */
+ if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
+ (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
+ (ees->second == 0 || ees->second == 1 || ees->second == 2) &&
+ (sincelast < 0 || sincelast > 122)
+ ) { /* 4ms jump at min boundry */
+ int old_sincelast;
+ int count=0;
+ int sum = 0;
+ /* Yes -- so compute the ramp time */
+ if (ees->last_step == 0) sincelast = 0;
+ old_sincelast = sincelast;
+
+ /* First time in, just set "ees->last_step" */
+ if(ees->last_step) {
+ int other_step = 0;
+ int third_step = 0;
+ int this_step = (sincelast + (60 /2)) / 60;
+ int p_step = ees->this_step;
+ int p;
+ ees->last_steps[p_step] = this_step;
+ p= p_step;
+ p_step++;
+ if (p_step >= LAST_STEPS) p_step = 0;
+ ees->this_step = p_step;
+ /* Find the "average" interval */
+ while (p != p_step) {
+ int this = ees->last_steps[p];
+ if (this == 0) break;
+ if (this != this_step) {
+ if (other_step == 0 && (
+ this== (this_step +2) ||
+ this== (this_step -2) ||
+ this== (this_step +1) ||
+ this== (this_step -1)))
+ other_step = this;
+ if (other_step != this) {
+ int delta = (this_step - other_step);
+ if (delta < 0) delta = - delta;
+ if (third_step == 0 && (
+ (delta == 1) ? (
+ this == (other_step +1) ||
+ this == (other_step -1) ||
+ this == (this_step +1) ||
+ this == (this_step -1))
+ :
+ (
+ this == (this_step + other_step)/2
+ )
+ )) third_step = this;
+ if (third_step != this) break;
+ }
+ }
+ sum += this;
+ p--;
+ if (p < 0) p += LAST_STEPS;
+ count++;
+ }
+syslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step);
+ if (count != 0) sum = ((sum * 60) + (count /2)) / count;
+#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
+syslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
+ ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
+ SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
+printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
+ SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
+#undef SV
+ ees->jump_fsecs = delta_sfsec;
+ ees->using_ramp = 1;
+ if (sincelast > 170)
+ ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
+ else ees->last_step_late = 30;
+ if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
+ if (ees->last_step_late < 0) ees->last_step_late = 0;
+ if (ees->last_step_late >= 60) ees->last_step_late = 59;
+ sincelast = 0;
+ }
+ else { /* First time in -- just save info */
+ ees->last_step_late = 30;
+ ees->jump_fsecs = delta_sfsec;
+ ees->using_ramp = 1;
+ sum = 4 * 60;
+ }
+ ees->last_step = this_uisec;
+printf("MSF%d: d=%3d.%04d@%d :%d:%d:$%d:%d:%d\n",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
+syslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
+ if (sum) ees->last_step_secs = sum;
+ }
+ /* OK, so not a 4ms step at a minute boundry */
+ else {
+ if (suspect_4ms_step) syslog(LOG_ERR,
+ "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
+ ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
+ msec(EES_STEP_F - EES_STEP_F_GRACE),
+ subms(EES_STEP_F - EES_STEP_F_GRACE),
+ msec(delta_f_abs),
+ subms(delta_f_abs),
+ msec(EES_STEP_F + EES_STEP_F_GRACE),
+ subms(EES_STEP_F + EES_STEP_F_GRACE),
+ ees->second,
+ sincelast);
+ if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
+ static ees_step_notes = EES_STEP_NOTES;
+ if (ees_step_notes > 0) {
+ ees_step_notes--;
+printf("MSF%d: D=%3d.%04d@%02d :%d%s\n",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
+syslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
+ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
+ }
+ }
+ }
+ }
+ ees->last_l = ees->arrvtime;
+
+ /* IF we have found that it's ramping
+ * && it's within twice the expected ramp period
+ * && there is a non zero step size (avoid /0 !)
+ * THEN we twiddle things
+ */
+ if (ees->using_ramp &&
+ sincelast < (ees->last_step_secs)*2 &&
+ ees->last_step_secs)
+ { long sec_of_ramp = sincelast + ees->last_step_late;
+ long fsecs;
+ l_fp inc;
+
+ /* Ramp time may vary, so may ramp for longer than last time */
+ if (sec_of_ramp > (ees->last_step_secs + 120))
+ sec_of_ramp = ees->last_step_secs;
+
+ /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
+ fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs);
+
+ if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
+ "[%x] MSF%d: %3d/%03d -> d=%11d (%d|%d)",
+ DB_LOG_DELTAS,
+ ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
+ pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
+ if (debug & DB_PRINT_DELTAS) printf(
+ "MSF%d: %3d/%03d -> d=%11d (%d|%d)\n",
+ ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
+ pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
+
+ /* Must sign extend the result */
+ inc.l_i = (fsecs < 0) ? -1 : 0;
+ inc.l_f = fsecs;
+ if (debug & DB_INC_PPS)
+ { L_SUB(&pps_arrvstamp, &inc);
+ L_SUB(&ees->arrvtime, &inc);
+ }
+ else
+ { L_ADD(&pps_arrvstamp, &inc);
+ L_ADD(&ees->arrvtime, &inc);
+ }
+ }
+ else {
+ if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
+ "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
+ DB_LOG_DELTAS,
+ ees->unit, ees->using_ramp,
+ sincelast,
+ (ees->last_step_secs)*2,
+ ees->last_step_secs);
+ if (debug & DB_PRINT_DELTAS) printf(
+ "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
+ DB_LOG_DELTAS,
+ ees->unit, ees->using_ramp,
+ sincelast,
+ (ees->last_step_secs)*2,
+ ees->last_step_secs);
+ }
+
+ L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
+ L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
+
+ if (call_pps_sample && !(debug & DB_NO_PPS)) {
+ /* Sigh -- it expects its args negated */
+ L_NEG(&pps_arrvstamp);
+ (void) pps_sample(&pps_arrvstamp);
+ }
+
+ /* Subtract off the local clock time stamp */
+ L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
+ if (debug & DB_LOG_SAMPLES) syslog(LOG_ERR,
+ "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
+ ees->unit, DB_LOG_DELTAS, n_sample,
+ ees->codeoffsets[n_sample].l_f,
+ ees->codeoffsets[n_sample].l_f / 4295,
+ pps_arrvstamp.l_f,
+ pps_arrvstamp.l_f /4295,
+ (debug & DB_NO_PPS) ? " [no PPS]" : "");
+
+ if (ees->nsamples++ == NCODES-1) ees_process(ees);
+
+ /* Done! */
+}
+
+
+static void set_x(fp_offset)
+l_fp *fp_offset;
+{
+ step_systime_real(fp_offset);
+}
+
+
+/* offcompare - auxiliary comparison routine for offset sort */
+
+static int
+offcompare(a, b)
+l_fp *a, *b;
+{
+ return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
+}
+
+
+/* ees_process - process a pile of samples from the clock */
+static void ees_process(ees)
+ struct eesunit *ees;
+{
+ static last_samples = -1;
+ register int i, j;
+ register int noff;
+ register l_fp *coffs = ees->codeoffsets;
+ l_fp offset, tmp;
+ u_fp dispersion; /* ++++ */
+ int lostsync, isinsync;
+ int samples = ees->nsamples;
+ int samplelog;
+ int samplereduce = (samples + 1) / 2;
+
+ /* Reset things to zero so we don't have to worry later */
+ ees_reset(ees);
+
+ if (sloppyclockflag[ees->unit]) {
+ samplelog = (samples < 2) ? 0 :
+ (samples < 5) ? 1 :
+ (samples < 9) ? 2 :
+ (samples < 17) ? 3 :
+ (samples < 33) ? 4 : 5;
+ samplereduce = (1 << samplelog);
+ }
+
+ if (samples != last_samples &&
+ ((samples != (last_samples-1)) || samples < 3)) {
+ syslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
+ samples, last_samples, samplereduce);
+ last_samples = samples;
+ }
+ if (samples < 1) return;
+
+ /* If requested, dump the raw data we have in the buffer */
+ if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
+
+ /* Sort the offsets, trim off the extremes, then choose one. */
+ qsort((char *) coffs, samples, sizeof(l_fp), offcompare);
+
+ noff = samples;
+ i = 0;
+ while ((noff - i) > samplereduce) {
+ /* Trim off the sample which is further away
+ * from the median. We work this out by doubling
+ * the median, subtracting off the end samples, and
+ * looking at the sign of the answer, using the
+ * identity (c-b)-(b-a) == 2*b-a-c
+ */
+ tmp = coffs[(noff + i)/2];
+ L_ADD(&tmp, &tmp);
+ L_SUB(&tmp, &coffs[i]);
+ L_SUB(&tmp, &coffs[noff-1]);
+ if (L_ISNEG(&tmp)) noff--; else i++;
+ }
+
+ /* If requested, dump the reduce data we have in the buffer */
+ if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:");
+
+ /* What we do next depends on the setting of the sloppy clock flag.
+ * If it is on, average the remainder to derive our estimate.
+ * Otherwise, just pick a representative value from the remaining stuff
+ */
+ if (sloppyclockflag[ees->unit]) {
+ offset.l_ui = offset.l_uf = 0;
+ for (j = i; j < noff; j++)
+ L_ADD(&offset, &coffs[j]);
+ for (j = samplelog; j > 0; j--)
+ L_RSHIFTU(&offset);
+ }
+ else offset = coffs[i+BESTSAMPLE];
+
+ /* Compute the dispersion as the difference between the
+ * lowest and highest offsets that remain in the
+ * consideration list.
+ *
+ * It looks like MOST clocks have MOD (max error), so halve it !
+ */
+ tmp = coffs[noff-1];
+ L_SUB(&tmp, &coffs[i]);
+#define FRACT_SEC(n) ((1 << 30) / (n/2))
+ dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
+ if (debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) syslog(
+ (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] Offset=%06d (%d), disp=%06d%s [%d], %d %d=%d %d:%d %d=%d %d",
+ debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
+ offset.l_f / 4295, offset.l_f,
+ (dispersion * 1526) / 100,
+ (sloppyclockflag[ees->unit]) ? " by averaging" : "",
+ FRACT_SEC(10) / 4295,
+ (coffs[0].l_f) / 4295,
+ i,
+ (coffs[i].l_f) / 4295,
+ (coffs[samples/2].l_f) / 4295,
+ (coffs[i+BESTSAMPLE].l_f) / 4295,
+ noff-1,
+ (coffs[noff-1].l_f) / 4295,
+ (coffs[samples-1].l_f) / 4295);
+
+ /* Are we playing silly wotsits ?
+ * If we are using all data, see if there is a "small" delta,
+ * and if so, blurr this with 3/4 of the delta from the last value
+ */
+ if (ees->usealldata && ees->offset.l_uf) {
+ long diff = (long) (ees->offset.l_uf - offset.l_uf);
+
+ /* is the delta small enough ? */
+ if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
+ int samd = (64 * 4) / samples;
+ long new;
+ if (samd < 2) samd = 2;
+ new = offset.l_uf + ((diff * (samd -1)) / samd);
+
+ /* Sign change -> need to fix up int part */
+ if ((new & (1 << 31)) !=
+ (((long) offset.l_uf) & ( 1 << 31)))
+ { syslog(LOG_INFO, "I: %x != %x (%x %x), so add %d",
+ new & (1 << 31),
+ ((long) offset.l_uf) & ( 1 << 31),
+ new, (long) offset.l_uf,
+ (new < 0) ? -1 : 1);
+ offset.l_ui += (new < 0) ? -1 : 1;
+ }
+ dispersion /= 4;
+ if (debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) syslog(
+ (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] Smooth data: %d -> %d, dispersion now %d",
+ debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
+ ((long) offset.l_uf) / 4295, new / 4295,
+ (dispersion * 1526) / 100);
+ offset.l_uf = (unsigned long) new;
+ }
+ else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
+ (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
+ "[%x] No smooth as delta not %d < %d < %d",
+ debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
+ - FRACT_SEC(100), diff, FRACT_SEC(100));
+ }
+ else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
+ (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
+ "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
+ debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
+ ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
+ offset.l_f, ees->offset.l_f - offset.l_f);
+
+ /* Collect offset info for debugging info */
+ ees->offset = offset;
+ ees->lowoffset = coffs[i];
+ ees->highoffset = coffs[noff-1];
+
+ /* Determine synchronization status. Can be unsync'd either
+ * by a report from the clock or by a leap hold.
+ *
+ * Loss of the radio signal for a short time does not cause
+ * us to go unsynchronised, since the receiver keeps quite
+ * good time on its own. The spec says 20ms in 4 hours; the
+ * observed drift in our clock (Cambridge) is about a second
+ * a day, but even that keeps us within the inherent tolerance
+ * of the clock for about 15 minutes. Observation shows that
+ * the typical "short" outage is 3 minutes, so to allow us
+ * to ride out those, we will give it 5 minutes.
+ */
+ lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
+ isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
+
+ /* Done. Use time of last good, synchronised code as the
+ * reference time, and lastsampletime as the receive time.
+ */
+ if (ees->fix_pending) {
+ syslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
+ ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
+ ees->fix_pending = 0;
+ set_x(&offset);
+ L_CLR(&offset);
+ }
+ refclock_receive(ees->peer,
+ &offset,
+ 0, /* delay */
+ dispersion,
+ &ees->reftime,
+ &ees->lastsampletime, /* receive time */
+ (isinsync) ? 0 : LEAP_NOTINSYNC);
+ ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
+}
+
+/* msfees_poll - called by the transmit procedure */
+static void msfees_poll(unit, peer)
+ int unit;
+ char *peer;
+{
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
+ unit);
+ return;
+ }
+
+ ees_process(eesunits[unit]);
+
+ if ((current_time - eesunits[unit]->lasttime) > 150)
+ ees_event(eesunits[unit], CEVNT_FAULT);
+}
+
+/* msfees_leap - called when a leap second occurs */
+static void msfees_leap()
+{
+ register int i;
+
+ /* This routine should be entered a few seconds after
+ * midnight UTC when a leap second occurs. To ensure we
+ * don't believe foolish time from the clock(s) we set a
+ * 40 minute hold on them. It shouldn't take anywhere
+ * near this amount of time to adjust if the clock is getTING
+ * data, but doing anything else is complicated.
+ */
+ for (i = 0; i < MAXUNITS; i++) if (unitinuse[i])
+ eesunits[i]->leaphold = current_time + EESLEAPHOLD;
+}
+
+/* msfees_control - set fudge factors, return statistics */
+static void msfees_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct eesunit *ees = eesunits[unit];
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ os_delay[unit] = in->fudgetime2;
+ offset_fudge[unit] = os_delay[unit];
+ L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
+ L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ if (unitinuse[unit]) {
+ /* Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ struct peer *peer = ees->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1) {
+ memmove((char *)&peer->refid,
+ EESREFID, 4);
+ if (unit>0 && unit<10)
+ ((char *)&peer->refid)[3] =
+ '0' + unit;
+ }
+ else peer->refid = htonl(EESHSREFID);
+ }
+ }
+ if (in->haveflags & CLK_HAVEVAL2) {
+ printf("Debug: %x -> %x\n", debug, in->fudgeval2);
+ syslog(LOG_ERR, "MSF%d: debug %x -> %x",
+ unit, debug, in->fudgeval2);
+ debug = in->fudgeval2;
+ }
+ if (in->haveflags & CLK_HAVEFLAG1) {
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ }
+ if (in->haveflags & CLK_HAVEFLAG2) {
+ ees->fix_pending++;
+ /* if (in->flags & CLK_FLAG2 && unitinuse[unit])
+ ees->leaphold = 0; */
+ }
+ if (in->haveflags & CLK_HAVEFLAG3 && unitinuse[unit]) {
+ printf("dump_vals: %x -> %x\n", ees->dump_vals, in->flags & CLK_FLAG3);
+ ees->dump_vals = in->flags & CLK_FLAG3;
+ }
+ if (in->haveflags & CLK_HAVEFLAG4 && unitinuse[unit]) {
+ ees->usealldata = in->flags & CLK_FLAG4;
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_MSF_EES;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4;
+ out->clockdesc = EESDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2 = os_delay[unit];
+ out->fudgeval1 = (long)stratumtouse[unit];
+ /*out->fudgeval2= debug*/;
+ memmove((char *)&out->fudgeval2, EESREFID, 4);
+ if (unit > 0 && unit < 10)
+ ((char *)&out->fudgeval2)[3] = '0' + unit;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ out->flags |= ees->dump_vals | ees->usealldata;
+ out->lencode = ees->lencode;
+ out->lastcode = ees->lastcode;
+ out->timereset = current_time - ees->timestarted;
+ out->polls = 0; /* we don't poll */
+ out->noresponse = 0; /* ditto */
+ out->badformat = ees->badformat;
+ out->baddata = ees->baddata;
+ out->lastevent = ees->lastevent;
+ out->currentstatus = ees->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
+}
+
+
+/* msfees_buginfo - return clock dependent debugging info */
+static void msfees_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct eesunit *ees;
+
+ bug->nvalues = bug->ntimes = 0;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ ees = eesunits[unit];
+
+ bug->nvalues = 16;
+ bug->svalues = 0x0800;
+ bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
+ bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
+ bug->values[2] = (u_long)ees->status;
+ bug->values[3] = (u_long)ees->lastevent;
+ bug->values[4] = (u_long)ees->reason;
+ bug->values[5] = (u_long)ees->nsamples;
+ bug->values[6] = (u_long)ees->codestate;
+ bug->values[7] = (u_long)ees->day;
+ bug->values[8] = (u_long)ees->hour;
+ bug->values[9] = (u_long)ees->minute;
+ bug->values[10] = (u_long)ees->second;
+ bug->values[11] = (u_long)ees->tz;
+ bug->values[12] = ees->yearstart;
+ bug->values[13] = (ees->leaphold > current_time) ?
+ ees->leaphold - current_time : 0;
+ bug->values[14] = inherent_delay[unit].l_uf;
+ bug->values[15] = offset_fudge[unit].l_uf;
+
+ bug->ntimes = 11;
+ bug->stimes = 0x3f8;
+ bug->times[0] = ees->reftime;
+ bug->times[1] = ees->arrvtime;
+ bug->times[2] = ees->lastsampletime;
+ bug->times[3] = ees->offset;
+ bug->times[4] = ees->lowoffset;
+ bug->times[5] = ees->highoffset;
+ bug->times[6] = inherent_delay[unit];
+ bug->times[8] = os_delay[unit];
+ bug->times[7] = fudgefactor[unit];
+ bug->times[9] = offset_fudge[unit];
+ bug->times[10].l_ui = ees->yearstart;
+ bug->times[10].l_uf = 0;
+}
+
+struct refclock refclock_msfees = {
+ msfees_start, msfees_shutdown, msfees_poll,
+ msfees_control, msfees_init, msfees_buginfo, NOFLAGS
+};
+#endif /* defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) */
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_mx4200.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_mx4200.c
new file mode 100644
index 000000000000..7cfa3cf0326b
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_mx4200.c
@@ -0,0 +1,1342 @@
+/*
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66.
+ *
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ * 4. The name of the University may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(REFCLOCK) && (defined(MX4200) || defined(MX4200CLK) || defined(MX4200PPS))
+
+#if !defined(lint) && !defined(__GNUC__)
+static char rcsid[] =
+ "@(#) /src/master/xntp-930612/xntpd/refclock_mx4200.c,v 1.5 1993/06/18 21:19:54 jbj Exp (LBL) ";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_calendar.h"
+#include "ntp_unixtime.h"
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(MX4200CLK)
+#include <sys/clkdefs.h>
+#endif /* MX4200CLK */
+#endif /* STREAM */
+
+#include <sys/ppsclock.h>
+
+#include "mx4200.h"
+#include "ntp_stdlib.h"
+
+/*
+ * This driver supports the Magnavox Model MX4200 GPS Receiver.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 2 /* max number of mx4200 units */
+#define MX4200232 "/dev/gps%d"
+#define SPEED232 B4800 /* baud */
+
+/*
+ * The number of raw samples which we acquire to derive a single estimate.
+ */
+#define NSTAMPS 64
+
+/*
+ * Radio interface parameters
+ */
+#define MX4200PRECISION (-18) /* precision assumed (about 4 us) */
+#define MX4200REFID "GPS" /* reference id */
+#define MX4200DESCRIPTION "Magnavox MX4200 GPS Receiver" /* who we are */
+#define DEFFUDGETIME 0 /* default fudge time (ms) */
+
+/* Leap stuff */
+extern U_LONG leap_hoursfromleap;
+extern U_LONG leap_happened;
+static int leap_debug;
+
+/*
+ * mx4200_reset - reset the count back to zero
+ */
+#define mx4200_reset(mx4200) \
+ do { \
+ (mx4200)->nsamples = 0; \
+ } while (0)
+
+/*
+ * mx4200_event - record and report an event
+ */
+#define mx4200_event(mx4200, evcode) \
+ do { \
+ if ((mx4200)->status != (u_char)(evcode)) \
+ mx4200_report_event((mx4200), (evcode)); \
+ } while (0)
+
+/*
+ * Imported from the timer module
+ */
+extern U_LONG current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * MX4200 unit control structure.
+ */
+struct mx4200unit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ U_LONG gpssamples[NSTAMPS]; /* the GPS time samples */
+ l_fp unixsamples[NSTAMPS]; /* the UNIX time samples */
+
+
+ l_fp lastsampletime; /* time of last estimate */
+ u_int lastserial; /* last pps serial number */
+#ifdef notdef
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+#endif
+ char lastcode[RX_BUFF_SIZE]; /* last timecode received */
+ U_LONG lasttime; /* last time clock heard from */
+ u_char nsamples; /* number of samples we've collected */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char lencode; /* length of last timecode */
+ u_char year; /* year of eternity */
+ u_short monthday; /* day of month */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ /*
+ * Status tallies
+ */
+#ifdef notdef
+ U_LONG polls; /* polls sent */
+ U_LONG noresponse; /* number of nonresponses */
+#endif
+ U_LONG badformat; /* bad format */
+ U_LONG baddata; /* bad data */
+ U_LONG timestarted; /* time we started this */
+};
+
+/*
+ * We demand that consecutive PPS samples are more than 0.995 seconds
+ * and less than 1.005 seconds apart.
+ */
+#define PPSLODIFF_UI 0 /* 0.900 as an l_fp */
+#define PPSLODIFF_UF 0xe6666610
+
+#define PPSHIDIFF_UI 1 /* 1.100 as an l_fp */
+#define PPSHIDIFF_UF 0x19999990
+
+/*
+ * reason codes
+ */
+#define PPSREASON 20
+#define CODEREASON 40
+#define PROCREASON 60
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct mx4200unit *mx4200units[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
+
+static const char pmvxg[] = "PMVXG";
+
+/*
+ * Function prototypes
+ */
+static void mx4200_init P((void));
+static int mx4200_start P((u_int, struct peer *));
+static void mx4200_shutdown P((int));
+static void mx4200_receive P((struct recvbuf *));
+static void mx4200_process P((struct mx4200unit *));
+static void mx4200_report_event P((struct mx4200unit *, int));
+static void mx4200_poll P((int, struct peer *));
+static void mx4200_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void mx4200_buginfo P((int, struct refclockbug *));
+
+static char * mx4200_parse P((char *, struct calendar *, int *, int *));
+static int mx4200_needconf P((char *));
+static void mx4200_config P((struct mx4200unit *));
+static void mx4200_send P((int, const char *, ...));
+static int mx4200_cmpl_fp P((void *, void *));
+static u_char cksum P((char *, u_int));
+
+#ifdef DEBUG
+static void opendfile P((int));
+static void checkdfile P((void));
+#endif /* DEBUG */
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_mx4200 = {
+ mx4200_start, mx4200_shutdown, mx4200_poll,
+ mx4200_control, mx4200_init, mx4200_buginfo, NOFLAGS
+};
+
+/*
+ * mx4200_init - initialize internal mx4200 driver data
+ */
+static void
+mx4200_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)mx4200units, 0, sizeof mx4200units);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = DEFFUDGETIME;
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ memcpy((char *)&refid[i], MX4200REFID, 4);
+ }
+}
+
+#ifdef DEBUG
+static char dfile[] = "/var/tmp/MX4200.debug";
+static FILE *df = NULL;
+
+static void
+opendfile(create)
+ int create;
+{
+ if (!create && access(dfile, F_OK) < 0) {
+ syslog(LOG_ERR, "mx4200: open %s: %m", dfile);
+ return;
+ }
+ df = fopen(dfile, "a");
+ if (df == NULL)
+ syslog(LOG_ERR, "mx4200: open %s: %m", dfile);
+ else if (setvbuf(df, NULL, _IOLBF, 0) < 0)
+ syslog(LOG_ERR, "mx4200: setvbuf %s: %m", dfile);
+}
+
+static void
+checkdfile()
+{
+
+ if (df == NULL)
+ return;
+
+ if (access(dfile, F_OK) < 0) {
+ fclose(df);
+ opendfile(1);
+ }
+}
+
+#endif
+
+
+/*
+ * mx4200_start - open the MX4200 devices and initialize data for processing
+ */
+static int
+mx4200_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct mx4200unit *mx4200;
+ register int i;
+ int fd232;
+ char mx4200dev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_start: unit %d invalid", unit);
+ return (0);
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "mx4200_start: unit %d in use", unit);
+ return (0);
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(mx4200dev, MX4200232, unit);
+ fd232 = open(mx4200dev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR,
+ "mx4200_start: open of %s: %m", mx4200dev);
+ return (0);
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, TCGETA): %m", mx4200dev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, TCSETA): %m", mx4200dev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The MX4200CLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The MX4200PPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: tcgetattr(%s): %m", mx4200dev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: tcsetattr(%s): %m", mx4200dev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: tcflush(%s): %m", mx4200dev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(MX4200CLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, I_PUSH, clk): %m", mx4200dev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, CLK_SETSTR): %m", mx4200dev);
+#endif /* MX4200CLK */
+#if defined(MX4200PPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, I_PUSH, ppsclock): %m", mx4200dev);
+ else
+ fdpps = fd232;
+#endif /* MX4200PPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The MX4200CLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(MX4200CLK)
+ int ldisc = CLKLDISC;
+#endif /* MX4200CLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, TIOCGETP): %m", mx4200dev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(MX4200CLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* MX4200CLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, TIOCSETP): %m", mx4200dev);
+ goto screwed;
+ }
+#if defined(MX4200CLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "mx4200_start: ioctl(%s, TIOCSETD): %m",mx4200dev);
+ goto screwed;
+ }
+#endif /* MX4200CLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (mx4200units[unit] != 0) {
+ mx4200 = mx4200units[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && mx4200units[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ mx4200 = mx4200units[i];
+ mx4200units[i] = 0;
+ } else {
+ mx4200 = (struct mx4200unit *)
+ emalloc(sizeof(struct mx4200unit));
+ }
+ }
+
+ memset((char *)mx4200, 0, sizeof(struct mx4200unit));
+ mx4200units[unit] = mx4200;
+
+ /*
+ * Set up the structures
+ */
+ mx4200->peer = peer;
+ mx4200->unit = (u_char)unit;
+ mx4200->timestarted = current_time;
+
+ mx4200->io.clock_recv = mx4200_receive;
+ mx4200->io.srcclock = (caddr_t)mx4200;
+ mx4200->io.datalen = 0;
+ mx4200->io.fd = fd232;
+ if (!io_addclock(&mx4200->io))
+ goto screwed;
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = MX4200PRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+
+ /* Insure the receiver is properly configured */
+ mx4200_config(mx4200);
+
+#ifdef DEBUG
+ opendfile(0);
+#endif
+ return (1);
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return (0);
+}
+
+/*
+ * mx4200_shutdown - shut down a MX4200 clock
+ */
+static void
+mx4200_shutdown(unit)
+ int unit;
+{
+ register struct mx4200unit *mx4200;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "mx4200_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ mx4200 = mx4200units[unit];
+ io_closeclock(&mx4200->io);
+ unitinuse[unit] = 0;
+}
+
+static void
+mx4200_config(mx4200)
+ register struct mx4200unit *mx4200;
+{
+ register int fd = mx4200->io.fd;
+
+syslog(LOG_DEBUG, "mx4200_config");
+
+ /* Zero the output list (do it twice to flush possible junk) */
+ mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1);
+ mx4200_send(fd, "%s,%03d,,%d,,,,,,", pmvxg, PMVXG_S_PORTCONF, 1);
+
+ /* Switch to 2d mode */
+ mx4200_send(fd, "%s,%03d,%d,,%.1f,%.1f,,%d,%d,%c,%d",
+ pmvxg, PMVXG_S_INITMODEB,
+ 2, /* 2d mode */
+ 0.1, /* hor accel fact as per Steve */
+ 0.1, /* ver accel fact as per Steve */
+ 10, /* hdop limit as per Steve */
+ 5, /* elevation limit as per Steve */
+ 'U', /* time output mode */
+ 0); /* local time offset from gmt */
+
+ /* Configure time recovery */
+ mx4200_send(fd, "%s,%03d,%c,%c,%c,%d,%d,%d,",
+ pmvxg, PMVXG_S_TRECOVCONF,
+#ifdef notdef
+ 'K', /* known position */
+ 'D', /* dynamic position */
+#else
+ 'S', /* static position */
+#endif
+ 'U', /* steer clock to gps time */
+ 'A', /* always output time pulse */
+ 500, /* max time error in ns */
+ 0, /* user bias in ns */
+ 1); /* output to control port */
+}
+
+/*
+ * mx4200_report_event - note the occurrence of an event
+ */
+static void
+mx4200_report_event(mx4200, code)
+ struct mx4200unit *mx4200;
+ int code;
+{
+ struct peer *peer;
+
+ peer = mx4200->peer;
+ if (mx4200->status != (u_char)code) {
+ mx4200->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ mx4200->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "mx4200 clock %s event %x", ntoa(&peer->srcadr), code);
+ }
+}
+
+/*
+ * mx4200_poll - mx4200 watchdog routine
+ */
+static void
+mx4200_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct mx4200unit *mx4200;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "mx4200_poll: unit %d not used", unit);
+ return;
+ }
+
+ mx4200 = mx4200units[unit];
+ if ((current_time - mx4200->lasttime) > 150) {
+ mx4200_event(mx4200, CEVNT_FAULT);
+
+ /* Request a status message which should trigger a reconfig */
+ mx4200_send(mx4200->io.fd, "%s,%03d", "CDGPQ", PMVXG_D_STATUS);
+ syslog(LOG_DEBUG, "mx4200_poll: request status");
+ }
+}
+
+static const char char2hex[] = "0123456789ABCDEF";
+
+/*
+ * mx4200_receive - receive gps data
+ */
+static void
+mx4200_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register struct mx4200unit *mx4200;
+ register char *dpt, *cp;
+ register U_LONG tmp_ui;
+ register U_LONG tmp_uf;
+ register U_LONG gpstime;
+ struct ppsclockev ev;
+ register struct calendar *jt;
+ struct calendar sjt;
+ register int n;
+ int valid, leapsec;
+ register u_char ck;
+
+ mx4200 = (struct mx4200unit *)rbufp->recv_srcclock;
+
+#ifdef DEBUG
+ if (debug > 3)
+ printf("mx4200_receive: nsamples = %d\n", mx4200->nsamples);
+#endif
+
+ /* Record the time of this event */
+ mx4200->lasttime = current_time;
+
+ /* Get the pps value */
+ if (ioctl(mx4200->io.fd, CIOGETEV, (char *)&ev) < 0) {
+ /* XXX Actually, if this fails, we're pretty much screwed */
+#ifdef DEBUG
+ if (debug) {
+ fprintf(stderr, "mx4200_receive: ");
+ perror("CIOGETEV");
+ }
+#endif
+ mx4200->reason = PPSREASON + 1;
+ mx4200_event(mx4200, CEVNT_FAULT);
+ mx4200_reset(mx4200);
+ return;
+ }
+ tmp_ui = ev.tv.tv_sec + (U_LONG)JAN_1970;
+ TVUTOTSF(ev.tv.tv_usec, tmp_uf);
+
+ /* Get buffer and length; sock away last timecode */
+ n = rbufp->recv_length;
+ dpt = rbufp->recv_buffer;
+ if (n <= 1)
+ return;
+ mx4200->lencode = n;
+ memmove(mx4200->lastcode, dpt, n);
+
+ /*
+ * We expect to see something like:
+ *
+ * $PMVXG,830,T,1992,07,09,04:18:34,U,S,-02154,00019,000000,00*1D\n
+ *
+ * Reject if any important landmarks are missing.
+ */
+ cp = dpt + n - 4;
+ if (cp < dpt || *dpt != '$' || cp[0] != '*' || cp[3] != '\n') {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad format\n");
+#endif
+ mx4200->badformat++;
+ mx4200->reason = PPSREASON + 2;
+ mx4200_event(mx4200, CEVNT_BADREPLY);
+ mx4200_reset(mx4200);
+ return;
+ }
+
+ /* Check checksum */
+ ck = cksum(&dpt[1], n - 5);
+ if (char2hex[ck >> 4] != cp[1] || char2hex[ck & 0xf] != cp[2]) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad checksum\n");
+#endif
+ mx4200->badformat++;
+ mx4200->reason = PPSREASON + 3;
+ mx4200_event(mx4200, CEVNT_BADREPLY);
+ mx4200_reset(mx4200);
+ return;
+ }
+
+ /* Truncate checksum (and the buffer for that matter) */
+ *cp = '\0';
+
+ /* Leap second debugging stuff */
+ if ((leap_hoursfromleap && !leap_happened) || leap_debug > 0) {
+ /* generate reports for awhile after leap */
+ if (leap_hoursfromleap && !leap_happened)
+ leap_debug = 3600;
+ else
+ --leap_debug;
+ syslog(LOG_INFO, "mx4200 leap: %s \"%s\"",
+ umfptoa(tmp_ui, tmp_uf, 6), dpt);
+ }
+
+ /* Parse time recovery message */
+ jt = &sjt;
+ if ((cp = mx4200_parse(dpt, jt, &valid, &leapsec)) != NULL) {
+ /* Configure the receiver if necessary */
+ if (mx4200_needconf(dpt))
+ mx4200_config(mx4200);
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: mx4200_parse: %s\n", cp);
+#endif
+ mx4200->badformat++;
+ mx4200->reason = PPSREASON + 5;
+ mx4200_event(mx4200, CEVNT_BADREPLY);
+ mx4200_reset(mx4200);
+ return;
+ }
+
+ /* Setup leap second indicator */
+ if (leapsec == 0)
+ mx4200->leap = LEAP_NOWARNING;
+ else if (leapsec == 1)
+ mx4200->leap = LEAP_ADDSECOND;
+ else if (leapsec == -1)
+ mx4200->leap = LEAP_DELSECOND;
+ else
+ mx4200->leap = LEAP_NOTINSYNC; /* shouldn't happen */
+
+ /* Check parsed time (allow for possible leap seconds) */
+ if (jt->second >= 61 || jt->minute >= 60 || jt->hour >= 24) {
+#ifdef DEBUG
+ if (debug) {
+ printf("mx4200_receive: bad time %d:%02d:%02d",
+ jt->hour, jt->minute, jt->second);
+ if (leapsec != 0)
+ printf(" (leap %+d)", leapsec);
+ putchar('\n');
+ }
+#endif
+ mx4200->baddata++;
+ mx4200->reason = PPSREASON + 6;
+ mx4200_event(mx4200, CEVNT_BADTIME);
+ mx4200_reset(mx4200);
+ /* Eat the next pulse which the clock claims will be bad */
+ mx4200->nsamples = -1;
+ return;
+ }
+
+ /* Check parsed date */
+ if (jt->monthday > 31 || jt->month > 12 || jt->year < 1900) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: bad date (%d/%d/%d)\n",
+ jt->monthday, jt->month, jt->year);
+#endif
+ mx4200->baddata++;
+ mx4200->reason = PPSREASON + 7;
+ mx4200_event(mx4200, CEVNT_BADDATE);
+ mx4200_reset(mx4200);
+ return;
+ }
+
+ /* Convert to ntp time */
+ gpstime = caltontp(jt);
+
+ /* The gps message describes the *next* pulse; pretend it's this one */
+ --gpstime;
+
+ /* Debugging */
+#ifdef DEBUG
+ checkdfile();
+ if (df != NULL) {
+ l_fp t;
+
+ t.l_ui = gpstime;
+ t.l_uf = 0;
+ M_SUB(t.l_ui, t.l_uf, tmp_ui, tmp_uf);
+ fprintf(df, "%s\t%s",
+ umfptoa(tmp_ui, tmp_uf, 6), mfptoa(t.l_ui, t.l_uf, 6));
+ if (debug > 3)
+ fprintf(df, "\t(gps: %lu)", gpstime);
+ if (leapsec != 0)
+ fprintf(df, "\t(leap sec %+d)", leapsec);
+ if (!valid)
+ fprintf(df, "\t(pulse not valid)");
+ fputc('\n', df);
+ }
+#endif
+
+ /* Check pps serial number against last one */
+ if (mx4200->lastserial + 1 != ev.serial && mx4200->lastserial != 0) {
+#ifdef DEBUG
+ if (debug) {
+ if (ev.serial == mx4200->lastserial)
+ printf("mx4200_receive: no new pps event\n");
+ else
+ printf("mx4200_receive: missed %d pps events\n",
+ ev.serial - mx4200->lastserial - 1);
+ }
+#endif
+ mx4200->reason = PPSREASON + 8;
+ mx4200_event(mx4200, CEVNT_FAULT);
+ mx4200_reset(mx4200);
+ /* fall through and this one collect as first sample */
+ }
+ mx4200->lastserial = ev.serial;
+
+/*
+ * XXX
+ * Since this message is for the next pulse, it's really the next pulse
+ * that the clock might be telling us will be invalid.
+ */
+ /* Toss if not designated "valid" by the gps */
+ if (!valid) {
+#ifdef DEBUG
+ if (debug)
+ printf("mx4200_receive: pps not valid\n");
+#endif
+ mx4200->reason = PPSREASON + 9;
+ mx4200_event(mx4200, CEVNT_BADTIME);
+ mx4200_reset(mx4200);
+ return;
+ }
+
+ /* Copy time into mx4200unit struct */
+ /* XXX (why?) */
+ mx4200->year = jt->year;
+ mx4200->monthday = jt->monthday;
+ mx4200->hour = jt->hour;
+ mx4200->minute = jt->minute;
+ mx4200->second = jt->second;
+
+ /* Sock away the GPS and UNIX timesamples */
+ n = mx4200->nsamples++;
+ if (n < 0)
+ return; /* oops, this pulse is bad */
+ mx4200->gpssamples[n] = gpstime;
+ mx4200->unixsamples[n].l_ui = mx4200->lastsampletime.l_ui = tmp_ui;
+ mx4200->unixsamples[n].l_uf = mx4200->lastsampletime.l_uf = tmp_uf;
+ if (mx4200->nsamples >= NSTAMPS) {
+ /*
+ * Here we've managed to complete an entire NSTAMPS
+ * second cycle without major mishap. Process what has
+ * been received.
+ */
+ mx4200_process(mx4200);
+ mx4200_reset(mx4200);
+ }
+}
+
+/* Compare two l_fp's, used with qsort() */
+static int
+mx4200_cmpl_fp(p1, p2)
+ register void *p1, *p2;
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+/*
+ * mx4200_process - process a pile of samples from the clock
+ */
+static void
+mx4200_process(mx4200)
+ struct mx4200unit *mx4200;
+{
+ register int i, n;
+ register l_fp *fp, *op;
+ register U_LONG *lp;
+ l_fp off[NSTAMPS];
+ register U_LONG tmp_ui, tmp_uf;
+ register U_LONG date_ui, date_uf;
+ u_fp dispersion;
+
+ /* Compute offsets from the raw data. */
+ fp = mx4200->unixsamples;
+ op = off;
+ lp = mx4200->gpssamples;
+ for (i = 0; i < NSTAMPS; ++i, ++lp, ++op, ++fp) {
+ op->l_ui = *lp;
+ op->l_uf = 0;
+ L_SUB(op, fp);
+ }
+
+ /* Sort offsets into ascending order. */
+ qsort((char *)off, NSTAMPS, sizeof(l_fp), mx4200_cmpl_fp);
+
+ /*
+ * Reject the furthest from the median until 8 samples left
+ */
+ i = 0;
+ n = NSTAMPS;
+ while ((n - i) > 8) {
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ date_ui = off[(n+i)/2].l_ui;
+ date_uf = off[(n+i)/2].l_uf;
+ M_SUB(tmp_ui, tmp_uf, date_ui, date_uf);
+ M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf);
+ if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) {
+ /*
+ * reject low end
+ */
+ i++;
+ } else {
+ /*
+ * reject high end
+ */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets.
+ */
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ dispersion = MFPTOFP(tmp_ui, tmp_uf);
+
+ /*
+ * Now compute the offset estimate. If the sloppy clock
+ * flag is set, average the remainder, otherwise pick the
+ * median.
+ */
+ if (sloppyclockflag[mx4200->unit]) {
+ tmp_ui = tmp_uf = 0;
+ while (i < n) {
+ M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ i++;
+ }
+ M_RSHIFT(tmp_ui, tmp_uf);
+ M_RSHIFT(tmp_ui, tmp_uf);
+ M_RSHIFT(tmp_ui, tmp_uf);
+ i = 0;
+ off[0].l_ui = tmp_ui;
+ off[0].l_uf = tmp_uf;
+ } else {
+ i = (n + i) / 2;
+ }
+
+ /*
+ * Add the default MX4200 QT delay into this.
+ */
+#ifdef notdef
+ L_ADDUF(&off[i], MX4200QTFUDGE);
+#endif
+
+ /*
+ * Done. Use lastref as the reference time and lastrec
+ * as the receive time. ** note this can result in tossing
+ * out the peer in the protocol module if lastref > lastrec,
+ * so last rec is used for both values - dlm ***
+ */
+ refclock_receive(mx4200->peer, &off[i],
+ (s_fp)0, /* delay */
+ dispersion,
+ &mx4200->unixsamples[NSTAMPS-1], /* reftime */
+ &mx4200->unixsamples[NSTAMPS-1], /* rectime */
+ mx4200->leap);
+
+ mx4200_event(mx4200, CEVNT_NOMINAL);
+}
+
+/*
+ * mx4200_control - set fudge factors, return statistics
+ */
+static void
+mx4200_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct mx4200unit *mx4200;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
+ sloppyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = mx4200units[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out != 0) {
+ memset((char *)out, 0, sizeof (struct refclockstat));
+ out->type = REFCLK_GPS_MX4200;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 | CLK_HAVEVAL2 |
+ CLK_HAVEFLAG1;
+ out->clockdesc = MX4200DESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = refid[unit];;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ mx4200 = mx4200units[unit];
+ out->lencode = mx4200->lencode;
+ out->lastcode = mx4200->lastcode;
+ out->lastevent = mx4200->lastevent;
+ out->currentstatus = mx4200->status;
+
+ out->polls = 0; /* mx4200->polls; */
+ out->noresponse = 0; /* mx4200->noresponse; */
+ out->badformat = mx4200->badformat;
+ out->baddata = mx4200->baddata;
+ out->timereset = current_time - mx4200->timestarted;
+ }
+ }
+}
+
+/*
+ * mx4200_buginfo - return clock dependent debugging info
+ */
+static void
+mx4200_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct mx4200unit *mx4200;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "mx4200_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ mx4200 = mx4200units[unit];
+
+ memset((char *)bug, 0, sizeof(*bug));
+ bug->nvalues = 10;
+ bug->ntimes = 2;
+ if (mx4200->lasttime != 0)
+ bug->values[0] = current_time - mx4200->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)mx4200->reason;
+ bug->values[2] = (U_LONG)mx4200->year;
+ bug->values[3] = (U_LONG)mx4200->monthday;
+ bug->values[4] = (U_LONG)mx4200->hour;
+ bug->values[5] = (U_LONG)mx4200->minute;
+ bug->values[6] = (U_LONG)mx4200->second;
+#ifdef notdef
+ bug->values[7] = mx4200->msec;
+ bug->values[8] = mx4200->noreply;
+ bug->values[9] = mx4200->yearstart;
+#endif
+ bug->stimes = 0x1c;
+#ifdef notdef
+ bug->times[0] = mx4200->lastref;
+ bug->times[1] = mx4200->lastrec;
+#endif
+}
+
+/*
+ * Returns true if the this is a status message. We use this as
+ * an indication that the receiver needs to be initialized.
+ */
+static int
+mx4200_needconf(buf)
+ char *buf;
+{
+ register LONG v;
+ char *cp;
+
+ cp = buf;
+
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Record type */
+ v = strtol(cp, &cp, 10);
+ if (v != PMVXG_D_STATUS)
+ return (0);
+ /*
+ * XXX
+ * Since we configure the receiver to not give us status
+ * messages and since the receiver outputs status messages by
+ * default after being reset to factory defaults when sent the
+ * "$PMVXG,018,C\r\n" message, any status message we get
+ * indicates the reciever needs to be initialized; thus, it is
+ * not necessary to decode the status message.
+ */
+#ifdef notdef
+ ++cp;
+
+ /* Receiver status */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Number of satellites which should be visible */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Number of satellites being tracked */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Time since last NAV */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return (0);
+ ++cp;
+
+ /* Initialization status */
+ v = strtol(cp, &cp, 10);
+ if (v == 0)
+#endif
+ return (1);
+}
+
+/* Parse a mx4200 time recovery message. Returns a string if error */
+static char *
+mx4200_parse(buf, jt, validp, leapsecp)
+ register char *buf;
+ register struct calendar *jt;
+ register int *validp, *leapsecp;
+{
+ register LONG v;
+ char *cp;
+
+ cp = buf;
+ memset((char *)jt, 0, sizeof(*jt));
+
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no rec-type");
+ ++cp;
+
+ /* Record type */
+ v = strtol(cp, &cp, 10);
+ if (v != PMVXG_D_TRECOVOUT)
+ return ("wrong rec-type");
+
+ /* Pulse valid indicator */
+ if (*cp++ != ',')
+ return ("no pulse-valid");
+ if (*cp == 'T')
+ *validp = 1;
+ else if (*cp == 'F')
+ *validp = 0;
+ else
+ return ("bad pulse-valid");
+ ++cp;
+
+ /* Year */
+ if (*cp++ != ',')
+ return ("no year");
+ jt->year = strtol(cp, &cp, 10);
+
+ /* Month of year */
+ if (*cp++ != ',')
+ return ("no month");
+ jt->month = strtol(cp, &cp, 10);
+
+ /* Day of month */
+ if (*cp++ != ',')
+ return ("no month day");
+ jt->monthday = strtol(cp, &cp, 10);
+
+ /* Hour */
+ if (*cp++ != ',')
+ return ("no hour");
+ jt->hour = strtol(cp, &cp, 10);
+
+ /* Minute */
+ if (*cp++ != ':')
+ return ("no minute");
+ jt->minute = strtol(cp, &cp, 10);
+
+ /* Second */
+ if (*cp++ != ':')
+ return ("no second");
+ jt->second = strtol(cp, &cp, 10);
+
+ /* Time indicator */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time indicator");
+
+ /* Time recovery mode */
+ if (*cp++ != ',' || *cp++ == '\0')
+ return ("no time mode");
+
+ /* Oscillator offset */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no osc off");
+ ++cp;
+
+ /* Time mark error */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no time mark err");
+ ++cp;
+
+ /* User time bias */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no user bias");
+ ++cp;
+
+ /* Leap second flag */
+ if ((cp = strchr(cp, ',')) == NULL)
+ return ("no leap");
+ ++cp;
+ *leapsecp = strtol(cp, &cp, 10);
+
+ return (NULL);
+}
+
+/* Calculate the checksum */
+static u_char
+cksum(cp, n)
+ register char *cp;
+ register u_int n;
+{
+ register u_char ck;
+
+ for (ck = 0; n-- > 0; ++cp)
+ ck ^= *cp;
+ return (ck);
+}
+
+static void
+#if __STDC__
+mx4200_send(register int fd, const char *fmt, ...)
+#else
+mx4200_send(fd, fmt, va_alist)
+ register int fd;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ register char *cp;
+ register int n, m;
+ va_list ap;
+ char buf[1024];
+ u_char ck;
+
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ cp = buf;
+ *cp++ = '$';
+#ifdef notdef
+ /* BSD is rational */
+ n = vsnprintf(cp, sizeof(buf) - 1, fmt, ap);
+#else
+ /* SunOS sucks */
+ (void)vsprintf(cp, fmt, ap);
+ n = strlen(cp);
+#endif
+ ck = cksum(cp, n);
+ cp += n;
+ ++n;
+#ifdef notdef
+ /* BSD is rational */
+ n += snprintf(cp, sizeof(buf) - n - 5, "*%02X\r\n", ck);
+#else
+ /* SunOS sucks */
+ sprintf(cp, "*%02X\r\n", ck);
+ n += strlen(cp);
+#endif
+
+ m = write(fd, buf, n);
+ if (m < 0)
+ syslog(LOG_ERR, "mx4200_send: write: %m (%s)", buf);
+ else if (m != n)
+ syslog(LOG_ERR, "mx4200_send: write: %d != %d (%s)", m, n, buf);
+ va_end(ap);
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_omega.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_omega.c
new file mode 100644
index 000000000000..95a20a0d2c44
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_omega.c
@@ -0,0 +1,999 @@
+/*
+ * refclock_omega - clock driver for the Kinemetrics Truetime OM-DC OMEGA
+ * receiver.
+ *
+ * Version 1.0 11-Dec-92 Steve Clift (clift@ml.csiro.au)
+ * Initial version, mostly lifted from refclock_goes.c.
+ *
+ * 1.1 03-May-93 Steve Clift
+ * Tarted up the sample filtering mechanism to give improved
+ * one-off measurements. Improved measurement dispersion code
+ * to account for accumulated drift when the clock loses lock.
+ *
+ */
+
+#if defined(REFCLOCK) && (defined(OMEGA) || defined(OMEGACLK) || defined(OMEGAPPS))
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(HAVE_TERMIOS)
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(OMEGACLK)
+#include <sys/clkdefs.h>
+#endif /* OMEGACLK */
+#endif /* STREAM */
+
+#if defined (OMEGAPPS)
+#include <sys/ppsclock.h>
+#endif /* OMEGAPPS */
+
+#include "ntp_stdlib.h"
+
+/*
+ * Support for Kinemetrics Truetime OM-DC OMEGA Receiver
+ *
+ * Most of this code is copied from refclock_goes.c with thanks.
+ *
+ * the time code looks like follows; Send the clock a R or C and once per
+ * second a timestamp will appear that looks like this:
+ * ADDD:HH:MM:SSQCL
+ * A - control A
+ * Q Quality indication: indicates possible error of
+ * > >+- 5 seconds
+ * ? >+/- 500 milliseconds # >+/- 50 milliseconds
+ * * >+/- 5 milliseconds . >+/- 1 millisecond
+ * A-H less than 1 millisecond. Character indicates which station
+ * is being received as follows:
+ * A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
+ * E = La Reunion, F = Argentina, G = Australia, H = Japan.
+ * C - Carriage return
+ * L - Line feed
+ * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* max number of OMEGA units */
+#define OMEGA232 "/dev/omega%d"
+#define SPEED232 B9600 /* 9600 baud */
+
+/*
+ * Radio interface parameters
+ */
+#define OMEGADESCRIPTION "Kinemetrics OM-DC OMEGA Receiver" /* who we are */
+#define OMEGAMAXDISPERSE (FP_SECOND/32) /* max allowed sample dispersion */
+#define OMEGAPRECISION (-10) /* precision assumed (about 1 ms) */
+#define OMEGAREFID "VLF\0" /* reference id */
+#define LENOMEGA 13 /* length of standard response */
+#define GMT 0 /* hour offset from Greenwich */
+#define NSTAMPS 9 /* samples collected when polled */
+#define NSKEEP 5 /* samples to keep after discards */
+#define BMAX 50 /* timecode buffer length */
+
+/*
+ * The OM-DC puts out the start bit of the <CR> on the second, but
+ * we see the result after the <LF> is received, about 2ms later at
+ * 9600 baud. Use this as the default fudge time, and let the user
+ * fiddle it to account for driver latency etc.
+ */
+#define DEFFUDGETIME 0x00830000 /* default fudge time (~2ms) */
+
+/*
+ * Clock drift errors as u_fp values.
+ */
+#define U_FP5000MS (5*FP_SECOND) /* 5 seconds */
+#define U_FP500MS (FP_SECOND/2) /* 500 msec */
+#define U_FP50MS (FP_SECOND/20) /* 50 msec */
+#define U_FP5MS (FP_SECOND/200) /* 5 msec */
+
+/*
+ * Station codes
+ */
+#define STATION_NONE 0
+#define STATION_NORWAY 1
+#define STATION_LIBERIA 2
+#define STATION_HAWAII 3
+#define STATION_N_DAKOTA 4
+#define STATION_LA_REUNION 5
+#define STATION_ARGENTINA 6
+#define STATION_AUSTRALIA 7
+#define STATION_JAPAN 8
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
+
+/*
+ * Imported from the timer module
+ */
+extern U_LONG current_time;
+extern struct event timerqueue[];
+
+/*
+ * Imported from ntp_loopfilter module
+ */
+extern int fdpps; /* pps file descriptor */
+
+/*
+ * Imported from ntpd module
+ */
+extern int debug; /* global debug flag */
+
+/*
+ * OMEGA unit control structure
+ */
+struct omegaunit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NSTAMPS]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short station; /* which station we're locked to */
+ u_short polled; /* Hand in a time sample? */
+ U_LONG coderecv; /* timecodes received */
+ u_char lencode; /* length of last timecode */
+ U_LONG lasttime; /* last time clock heard from */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last failure */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_char leap; /* leap indicators */
+ u_short msec; /* millisecond of second */
+ u_char quality; /* quality char from last timecode */
+ U_LONG yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ U_LONG polls; /* polls sent */
+ U_LONG noreply; /* no replies to polls */
+ U_LONG badformat; /* bad format */
+ U_LONG baddata; /* bad data */
+ U_LONG timestarted; /* time we started this */
+};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct omegaunit *omegaunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor1[MAXUNITS];
+static l_fp fudgefactor2[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char readonlyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
+
+/*
+ * Function prototypes
+ */
+static void omega_init P((void));
+static int omega_start P((u_int, struct peer *));
+static void omega_shutdown P((int));
+static void omega_report_event P((struct omegaunit *, int));
+static void omega_receive P((struct recvbuf *));
+static char omega_process P((struct omegaunit *, l_fp *, u_fp *));
+static void omega_poll P((int, struct peer *));
+static void omega_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void omega_buginfo P((int, struct refclockbug *));
+static void omega_send P((struct omegaunit *, char *));
+
+/*
+ * Transfer vector
+ */
+struct refclock refclock_omega = {
+ omega_start, omega_shutdown, omega_poll,
+ omega_control, omega_init, omega_buginfo, NOFLAGS
+};
+
+/*
+ * omega_init - initialize internal omega driver data
+ */
+static void
+omega_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)omegaunits, 0, sizeof omegaunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor1[i].l_ui = 0;
+ fudgefactor1[i].l_uf = DEFFUDGETIME;
+ fudgefactor2[i].l_ui = 0;
+ fudgefactor2[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], OMEGAREFID, 4);
+ }
+}
+
+
+/*
+ * omega_start - open the OMEGA devices and initialize data for processing
+ */
+static int
+omega_start(unit, peer)
+ u_int unit;
+ struct peer *peer;
+{
+ register struct omegaunit *omega;
+ register int i;
+ int fd232;
+ char omegadev[20];
+
+ /*
+ * Check configuration info
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,"omega_start: unit %d invalid", unit);
+ return 0;
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_start: unit %d in use", unit);
+ return 0;
+ }
+
+ /*
+ * Open serial port
+ */
+ (void) sprintf(omegadev, OMEGA232, unit);
+ fd232 = open(omegadev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "omega_start: open of %s: %m", omegadev);
+ return 0;
+ }
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TCGETA): %m", omegadev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TCSETA): %m", omegadev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The OMEGACLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The OMEGAPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcgetattr(%s): %m", omegadev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcsetattr(%s): %m", omegadev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: tcflush(%s): %m", omegadev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#ifdef STREAM
+#if defined(OMEGACLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, I_PUSH, clk): %m", omegadev);
+ if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, CLK_SETSTR): %m", omegadev);
+#endif /* OMEGACLK */
+#if defined(OMEGAPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, I_PUSH, ppsclock): %m", omegadev);
+ else
+ fdpps = fd232;
+#endif /* OMEGAPPS */
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The OMEGACLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(OMEGACLK)
+ int ldisc = CLKLDISC;
+#endif /* OMEGACLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCGETP): %m", omegadev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(OMEGACLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* OMEGACLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCSETP): %m", omegadev);
+ goto screwed;
+ }
+#if defined(OMEGACLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "omega_start: ioctl(%s, TIOCSETD): %m",omegadev);
+ goto screwed;
+ }
+#endif /* OMEGACLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (omegaunits[unit] != 0) {
+ omega = omegaunits[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && omegaunits[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ omega = omegaunits[i];
+ omegaunits[i] = 0;
+ } else {
+ omega = (struct omegaunit *)
+ emalloc(sizeof(struct omegaunit));
+ }
+ }
+ memset((char *)omega, 0, sizeof(struct omegaunit));
+ omegaunits[unit] = omega;
+
+ /*
+ * Set up the structures
+ */
+ omega->peer = peer;
+ omega->unit = (u_char)unit;
+ omega->timestarted = current_time;
+ omega->station = STATION_NONE;
+
+ omega->io.clock_recv = omega_receive;
+ omega->io.srcclock = (caddr_t)omega;
+ omega->io.datalen = 0;
+ omega->io.fd = fd232;
+ if (!io_addclock(&omega->io)) {
+ goto screwed;
+ }
+
+ /*
+ * All done. Initialize a few random peer variables, then
+ * return success.
+ */
+ peer->precision = OMEGAPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ unitinuse[unit] = 1;
+ return 1;
+
+ /*
+ * Something broke; abandon ship
+ */
+screwed:
+ (void) close(fd232);
+ return 0;
+}
+
+
+/*
+ * omega_shutdown - shut down a OMEGA clock
+ */
+static void
+omega_shutdown(unit)
+ int unit;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_shutdown: unit %d invalid",
+ unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_shutdown: unit %d not in use", unit);
+ return;
+ }
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ omega = omegaunits[unit];
+ io_closeclock(&omega->io);
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * omega_report_event - note the occurance of an event
+ */
+static void
+omega_report_event(omega, code)
+ struct omegaunit *omega;
+ int code;
+{
+ struct peer *peer;
+
+ peer = omega->peer;
+ if (omega->status != (u_char)code) {
+ omega->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ omega->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "omega clock %s event %x\n", ntoa(&peer->srcadr), code);
+ }
+}
+
+
+/*
+ * omega_receive - receive data from the serial interface on a
+ * Kinemetrics OM-DC OMEGA clock.
+ */
+static void
+omega_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ register int i;
+ register struct omegaunit *omega;
+ register u_char *dpt;
+ register char *cp, *cpend;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion, drift;
+
+ /*
+ * Get the clock this applies to and a pointers to the data
+ */
+ omega = (struct omegaunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+
+#ifndef PEDANTIC
+ /*
+ * The OM-DC outputs a timecode every second, but we only want
+ * a set of NSTAMPS timecodes when polled (every 64 seconds).
+ * Setting PEDANTIC causes a sanity check on every timecode.
+ */
+ if (!omega->polled)
+ return;
+#endif
+
+ /*
+ * Edit timecode to remove control chars
+ */
+ dpend = dpt + rbufp->recv_length;
+ cp = omega->lastcode;
+ cpend = omega->lastcode + BMAX - 1;
+ while (dpt < dpend && cp < cpend) {
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#ifdef OMEGACLK
+ else if (*cp == '\r') {
+ if (dpend - dpt < 8) {
+ /* short timestamp */
+ return;
+ }
+ if (!buftvtots(dpt,&omega->lastrec)) {
+ /* screwy timestamp */
+ return;
+ }
+ dpt += 8;
+ }
+#endif
+ }
+ *cp = '\0';
+ omega->lencode = cp - omega->lastcode;
+
+ if (omega->lencode == 0)
+ return;
+ else if (omega->lencode != LENOMEGA) {
+ omega->badformat++;
+ /* Sometimes get a lot of these, filling the log with noise */
+ /* omega_report_event(omega, CEVNT_BADREPLY); */
+ return;
+ }
+
+#ifndef OMEGACLK
+ omega->lastrec = rbufp->recv_time;
+#endif
+
+#ifdef DEBUG
+ if (debug)
+ printf("omega: timecode %d %s\n",
+ omega->lencode, omega->lastcode);
+#endif
+
+ /*
+ * We get down to business, check the timecode format
+ * and decode its contents.
+ */
+ cp = omega->lastcode;
+ omega->leap = 0;
+ /*
+ * Check timecode format.
+ */
+ if (!isdigit(cp[0]) || /* day of year */
+ !isdigit(cp[1]) ||
+ !isdigit(cp[2]) ||
+ cp[3] != ':' || /* <sp> */
+ !isdigit(cp[4]) || /* hours */
+ !isdigit(cp[5]) ||
+ cp[6] != ':' || /* : separator */
+ !isdigit(cp[7]) || /* minutes */
+ !isdigit(cp[8]) ||
+ cp[9] != ':' || /* : separator */
+ !isdigit(cp[10]) || /* seconds */
+ !isdigit(cp[11])) {
+ omega->badformat++;
+ omega_report_event(omega, CEVNT_BADREPLY);
+ return;
+ }
+
+ /*
+ * Convert and check values.
+ */
+ omega->year = 0; /* fake */
+ omega->day = cp[0] - '0';
+ omega->day = MULBY10(omega->day) + cp[1] - '0';
+ omega->day = MULBY10(omega->day) + cp[2] - '0';
+ omega->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ omega->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ omega->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ omega->msec = 0;
+
+ if (omega->day < 1 || omega->day > 366) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADDATE);
+ return;
+ }
+ if (omega->hour > 23 || omega->minute > 59 || omega->second > 59) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+
+ /*
+ * Check quality/station-id flag. The OM-DC should normally stay
+ * permanently locked to a station, and its time error should be less
+ * than 1 msec. If it loses lock for any reason, it makes a worst
+ * case drift estimate based on the internally stored stability figure
+ * for its reference oscillator. The stability figure can be adjusted
+ * by the user based on experience. The default value is 1E05, which
+ * is pretty bad - 2E07 is about right for the unit I have.
+ *
+ * The following is arbitrary, change it if you're offended:
+ * For errors less than 50 msec, just clear the station indicator.
+ * For errors greater than 50 msec, flag loss of sync and report a
+ * propagation problem. If the error is greater than 500 msec,
+ * something is dreadfully wrong - report a clock fault.
+ *
+ * In each case, we set a drift estimate which is used below as an
+ * estimate of measurement accuracy.
+ */
+ omega->quality = cp[12];
+ if (cp[12] == '>' || cp[12] == '?') {
+ /* Error 500 to 5000 msec */
+ omega_report_event(omega, CEVNT_FAULT);
+ omega->leap = LEAP_NOTINSYNC;
+ omega->station = STATION_NONE;
+ drift = U_FP5000MS;
+ } else if (cp[12] == '#') {
+ /* Error 50 to 500 msec */
+ omega_report_event(omega, CEVNT_PROP);
+ omega->leap = LEAP_NOTINSYNC;
+ omega->station = STATION_NONE;
+ drift = U_FP500MS;
+ } else if (cp[12] == '*') {
+ /* Error 5 to 50 msec */
+ omega->lasttime = current_time;
+ omega->station = STATION_NONE;
+ drift = U_FP50MS;
+ } else if (cp[12] == '.') {
+ /* Error 1 to 5 msec */
+ omega->lasttime = current_time;
+ omega->station = STATION_NONE;
+ drift = U_FP5MS;
+ } else if ('A' <= cp[12] && cp[12] <= 'H') {
+ /* Error less than 1 msec */
+ omega->lasttime = current_time;
+ omega->station = cp[12] - 'A' + 1;
+ drift = 0;
+ } else {
+ omega->badformat++;
+ omega_report_event(omega, CEVNT_BADREPLY);
+ return;
+ }
+
+#ifdef PEDANTIC
+ /* If we haven't been polled, bail out. */
+ if (!omega->polled)
+ return;
+#endif
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the seconds and the millisecond field for the
+ * fraction when present.
+ *
+ * this code does not yet know how to do the years
+ */
+ tstmp = omega->lastrec;
+ if (!clocktime(omega->day, omega->hour, omega->minute,
+ omega->second, GMT, tstmp.l_ui,
+ &omega->yearstart, &omega->lastref.l_ui)) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+ MSUTOTSF(omega->msec, omega->lastref.l_uf);
+
+ /*
+ * Adjust the read value by fudgefactor1 to correct RS232 delays.
+ */
+ L_ADD(&omega->lastref, &fudgefactor1[omega->unit]);
+
+ /* Carousel of NSTAMPS offsets. */
+ i = omega->coderecv % NSTAMPS;
+ omega->offset[i] = omega->lastref;
+ L_SUB(&omega->offset[i], &tstmp);
+ omega->coderecv++;
+
+ /* If we don't yet have a full set, return. */
+ if (omega->coderecv < NSTAMPS)
+ return;
+
+ /*
+ * Filter the samples, add the fudge factor and pass the
+ * offset and dispersion along. We use lastrec as both the
+ * reference time and receive time in order to avoid being cute,
+ * like setting the reference time later than the receive time,
+ * which may cause a paranoid protocol module to chuck out the
+ * data. If the sample filter chokes because of excessive
+ * dispersion or whatever, get a new sample (omega->coderecv
+ * is still >= NSTAMPS) and try again.
+ */
+ if (!omega_process(omega, &tstmp, &dispersion)) {
+ omega->baddata++;
+ omega_report_event(omega, CEVNT_BADTIME);
+ return;
+ }
+
+ /*
+ * Add accumulated clock drift to the dispersion to get
+ * a (hopefully) meaningful measurement accuracy estimate.
+ */
+ dispersion += drift;
+ refclock_receive(omega->peer, &tstmp, GMT, dispersion,
+ &omega->lastrec, &omega->lastrec, omega->leap);
+
+ /*
+ * We have succeeded in answering the poll. If the clock
+ * is locked, we're nominal.
+ */
+ omega->polled = 0;
+ omega->coderecv = 0;
+ if (omega->leap != LEAP_NOTINSYNC)
+ omega_report_event(omega, CEVNT_NOMINAL);
+}
+
+
+/*
+ * omega_send - time to send the clock a signal to cough up a time sample
+ */
+static void
+omega_send(omega,cmd)
+ struct omegaunit *omega;
+ char *cmd;
+{
+ if (!readonlyclockflag[omega->unit]) {
+ /*
+ * Send a command to the clock.
+ */
+ if (write(omega->io.fd, cmd, 1) != 1) {
+ syslog(LOG_ERR, "omega_send: unit %d: %m", omega->unit);
+ omega_report_event(omega, CEVNT_FAULT);
+ }
+ }
+}
+
+
+/*
+ * Compare two l_fp's, used with qsort()
+ */
+static int
+omega_cmpl_fp(p1, p2)
+ register void *p1, *p2;
+{
+
+ if (!L_ISGEQ((l_fp *)p1, (l_fp *)p2))
+ return (-1);
+ if (L_ISEQU((l_fp *)p1, (l_fp *)p2))
+ return (0);
+ return (1);
+}
+
+
+/*
+ * omega_process - process a pile of samples from the clock
+ */
+static char
+omega_process(omega, offset, dispersion)
+ struct omegaunit *omega;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, n;
+ register U_LONG med_ui, med_uf, tmp_ui, tmp_uf;
+ l_fp off[NSTAMPS];
+ u_fp disp;
+
+ /* Copy in offsets and sort into ascending order */
+ for (i = 0; i < NSTAMPS; i++)
+ off[i] = omega->offset[i];
+ qsort((char *)off, NSTAMPS, sizeof(l_fp), omega_cmpl_fp);
+ /*
+ * Reject the furthest from the median until NSKEEP samples remain
+ */
+ i = 0;
+ n = NSTAMPS;
+ while ((n - i) > NSKEEP) {
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ med_ui = off[(n+i)/2].l_ui;
+ med_uf = off[(n+i)/2].l_uf;
+ M_SUB(tmp_ui, tmp_uf, med_ui, med_uf);
+ M_SUB(med_ui, med_uf, off[i].l_ui, off[i].l_uf);
+ if (M_ISHIS(med_ui, med_uf, tmp_ui, tmp_uf)) {
+ /* reject low end */
+ i++;
+ } else {
+ /* reject high end */
+ n--;
+ }
+ }
+
+ /*
+ * Compute the dispersion based on the difference between the
+ * extremes of the remaining offsets. If this is greater than
+ * the allowed sample set dispersion, bail out. Otherwise,
+ * return the median offset and the dispersion.
+ */
+ tmp_ui = off[n-1].l_ui;
+ tmp_uf = off[n-1].l_uf;
+ M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
+ disp = MFPTOFP(tmp_ui, tmp_uf);
+ if (disp > OMEGAMAXDISPERSE)
+ return 0;
+ *offset = off[(n+1)/2];
+ *dispersion = disp;
+ return 1;
+}
+
+
+/*
+ * omega_poll - called by the transmit procedure
+ */
+static void
+omega_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ struct omegaunit *omega;
+
+ /*
+ * You don't need to poll this clock. It puts out timecodes
+ * once per second. If asked for a timestamp, take note.
+ * The next time a timecode comes in, it will be fed back.
+ */
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "omega_poll: unit %d not in use", unit);
+ return;
+ }
+ omega = omegaunits[unit];
+ if ((current_time - omega->lasttime) > 150) {
+ omega->noreply++;
+ omega_report_event(omegaunits[unit], CEVNT_TIMEOUT);
+ }
+
+ /*
+ * polled every 64 seconds. Ask OMEGA_RECEIVE to hand in a timestamp.
+ */
+ omega->polled = 1;
+ omega->polls++;
+ /*
+ * Ensure the clock is running in the correct mode - on-second
+ * timestamps.
+ */
+ omega_send(omega,"C");
+}
+
+
+/*
+ * omega_control - set fudge factors, return statistics
+ */
+static void
+omega_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor1[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVETIME2)
+ fudgefactor2[unit] = in->fudgetime2;
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
+ readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = omegaunits[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_OMEGA_TRUETIME;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2| CLK_HAVEFLAG1;
+ out->clockdesc = OMEGADESCRIPTION;
+ out->fudgetime1 = fudgefactor1[unit];
+ out->fudgetime2 = fudgefactor2[unit];
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = refid[unit];
+ out->flags = readonlyclockflag[unit];
+ if (unitinuse[unit]) {
+ omega = omegaunits[unit];
+ out->flags |= omega->station << 1;
+ out->lencode = omega->lencode;
+ out->lastcode = omega->lastcode;
+ out->timereset = current_time - omega->timestarted;
+ out->polls = omega->polls;
+ out->noresponse = omega->noreply;
+ out->badformat = omega->badformat;
+ out->baddata = omega->baddata;
+ out->lastevent = omega->lastevent;
+ out->currentstatus = omega->status;
+ }
+ }
+}
+
+
+/*
+ * omega_buginfo - return clock dependent debugging info
+ */
+static void
+omega_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct omegaunit *omega;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "omega_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ omega = omegaunits[unit];
+
+ bug->nvalues = 11;
+ bug->ntimes = 5;
+ if (omega->lasttime != 0)
+ bug->values[0] = current_time - omega->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)omega->reason;
+ bug->values[2] = (U_LONG)omega->year;
+ bug->values[3] = (U_LONG)omega->day;
+ bug->values[4] = (U_LONG)omega->hour;
+ bug->values[5] = (U_LONG)omega->minute;
+ bug->values[6] = (U_LONG)omega->second;
+ bug->values[7] = (U_LONG)omega->msec;
+ bug->values[8] = omega->noreply;
+ bug->values[9] = omega->yearstart;
+ bug->values[10] = omega->quality;
+ bug->stimes = 0x1c;
+ bug->times[0] = omega->lastref;
+ bug->times[1] = omega->lastrec;
+ bug->times[2] = omega->offset[0];
+ bug->times[3] = omega->offset[1];
+ bug->times[4] = omega->offset[2];
+}
+#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_old/refclock_parse.c b/usr.sbin/xntpd/xntpd/refclock_old/refclock_parse.c
new file mode 100644
index 000000000000..0d95d18908a5
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/refclock_old/refclock_parse.c
@@ -0,0 +1,3605 @@
+#if defined(REFCLOCK) && (defined(PARSE) || defined(PARSEPPS))
+/*
+ * /src/NTP/REPOSITORY/v3/xntpd/refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp
+ *
+ * refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp
+ *
+ * generic reference clock driver for receivers
+ *
+ * make use of a STREAMS module for input processing where
+ * available and configured. Currently the STREAMS module
+ * is only available for Suns running SunOS 4.x and SunOS5.x (new - careful!)
+ *
+ * Copyright (c) 1989,1990,1991,1992,1993,1994
+ * Frank Kardel Friedrich-Alexander Universitaet Erlangen-Nuernberg
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * Defines:
+ * REFCLOCK && (PARSE||PARSEPPS)
+ * - enable this mess
+ * STREAM - allow for STREAMS modules
+ * ("parse", "ppsclocd", "ppsclock")
+ * PARSEPPS - provide PPS information to loopfilter (for
+ * backward compatibilty only)
+ * PPS - supply loopfilter with PPS samples (if configured)
+ * PPSPPS - notify loopfilter of PPS file descriptor
+ *
+ * FREEBSD_CONRAD - Make very cheap "Conrad DCF77 RS-232" gadget work
+ * with FreeBSD.
+ * TTY defines:
+ * HAVE_BSD_TTYS - currently unsupported
+ * HAVE_SYSV_TTYS - will use termio.h
+ * HAVE_TERMIOS - will use termios.h
+ * STREAM - will use streams and implies HAVE_TERMIOS
+ */
+
+/*
+ * This driver currently provides the support for
+ * - Meinberg DCF77 receiver DCF77 PZF 535 (TCXO version) (DCF)
+ * - Meinberg DCF77 receiver DCF77 PZF 535 (OCXO version) (DCF)
+ * - Meinberg DCF77 receiver U/A 31 (DCF)
+ * - ELV DCF7000 (DCF)
+ * - Schmid clock (DCF)
+ * - Conrad DCF77 receiver module (DCF)
+ * - FAU DCF77 NTP receiver (TimeBrick) (DCF)
+ * - Meinberg GPS166 (GPS)
+ * - Trimble SV6 (GPS)
+ *
+ */
+
+/*
+ * Meinberg receivers are connected via a 9600 baud serial line
+ *
+ * Receivers that do NOT support:
+ * - leap second indication
+ * DCF U/A 31
+ * DCF PZF535 (stock version)
+ *
+ * so...
+ * - for PZF535 please ask for revision PZFUERL4.6 or higher
+ * (support for leap second and alternate antenna)
+ *
+ * The Meinberg GPS receiver also has a special NTP time stamp
+ * format. The firmware release is Uni-Erlangen. Only this
+ * firmware release is supported by xntp3.
+ *
+ * Meinberg generic receiver setup:
+ * output time code every second
+ * Baud rate 9600 7E2S
+ */
+
+#include "ntpd.h"
+#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+#include "ntp_control.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <sys/errno.h>
+#ifdef FREEBSD_CONRAD
+#include <sys/ioctl.h>
+#endif
+extern int errno;
+
+#if !defined(STREAM) && !defined(HAVE_SYSV_TTYS) && !defined(HAVE_BSD_TTYS) && !defined(HAVE_TERMIOS)
+/* #error NEED TO DEFINE ONE OF "STREAM" or "HAVE_SYSV_TTYS" */
+NEED TO DEFINE ONE OF "STREAM", "HAVE_SYSV_TTYS" or "HAVE_TERMIOS"
+#endif
+
+#ifdef STREAM
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#ifndef HAVE_TERMIOS
+#define HAVE_TERMIOS
+#endif
+#endif
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
+#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
+#undef HAVE_SYSV_TTYS
+#endif
+
+#ifdef HAVE_SYSV_TTYS
+#include <termio.h>
+#define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
+#define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
+#endif
+
+#ifdef HAVE_BSD_TTYS
+/* #error CURRENTLY NO BSD TTY SUPPORT */
+CURRENTLY NO BSD TTY SUPPORT
+#endif
+
+#if !defined(O_RDWR) /* XXX SOLARIS */
+#include <fcntl.h>
+#endif /* !def(O_RDWR) */
+
+#ifdef PPSPPS
+#include <sys/ppsclock.h>
+#endif
+
+#include "ntp_select.h"
+#include "ntp_stdlib.h"
+
+#include "parse.h"
+
+#if !defined(NO_SCCSID) && !defined(lint) && !defined(__GNUC__)
+static char rcsid[]="refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp";
+#endif
+
+/**===========================================================================
+ ** external interface to xntp mechanism
+ **/
+
+static void parse_init P((void));
+static int parse_start P((u_int, struct peer *));
+static void parse_shutdown P((int));
+static void parse_poll P((int, struct peer *));
+static void parse_control P((u_int, struct refclockstat *, struct refclockstat *));
+
+#define parse_buginfo noentry
+
+struct refclock refclock_parse = {
+ parse_start,
+ parse_shutdown,
+ parse_poll,
+ parse_control,
+ parse_init,
+ parse_buginfo,
+ NOFLAGS
+};
+
+/*
+ * the unit field selects for one the prototype to be used (lower 4 bits)
+ * and for the other the clock type in case of different but similar
+ * receivers (bits 4-6)
+ * the most significant bit encodes PPS support
+ * when the most significant bit is set the pps telegrams will be used
+ * for controlling the local clock (ntp_loopfilter.c)
+ * receiver specific configration data is kept in the clockinfo field.
+ */
+
+/*
+ * Definitions
+ */
+#define MAXUNITS 4 /* maximum number of "PARSE" units permitted */
+#define PARSEDEVICE "/dev/refclock-%d" /* device to open %d is unit number */
+
+/**===========================================================================
+ ** function vector for dynamically binding io handling mechanism
+ **/
+
+typedef struct bind
+{
+ char *bd_description; /* name of type of binding */
+ int (*bd_init)(); /* initialize */
+ void (*bd_end)(); /* end */
+ int (*bd_setcs)(); /* set character size */
+ int (*bd_disable)(); /* disable */
+ int (*bd_enable)(); /* enable */
+ int (*bd_getfmt)(); /* get format */
+ int (*bd_setfmt)(); /* setfmt */
+ int (*bd_getstat)(); /* getstat */
+ int (*bd_setstat)(); /* setstat */
+ int (*bd_timecode)(); /* get time code */
+ void (*bd_receive)(); /* receive operation */
+ void (*bd_poll)(); /* poll operation */
+} bind_t;
+
+#define PARSE_END(_X_) (*(_X_)->binding->bd_end)(_X_)
+#define PARSE_SETCS(_X_, _CS_) (*(_X_)->binding->bd_setcs)(_X_, _CS_)
+#define PARSE_ENABLE(_X_) (*(_X_)->binding->bd_enable)(_X_)
+#define PARSE_DISABLE(_X_) (*(_X_)->binding->bd_disable)(_X_)
+#define PARSE_GETFMT(_X_, _DCT_) (*(_X_)->binding->bd_getfmt)(_X_, _DCT_)
+#define PARSE_SETFMT(_X_, _DCT_) (*(_X_)->binding->bd_setfmt)(_X_, _DCT_)
+#define PARSE_GETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_getstat)(_X_, _DCT_)
+#define PARSE_SETSTAT(_X_, _DCT_) (*(_X_)->binding->bd_setstat)(_X_, _DCT_)
+#define PARSE_GETTIMECODE(_X_, _DCT_) (*(_X_)->binding->bd_timecode)(_X_, _DCT_)
+#define PARSE_POLL(_X_) (*(_X_)->binding->bd_poll)(_X_)
+
+/*
+ * io modes
+ */
+#define PARSE_F_NOPOLLONLY 0x0001 /* always do async io (possible PPS support via PARSE) */
+#define PARSE_F_POLLONLY 0x0002 /* never do async io (no PPS support via PARSE) */
+#define PARSE_F_PPSPPS 0x0004 /* use loopfilter PPS code (CIOGETEV) */
+#define PARSE_F_PPSONSECOND 0x0008 /* PPS pulses are on second */
+
+/**===========================================================================
+ ** refclock instance data
+ **/
+
+struct parseunit
+{
+ /*
+ * XNTP management
+ */
+ struct peer *peer; /* backlink to peer structure - refclock inactive if 0 */
+ int fd; /* device file descriptor */
+ u_char unit; /* encoded unit/type/PPS */
+
+ /*
+ * XNTP io
+ */
+ struct refclockio io; /* io system structure (used in PPS mode) */
+ bind_t *binding; /* io handling binding */
+
+ /*
+ * parse state
+ */
+ parse_t parseio; /* io handling structure (user level parsing) */
+
+ /*
+ * type specific parameters
+ */
+ struct clockinfo *parse_type; /* link to clock description */
+
+ /*
+ * clock specific configuration
+ */
+ l_fp basedelay; /* clock local phase offset */
+ l_fp ppsdelay; /* clock local pps phase offset */
+
+ /*
+ * clock state handling/reporting
+ */
+ u_char flags; /* flags (leap_control) */
+ u_char status; /* current status */
+ u_char lastevent; /* last not NORMAL status */
+ U_LONG lastchange; /* time (xntp) when last state change accured */
+ U_LONG statetime[CEVNT_MAX+1]; /* accumulated time of clock states */
+ struct event stattimer; /* statistics timer */
+ U_LONG polls; /* polls from NTP protocol machine */
+ U_LONG noresponse; /* number of expected but not seen datagrams */
+ U_LONG badformat; /* bad format (failed format conversions) */
+ U_LONG baddata; /* usually bad receive length, bad format */
+
+ u_char pollonly; /* 1 for polling only (no PPS mode) */
+ u_char pollneeddata; /* 1 for receive sample expected in PPS mode */
+ U_LONG laststatus; /* last packet status (error indication) */
+ u_short lastformat; /* last format used */
+ U_LONG lastsync; /* time (xntp) when clock was last seen fully synchronized */
+ U_LONG timestarted; /* time (xntp) when peer clock was instantiated */
+ U_LONG nosynctime; /* time (xntp) when last nosync message was posted */
+ U_LONG lastmissed; /* time (xntp) when poll didn't get data (powerup heuristic) */
+ U_LONG ppsserial; /* magic cookie for ppsclock serials (avoids stale ppsclock data) */
+ parsetime_t time; /* last (parse module) data */
+ void *localdata; /* optional local data */
+};
+
+
+/**===========================================================================
+ ** Clockinfo section all parameter for specific clock types
+ ** includes NTP paramaters, TTY parameters and IO handling parameters
+ **/
+
+static void poll_dpoll P((struct parseunit *));
+static void poll_poll P((struct parseunit *));
+static int poll_init P((struct parseunit *));
+static void poll_end P((struct parseunit *));
+
+typedef struct poll_info
+{
+ U_LONG rate; /* poll rate - once every "rate" seconds - 0 off */
+ char * string; /* string to send for polling */
+ U_LONG count; /* number of charcters in string */
+} poll_info_t;
+
+#define NO_FLAGS 0
+#define NO_POLL (void (*)())0
+#define NO_INIT (int (*)())0
+#define NO_END (void (*)())0
+#define NO_DATA (void *)0
+#define NO_FORMAT ""
+#define NO_PPSDELAY 0
+
+#define DCF_ID "DCF" /* generic DCF */
+#define DCF_A_ID "DCFa" /* AM demodulation */
+#define DCF_P_ID "DCFp" /* psuedo random phase shift */
+#define GPS_ID "GPS" /* GPS receiver */
+
+#define NOCLOCK_ROOTDELAY 0x00000000
+#define NOCLOCK_BASEDELAY 0x00000000
+#define NOCLOCK_DESCRIPTION ((char *)0)
+#define NOCLOCK_MAXUNSYNC 0
+#define NOCLOCK_CFLAG 0
+#define NOCLOCK_IFLAG 0
+#define NOCLOCK_OFLAG 0
+#define NOCLOCK_LFLAG 0
+#define NOCLOCK_ID "TILT"
+#define NOCLOCK_POLL NO_POLL
+#define NOCLOCK_INIT NO_INIT
+#define NOCLOCK_END NO_END
+#define NOCLOCK_DATA NO_DATA
+#define NOCLOCK_FORMAT NO_FORMAT
+#define NOCLOCK_TYPE CTL_SST_TS_UNSPEC
+
+#define DCF_TYPE CTL_SST_TS_LF
+#define GPS_TYPE CTL_SST_TS_UHF
+
+/*
+ * receiver specific constants
+ */
+#define MBG_CFLAG19200 (B19200|CS7|PARENB|CREAD|HUPCL)
+#define MBG_CFLAG (B9600|CS7|PARENB|CREAD|HUPCL)
+#define MBG_IFLAG (IGNBRK|IGNPAR|ISTRIP)
+#define MBG_OFLAG 0
+#define MBG_LFLAG 0
+/*
+ * Meinberg DCF U/A 31 (AM) receiver
+ */
+#define DCFUA31_ROOTDELAY 0x00000D00 /* 50.78125ms */
+#define DCFUA31_BASEDELAY 0x02C00000 /* 10.7421875ms: 10 ms (+/- 3 ms) */
+#define DCFUA31_DESCRIPTION "Meinberg DCF U/A 31"
+#define DCFUA31_MAXUNSYNC 60*30 /* only trust clock for 1/2 hour */
+#define DCFUA31_CFLAG MBG_CFLAG
+#define DCFUA31_IFLAG MBG_IFLAG
+#define DCFUA31_OFLAG MBG_OFLAG
+#define DCFUA31_LFLAG MBG_LFLAG
+
+/*
+ * Meinberg DCF PZF535/TCXO (FM/PZF) receiver
+ */
+#define DCFPZF535_ROOTDELAY 0x00000034 /* 800us */
+#define DCFPZF535_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define DCFPZF535_DESCRIPTION "Meinberg DCF PZF 535/TCXO"
+#define DCFPZF535_MAXUNSYNC 60*60*12 /* only trust clock for 12 hours
+ * @ 5e-8df/f we have accumulated
+ * at most 2.16 ms (thus we move to
+ * NTP synchronisation */
+#define DCFPZF535_CFLAG MBG_CFLAG
+#define DCFPZF535_IFLAG MBG_IFLAG
+#define DCFPZF535_OFLAG MBG_OFLAG
+#define DCFPZF535_LFLAG MBG_LFLAG
+
+
+/*
+ * Meinberg DCF PZF535/OCXO receiver
+ */
+#define DCFPZF535OCXO_ROOTDELAY 0x00000034 /* 800us (max error * 10) */
+#define DCFPZF535OCXO_BASEDELAY 0x00800000 /* 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define DCFPZF535OCXO_DESCRIPTION "Meinberg DCF PZF 535/OCXO"
+#define DCFPZF535OCXO_MAXUNSYNC 60*60*96 /* only trust clock for 4 days
+ * @ 5e-9df/f we have accumulated
+ * at most an error of 1.73 ms
+ * (thus we move to NTP synchronisation) */
+#define DCFPZF535OCXO_CFLAG MBG_CFLAG
+#define DCFPZF535OCXO_IFLAG MBG_IFLAG
+#define DCFPZF535OCXO_OFLAG MBG_OFLAG
+#define DCFPZF535OCXO_LFLAG MBG_LFLAG
+
+/*
+ * Meinberg GPS166 receiver
+ */
+#define GPS166_ROOTDELAY 0x00000000 /* nothing here */
+#define GPS166_BASEDELAY 0x00800000 /* XXX to be fixed ! 1.968ms +- 104us (oscilloscope) - relative to start (end of STX) */
+#define GPS166_DESCRIPTION "Meinberg GPS166 receiver"
+#define GPS166_MAXUNSYNC 0 /* this clock is immediately lost */
+#define GPS166_CFLAG MBG_CFLAG
+#define GPS166_IFLAG MBG_IFLAG
+#define GPS166_OFLAG MBG_OFLAG
+#define GPS166_LFLAG MBG_LFLAG
+#define GPS166_POLL NO_POLL
+#define GPS166_INIT NO_INIT
+#define GPS166_END NO_END
+#define GPS166_DATA NO_DATA
+#define GPS166_ID GPS_ID
+#define GPS166_FORMAT NO_FORMAT
+
+/*
+ * ELV DCF7000 Wallclock-Receiver/Switching Clock (Kit)
+ *
+ * This is really not the hottest clock - but before you have nothing ...
+ */
+#define DCF7000_ROOTDELAY 0x00000364 /* 13 ms */
+#define DCF7000_BASEDELAY 0x67AE0000 /* 405 ms - slow blow */
+#define DCF7000_DESCRIPTION "ELV DCF7000"
+#define DCF7000_MAXUNSYNC (60*5) /* sorry - but it just was not build as a clock */
+#define DCF7000_CFLAG (B9600|CS8|CREAD|PARENB|PARODD|CLOCAL|HUPCL)
+#define DCF7000_IFLAG (IGNBRK)
+#define DCF7000_OFLAG 0
+#define DCF7000_LFLAG 0
+
+/*
+ * Schmid DCF Receiver Kit
+ *
+ * When the WSDCF clock is operating optimally we want the primary clock
+ * distance to come out at 300 ms. Thus, peer.distance in the WSDCF peer
+ * structure is set to 290 ms and we compute delays which are at least
+ * 10 ms long. The following are 290 ms and 10 ms expressed in u_fp format
+ */
+#define WS_POLLRATE 1 /* every second - watch interdependency with poll routine */
+#define WS_POLLCMD "\163"
+#define WS_CMDSIZE 1
+
+static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
+
+#define WSDCF_INIT poll_init
+#define WSDCF_POLL poll_dpoll
+#define WSDCF_END poll_end
+#define WSDCF_DATA ((void *)(&wsdcf_pollinfo))
+#define WSDCF_ROOTDELAY 0X00004A3D /* ~ 290ms */
+#define WSDCF_BASEDELAY 0x028F5C29 /* ~ 10ms */
+#define WSDCF_DESCRIPTION "WS/DCF Receiver"
+#define WSDCF_FORMAT "Schmid"
+#define WSDCF_MAXUNSYNC (60*60) /* assume this beast hold at 1 h better than 2 ms XXX-must verify */
+#define WSDCF_CFLAG (B1200|CS8|CREAD|CLOCAL)
+#define WSDCF_IFLAG 0
+#define WSDCF_OFLAG 0
+#define WSDCF_LFLAG 0
+
+/*
+ * RAW DCF77 - input of DCF marks via RS232 - many variants
+ */
+#define RAWDCF_FLAGS PARSE_F_NOPOLLONLY
+#define RAWDCF_ROOTDELAY 0x00000364 /* 13 ms */
+#define RAWDCF_FORMAT "RAW DCF77 Timecode"
+#define RAWDCF_MAXUNSYNC (0) /* sorry - its a true receiver - no signal - no time */
+
+#ifdef FREEBSD_CONRAD
+#define RAWDCF_CFLAG (CS8|CREAD|CLOCAL)
+#else
+#define RAWDCF_CFLAG (B50|CS8|CREAD|CLOCAL)
+#endif
+#define RAWDCF_IFLAG 0
+#define RAWDCF_OFLAG 0
+#define RAWDCF_LFLAG 0
+
+/*
+ * RAW DCF variants
+ */
+/*
+ * Conrad receiver
+ *
+ * simplest (cheapest) DCF clock - e. g. DCF77 receiver by Conrad
+ * (~40DM - roughly $30 ) followed by a level converter for RS232
+ */
+#define CONRAD_BASEDELAY 0x420C49B0 /* ~258 ms - Conrad receiver @ 50 Baud on a Sun */
+#define CONRAD_DESCRIPTION "RAW DCF77 CODE (Conrad DCF77 receiver module)"
+
+/*
+ * TimeBrick receiver
+ */
+#define TIMEBRICK_BASEDELAY 0x35C29000 /* ~210 ms - TimeBrick @ 50 Baud on a Sun */
+#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
+
+/*
+ * Trimble SV6 GPS receiver
+ */
+#define TRIM_POLLRATE 0 /* only true direct polling */
+#define TRIM_POLLCMD ">QTM<"
+#define TRIM_CMDSIZE 5
+
+static poll_info_t trimble_pollinfo = { TRIM_POLLRATE, TRIM_POLLCMD, TRIM_CMDSIZE };
+static int trimble_init P((struct parseunit *));
+
+#define TRIMBLESV6_CFLAG (B4800|CS8|CREAD)
+#define TRIMBLESV6_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
+#define TRIMBLESV6_OFLAG (OPOST|ONLCR)
+#define TRIMBLESV6_LFLAG (ICANON|ECHOK)
+#define TRIMBLESV6_FLAGS (PARSE_F_PPSPPS|PARSE_F_PPSONSECOND)
+#define TRIMBLESV6_POLL poll_dpoll
+#define TRIMBLESV6_INIT trimble_init
+#define TRIMBLESV6_END poll_end
+#define TRIMBLESV6_DATA ((void *)(&trimble_pollinfo))
+#define TRIMBLESV6_ID GPS_ID
+#define TRIMBLESV6_FORMAT NO_FORMAT
+#define TRIMBLESV6_ROOTDELAY 0x0
+#define TRIMBLESV6_BASEDELAY 0x0
+#define TRIMBLESV6_DESCRIPTION "Trimble SV6 GPS receiver"
+#define TRIMBLESV6_MAXUNSYNC 0
+#define TRIMBLESV6_EOL '<'
+
+static struct clockinfo
+{
+ U_LONG cl_flags; /* operation flags (io modes) */
+ void (*cl_poll)(); /* active poll routine */
+ int (*cl_init)(); /* active poll init routine */
+ void (*cl_end)(); /* active poll end routine */
+ void *cl_data; /* local data area for "poll" mechanism */
+ u_fp cl_rootdelay; /* rootdelay */
+ U_LONG cl_basedelay; /* current offset - unsigned l_fp fractional part */
+ U_LONG cl_ppsdelay; /* current PPS offset - unsigned l_fp fractional part */
+ char *cl_id; /* ID code (usually "DCF") */
+ char *cl_description; /* device name */
+ char *cl_format; /* fixed format */
+ u_char cl_type; /* clock type (ntp control) */
+ U_LONG cl_maxunsync; /* time to trust oscillator after loosing synch */
+ U_LONG cl_cflag; /* terminal io flags */
+ U_LONG cl_iflag; /* terminal io flags */
+ U_LONG cl_oflag; /* terminal io flags */
+ U_LONG cl_lflag; /* terminal io flags */
+} clockinfo[] =
+{ /* 0. 0.0.128 - base offset for PPS support */
+ { /* 127.127.8.<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFPZF535_ROOTDELAY,
+ DCFPZF535_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_P_ID,
+ DCFPZF535_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFPZF535_MAXUNSYNC,
+ DCFPZF535_CFLAG,
+ DCFPZF535_IFLAG,
+ DCFPZF535_OFLAG,
+ DCFPZF535_LFLAG
+ },
+ { /* 127.127.8.4+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFPZF535OCXO_ROOTDELAY,
+ DCFPZF535OCXO_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_P_ID,
+ DCFPZF535OCXO_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFPZF535OCXO_MAXUNSYNC,
+ DCFPZF535OCXO_CFLAG,
+ DCFPZF535OCXO_IFLAG,
+ DCFPZF535OCXO_OFLAG,
+ DCFPZF535OCXO_LFLAG
+ },
+ { /* 127.127.8.8+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCFUA31_ROOTDELAY,
+ DCFUA31_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ DCFUA31_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCFUA31_MAXUNSYNC,
+ DCFUA31_CFLAG,
+ DCFUA31_IFLAG,
+ DCFUA31_OFLAG,
+ DCFUA31_LFLAG
+ },
+ { /* 127.127.8.12+<device> */
+ NO_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ DCF7000_ROOTDELAY,
+ DCF7000_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ DCF7000_DESCRIPTION,
+ NO_FORMAT,
+ DCF_TYPE,
+ DCF7000_MAXUNSYNC,
+ DCF7000_CFLAG,
+ DCF7000_IFLAG,
+ DCF7000_OFLAG,
+ DCF7000_LFLAG
+ },
+ { /* 127.127.8.16+<device> */
+ NO_FLAGS,
+ WSDCF_POLL,
+ WSDCF_INIT,
+ WSDCF_END,
+ WSDCF_DATA,
+ WSDCF_ROOTDELAY,
+ WSDCF_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ WSDCF_DESCRIPTION,
+ WSDCF_FORMAT,
+ DCF_TYPE,
+ WSDCF_MAXUNSYNC,
+ WSDCF_CFLAG,
+ WSDCF_IFLAG,
+ WSDCF_OFLAG,
+ WSDCF_LFLAG
+ },
+ { /* 127.127.8.20+<device> */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ RAWDCF_ROOTDELAY,
+ CONRAD_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ CONRAD_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG
+ },
+ { /* 127.127.8.24+<device> */
+ RAWDCF_FLAGS,
+ NO_POLL,
+ NO_INIT,
+ NO_END,
+ NO_DATA,
+ RAWDCF_ROOTDELAY,
+ TIMEBRICK_BASEDELAY,
+ NO_PPSDELAY,
+ DCF_A_ID,
+ TIMEBRICK_DESCRIPTION,
+ RAWDCF_FORMAT,
+ DCF_TYPE,
+ RAWDCF_MAXUNSYNC,
+ RAWDCF_CFLAG,
+ RAWDCF_IFLAG,
+ RAWDCF_OFLAG,
+ RAWDCF_LFLAG
+ },
+ { /* 127.127.8.28+<device> */
+ NO_FLAGS,
+ GPS166_POLL,
+ GPS166_INIT,
+ GPS166_END,
+ GPS166_DATA,
+ GPS166_ROOTDELAY,
+ GPS166_BASEDELAY,
+ NO_PPSDELAY,
+ GPS166_ID,
+ GPS166_DESCRIPTION,
+ GPS166_FORMAT,
+ GPS_TYPE,
+ GPS166_MAXUNSYNC,
+ GPS166_CFLAG,
+ GPS166_IFLAG,
+ GPS166_OFLAG,
+ GPS166_LFLAG
+ },
+ { /* 127.127.8.32+<device> */
+ TRIMBLESV6_FLAGS,
+ TRIMBLESV6_POLL,
+ TRIMBLESV6_INIT,
+ TRIMBLESV6_END,
+ TRIMBLESV6_DATA,
+ TRIMBLESV6_ROOTDELAY,
+ TRIMBLESV6_BASEDELAY,
+ NO_PPSDELAY,
+ TRIMBLESV6_ID,
+ TRIMBLESV6_DESCRIPTION,
+ TRIMBLESV6_FORMAT,
+ GPS_TYPE,
+ TRIMBLESV6_MAXUNSYNC,
+ TRIMBLESV6_CFLAG,
+ TRIMBLESV6_IFLAG,
+ TRIMBLESV6_OFLAG,
+ TRIMBLESV6_LFLAG
+ }
+};
+
+static int ncltypes = sizeof(clockinfo) / sizeof(struct clockinfo);
+
+#define CL_REALTYPE(x) (((x) >> 2) & 0x1F)
+#define CL_TYPE(x) ((CL_REALTYPE(x) >= ncltypes) ? ~0 : CL_REALTYPE(x))
+#define CL_PPS(x) ((x) & 0x80)
+#define CL_UNIT(x) ((x) & 0x3)
+
+/*
+ * Other constant stuff
+ */
+#define PARSEHSREFID 0x7f7f08ff /* 127.127.8.255 refid for hi strata */
+
+#define PARSENOSYNCREPEAT (10*60) /* mention uninitialized clocks all 10 minutes */
+#define PARSESTATISTICS (60*60) /* output state statistics every hour */
+
+static struct parseunit *parseunits[MAXUNITS];
+
+extern U_LONG current_time;
+extern s_char sys_precision;
+extern struct event timerqueue[];
+#ifdef PPSPPS
+extern int fdpps;
+#endif
+
+static int notice = 0;
+
+#define PARSE_STATETIME(parse, i) ((parse->status == i) ? parse->statetime[i] + current_time - parse->lastchange : parse->statetime[i])
+
+static void parse_event P((struct parseunit *, int));
+static void parse_process P((struct parseunit *, parsetime_t *));
+
+/**===========================================================================
+ ** implementation of i/o handling methods
+ ** (all STREAM, partial STREAM, user level)
+ **/
+
+/*
+ * define possible io handling methods
+ */
+#ifdef STREAM
+static int ppsclock_init P((struct parseunit *));
+static int stream_init P((struct parseunit *));
+static void stream_nop P((struct parseunit *));
+static int stream_enable P((struct parseunit *));
+static int stream_disable P((struct parseunit *));
+static int stream_setcs P((struct parseunit *, parsectl_t *));
+static int stream_getfmt P((struct parseunit *, parsectl_t *));
+static int stream_setfmt P((struct parseunit *, parsectl_t *));
+static int stream_getstat P((struct parseunit *, parsectl_t *));
+static int stream_setstat P((struct parseunit *, parsectl_t *));
+static int stream_timecode P((struct parseunit *, parsectl_t *));
+static void stream_receive P((struct recvbuf *));
+static void stream_poll P((struct parseunit *));
+#endif
+
+static int local_init P((struct parseunit *));
+static void local_end P((struct parseunit *));
+static int local_nop P((struct parseunit *));
+static int local_setcs P((struct parseunit *, parsectl_t *));
+static int local_getfmt P((struct parseunit *, parsectl_t *));
+static int local_setfmt P((struct parseunit *, parsectl_t *));
+static int local_getstat P((struct parseunit *, parsectl_t *));
+static int local_setstat P((struct parseunit *, parsectl_t *));
+static int local_timecode P((struct parseunit *, parsectl_t *));
+static void local_receive P((struct recvbuf *));
+static void local_poll P((struct parseunit *));
+
+static bind_t io_bindings[] =
+{
+#ifdef STREAM
+ {
+ "parse STREAM",
+ stream_init,
+ stream_nop,
+ stream_setcs,
+ stream_disable,
+ stream_enable,
+ stream_getfmt,
+ stream_setfmt,
+ stream_getstat,
+ stream_setstat,
+ stream_timecode,
+ stream_receive,
+ stream_poll
+ },
+ {
+ "ppsclock STREAM",
+ ppsclock_init,
+ local_end,
+ local_setcs,
+ local_nop,
+ local_nop,
+ local_getfmt,
+ local_setfmt,
+ local_getstat,
+ local_setstat,
+ local_timecode,
+ local_receive,
+ local_poll
+ },
+#endif
+ {
+ "normal",
+ local_init,
+ local_end,
+ local_setcs,
+ local_nop,
+ local_nop,
+ local_getfmt,
+ local_setfmt,
+ local_getstat,
+ local_setstat,
+ local_timecode,
+ local_receive,
+ local_poll
+ },
+ {
+ (char *)0,
+ }
+};
+
+#ifdef STREAM
+/*--------------------------------------------------
+ * ppsclock STREAM init
+ */
+static int
+ppsclock_init(parse)
+ struct parseunit *parse;
+{
+ /*
+ * now push the parse streams module
+ * it will ensure exclusive access to the device
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclocd") == -1 &&
+ ioctl(parse->fd, I_PUSH, (caddr_t)"ppsclock") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: ppsclock_init: ioctl(fd, I_PUSH, \"ppsclock\"): %m",
+ CL_UNIT(parse->unit));
+ return 0;
+ }
+ if (!local_init(parse))
+ {
+ (void)ioctl(parse->fd, I_POP, (caddr_t)0);
+ return 0;
+ }
+
+ parse->flags |= PARSE_PPSCLOCK;
+ return 1;
+}
+
+/*--------------------------------------------------
+ * parse STREAM init
+ */
+static int
+stream_init(parse)
+ struct parseunit *parse;
+{
+ /*
+ * now push the parse streams module
+ * to test whether it is there (Oh boy - neat kernel interface)
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"parse") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ while(ioctl(parse->fd, I_POP, (caddr_t)0) == 0)
+ /* empty loop */;
+
+ /*
+ * now push it a second time after we have removed all
+ * module garbage
+ */
+ if (ioctl(parse->fd, I_PUSH, (caddr_t)"parse") == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_init: ioctl(fd, I_PUSH, \"parse\"): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+}
+
+ /*--------------------------------------------------
+ * STREAM setcs
+ */
+static int
+stream_setcs(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETCS;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setcs: ioctl(fd, I_STR, PARSEIOC_SETCS): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM nop
+ */
+static void
+stream_nop(parse)
+ struct parseunit *parse;
+{
+}
+
+/*--------------------------------------------------
+ * STREAM enable
+ */
+static int
+stream_enable(parse)
+ struct parseunit *parse;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_ENABLE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)0;
+ strioc.ic_len = 0;
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_enable: ioctl(fd, I_STR, PARSEIOC_ENABLE): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM disable
+ */
+static int
+stream_disable(parse)
+ struct parseunit *parse;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_DISABLE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)0;
+ strioc.ic_len = 0;
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_disable: ioctl(fd, I_STR, PARSEIOC_DISABLE): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM getfmt
+ */
+static int
+stream_getfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_GETFMT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: ioctl(fd, I_STR, PARSEIOC_GETFMT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM setfmt
+ */
+static int
+stream_setfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETFMT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setfmt: ioctl(fd, I_STR, PARSEIOC_SETFMT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM getstat
+ */
+static int
+stream_getstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_GETSTAT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_getstat: ioctl(fd, I_STR, PARSEIOC_GETSTAT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM setstat
+ */
+static int
+stream_setstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_SETSTAT;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: stream_setstat: ioctl(fd, I_STR, PARSEIOC_SETSTAT): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM timecode
+ */
+static int
+stream_timecode(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ struct strioctl strioc;
+
+ strioc.ic_cmd = PARSEIOC_TIMECODE;
+ strioc.ic_timout = 0;
+ strioc.ic_dp = (char *)tcl;
+ strioc.ic_len = sizeof (*tcl);
+
+ if (ioctl(parse->fd, I_STR, (caddr_t)&strioc) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_process: ioctl(fd, I_STR, PARSEIOC_TIMECODE): %m", CL_UNIT(parse->unit), parse->fd);
+ return 0;
+ }
+ return 1;
+}
+
+/*--------------------------------------------------
+ * STREAM receive
+ */
+static void
+stream_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock;
+ parsetime_t parsetime;
+
+ if (rbufp->recv_length != sizeof(parsetime_t))
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: parse_receive: bad size (got %d expected %d)",
+ CL_UNIT(parse->unit), rbufp->recv_length, sizeof(parsetime_t));
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+ return;
+ }
+ memmove((caddr_t)&parsetime,
+ (caddr_t)&rbufp->recv_space,
+ sizeof(parsetime_t));
+
+ /*
+ * switch time stamp world - be sure to normalize small usec field
+ * errors.
+ */
+
+#define fix_ts(_X_) \
+ if ((&(_X_))->tv.tv_usec >= 1000000) \
+ { \
+ (&(_X_))->tv.tv_usec -= 1000000; \
+ (&(_X_))->tv.tv_sec += 1; \
+ }
+
+#define cvt_ts(_X_, _Y_) \
+ { \
+ l_fp ts; \
+ \
+ fix_ts((_X_)); \
+ if (!buftvtots((const char *)&(&(_X_))->tv, &ts)) \
+ { \
+ syslog(LOG_ERR,"parse: stream_receive: timestamp conversion error (buftvtots) (%s) (%d.%06d) ", (_Y_), (&(_X_))->tv.tv_sec, (&(_X_))->tv.tv_usec);\
+ return; \
+ } \
+ else \
+ { \
+ (&(_X_))->fp = ts; \
+ } \
+ }
+
+ if (PARSE_TIMECODE(parsetime.parse_state))
+ {
+ cvt_ts(parsetime.parse_time, "parse_time");
+ cvt_ts(parsetime.parse_stime, "parse_stime");
+ }
+
+ if (PARSE_PPS(parsetime.parse_state))
+ cvt_ts(parsetime.parse_ptime, "parse_ptime");
+
+ parse_process(parse, &parsetime);
+}
+
+/*--------------------------------------------------
+ * STREAM poll
+ */
+static void
+stream_poll(parse)
+ struct parseunit *parse;
+{
+ register int fd, i, rtc;
+ fd_set fdmask;
+ struct timeval timeout, starttime, curtime, selecttime;
+ parsetime_t parsetime;
+
+ /*
+ * now we do the following:
+ * - read the first packet from the parse module (OLD !!!)
+ * - read the second packet from the parse module (fresh)
+ * - compute values for xntp
+ */
+
+ FD_ZERO(&fdmask);
+ fd = parse->fd;
+ FD_SET(fd, &fdmask);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500000; /* 0.5 sec */
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * elapsed real time passed timeout value - consider it timed out
+ */
+ break;
+ }
+
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[old] from device", CL_UNIT(parse->unit));
+ }
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ return;
+ }
+
+ while (((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime)))
+ {
+ /* bad packet */
+ if ( i == -1)
+ {
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[old] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+
+ return;
+ }
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 500000; /* 1.500 sec */
+ FD_ZERO(&fdmask);
+ FD_SET(fd, &fdmask);
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * elapsed real time passed timeout value - consider it timed out
+ */
+ break;
+ }
+
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data[new] from device", CL_UNIT(parse->unit));
+ }
+
+ /*
+ * we will return here iff we got a good old sample as this would
+ * be misinterpreted. bad samples are passed on to be logged into the
+ * state statistics
+ */
+ if ((parsetime.parse_status & CVT_MASK) == CVT_OK)
+ {
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+ return;
+ }
+ }
+
+ /*
+ * we get here either by a possible read() (rtc == 1 - while assertion)
+ * or by a timeout or a system call error. when a read() is possible we
+ * get the new data, otherwise we stick with the old
+ */
+ if ((rtc == 1) && ((i = read(fd, (char *)&parsetime, sizeof(parsetime))) < sizeof(parsetime)))
+ {
+ /* bad packet */
+ if ( i== -1)
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (read() error: %m)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: bad read[new] from streams module (got %d bytes - expected %d bytes)", CL_UNIT(parse->unit), i, sizeof(parsetime));
+ }
+ parse->baddata++;
+ parse_event(parse, CEVNT_BADREPLY);
+
+ return;
+ }
+
+ /*
+ * process what we got
+ */
+ parse_process(parse, &parsetime);
+}
+#endif
+
+/*--------------------------------------------------
+ * local init
+ */
+static int
+local_init(parse)
+ struct parseunit *parse;
+{
+ return parse_ioinit(&parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local end
+ */
+static void
+local_end(parse)
+ struct parseunit *parse;
+{
+ parse_ioend(&parse->parseio);
+}
+
+
+/*--------------------------------------------------
+ * local nop
+ */
+static int
+local_nop(parse)
+ struct parseunit *parse;
+{
+ return 1;
+}
+
+/*--------------------------------------------------
+ * local setcs
+ */
+static int
+local_setcs(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setcs(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local getfmt
+ */
+static int
+local_getfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_getfmt(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local setfmt
+ */
+static int
+local_setfmt(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setfmt(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local getstat
+ */
+static int
+local_getstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_getstat(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local setstat
+ */
+static int
+local_setstat(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_setstat(tcl, &parse->parseio);
+}
+
+/*--------------------------------------------------
+ * local timecode
+ */
+static int
+local_timecode(parse, tcl)
+ struct parseunit *parse;
+ parsectl_t *tcl;
+{
+ return parse_timecode(tcl, &parse->parseio);
+}
+
+
+/*--------------------------------------------------
+ * local receive
+ */
+static void
+local_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ struct parseunit *parse = (struct parseunit *)rbufp->recv_srcclock;
+ register int count;
+ register char *s;
+#ifdef FREEBSD_CONRAD
+ struct timeval foo;
+#endif
+
+ /*
+ * eat all characters, parsing then and feeding complete samples
+ */
+ count = rbufp->recv_length;
+ s = rbufp->recv_buffer;
+#ifdef FREEBSD_CONRAD
+ ioctl(parse->fd,TIOCTIMESTAMP,&foo);
+ TVTOTS(&foo, &rbufp->recv_time);
+ rbufp->recv_time.l_uf += TS_ROUNDBIT;
+ rbufp->recv_time.l_ui += JAN_1970;
+ rbufp->recv_time.l_uf &= TS_MASK;
+#endif
+
+ while (count--)
+ {
+ if (parse_ioread(&parse->parseio, *s++, &rbufp->recv_time))
+ {
+ /*
+ * got something good to eat
+ */
+#ifdef PPSPPS
+ if (!PARSE_PPS(parse->parseio.parse_dtime.parse_state) &&
+ (parse->flags & PARSE_PPSCLOCK))
+ {
+ l_fp ts;
+ struct ppsclockev ev;
+
+ if (ioctl(parse->fd, CIOGETEV, (caddr_t)&ev) == 0)
+ {
+ if (ev.serial != parse->ppsserial)
+ {
+ /*
+ * add PPS time stamp if available via ppsclock module
+ * and not supplied already.
+ */
+ if (!buftvtots((const char *)&ev.tv, &ts))
+ {
+ syslog(LOG_ERR,"parse: local_receive: timestamp conversion error (buftvtots) (ppsclockev.tv)");
+ }
+ else
+ {
+ parse->parseio.parse_dtime.parse_ptime.fp = ts;
+ parse->parseio.parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
+ }
+ }
+ parse->ppsserial = ev.serial;
+ }
+ }
+#endif
+ parse_process(parse, &parse->parseio.parse_dtime);
+ parse_iodone(&parse->parseio);
+ }
+ }
+}
+
+/*--------------------------------------------------
+ * local poll
+ */
+static void
+local_poll(parse)
+ struct parseunit *parse;
+{
+ register int fd, i, rtc;
+ fd_set fdmask;
+ struct timeval timeout, starttime, curtime, selecttime;
+ static struct timeval null_time = { 0, 0};
+ timestamp_t ts;
+
+ FD_ZERO(&fdmask);
+ fd = parse->fd;
+ FD_SET(fd, &fdmask);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 500000; /* 1.5 sec */
+
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+
+ if (GETTIMEOFDAY(&starttime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+
+ selecttime = timeout;
+
+ do
+ {
+ while ((rtc = select(fd + 1, &fdmask, 0, 0, &selecttime)) != 1)
+ {
+ /* no data from the radio clock */
+
+ if (rtc == -1)
+ {
+ if (errno == EINTR)
+ {
+ if (GETTIMEOFDAY(&curtime, 0L) == -1)
+ {
+ syslog(LOG_ERR,"gettimeofday failed: %m");
+ exit(1);
+ }
+ selecttime.tv_sec = curtime.tv_sec - starttime.tv_sec;
+ if (curtime.tv_usec < starttime.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + curtime.tv_usec - starttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = curtime.tv_usec - starttime.tv_usec;
+ }
+
+
+ if (!timercmp(&selecttime, &timeout, >))
+ {
+ /*
+ * calculate residual timeout value
+ */
+ selecttime.tv_sec = timeout.tv_sec - selecttime.tv_sec;
+
+ if (selecttime.tv_usec > timeout.tv_usec)
+ {
+ selecttime.tv_sec -= 1;
+ selecttime.tv_usec = 1000000 + timeout.tv_usec - selecttime.tv_usec;
+ }
+ else
+ {
+ selecttime.tv_usec = timeout.tv_usec - selecttime.tv_usec;
+ }
+
+ FD_SET(fd, &fdmask);
+ continue;
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device (select() error: %m)", CL_UNIT(parse->unit));
+ }
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device", CL_UNIT(parse->unit));
+ }
+
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ return;
+ }
+
+ /*
+ * at least 1 character is available - gobble everthing up that is available
+ */
+ do
+ {
+ char inbuf[256];
+
+ register char *s = inbuf;
+
+ rtc = i = read(fd, inbuf, sizeof(inbuf));
+
+ get_systime(&ts.fp);
+
+ while (i-- > 0)
+ {
+ if (parse_ioread(&parse->parseio, *s++, ts))
+ {
+ /*
+ * got something good to eat
+ */
+ parse_process(parse, &parse->parseio.parse_dtime);
+ parse_iodone(&parse->parseio);
+ /*
+ * done if no more characters are available
+ */
+ FD_SET(fd, &fdmask);
+ if ((i == 0) &&
+ (select(fd + 1, &fdmask, 0, 0, &null_time) == 0))
+ return;
+ }
+ }
+ FD_SET(fd, &fdmask);
+ } while ((rtc = select(fd + 1, &fdmask, 0, 0, &null_time)) == 1);
+ FD_SET(fd, &fdmask);
+ } while (1);
+}
+
+/*--------------------------------------------------
+ * init_iobinding - find and initialize lower layers
+ */
+static bind_t *
+init_iobinding(parse)
+ struct parseunit *parse;
+{
+ register bind_t *b = io_bindings;
+
+ while (b->bd_description != (char *)0)
+ {
+ if ((*b->bd_init)(parse))
+ {
+ return b;
+ }
+ b++;
+ }
+ return (bind_t *)0;
+}
+
+/**===========================================================================
+ ** support routines
+ **/
+
+/*--------------------------------------------------
+ * convert a flag field to a string
+ */
+static char *
+parsestate(state, buffer)
+ unsigned LONG state;
+ char *buffer;
+{
+ static struct bits
+ {
+ unsigned LONG bit;
+ char *name;
+ } flagstrings[] =
+ {
+ { PARSEB_ANNOUNCE, "DST SWITCH WARNING" },
+ { PARSEB_POWERUP, "NOT SYNCHRONIZED" },
+ { PARSEB_NOSYNC, "TIME CODE NOT CONFIRMED" },
+ { PARSEB_DST, "DST" },
+ { PARSEB_UTC, "UTC DISPLAY" },
+ { PARSEB_LEAPADD, "LEAP ADD WARNING" },
+ { PARSEB_LEAPDEL, "LEAP DELETE WARNING" },
+ { PARSEB_LEAPSECOND, "LEAP SECOND" },
+ { PARSEB_ALTERNATE,"ALTERNATE ANTENNA" },
+ { PARSEB_TIMECODE, "TIME CODE" },
+ { PARSEB_PPS, "PPS" },
+ { PARSEB_POSITION, "POSITION" },
+ { 0 }
+ };
+
+ static struct sbits
+ {
+ unsigned LONG bit;
+ char *name;
+ } sflagstrings[] =
+ {
+ { PARSEB_S_LEAP, "LEAP INDICATION" },
+ { PARSEB_S_PPS, "PPS SIGNAL" },
+ { PARSEB_S_ANTENNA, "ANTENNA" },
+ { PARSEB_S_POSITION, "POSITION" },
+ { 0 }
+ };
+ int i;
+
+ *buffer = '\0';
+
+ i = 0;
+ while (flagstrings[i].bit)
+ {
+ if (flagstrings[i].bit & state)
+ {
+ if (buffer[0])
+ strcat(buffer, "; ");
+ strcat(buffer, flagstrings[i].name);
+ }
+ i++;
+ }
+
+ if (state & (PARSEB_S_LEAP|PARSEB_S_ANTENNA|PARSEB_S_PPS|PARSEB_S_POSITION))
+ {
+ register char *s, *t;
+
+ if (buffer[0])
+ strcat(buffer, "; ");
+
+ strcat(buffer, "(");
+
+ t = s = buffer + strlen(buffer);
+
+ i = 0;
+ while (sflagstrings[i].bit)
+ {
+ if (sflagstrings[i].bit & state)
+ {
+ if (t != s)
+ {
+ strcpy(t, "; ");
+ t += 2;
+ }
+
+ strcpy(t, sflagstrings[i].name);
+ t += strlen(t);
+ }
+ i++;
+ }
+ strcpy(t, ")");
+ }
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * convert a status flag field to a string
+ */
+static char *
+parsestatus(state, buffer)
+ unsigned LONG state;
+ char *buffer;
+{
+ static struct bits
+ {
+ unsigned LONG bit;
+ char *name;
+ } flagstrings[] =
+ {
+ { CVT_OK, "CONVERSION SUCCESSFUL" },
+ { CVT_NONE, "NO CONVERSION" },
+ { CVT_FAIL, "CONVERSION FAILED" },
+ { CVT_BADFMT, "ILLEGAL FORMAT" },
+ { CVT_BADDATE, "DATE ILLEGAL" },
+ { CVT_BADTIME, "TIME ILLEGAL" },
+ { 0 }
+ };
+ int i;
+
+ *buffer = '\0';
+
+ i = 0;
+ while (flagstrings[i].bit)
+ {
+ if (flagstrings[i].bit & state)
+ {
+ if (buffer[0])
+ strcat(buffer, "; ");
+ strcat(buffer, flagstrings[i].name);
+ }
+ i++;
+ }
+
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * convert a clock status flag field to a string
+ */
+static char *
+clockstatus(state)
+ unsigned LONG state;
+{
+ static char buffer[20];
+ static struct status
+ {
+ unsigned LONG value;
+ char *name;
+ } flagstrings[] =
+ {
+ { CEVNT_NOMINAL, "NOMINAL" },
+ { CEVNT_TIMEOUT, "NO RESPONSE" },
+ { CEVNT_BADREPLY,"BAD FORMAT" },
+ { CEVNT_FAULT, "FAULT" },
+ { CEVNT_PROP, "PROPAGATION DELAY" },
+ { CEVNT_BADDATE, "ILLEGAL DATE" },
+ { CEVNT_BADTIME, "ILLEGAL TIME" },
+ { ~0 }
+ };
+ int i;
+
+ i = 0;
+ while (flagstrings[i].value != ~0)
+ {
+ if (flagstrings[i].value == state)
+ {
+ return flagstrings[i].name;
+ }
+ i++;
+ }
+
+ sprintf(buffer, "unknown #%d", state);
+
+ return buffer;
+}
+
+/*--------------------------------------------------
+ * mkascii - make a printable ascii string
+ * assumes (unless defined better) 7-bit ASCII
+ */
+#ifndef isprint
+#define isprint(_X_) (((_X_) > 0x1F) && ((_X_) < 0x7F))
+#endif
+
+static char *
+mkascii(buffer, blen, src, srclen)
+ register char *buffer;
+ register LONG blen;
+ register char *src;
+ register LONG srclen;
+{
+ register char *b = buffer;
+ register char *endb = (char *)0;
+
+ if (blen < 4)
+ return (char *)0; /* don't bother with mini buffers */
+
+ endb = buffer + blen - 4;
+
+ blen--; /* account for '\0' */
+
+ while (blen && srclen--)
+ {
+ if ((*src != '\\') && isprint(*src))
+ { /* printables are easy... */
+ *buffer++ = *src++;
+ blen--;
+ }
+ else
+ {
+ if (blen < 4)
+ {
+ while (blen--)
+ {
+ *buffer++ = '.';
+ }
+ *buffer = '\0';
+ return b;
+ }
+ else
+ {
+ if (*src == '\\')
+ {
+ strcpy(buffer,"\\\\");
+ buffer += 2;
+ blen -= 2;
+ }
+ else
+ {
+ sprintf(buffer, "\\x%02x", *src++);
+ blen -= 4;
+ buffer += 4;
+ }
+ }
+ }
+ if (srclen && !blen && endb) /* overflow - set last chars to ... */
+ strcpy(endb, "...");
+ }
+
+ *buffer = '\0';
+ return b;
+}
+
+
+/*--------------------------------------------------
+ * l_mktime - make representation of a relative time
+ */
+static char *
+l_mktime(delta)
+ unsigned LONG delta;
+{
+ unsigned LONG tmp, m, s;
+ static char buffer[40];
+
+ buffer[0] = '\0';
+
+ if ((tmp = delta / (60*60*24)) != 0)
+ {
+ sprintf(buffer, "%dd+", tmp);
+ delta -= tmp * 60*60*24;
+ }
+
+ s = delta % 60;
+ delta /= 60;
+ m = delta % 60;
+ delta /= 60;
+
+ sprintf(buffer+strlen(buffer), "%02d:%02d:%02d",
+ delta, m, s);
+
+ return buffer;
+}
+
+
+/*--------------------------------------------------
+ * parse_statistics - list summary of clock states
+ */
+static void
+parse_statistics(parse)
+ register struct parseunit *parse;
+{
+ register int i;
+
+ syslog(LOG_INFO, "PARSE receiver #%d: running time: %s",
+ CL_UNIT(parse->unit),
+ l_mktime(current_time - parse->timestarted));
+
+ syslog(LOG_INFO, "PARSE receiver #%d: current status: %s",
+ CL_UNIT(parse->unit),
+ clockstatus(parse->status));
+
+ for (i = 0; i <= CEVNT_MAX; i++)
+ {
+ register unsigned LONG stime;
+ register unsigned LONG percent, div = current_time - parse->timestarted;
+
+ percent = stime = PARSE_STATETIME(parse, i);
+
+ while (((unsigned LONG)(~0) / 10000) < percent)
+ {
+ percent /= 10;
+ div /= 10;
+ }
+
+ if (div)
+ percent = (percent * 10000) / div;
+ else
+ percent = 10000;
+
+ if (stime)
+ syslog(LOG_INFO, "PARSE receiver #%d: state %18s: %13s (%3d.%02d%%)",
+ CL_UNIT(parse->unit),
+ clockstatus(i),
+ l_mktime(stime),
+ percent / 100, percent % 100);
+ }
+}
+
+/*--------------------------------------------------
+ * cparse_statistics - wrapper for statistics call
+ */
+static void
+cparse_statistics(peer)
+ register struct peer *peer;
+{
+ register struct parseunit *parse = (struct parseunit *)peer;
+
+ parse_statistics(parse);
+ parse->stattimer.event_time = current_time + PARSESTATISTICS;
+ TIMER_ENQUEUE(timerqueue, &parse->stattimer);
+}
+
+/**===========================================================================
+ ** xntp interface routines
+ **/
+
+/*--------------------------------------------------
+ * parse_init - initialize internal parse driver data
+ */
+static void
+parse_init()
+{
+ memset((caddr_t)parseunits, 0, sizeof parseunits);
+}
+
+
+/*--------------------------------------------------
+ * parse_shutdown - shut down a PARSE clock
+ */
+static void
+parse_shutdown(unit)
+ int unit;
+{
+ register struct parseunit *parse;
+
+ unit = CL_UNIT(unit);
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit invalid (max %d)",
+ unit,MAXUNITS);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (parse && !parse->peer) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_shutdown: INTERNAL ERROR, unit not in use", unit);
+ return;
+ }
+
+ /*
+ * print statistics a last time and
+ * stop statistics machine
+ */
+ parse_statistics(parse);
+ TIMER_DEQUEUE(&parse->stattimer);
+
+#if PPSPPS
+ {
+ /*
+ * kill possible PPS association
+ */
+ if (fdpps == parse->fd)
+ fdpps = -1;
+ }
+#endif
+
+ if (parse->parse_type->cl_end)
+ {
+ parse->parse_type->cl_end(parse);
+ }
+
+ if (parse->binding)
+ PARSE_END(parse);
+
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ if (!parse->pollonly)
+ io_closeclock(&parse->io);
+ else
+ (void) close(parse->fd);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" removed",
+ CL_UNIT(parse->unit), parse->parse_type->cl_description);
+
+ parse->peer = (struct peer *)0; /* unused now */
+}
+
+/*--------------------------------------------------
+ * parse_start - open the PARSE devices and initialize data for processing
+ */
+static int
+parse_start(sysunit, peer)
+ u_int sysunit;
+ struct peer *peer;
+{
+ u_int unit;
+ int fd232, i;
+#ifdef HAVE_TERMIOS
+ struct termios tm; /* NEEDED FOR A LONG TIME ! */
+#endif
+#ifdef HAVE_SYSV_TTYS
+ struct termio tm; /* NEEDED FOR A LONG TIME ! */
+#endif
+ struct parseunit * parse;
+ char parsedev[sizeof(PARSEDEVICE)+20];
+ parsectl_t tmp_ctl;
+ u_int type;
+
+ type = CL_TYPE(sysunit);
+ unit = CL_UNIT(sysunit);
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit number invalid (max %d)",
+ unit, MAXUNITS-1);
+ return 0;
+ }
+
+ if ((type == ~0) || (clockinfo[type].cl_description == (char *)0))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unsupported clock type %d (max %d)",
+ unit, CL_REALTYPE(sysunit), ncltypes-1);
+ return 0;
+ }
+
+ if (parseunits[unit] && parseunits[unit]->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: unit in use", unit);
+ return 0;
+ }
+
+ /*
+ * Unit okay, attempt to open the device.
+ */
+ (void) sprintf(parsedev, PARSEDEVICE, unit);
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+ fd232 = open(parsedev, O_RDWR|O_NOCTTY, 0777);
+ if (fd232 == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: open of %s failed: %m", unit, parsedev);
+ return 0;
+ }
+
+ /*
+ * Looks like this might succeed. Find memory for the structure.
+ * Look to see if there are any unused ones, if not we malloc()
+ * one.
+ */
+ if (parseunits[unit])
+ {
+ parse = parseunits[unit]; /* The one we want is okay - and free */
+ }
+ else
+ {
+ for (i = 0; i < MAXUNITS; i++)
+ {
+ if (parseunits[i] && !parseunits[i]->peer)
+ break;
+ }
+ if (i < MAXUNITS)
+ {
+ /*
+ * Reclaim this one
+ */
+ parse = parseunits[i];
+ parseunits[i] = (struct parseunit *)0;
+ }
+ else
+ {
+ parse = (struct parseunit *)
+ emalloc(sizeof(struct parseunit));
+ }
+ }
+
+ memset((char *)parse, 0, sizeof(struct parseunit));
+ parseunits[unit] = parse;
+
+ /*
+ * Set up the structures
+ */
+ parse->unit = (u_char)sysunit;
+ parse->timestarted = current_time;
+ parse->lastchange = current_time;
+ /*
+ * we want to filter input for the sake of
+ * getting an impression on dispersion
+ * also we like to average the median range
+ */
+ parse->flags = PARSE_STAT_FILTER|PARSE_STAT_AVG;
+ parse->pollneeddata = 0;
+ parse->pollonly = 1; /* go for default polling mode */
+ parse->lastformat = ~0; /* assume no format known */
+ parse->status = CEVNT_TIMEOUT; /* expect the worst */
+ parse->laststatus = ~0; /* be sure to mark initial status change */
+ parse->nosynctime = 0; /* assume clock reasonable */
+ parse->lastmissed = 0; /* assume got everything */
+ parse->ppsserial = 0;
+ parse->localdata = (void *)0;
+
+ parse->parse_type = &clockinfo[type];
+
+ parse->basedelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */
+ parse->basedelay.l_uf = parse->parse_type->cl_basedelay;
+
+ parse->ppsdelay.l_ui = 0; /* we can only pre-configure delays less than 1 second */
+ parse->ppsdelay.l_uf = parse->parse_type->cl_ppsdelay;
+
+ peer->rootdelay = parse->parse_type->cl_rootdelay;
+ peer->sstclktype = parse->parse_type->cl_type;
+ peer->precision = sys_precision;
+ peer->stratum = STRATUM_REFCLOCK;
+ if (peer->stratum <= 1)
+ memmove((char *)&peer->refid, parse->parse_type->cl_id, 4);
+ else
+ peer->refid = htonl(PARSEHSREFID);
+
+ parse->fd = fd232;
+
+ parse->peer = peer; /* marks it also as busy */
+
+ parse->binding = init_iobinding(parse);
+
+ if (parse->binding == (bind_t *)0)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: io sub system initialisation failed.");
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+ /*
+ * configure terminal line
+ */
+ if (TTY_GETATTR(fd232, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcgetattr(%d, &tm): %m", unit, fd232);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ else
+ {
+#ifndef _PC_VDISABLE
+ memset((char *)tm.c_cc, 0, sizeof(tm.c_cc));
+#else
+ int disablec;
+ errno = 0; /* pathconf can deliver -1 without changing errno ! */
+
+ disablec = fpathconf(parse->fd, _PC_VDISABLE);
+ if (disablec == -1 && errno)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: fpathconf(fd, _PC_VDISABLE): %m", CL_UNIT(parse->unit));
+ memset((char *)tm.c_cc, 0, sizeof(tm.c_cc)); /* best guess */
+ }
+ else
+ if (disablec != -1)
+ memset((char *)tm.c_cc, disablec, sizeof(tm.c_cc));
+#endif
+
+ tm.c_cflag = clockinfo[type].cl_cflag;
+ tm.c_iflag = clockinfo[type].cl_iflag;
+ tm.c_oflag = clockinfo[type].cl_oflag;
+ tm.c_lflag = clockinfo[type].cl_lflag;
+#ifdef FREEBSD_CONRAD
+ tm.c_ispeed = 50;
+ tm.c_ospeed = 50;
+#endif
+ if (TTY_SETATTR(fd232, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: tcsetattr(%d, &tm): %m", unit, fd232);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ }
+
+ /*
+ * as we always(?) get 8 bit chars we want to be
+ * sure, that the upper bits are zero for less
+ * than 8 bit I/O - so we pass that information on.
+ * note that there can be only one bit count format
+ * per file descriptor
+ */
+
+ switch (tm.c_cflag & CSIZE)
+ {
+ case CS5:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS5;
+ break;
+
+ case CS6:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS6;
+ break;
+
+ case CS7:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS7;
+ break;
+
+ case CS8:
+ tmp_ctl.parsesetcs.parse_cs = PARSE_IO_CS8;
+ break;
+ }
+
+ if (!PARSE_SETCS(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setcs() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+#ifdef FREEBSD_CONRAD
+ {
+ int i,j;
+ struct timeval tv;
+ ioctl(parse->fd,TIOCTIMESTAMP,&tv);
+ j = TIOCM_RTS;
+ i = ioctl(fd232, TIOCMBIC, &j);
+ if (i < 0) {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: lowrts_poll: failed to lower RTS: %m",
+ CL_UNIT(parse->unit));
+ }
+ }
+#endif
+
+ strcpy(tmp_ctl.parseformat.parse_buffer, parse->parse_type->cl_format);
+ tmp_ctl.parseformat.parse_count = strlen(tmp_ctl.parseformat.parse_buffer);
+
+ if (!PARSE_SETFMT(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setfmt() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+#ifdef TCFLSH
+ /*
+ * get rid of all IO accumulated so far
+ */
+ {
+#ifndef TCIOFLUSH
+#define TCIOFLUSH 2
+#endif
+ int flshcmd = TCIOFLUSH;
+
+ (void) ioctl(parse->fd, TCFLSH, (caddr_t)&flshcmd);
+ }
+#endif
+
+ tmp_ctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS;
+
+ if (!PARSE_SETSTAT(parse, &tmp_ctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_setstat() FAILED.", unit);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+
+ /*
+ * try to do any special initializations
+ */
+ if (parse->parse_type->cl_init)
+ {
+ if (parse->parse_type->cl_init(parse))
+ {
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0; /* well, ok - special initialisation broke */
+ }
+ }
+
+ if (!(parse->parse_type->cl_flags & PARSE_F_POLLONLY) &&
+ (CL_PPS(parse->unit) || (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY)))
+ {
+ /*
+ * Insert in async io device list.
+ */
+ parse->io.clock_recv = parse->binding->bd_receive; /* pick correct receive routine */
+ parse->io.srcclock = (caddr_t)parse;
+ parse->io.datalen = 0;
+ parse->io.fd = parse->fd; /* replicated, but what the heck */
+ if (!io_addclock(&parse->io))
+ {
+ if (parse->parse_type->cl_flags & PARSE_F_NOPOLLONLY)
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_start: addclock %s fails (ABORT - clock type requires async io)", CL_UNIT(parse->unit), parsedev);
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ else
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: parse_start: addclock %s fails (switching to polling mode)", CL_UNIT(parse->unit), parsedev);
+ }
+ }
+ else
+ {
+ parse->pollonly = 0; /*
+ * update at receipt of time_stamp - also
+ * supports PPS processing
+ */
+ }
+ }
+
+#ifdef PPSPPS
+ if (parse->pollonly || (parse->parse_type->cl_flags & PARSE_F_PPSPPS))
+ {
+ if (fdpps == -1)
+ {
+ fdpps = parse->fd;
+ if (!PARSE_DISABLE(parse))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_start: parse_disable() FAILED", CL_UNIT(parse->unit));
+ parse_shutdown(parse->unit); /* let our cleaning staff do the work */
+ return 0;
+ }
+ }
+ else
+ {
+ syslog(LOG_NOTICE, "PARSE receiver #%d: parse_start: loopfilter PPS already active - no PPS via CIOGETEV", CL_UNIT(parse->unit));
+ }
+ }
+#endif
+
+ /*
+ * wind up statistics timer
+ */
+ parse->stattimer.peer = (struct peer *)parse; /* we know better, but what the heck */
+ parse->stattimer.event_handler = cparse_statistics;
+ parse->stattimer.event_time = current_time + PARSESTATISTICS;
+ TIMER_ENQUEUE(timerqueue, &parse->stattimer);
+
+ /*
+ * get out Copyright information once
+ */
+ if (!notice)
+ {
+ syslog(LOG_INFO, "NTP PARSE support: Copyright (c) 1989-1993, Frank Kardel");
+ notice = 1;
+ }
+
+ /*
+ * print out configuration
+ */
+ syslog(LOG_INFO, "PARSE receiver #%d: reference clock \"%s\" (device %s) added",
+ CL_UNIT(parse->unit),
+ parse->parse_type->cl_description, parsedev);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: Stratum %d, %sPPS support, trust time %s, precision %d",
+ CL_UNIT(parse->unit),
+ parse->peer->stratum, (parse->pollonly || !CL_PPS(parse->unit)) ? "no " : "",
+ l_mktime(parse->parse_type->cl_maxunsync), parse->peer->precision);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: rootdelay %s s, phaseadjust %s s, %s IO handling",
+ CL_UNIT(parse->unit),
+ ufptoa(parse->parse_type->cl_rootdelay, 6),
+ lfptoa(&parse->basedelay, 8),
+ parse->binding->bd_description);
+
+ syslog(LOG_INFO, "PARSE receiver #%d: Format recognition: %s", CL_UNIT(parse->unit),
+ !(*parse->parse_type->cl_format) ? "<AUTOMATIC>" : parse->parse_type->cl_format);
+
+#ifdef PPSPPS
+ syslog(LOG_INFO, "PARSE receiver #%d: %sCD PPS support",
+ CL_UNIT(parse->unit),
+ (fdpps == parse->fd) ? "" : "NO ");
+#endif
+
+ return 1;
+}
+
+/*--------------------------------------------------
+ * parse_poll - called by the transmit procedure
+ */
+static void
+parse_poll(unit, peer)
+ int unit;
+ struct peer *peer;
+{
+ register struct parseunit *parse;
+
+ unit = CL_UNIT(unit);
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit invalid",
+ unit);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (!parse->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll: INTERNAL: unit unused",
+ unit);
+ return;
+ }
+
+ if (peer != parse->peer)
+ {
+ syslog(LOG_ERR,
+ "PARSE receiver #%d: poll: INTERNAL: peer incorrect",
+ unit);
+ return;
+ }
+
+ /*
+ * Update clock stat counters
+ */
+ parse->polls++;
+
+ /*
+ * in PPS mode we just mark that we want the next sample
+ * for the clock filter
+ */
+ if (!parse->pollonly)
+ {
+ if (parse->pollneeddata)
+ {
+ /*
+ * bad news - didn't get a response last time
+ */
+ parse->noresponse++;
+ parse->lastmissed = current_time;
+ parse_event(parse, CEVNT_TIMEOUT);
+
+ syslog(LOG_WARNING, "PARSE receiver #%d: no data from device within poll interval", CL_UNIT(parse->unit));
+ }
+ parse->pollneeddata = 1;
+ if (parse->parse_type->cl_poll)
+ {
+ parse->parse_type->cl_poll(parse);
+ }
+ return;
+ }
+
+ /*
+ * the following code is only executed only when polling is used
+ */
+
+ PARSE_POLL(parse);
+}
+
+/*--------------------------------------------------
+ * parse_leap - called when a leap second occurs
+ */
+
+static void
+parse_leap()
+{
+ /*
+ * PARSE encodes the LEAP correction direction.
+ * For timecodes that do not pass on the leap correction direction
+ * the default PARSEB_LEAPADD must be used. It may then be modified
+ * with a fudge flag (flag2).
+ */
+}
+
+
+/*--------------------------------------------------
+ * parse_control - set fudge factors, return statistics
+ */
+static void
+parse_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct parseunit *parse;
+ parsectl_t tmpctl;
+ unsigned LONG type;
+ static char outstatus[400]; /* status output buffer */
+
+ type = CL_TYPE(unit);
+ unit = CL_UNIT(unit);
+
+ if (out)
+ {
+ out->lencode = 0;
+ out->lastcode = 0;
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ out->kv_list = (struct ctl_var *)0;
+ }
+
+ if (unit >= MAXUNITS)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (max %d)",
+ unit, MAXUNITS-1);
+ return;
+ }
+
+ parse = parseunits[unit];
+
+ if (!parse || !parse->peer)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: unit invalid (UNIT INACTIVE)",
+ unit);
+ return;
+ }
+
+ if (in)
+ {
+ if (in->haveflags & CLK_HAVETIME1)
+ parse->basedelay = in->fudgetime1;
+
+ if (in->haveflags & CLK_HAVETIME2)
+ {
+ parse->ppsdelay = in->fudgetime2;
+ }
+
+ if (in->haveflags & CLK_HAVEVAL1)
+ {
+ parse->peer->stratum = (u_char)(in->fudgeval1 & 0xf);
+ if (parse->peer->stratum <= 1)
+ memmove((char *)&parse->peer->refid,
+ parse->parse_type->cl_id,
+ 4);
+ else
+ parse->peer->refid = htonl(PARSEHSREFID);
+ }
+
+ /*
+ * NOT USED - yet
+ *
+ if (in->haveflags & CLK_HAVEVAL2)
+ {
+ }
+ */
+ if (in->haveflags & (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
+ {
+ parse->flags = (in->flags & (CLK_FLAG1|CLK_FLAG2|CLK_FLAG3|CLK_FLAG4)) |
+ (parse->flags & ~PARSE_STAT_FLAGS);
+ }
+
+ if (in->haveflags & (CLK_HAVEVAL2|CLK_HAVETIME2|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4))
+ {
+ parsectl_t tmpctl;
+ tmpctl.parsestatus.flags = parse->flags & PARSE_STAT_FLAGS;
+
+ if (!PARSE_SETSTAT(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_setstat() FAILED", unit);
+ }
+ }
+ }
+
+ if (out)
+ {
+ register unsigned LONG sum = 0;
+ register char *t, *tt;
+ register struct tm *tm;
+ register short utcoff;
+ register char sign;
+ register int i;
+ time_t tim;
+
+ outstatus[0] = '\0';
+
+ out->haveflags = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3;
+ out->clockdesc = parse->parse_type->cl_description;
+
+ out->fudgetime1 = parse->basedelay;
+
+ out->fudgetime2 = parse->ppsdelay;
+
+ out->fudgeval1 = (LONG)parse->peer->stratum;
+
+ out->fudgeval2 = 0;
+
+ out->flags = parse->flags & PARSE_STAT_FLAGS;
+
+ out->type = REFCLK_PARSE;
+
+ /*
+ * figure out skew between PPS and RS232 - just for informational
+ * purposes - returned in time2 value
+ */
+ if (PARSE_SYNC(parse->time.parse_state))
+ {
+ if (PARSE_PPS(parse->time.parse_state) && PARSE_TIMECODE(parse->time.parse_state))
+ {
+ l_fp off;
+
+ /*
+ * we have a PPS and RS232 signal - calculate the skew
+ * WARNING: assumes on TIMECODE == PULSE (timecode after pulse)
+ */
+ off = parse->time.parse_stime.fp;
+ L_SUB(&off, &parse->time.parse_ptime.fp); /* true offset */
+ tt = add_var(&out->kv_list, 40, RO);
+ sprintf(tt, "refclock_ppsskew=%s", lfptoms(&off, 6));
+ }
+ }
+
+ if (PARSE_PPS(parse->time.parse_state))
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_ppstime=\"%s\"", prettydate(&parse->time.parse_ptime.fp));
+ }
+
+ /*
+ * all this for just finding out the +-xxxx part (there are always
+ * new and changing fields in the standards 8-().
+ *
+ * but we do it for the human user...
+ */
+ tim = parse->time.parse_time.fp.l_ui - JAN_1970;
+ tm = gmtime(&tim);
+ utcoff = tm->tm_hour * 60 + tm->tm_min;
+ tm = localtime(&tim);
+ utcoff = tm->tm_hour * 60 + tm->tm_min - utcoff + 12 * 60;
+ utcoff += 24 * 60;
+ utcoff %= 24 * 60;
+ utcoff -= 12 * 60;
+ if (utcoff < 0)
+ {
+ utcoff = -utcoff;
+ sign = '-';
+ }
+ else
+ {
+ sign = '+';
+ }
+
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_time=\"");
+ tt += strlen(tt);
+
+ if (parse->time.parse_time.fp.l_ui == 0)
+ {
+ strcpy(tt, "<UNDEFINED>\"");
+ }
+ else
+ {
+ strcpy(tt, prettydate(&parse->time.parse_time.fp));
+ t = tt + strlen(tt);
+
+ sprintf(t, " (%c%02d%02d)\"", sign, utcoff / 60, utcoff % 60);
+ }
+
+ if (!PARSE_GETTIMECODE(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_control: parse_timecode() FAILED", unit);
+ }
+ else
+ {
+ tt = add_var(&out->kv_list, 128, RO|DEF);
+ sprintf(tt, "refclock_status=\"");
+ tt += strlen(tt);
+
+ /*
+ * copy PPS flags from last read transaction (informational only)
+ */
+ tmpctl.parsegettc.parse_state |= parse->time.parse_state &
+ (PARSEB_PPS|PARSEB_S_PPS);
+
+ (void) parsestate(tmpctl.parsegettc.parse_state, tt);
+
+ strcat(tt, "\"");
+
+ if (tmpctl.parsegettc.parse_count)
+ mkascii(outstatus+strlen(outstatus), sizeof(outstatus)- strlen(outstatus) - 1,
+ tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1);
+
+ parse->badformat += tmpctl.parsegettc.parse_badformat;
+ }
+
+ tmpctl.parseformat.parse_format = tmpctl.parsegettc.parse_format;
+
+ if (!PARSE_GETFMT(parse, &tmpctl))
+ {
+ syslog (LOG_ERR, "PARSE receiver #%d: parse_control: parse_getfmt() FAILED", unit);
+ }
+ else
+ {
+ tt = add_var(&out->kv_list, 80, RO|DEF);
+ sprintf(tt, "refclock_format=\"");
+
+ strncat(tt, tmpctl.parseformat.parse_buffer, tmpctl.parseformat.parse_count);
+ strcat(tt,"\"");
+ }
+
+ /*
+ * gather state statistics
+ */
+
+ tt = add_var(&out->kv_list, 200, RO|DEF);
+ strcpy(tt, "refclock_states=\"");
+ tt += strlen(tt);
+
+ for (i = 0; i <= CEVNT_MAX; i++)
+ {
+ register unsigned LONG stime;
+ register unsigned LONG div = current_time - parse->timestarted;
+ register unsigned LONG percent;
+
+ percent = stime = PARSE_STATETIME(parse, i);
+
+ while (((unsigned LONG)(~0) / 10000) < percent)
+ {
+ percent /= 10;
+ div /= 10;
+ }
+
+ if (div)
+ percent = (percent * 10000) / div;
+ else
+ percent = 10000;
+
+ if (stime)
+ {
+ sprintf(tt, "%s%s%s: %s (%d.%02d%%)",
+ sum ? "; " : "",
+ (parse->status == i) ? "*" : "",
+ clockstatus(i),
+ l_mktime(stime),
+ percent / 100, percent % 100);
+ sum += stime;
+ tt += strlen(tt);
+ }
+ }
+
+ sprintf(tt, "; running time: %s\"", l_mktime(sum));
+
+ tt = add_var(&out->kv_list, 32, RO);
+ sprintf(tt, "refclock_id=\"%s\"", parse->parse_type->cl_id);
+
+ tt = add_var(&out->kv_list, 80, RO);
+ sprintf(tt, "refclock_iomode=\"%s\"", parse->binding->bd_description);
+
+ tt = add_var(&out->kv_list, 128, RO);
+ sprintf(tt, "refclock_driver_version=\"refclock_parse.c,v 3.53 1994/03/25 13:07:39 kardel Exp\"");
+
+ out->lencode = strlen(outstatus);
+ out->lastcode = outstatus;
+ out->timereset = parse->timestarted;
+ out->polls = parse->polls;
+ out->noresponse = parse->noresponse;
+ out->badformat = parse->badformat;
+ out->baddata = parse->baddata;
+ out->lastevent = parse->lastevent;
+ out->currentstatus = parse->status;
+ }
+}
+
+/**===========================================================================
+ ** processing routines
+ **/
+
+/*--------------------------------------------------
+ * event handling - note that nominal events will also be posted
+ */
+static void
+parse_event(parse, event)
+ struct parseunit *parse;
+ int event;
+{
+ if (parse->status != (u_char) event)
+ {
+ parse->statetime[parse->status] += current_time - parse->lastchange;
+ parse->lastchange = current_time;
+
+ parse->status = (u_char)event;
+ if (event != CEVNT_NOMINAL)
+ parse->lastevent = parse->status;
+
+ report_event(EVNT_PEERCLOCK, parse->peer);
+ }
+}
+
+/*--------------------------------------------------
+ * process a PARSE time sample
+ */
+static void
+parse_process(parse, parsetime)
+ struct parseunit *parse;
+ parsetime_t *parsetime;
+{
+ unsigned char leap;
+ struct timeval usecdisp;
+ l_fp off, rectime, reftime, dispersion;
+
+ /*
+ * check for changes in conversion status
+ * (only one for each new status !)
+ */
+ if (parse->laststatus != parsetime->parse_status)
+ {
+ char buffer[200];
+
+ syslog(LOG_WARNING, "PARSE receiver #%d: conversion status \"%s\"",
+ CL_UNIT(parse->unit), parsestatus(parsetime->parse_status, buffer));
+
+ if ((parsetime->parse_status & CVT_MASK) == CVT_FAIL)
+ {
+ /*
+ * tell more about the story - list time code
+ * there is a slight change for a race condition and
+ * the time code might be overwritten by the next packet
+ */
+ parsectl_t tmpctl;
+
+ if (!PARSE_GETTIMECODE(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_process: parse_timecode() FAILED", CL_UNIT(parse->unit));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "PARSE receiver #%d: FAILED TIMECODE: \"%s\"",
+ CL_UNIT(parse->unit), mkascii(buffer, sizeof buffer, tmpctl.parsegettc.parse_buffer, tmpctl.parsegettc.parse_count - 1));
+ parse->badformat += tmpctl.parsegettc.parse_badformat;
+ }
+ }
+
+ parse->laststatus = parsetime->parse_status;
+ }
+
+ /*
+ * examine status and post appropriate events
+ */
+ if ((parsetime->parse_status & CVT_MASK) != CVT_OK)
+ {
+ /*
+ * got bad data - tell the rest of the system
+ */
+ switch (parsetime->parse_status & CVT_MASK)
+ {
+ case CVT_NONE:
+ break; /* well, still waiting - timeout is handled at higher levels */
+
+ case CVT_FAIL:
+ parse->badformat++;
+ if (parsetime->parse_status & CVT_BADFMT)
+ {
+ parse_event(parse, CEVNT_BADREPLY);
+ }
+ else
+ if (parsetime->parse_status & CVT_BADDATE)
+ {
+ parse_event(parse, CEVNT_BADDATE);
+ }
+ else
+ if (parsetime->parse_status & CVT_BADTIME)
+ {
+ parse_event(parse, CEVNT_BADTIME);
+ }
+ else
+ {
+ parse_event(parse, CEVNT_BADREPLY); /* for the lack of something better */
+ }
+ }
+ return; /* skip the rest - useless */
+ }
+
+ /*
+ * check for format changes
+ * (in case somebody has swapped clocks 8-)
+ */
+ if (parse->lastformat != parsetime->parse_format)
+ {
+ parsectl_t tmpctl;
+
+ tmpctl.parseformat.parse_format = parsetime->parse_format;
+
+ if (!PARSE_GETFMT(parse, &tmpctl))
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: parse_getfmt() FAILED", CL_UNIT(parse->unit));
+ }
+ else
+ {
+ syslog(LOG_INFO, "PARSE receiver #%d: new packet format \"%s\"",
+ CL_UNIT(parse->unit), tmpctl.parseformat.parse_buffer);
+ }
+ parse->lastformat = parsetime->parse_format;
+ }
+
+ /*
+ * now, any changes ?
+ */
+ if (parse->time.parse_state != parsetime->parse_state)
+ {
+ char tmp1[200];
+ char tmp2[200];
+ /*
+ * something happend
+ */
+
+ (void) parsestate(parsetime->parse_state, tmp1);
+ (void) parsestate(parse->time.parse_state, tmp2);
+
+ syslog(LOG_INFO,"PARSE receiver #%d: STATE CHANGE: %s -> %s",
+ CL_UNIT(parse->unit), tmp2, tmp1);
+ }
+
+ /*
+ * remember for future
+ */
+ parse->time = *parsetime;
+
+ /*
+ * check to see, whether the clock did a complete powerup or lost PZF signal
+ * and post correct events for current condition
+ */
+ if (PARSE_POWERUP(parsetime->parse_state))
+ {
+ /*
+ * this is bad, as we have completely lost synchronisation
+ * well this is a problem with the receiver here
+ * for PARSE U/A 31 the lost synchronisation ist true
+ * as it is the powerup state and the time is taken
+ * from a crude real time clock chip
+ * for the PZF series this is only partly true, as
+ * PARSE_POWERUP only means that the pseudo random
+ * phase shift sequence cannot be found. this is only
+ * bad, if we have never seen the clock in the SYNC
+ * state, where the PHASE and EPOCH are correct.
+ * for reporting events the above business does not
+ * really matter, but we can use the time code
+ * even in the POWERUP state after having seen
+ * the clock in the synchronized state (PZF class
+ * receivers) unless we have had a telegram disruption
+ * after having seen the clock in the SYNC state. we
+ * thus require having seen the clock in SYNC state
+ * *after* having missed telegrams (noresponse) from
+ * the clock. one problem remains: we might use erroneously
+ * POWERUP data if the disruption is shorter than 1 polling
+ * interval. fortunately powerdowns last usually longer than 64
+ * seconds and the receiver is at least 2 minutes in the
+ * POWERUP or NOSYNC state before switching to SYNC
+ */
+ parse_event(parse, CEVNT_FAULT);
+ if (parse->nosynctime)
+ {
+ /*
+ * repeated POWERUP/NOSYNC state - look whether
+ * the message should be repeated
+ */
+ if (current_time - parse->nosynctime > PARSENOSYNCREPEAT)
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: *STILL* NOT SYNCHRONIZED (POWERUP or no PZF signal)",
+ CL_UNIT(parse->unit));
+ parse->nosynctime = current_time;
+ }
+ }
+ else
+ {
+ syslog(LOG_ERR,"PARSE receiver #%d: NOT SYNCHRONIZED",
+ CL_UNIT(parse->unit));
+ parse->nosynctime = current_time;
+ }
+ }
+ else
+ {
+ /*
+ * we have two states left
+ *
+ * SYNC:
+ * this state means that the EPOCH (timecode) and PHASE
+ * information has be read correctly (at least two
+ * successive PARSE timecodes were received correctly)
+ * this is the best possible state - full trust
+ *
+ * NOSYNC:
+ * The clock should be on phase with respect to the second
+ * signal, but the timecode has not been received correctly within
+ * at least the last two minutes. this is a sort of half baked state
+ * for PARSE U/A 31 this is bad news (clock running without timecode
+ * confirmation)
+ * PZF 535 has also no time confirmation, but the phase should be
+ * very precise as the PZF signal can be decoded
+ */
+ parse->nosynctime = 0; /* current state is better than worst state */
+
+ if (PARSE_SYNC(parsetime->parse_state))
+ {
+ /*
+ * currently completely synchronized - best possible state
+ */
+ parse->lastsync = current_time;
+ /*
+ * log OK status
+ */
+ parse_event(parse, CEVNT_NOMINAL);
+ }
+ else
+ {
+ /*
+ * we have had some problems receiving the time code
+ */
+ parse_event(parse, CEVNT_PROP);
+ }
+ }
+
+ if (PARSE_TIMECODE(parsetime->parse_state))
+ {
+ l_fp offset;
+
+ /*
+ * calculate time offset including systematic delays
+ * off = PARSE-timestamp + propagation delay - kernel time stamp
+ */
+ offset = parse->basedelay;
+
+ off = parsetime->parse_time.fp;
+
+ reftime = off;
+
+ L_ADD(&off, &offset);
+ rectime = off; /* this makes org time and xmt time somewhat artificial */
+
+ L_SUB(&off, &parsetime->parse_stime.fp);
+
+ if ((parse->flags & PARSE_STAT_FILTER) &&
+ (off.l_i > -60) &&
+ (off.l_i < 60)) /* take usec error only if within +- 60 secs */
+ {
+ struct timeval usecerror;
+ /*
+ * offset is already calculated
+ */
+ usecerror.tv_sec = parsetime->parse_usecerror / 1000000;
+ usecerror.tv_usec = parsetime->parse_usecerror % 1000000;
+
+ sTVTOTS(&usecerror, &off);
+ L_ADD(&off, &offset);
+ }
+ }
+
+ if (PARSE_PPS(parsetime->parse_state) && CL_PPS(parse->unit))
+ {
+ l_fp offset;
+
+ /*
+ * we have a PPS signal - much better than the RS232 stuff (we hope)
+ */
+ offset = parsetime->parse_ptime.fp;
+
+ L_ADD(&offset, &parse->ppsdelay);
+
+ if (PARSE_TIMECODE(parsetime->parse_state))
+ {
+ if (M_ISGEQ(off.l_i, off.l_f, -1, 0x80000000) &&
+ M_ISGEQ(0, 0x7fffffff, off.l_i, off.l_f))
+ {
+ /*
+ * RS232 offsets within [-0.5..0.5[ - take PPS offsets
+ */
+
+ if (parse->parse_type->cl_flags & PARSE_F_PPSONSECOND)
+ {
+ reftime = off = offset;
+ rectime = offset;
+ /*
+ * implied on second offset
+ */
+ off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
+ off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ }
+ else
+ {
+ /*
+ * time code describes pulse
+ */
+ off = parsetime->parse_time.fp;
+
+ rectime = reftime = off; /* take reference time - fake rectime */
+
+ L_SUB(&off, &offset); /* true offset */
+ }
+ }
+ /*
+ * take RS232 offset when PPS when out of bounds
+ */
+ }
+ else
+ {
+ /*
+ * Well, no time code to guide us - assume on second pulse
+ * and pray, that we are within [-0.5..0.5[
+ */
+ reftime = off = offset;
+ rectime = offset;
+ /*
+ * implied on second offset
+ */
+ off.l_uf = ~off.l_uf; /* map [0.5..1[ -> [-0.5..0[ */
+ off.l_ui = (off.l_f < 0) ? ~0 : 0; /* sign extend */
+ }
+ }
+ else
+ {
+ if (!PARSE_TIMECODE(parsetime->parse_state))
+ {
+ /*
+ * Well, no PPS, no TIMECODE, no more work ...
+ */
+ return;
+ }
+ }
+
+
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS) || defined(PARSEPPS)
+ if (CL_PPS(parse->unit) && !parse->pollonly && PARSE_SYNC(parsetime->parse_state))
+ {
+ /*
+ * only provide PPS information when clock
+ * is in sync
+ * thus PHASE and EPOCH are correct and PPS is not
+ * done via the CIOGETEV loopfilter mechanism
+ */
+#ifdef PPSPPS
+ if (fdpps != parse->fd)
+#endif
+ (void) pps_sample(&off);
+ }
+#endif /* PPS || PPSCLK || PPSPPS || PARSEPPS */
+
+ /*
+ * ready, unless the machine wants a sample
+ */
+ if (!parse->pollonly && !parse->pollneeddata)
+ return;
+
+ parse->pollneeddata = 0;
+
+ if (PARSE_PPS(parsetime->parse_state))
+ {
+ L_CLR(&dispersion);
+ }
+ else
+ {
+ /*
+ * convert usec dispersion into NTP TS world
+ */
+
+ usecdisp.tv_sec = parsetime->parse_usecdisp / 1000000;
+ usecdisp.tv_usec = parsetime->parse_usecdisp % 1000000;
+
+ TVTOTS(&usecdisp, &dispersion);
+ }
+
+ /*
+ * and now stick it into the clock machine
+ * samples are only valid iff lastsync is not too old and
+ * we have seen the clock in sync at least once
+ * after the last time we didn't see an expected data telegram
+ * see the clock states section above for more reasoning
+ */
+ if (((current_time - parse->lastsync) > parse->parse_type->cl_maxunsync) ||
+ (parse->lastsync <= parse->lastmissed))
+ {
+ leap = LEAP_NOTINSYNC;
+ }
+ else
+ {
+ if (PARSE_LEAPADD(parsetime->parse_state))
+ {
+ /*
+ * we pick this state also for time code that pass leap warnings
+ * without direction information (as earth is currently slowing
+ * down).
+ */
+ leap = (parse->flags & PARSE_LEAP_DELETE) ? LEAP_DELSECOND : LEAP_ADDSECOND;
+ }
+ else
+ if (PARSE_LEAPDEL(parsetime->parse_state))
+ {
+ leap = LEAP_DELSECOND;
+ }
+ else
+ {
+ leap = LEAP_NOWARNING;
+ }
+ }
+
+ refclock_receive(parse->peer, &off, 0, LFPTOFP(&dispersion), &reftime, &rectime, leap);
+}
+
+/**===========================================================================
+ ** clock polling support
+ **/
+
+struct poll_timer
+{
+ struct event timer; /* we'd like to poll a a higher rate than 1/64s */
+};
+
+typedef struct poll_timer poll_timer_t;
+
+/*--------------------------------------------------
+ * direct poll routine
+ */
+static void
+poll_dpoll(parse)
+ struct parseunit *parse;
+{
+ register int rtc;
+ register char *ps = ((poll_info_t *)parse->parse_type->cl_data)->string;
+ register int ct = ((poll_info_t *)parse->parse_type->cl_data)->count;
+
+ rtc = write(parse->fd, ps, ct);
+ if (rtc < 0)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd to clock: %m", CL_UNIT(parse->unit));
+ }
+ else
+ if (rtc != ct)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: poll_dpoll: failed to send cmd incomplete (%d of %d bytes sent)", CL_UNIT(parse->unit), rtc, ct);
+ }
+}
+
+/*--------------------------------------------------
+ * periodic poll routine
+ */
+static void
+poll_poll(parse)
+ struct parseunit *parse;
+{
+ register poll_timer_t *pt = (poll_timer_t *)parse->localdata;
+
+ poll_dpoll(parse);
+
+ if (pt != (poll_timer_t *)0)
+ {
+ pt->timer.event_time = current_time + ((poll_info_t *)parse->parse_type->cl_data)->rate;
+ TIMER_ENQUEUE(timerqueue, &pt->timer);
+ }
+}
+
+/*--------------------------------------------------
+ * init routine - setup timer
+ */
+static int
+poll_init(parse)
+ struct parseunit *parse;
+{
+ register poll_timer_t *pt;
+
+ if (((poll_info_t *)parse->parse_type->cl_data)->rate)
+ {
+ parse->localdata = (void *)malloc(sizeof(poll_timer_t));
+ memset((char *)parse->localdata, 0, sizeof(poll_timer_t));
+
+ pt = (poll_timer_t *)parse->localdata;
+
+ pt->timer.peer = (struct peer *)parse; /* well, only we know what it is */
+ pt->timer.event_handler = poll_poll;
+ poll_poll(parse);
+ }
+ else
+ {
+ parse->localdata = (void *)0;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------
+ * end routine - clean up timer
+ */
+static void
+poll_end(parse)
+ struct parseunit *parse;
+{
+ if (parse->localdata != (void *)0)
+ {
+ TIMER_DEQUEUE(&((poll_timer_t *)parse->localdata)->timer);
+ free((char *)parse->localdata);
+ parse->localdata = (void *)0;
+ }
+}
+
+/**===========================================================================
+ ** special code for special clocks
+ **/
+
+/*--------------------------------------------------
+ * trimble init routine - setup EOL and then do poll_init.
+ */
+static int
+trimble_init(parse)
+ struct parseunit *parse;
+{
+#ifdef HAVE_TERMIOS
+ struct termios tm;
+#endif
+#ifdef HAVE_SYSV_TTYS
+ struct termio tm;
+#endif
+ /*
+ * configure terminal line for trimble receiver
+ */
+ if (TTY_GETATTR(parse->fd, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcgetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ else
+ {
+ tm.c_cc[VEOL] = TRIMBLESV6_EOL;
+
+ if (TTY_SETATTR(parse->fd, &tm) == -1)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcsetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ return 0;
+ }
+ }
+ return poll_init(parse);
+}
+#endif /* defined(REFCLOCK) && defined(PARSE) */
+
+/*
+ * History:
+ *
+ * refclock_parse.c,v
+ * Revision 3.53 1994/03/25 13:07:39 kardel
+ * fixed offset calculation for large (>4 Min) offsets
+ *
+ * Revision 3.52 1994/03/03 09:58:00 kardel
+ * stick -kv in cvs is no fun
+ *
+ * Revision 3.49 1994/02/20 13:26:00 kardel
+ * rcs id cleanup
+ *
+ * Revision 3.48 1994/02/20 13:04:56 kardel
+ * parse add/delete second support
+ *
+ * Revision 3.47 1994/02/02 17:44:30 kardel
+ * rcs ids fixed
+ *
+ * Revision 3.45 1994/01/25 19:06:27 kardel
+ * 94/01/23 reconcilation
+ *
+ * Revision 3.44 1994/01/25 17:32:23 kardel
+ * settable extended variables
+ *
+ * Revision 3.43 1994/01/23 16:28:39 kardel
+ * HAVE_TERMIOS introduced
+ *
+ * Revision 3.42 1994/01/22 11:35:04 kardel
+ * added HAVE_TERMIOS
+ *
+ * Revision 3.41 1993/11/27 18:44:37 kardel
+ * can't trust GPS166 on unsync
+ *
+ * Revision 3.40 1993/11/21 18:03:36 kardel
+ * useless declaration deleted
+ *
+ * Revision 3.39 1993/11/21 15:30:15 kardel
+ * static funcitions may be declared only at outer level
+ *
+ * Revision 3.38 1993/11/15 21:26:49 kardel
+ * conditional define comments fixed
+ *
+ * Revision 3.37 1993/11/11 11:20:49 kardel
+ * declaration fixes
+ *
+ * Revision 3.36 1993/11/10 12:17:14 kardel
+ * #ifdef glitch
+ *
+ * Revision 3.35 1993/11/01 21:15:06 kardel
+ * comments updated
+ *
+ * Revision 3.34 1993/11/01 20:01:08 kardel
+ * parse Solaris support (initial version)
+ *
+ * Revision 3.33 1993/10/30 09:44:58 kardel
+ * conditional compilation flag cleanup
+ *
+ * Revision 3.32 1993/10/22 14:28:43 kardel
+ * Oct. 22nd 1993 reconcilation
+ *
+ * Revision 3.31 1993/10/10 21:19:10 kardel
+ * compilation cleanup - (minimal porting tests)
+ *
+ * Revision 3.30 1993/10/09 21:44:35 kardel
+ * syslog strings fixed
+ *
+ * Revision 3.29 1993/10/09 14:40:15 kardel
+ * default precision setting fixed
+ *
+ * Revision 3.28 1993/10/08 14:48:22 kardel
+ * Changed offset determination logic:
+ * Take the PPS offset if it is available and the time
+ * code offset is within [-0.5..0.5[, otherwise stick
+ * to the time code offset
+ *
+ * Revision 3.27 1993/10/08 00:53:17 kardel
+ * announce also simulated PPS via CIOGETEV in ntpq cl
+ *
+ * Revision 3.26 1993/10/07 23:29:35 kardel
+ * trimble fixes
+ *
+ * Revision 3.25 1993/10/06 21:13:35 kardel
+ * test reversed (CIOGETEV support)
+ *
+ * Revision 3.24 1993/10/03 20:18:26 kardel
+ * Well, values > 999999 in the usec field from uniqtime() timestamps
+ * can prove harmful.
+ *
+ * Revision 3.23 1993/10/03 19:49:54 kardel
+ * buftvtots where failing on uninitialized time stamps
+ *
+ * Revision 3.22 1993/10/03 19:11:09 kardel
+ * restructured I/O handling
+ *
+ * Revision 3.21 1993/09/29 11:30:18 kardel
+ * special init for trimble to set EOL
+ *
+ * Revision 3.20 1993/09/27 22:46:28 kardel
+ * preserve module stack if I_PUSH parse fails
+ *
+ * Revision 3.19 1993/09/27 21:10:11 kardel
+ * wrong structure member
+ *
+ * Revision 3.18 1993/09/27 13:05:06 kardel
+ * Trimble is true polling only
+ *
+ * Revision 3.17 1993/09/27 12:47:10 kardel
+ * poll string support generalized
+ *
+ * Revision 3.16 1993/09/26 23:40:56 kardel
+ * new parse driver logic
+ *
+ * Revision 3.15 1993/09/24 15:00:51 kardel
+ * Sep 23rd distribution...
+ *
+ * Revision 3.14 1993/09/22 18:21:15 kardel
+ * support ppsclock streams module (-DSTREAM -DPPSPPS -DPARSEPPS -UPARSESTREAM)
+ *
+ * Revision 3.13 1993/09/05 15:38:33 kardel
+ * not every cpp understands #error...
+ *
+ * Revision 3.12 1993/09/02 20:04:19 kardel
+ * TTY cleanup
+ *
+ * Revision 3.11 1993/09/01 21:48:47 kardel
+ * conditional cleanup
+ *
+ * Revision 3.10 1993/09/01 11:32:45 kardel
+ * assuming HAVE_POSIX_TTYS when STREAM defined
+ *
+ * Revision 3.9 1993/08/31 22:31:46 kardel
+ * SINIX-M SysVR4 integration
+ *
+ * Revision 3.8 1993/08/27 00:29:50 kardel
+ * compilation cleanup
+ *
+ * Revision 3.7 1993/08/24 22:27:30 kardel
+ * cleaned up AUTOCONF DCF77 mess 8-) - wasn't too bad
+ *
+ * Revision 3.6 1993/08/24 21:36:23 kardel
+ * casting and ifdefs
+ *
+ * Revision 3.5 1993/07/09 23:36:59 kardel
+ * HAVE_POSIX_TTYS used to produce errors 8-( - BSD driver support still lacking
+ *
+ * Revision 3.4 1993/07/09 12:42:29 kardel
+ * RAW DCF now officially released
+ *
+ * Revision 3.3 1993/07/09 11:50:37 kardel
+ * running GPS also on 960 to be able to switch GPS/DCF77
+ *
+ * Revision 3.2 1993/07/09 11:37:34 kardel
+ * Initial restructured version + GPS support
+ *
+ * Revision 3.1 1993/07/06 10:01:07 kardel
+ * DCF77 driver goes generic...
+ *
+ */
diff --git a/usr.sbin/xntpd/xntpd/refclock_omega.c b/usr.sbin/xntpd/xntpd/refclock_omega.c
index 73be84d3859b..3d4e4b91d920 100644
--- a/usr.sbin/xntpd/xntpd/refclock_omega.c
+++ b/usr.sbin/xntpd/xntpd/refclock_omega.c
@@ -83,12 +83,10 @@
#define OMEGAMAXDISPERSE (FP_SECOND/32) /* max allowed sample dispersion */
#define OMEGAPRECISION (-10) /* precision assumed (about 1 ms) */
#define OMEGAREFID "VLF\0" /* reference id */
-#define OMEGAHSREFID 0x7f7f0b0a /* 127.127.11.10 refid hi strata */
#define LENOMEGA 13 /* length of standard response */
#define GMT 0 /* hour offset from Greenwich */
#define NSTAMPS 9 /* samples collected when polled */
#define NSKEEP 5 /* samples to keep after discards */
-#define BMAX 50 /* timecode buffer length */
/*
* The OM-DC puts out the start bit of the <CR> on the second, but
@@ -167,7 +165,7 @@ struct omegaunit {
u_char leap; /* leap indicators */
u_short msec; /* millisecond of second */
u_char quality; /* quality char from last timecode */
- U_LONG yearstart; /* start of current year */
+ u_long yearstart; /* start of current year */
/*
* Status tallies
*/
@@ -193,18 +191,19 @@ static l_fp fudgefactor1[MAXUNITS];
static l_fp fudgefactor2[MAXUNITS];
static u_char stratumtouse[MAXUNITS];
static u_char readonlyclockflag[MAXUNITS];
+static U_LONG refid[MAXUNITS];
/*
* Function prototypes
*/
static void omega_init P((void));
-static int omega_start P((u_int, struct peer *));
-static void omega_shutdown P((int));
+static int omega_start P((int, struct peer *));
+static void omega_shutdown P((int, struct peer *));
static void omega_report_event P((struct omegaunit *, int));
static void omega_receive P((struct recvbuf *));
static char omega_process P((struct omegaunit *, l_fp *, u_fp *));
static void omega_poll P((int, struct peer *));
-static void omega_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void omega_control P((int, struct refclockstat *, struct refclockstat *));
static void omega_buginfo P((int, struct refclockbug *));
static void omega_send P((struct omegaunit *, char *));
@@ -239,6 +238,7 @@ omega_init()
fudgefactor2[i].l_uf = 0;
stratumtouse[i] = 0;
readonlyclockflag[i] = 0;
+ memcpy((char *)&refid[i], OMEGAREFID, 4);
}
}
@@ -248,7 +248,7 @@ omega_init()
*/
static int
omega_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
register struct omegaunit *omega;
@@ -443,10 +443,7 @@ omega_start(unit, peer)
peer->rootdelay = 0;
peer->rootdispersion = 0;
peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, OMEGAREFID, 4);
- else
- peer->refid = htonl(OMEGAHSREFID);
+ peer->refid = refid[unit];
unitinuse[unit] = 1;
return 1;
@@ -463,8 +460,9 @@ screwed:
* omega_shutdown - shut down a OMEGA clock
*/
static void
-omega_shutdown(unit)
+omega_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
register struct omegaunit *omega;
@@ -898,7 +896,7 @@ omega_poll(unit, peer)
*/
static void
omega_control(unit, in, out)
- u_int unit;
+ int unit;
struct refclockstat *in;
struct refclockstat *out;
{
@@ -914,41 +912,30 @@ omega_control(unit, in, out)
fudgefactor1[unit] = in->fudgetime1;
if (in->haveflags & CLK_HAVETIME2)
fudgefactor2[unit] = in->fudgetime2;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- omega = omegaunits[unit];
- peer = omega->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- OMEGAREFID, 4);
- else
- peer->refid = htonl(OMEGAHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
+ if (in->haveflags & CLK_HAVEVAL1)
+ stratumtouse[unit] = (u_char)(in->fudgeval1);
+ if (in->haveflags & CLK_HAVEVAL2)
+ refid[unit] = in->fudgeval2;
+ if (in->haveflags & CLK_HAVEFLAG1)
readonlyclockflag[unit] = in->flags & CLK_FLAG1;
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ peer = omegaunits[unit]->peer;
+ peer->stratum = stratumtouse[unit];
+ peer->refid = refid[unit];
}
}
if (out != 0) {
out->type = REFCLK_OMEGA_TRUETIME;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVETIME2|
- CLK_HAVEVAL1|CLK_HAVEVAL2|
- CLK_HAVEFLAG1|CLK_HAVEFLAG2;
+ out->haveflags = CLK_HAVETIME1 | CLK_HAVETIME2 | CLK_HAVEVAL1 |
+ CLK_HAVEVAL2| CLK_HAVEFLAG1;
out->clockdesc = OMEGADESCRIPTION;
out->fudgetime1 = fudgefactor1[unit];
out->fudgetime2 = fudgefactor2[unit];
out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
+ out->fudgeval2 = refid[unit];
out->flags = readonlyclockflag[unit];
if (unitinuse[unit]) {
omega = omegaunits[unit];
@@ -962,13 +949,6 @@ omega_control(unit, in, out)
out->baddata = omega->baddata;
out->lastevent = omega->lastevent;
out->currentstatus = omega->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
}
}
}
diff --git a/usr.sbin/xntpd/xntpd/refclock_parse.c b/usr.sbin/xntpd/xntpd/refclock_parse.c
index 0d95d18908a5..7ef54ab60ab9 100644
--- a/usr.sbin/xntpd/xntpd/refclock_parse.c
+++ b/usr.sbin/xntpd/xntpd/refclock_parse.c
@@ -49,7 +49,7 @@
* - Conrad DCF77 receiver module (DCF)
* - FAU DCF77 NTP receiver (TimeBrick) (DCF)
* - Meinberg GPS166 (GPS)
- * - Trimble SV6 (GPS)
+ * - Trimble SV6 (TSIP and TAIP protocol) (GPS)
*
*/
@@ -474,31 +474,67 @@ static poll_info_t wsdcf_pollinfo = { WS_POLLRATE, WS_POLLCMD, WS_CMDSIZE };
#define TIMEBRICK_DESCRIPTION "RAW DCF77 CODE (TimeBrick)"
/*
- * Trimble SV6 GPS receiver
+ * Trimble SV6 GPS receivers (TAIP and TSIP protocols)
*/
+#define ETX 0x03
+#define DLE 0x10
+
#define TRIM_POLLRATE 0 /* only true direct polling */
-#define TRIM_POLLCMD ">QTM<"
-#define TRIM_CMDSIZE 5
-
-static poll_info_t trimble_pollinfo = { TRIM_POLLRATE, TRIM_POLLCMD, TRIM_CMDSIZE };
-static int trimble_init P((struct parseunit *));
-
-#define TRIMBLESV6_CFLAG (B4800|CS8|CREAD)
-#define TRIMBLESV6_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
-#define TRIMBLESV6_OFLAG (OPOST|ONLCR)
-#define TRIMBLESV6_LFLAG (ICANON|ECHOK)
-#define TRIMBLESV6_FLAGS (PARSE_F_PPSPPS|PARSE_F_PPSONSECOND)
-#define TRIMBLESV6_POLL poll_dpoll
-#define TRIMBLESV6_INIT trimble_init
-#define TRIMBLESV6_END poll_end
-#define TRIMBLESV6_DATA ((void *)(&trimble_pollinfo))
-#define TRIMBLESV6_ID GPS_ID
-#define TRIMBLESV6_FORMAT NO_FORMAT
-#define TRIMBLESV6_ROOTDELAY 0x0
-#define TRIMBLESV6_BASEDELAY 0x0
-#define TRIMBLESV6_DESCRIPTION "Trimble SV6 GPS receiver"
-#define TRIMBLESV6_MAXUNSYNC 0
-#define TRIMBLESV6_EOL '<'
+
+#define TRIM_TAIPPOLLCMD ">QTM<"
+#define TRIM_TAIPCMDSIZE 5
+static poll_info_t trimbletaip_pollinfo = { TRIM_POLLRATE, TRIM_TAIPPOLLCMD, TRIM_TAIPCMDSIZE };
+static int trimbletaip_init P((struct parseunit *));
+
+/* query time & UTC correction data */
+static char tsipquery[] = { DLE, 0x21, DLE, ETX, DLE, 0x2F, DLE, ETX };
+
+static poll_info_t trimbletsip_pollinfo = { TRIM_POLLRATE, tsipquery, sizeof(tsipquery) };
+static int trimbletsip_init P((struct parseunit *));
+
+#define TRIMBLETAIP_CFLAG (B4800|CS8|CREAD)
+#define TRIMBLETAIP_IFLAG (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
+#define TRIMBLETAIP_OFLAG (OPOST|ONLCR)
+#define TRIMBLETAIP_LFLAG (ICANON|ECHOK)
+#define TRIMBLETSIP_CFLAG (B9600|CS8|CLOCAL|CREAD|PARENB|PARODD)
+#define TRIMBLETSIP_IFLAG (IGNBRK)
+#define TRIMBLETSIP_OFLAG (0)
+#define TRIMBLETSIP_LFLAG (0)
+
+#define TRIMBLETAIP_FLAGS (PARSE_F_PPSPPS|PARSE_F_PPSONSECOND)
+#define TRIMBLETSIP_FLAGS (TRIMBLETAIP_FLAGS|PARSE_F_NOPOLLONLY)
+
+#define TRIMBLETAIP_POLL poll_dpoll
+#define TRIMBLETSIP_POLL poll_dpoll
+
+#define TRIMBLETAIP_INIT trimbletaip_init
+#define TRIMBLETSIP_INIT trimbletsip_init
+
+#define TRIMBLETAIP_END poll_end
+#define TRIMBLETSIP_END poll_end
+
+#define TRIMBLETAIP_DATA ((void *)(&trimbletaip_pollinfo))
+#define TRIMBLETSIP_DATA ((void *)(&trimbletsip_pollinfo))
+
+#define TRIMBLETAIP_ID GPS_ID
+#define TRIMBLETSIP_ID GPS_ID
+
+#define TRIMBLETAIP_FORMAT NO_FORMAT
+#define TRIMBLETSIP_FORMAT "Trimble SV6/TSIP"
+
+#define TRIMBLETAIP_ROOTDELAY 0x0
+#define TRIMBLETSIP_ROOTDELAY 0x0
+
+#define TRIMBLETAIP_BASEDELAY 0x0
+#define TRIMBLETSIP_BASEDELAY 0x51EB852 /* 20 ms as a l_uf - avg GPS time message latency */
+
+#define TRIMBLETAIP_DESCRIPTION "Trimble GPS (TAIP) receiver"
+#define TRIMBLETSIP_DESCRIPTION "Trimble GPS (TSIP) receiver"
+
+#define TRIMBLETAIP_MAXUNSYNC 0
+#define TRIMBLETSIP_MAXUNSYNC 0
+
+#define TRIMBLETAIP_EOL '<'
static struct clockinfo
{
@@ -674,23 +710,42 @@ static struct clockinfo
GPS166_LFLAG
},
{ /* 127.127.8.32+<device> */
- TRIMBLESV6_FLAGS,
- TRIMBLESV6_POLL,
- TRIMBLESV6_INIT,
- TRIMBLESV6_END,
- TRIMBLESV6_DATA,
- TRIMBLESV6_ROOTDELAY,
- TRIMBLESV6_BASEDELAY,
+ TRIMBLETAIP_FLAGS,
+ TRIMBLETAIP_POLL,
+ TRIMBLETAIP_INIT,
+ TRIMBLETAIP_END,
+ TRIMBLETAIP_DATA,
+ TRIMBLETAIP_ROOTDELAY,
+ TRIMBLETAIP_BASEDELAY,
+ NO_PPSDELAY,
+ TRIMBLETAIP_ID,
+ TRIMBLETAIP_DESCRIPTION,
+ TRIMBLETAIP_FORMAT,
+ GPS_TYPE,
+ TRIMBLETAIP_MAXUNSYNC,
+ TRIMBLETAIP_CFLAG,
+ TRIMBLETAIP_IFLAG,
+ TRIMBLETAIP_OFLAG,
+ TRIMBLETAIP_LFLAG
+ },
+ { /* 127.127.8.36+<device> */
+ TRIMBLETSIP_FLAGS,
+ TRIMBLETSIP_POLL,
+ TRIMBLETSIP_INIT,
+ TRIMBLETSIP_END,
+ TRIMBLETSIP_DATA,
+ TRIMBLETSIP_ROOTDELAY,
+ TRIMBLETSIP_BASEDELAY,
NO_PPSDELAY,
- TRIMBLESV6_ID,
- TRIMBLESV6_DESCRIPTION,
- TRIMBLESV6_FORMAT,
+ TRIMBLETSIP_ID,
+ TRIMBLETSIP_DESCRIPTION,
+ TRIMBLETSIP_FORMAT,
GPS_TYPE,
- TRIMBLESV6_MAXUNSYNC,
- TRIMBLESV6_CFLAG,
- TRIMBLESV6_IFLAG,
- TRIMBLESV6_OFLAG,
- TRIMBLESV6_LFLAG
+ TRIMBLETSIP_MAXUNSYNC,
+ TRIMBLETSIP_CFLAG,
+ TRIMBLETSIP_IFLAG,
+ TRIMBLETSIP_OFLAG,
+ TRIMBLETSIP_LFLAG
}
};
@@ -3409,11 +3464,12 @@ poll_end(parse)
** special code for special clocks
**/
+
/*--------------------------------------------------
- * trimble init routine - setup EOL and then do poll_init.
+ * trimble TAIP init routine - setup EOL and then do poll_init.
*/
static int
-trimble_init(parse)
+trimbletaip_init(parse)
struct parseunit *parse;
{
#ifdef HAVE_TERMIOS
@@ -3427,21 +3483,221 @@ trimble_init(parse)
*/
if (TTY_GETATTR(parse->fd, &tm) == -1)
{
- syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcgetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ syslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcgetattr(fd, &tm): %m", CL_UNIT(parse->unit));
return 0;
}
else
{
- tm.c_cc[VEOL] = TRIMBLESV6_EOL;
+ tm.c_cc[VEOL] = TRIMBLETAIP_EOL;
if (TTY_SETATTR(parse->fd, &tm) == -1)
{
- syslog(LOG_ERR, "PARSE receiver #%d: trimble_init: tcsetattr(fd, &tm): %m", CL_UNIT(parse->unit));
+ syslog(LOG_ERR, "PARSE receiver #%d: trimbletaip_init: tcsetattr(fd, &tm): %m", CL_UNIT(parse->unit));
return 0;
}
}
return poll_init(parse);
}
+
+/*
+ * This driver supports the Trimble SVee Six Plus GPS receiver module.
+ * It should support other Trimble receivers which use the Trimble Standard
+ * Interface Protocol (see below).
+ *
+ * The module has a serial I/O port for command/data and a 1 pulse-per-second
+ * output, about 1 microsecond wide. The leading edge of the pulse is
+ * coincident with the change of the GPS second. This is the same as
+ * the change of the UTC second +/- ~1 microsecond. Some other clocks
+ * specifically use a feature in the data message as a timing reference, but
+ * the SVee Six Plus does not do this. In fact there is considerable jitter
+ * on the timing of the messages, so this driver only supports the use
+ * of the PPS pulse for accurate timing. Where it is determined that
+ * the offset is way off, when first starting up xntpd for example,
+ * the timing of the data stream is used until the offset becomes low enough
+ * (|offset| < CLOCK_MAX), at which point the pps offset is used.
+ *
+ * It can use either option for receiving PPS information - the 'ppsclock'
+ * stream pushed onto the serial data interface to timestamp the Carrier
+ * Detect interrupts, where the 1PPS connects to the CD line. This only
+ * works on SunOS 4.1.x currently. To select this, define PPSPPS in
+ * Config.local. The other option is to use a pulse-stretcher/level-converter
+ * to convert the PPS pulse into a RS232 start pulse & feed this into another
+ * tty port. To use this option, define PPSCLK in Config.local. The pps input,
+ * by whichever method, is handled in ntp_loopfilter.c
+ *
+ * The receiver uses a serial message protocol called Trimble Standard
+ * Interface Protocol (it can support others but this driver only supports
+ * TSIP). Messages in this protocol have the following form:
+ *
+ * <DLE><id> ... <data> ... <DLE><ETX>
+ *
+ * Any bytes within the <data> portion of value 10 hex (<DLE>) are doubled
+ * on transmission and compressed back to one on reception. Otherwise
+ * the values of data bytes can be anything. The serial interface is RS-422
+ * asynchronous using 9600 baud, 8 data bits with odd party (**note** 9 bits
+ * in total!), and 1 stop bit. The protocol supports byte, integer, single,
+ * and double datatypes. Integers are two bytes, sent most significant first.
+ * Singles are IEEE754 single precision floating point numbers (4 byte) sent
+ * sign & exponent first. Doubles are IEEE754 double precision floating point
+ * numbers (8 byte) sent sign & exponent first.
+ * The receiver supports a large set of messages, only a small subset of
+ * which are used here. From driver to receiver the following are used:
+ *
+ * ID Description
+ *
+ * 21 Request current time
+ * 22 Mode Select
+ * 2C Set/Request operating parameters
+ * 2F Request UTC info
+ * 35 Set/Request I/O options
+
+ * From receiver to driver the following are recognised:
+ *
+ * ID Description
+ *
+ * 41 GPS Time
+ * 44 Satellite selection, PDOP, mode
+ * 46 Receiver health
+ * 4B Machine code/status
+ * 4C Report operating parameters (debug only)
+ * 4F UTC correction data (used to get leap second warnings)
+ * 55 I/O options (debug only)
+ *
+ * All others are accepted but ignored.
+ *
+ */
+
+#define PI 3.1415926535898 /* lots of sig figs */
+#define D2R PI/180.0
+
+/*-------------------------------------------------------------------
+ * sendcmd, sendbyte, sendetx, sendflt, sendint implement the command
+ * interface to the receiver.
+ *
+ * CAVEAT: the sendflt, sendint routines are byte order dependend and
+ * float implementation dependend - these must be converted to portable
+ * versions !
+ */
+
+union {
+ u_char bd[8];
+ int iv;
+ float fv;
+ double dv;
+} uval;
+
+struct txbuf
+{
+ short idx; /* index to first unused byte */
+ u_char *txt; /* pointer to actual data buffer */
+};
+
+void
+sendcmd(buf, c)
+ struct txbuf *buf;
+ u_char c;
+{
+ buf->txt[0] = DLE;
+ buf->txt[1] = c;
+ buf->idx = 2;
+}
+
+void sendbyte(buf, b)
+ struct txbuf *buf;
+ u_char b;
+{
+ if (b == DLE)
+ buf->txt[buf->idx++] = DLE;
+ buf->txt[buf->idx++] = b;
+}
+
+void
+sendetx(buf, parse)
+ struct txbuf *buf;
+ struct parseunit *parse;
+{
+ buf->txt[buf->idx++] = DLE;
+ buf->txt[buf->idx++] = ETX;
+
+ if (write(parse->fd, buf->txt, buf->idx) != buf->idx)
+ {
+ syslog(LOG_ERR, "PARSE receiver #%d: sendetx: failed to send cmd to clock: %m", CL_UNIT(parse->unit));
+ }
+}
+
+void
+sendint(buf, a)
+ struct txbuf *buf;
+ int a;
+{
+ uval.iv = a;
+ sendbyte(buf, uval.bd[2]);
+ sendbyte(buf, uval.bd[3]);
+}
+
+void
+sendflt(buf, a)
+ struct txbuf *buf;
+ float a;
+{
+ int i;
+
+ uval.fv = a;
+ for (i=0; i<=3; i++)
+ sendbyte(buf, uval.bd[i]);
+}
+
+/*--------------------------------------------------
+ * trimble TSIP init routine
+ */
+static int
+trimbletsip_init(parse)
+ struct parseunit *parse;
+{
+ u_char buffer[256];
+ struct txbuf buf;
+
+ buf.txt = buffer;
+
+ if (!poll_init(parse))
+ {
+ sendcmd(&buf, 0x1f); /* request software versions */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x2c); /* set operating parameters */
+ sendbyte(&buf, 4); /* static */
+ sendflt(&buf, 5.0*D2R); /* elevation angle mask = 10 deg XXX */
+ sendflt(&buf, 4.0); /* s/n ratio mask = 6 XXX */
+ sendflt(&buf, 12.0); /* PDOP mask = 12 */
+ sendflt(&buf, 8.0); /* PDOP switch level = 8 */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x22); /* fix mode select */
+ sendbyte(&buf, 0); /* automatic */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x28); /* request system message */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x8e); /* superpacket fix */
+ sendbyte(&buf, 0x2); /* binary mode */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x35); /* set I/O options */
+ sendbyte(&buf, 0); /* no position output */
+ sendbyte(&buf, 0); /* no velocity output */
+ sendbyte(&buf, 7); /* UTC, compute on seconds, send only on request */
+ sendbyte(&buf, 0); /* no raw measurements */
+ sendetx(&buf, parse);
+
+ sendcmd(&buf, 0x2f); /* request UTC correction data */
+ sendetx(&buf, parse);
+ return 0;
+ }
+ else
+ return 1;
+}
+
#endif /* defined(REFCLOCK) && defined(PARSE) */
/*
diff --git a/usr.sbin/xntpd/xntpd/refclock_pst.c b/usr.sbin/xntpd/xntpd/refclock_pst.c
index 4b8909afb801..29cbfb1201ec 100644
--- a/usr.sbin/xntpd/xntpd/refclock_pst.c
+++ b/usr.sbin/xntpd/xntpd/refclock_pst.c
@@ -1,7 +1,7 @@
/*
- * refclock_pst - driver for the PSTI 1010/1020 WWV clock
+ * refclock_pst - clock driver for PSTI/Traconex WWV/WWVH receivers
*/
-#if defined(REFCLOCK) && (defined(PST) || defined(PSTCLK) || defined(PSTPPS))
+#if defined(REFCLOCK) && defined(PST)
#include <stdio.h>
#include <ctype.h>
@@ -10,1795 +10,320 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#if defined(PSTCLK)
-#include <sys/clkdefs.h>
-#endif /* PSTCLK */
-#endif /* STREAM */
-
-#if defined (PSTPPS)
-#include <sys/ppsclock.h>
-#endif /* PSTPPS */
-
#include "ntp_stdlib.h"
/*
- * This driver is in good measure due to David Schachter, who wrote
- * the firmware for the PST clock. Not that he is to blame for
- * any of this, but he kindly loaned me a clock to allow me to
- * debug this.
- *
- * Postscript:
- *
- * The strategy in here is actually pretty good, especially if
- * you try to support the clock on something lacking low order
- * clock bits like a Sun, since all the business which is done
- * before taking a time stamp tends to randomize the taking of
- * the stamp with respect to the timer interrupt. It is, however,
- * a big cpu hog, and in some ways is a bit of a waste since, as
- * it turns out, the PST clock can give you no better than a
- * millisecond precision and it doesn't pay to try to push it
- * harder.
- *
- * In any event, like the first waffle off the iron, this one
- * should probably be tossed. My current preference would be
- * to retain the 12-a-minute schedule, but to use the QU command
- * instead of the QD and QT, and to only send a QM command with
- * the 12th poll of the minute to get the minutes-since-sync
- * and the station. Need to get a clock which supports QU,
- * however.
- *
- * End postscript
- *
- * This driver polls the clock using the QM, QT and QD commands.
- * Ntpd actually uses QU instead of the last two, something I would
- * like to have done as well since it gives you the day and time
- * atom, but the firmware in the clock I had (X04.01.999) didn't know
- * about this command.
- *
- * The QM command produces output like:
- *
- * O6B532352823C00270322
- * b c deeee
- *
- * We use (b) for the time zone, (c) to see whether time is available,
- * (d) to tell whether we are sync'd to WWV or WWVH, and (e) to determine
- * the number of minutes since the last signal was received. We
- * don't trust the clock for more than about 20 minutes on its own.
- * After this, we keep taking the time but mark the clock unsynchronized.
+ * This driver supports the PSTI 1010 and Traconex 1020 WWV/WWVH
+ * Receivers. No specific claim of accuracy is made for these receiver,
+ * but actual experience suggests that 10 ms would be a conservative
+ * assumption.
+ *
+ * The DIPswitches should be set for 9600 bps line speed, 24-hour day-
+ * of-year format and UTC time zone. Automatic correction for DST should
+ * be disabled. It is very important that the year be set correctly in
+ * the DIPswitches; otherwise, the day of year will be incorrect after
+ * 28 April of a normal or leap year. The propagation delay DIPswitches
+ * should be set according to the distance from the transmitter for both
+ * WWV and WWVH, as described in the instructions. While the delay can
+ * be set only to within 11 ms, the fudge time1 parameter can be used
+ * for vernier corrections.
*
- * The QT command returns something that looks like this:
+ * Using the poll sequence QTQDQM, the response timecode is in three
+ * sections totalling 50 ASCII printing characters, as concatenated by
+ * the driver, in the following format:
*
- * 18:57:50.263D
+ * ahh:mm:ss.fffs<cr> yy/dd/mm/ddd<cr> frdzycchhSSFTttttuuxx<cr>
*
- * Note that this particular sample is in 24 hour format, local time
- * (daylight savings time even). We allow just about anything for
- * this (sigh) since this leaves the clock owner free to set the
- * display mode in whatever way he finds convenient for setting
- * his watch.
+ * on-time = first <cr> * hh:mm:ss.fff = hours, minutes, seconds, milliseconds
+ * a = AM/PM indicator (' ' for 24-hour mode)
+ * yy = year (from internal switches)
+ * dd/mm/ddd = day of month, month, day of year
+ * s = daylight-saving indicator (' ' for 24-hour mode)
+ * f = frequency enable (O = all frequencies enabled)
+ * r = baud rate (3 = 1200, 6 = 9600)
+ * d = features indicator (@ = month/day display enabled)
+ * z = time zone (0 = UTC)
+ * y = year (5 = 91)
+ * cc = WWV propagation delay (52 = 22 ms)
+ * hh = WWVH propagation delay (81 = 33 ms)
+ * SS = status (80 or 82 = operating correctly)
+ * F = current receive frequency (4 = 15 MHz)
+ * T = transmitter (C = WWV, H = WWVH)
+ * tttt = time since last update (0000 = minutes)
+ * uu = flush character (03 = ^c)
+ * xx = 94 (unknown)
*
- * The QD command returns:
+ * The alarm condition is indicated by other than '8' at A, which occurs
+ * during initial synchronization and when received signal is lost for
+ * an extended period; unlock condition is indicated by other than
+ * "0000" in the tttt subfield at Q.
*
- * 89/10/19/292
+ * Fudge Factors
*
- * We actually only use the day-of-the-year here. We use the year
- * only to determine whether the PST clock thinks the current year
- * has 365 or 366 days in it.
- *
- * At the current writing, this code expects to be using a BSD-style
- * terminal driver. It will compile code which uses the CLKLDISC
- * line discipline if it thinks this is available, but use cooked
- * mode otherwise. The cooked mode stuff may not have been tested.
- */
-
-/*
- * Definitions
- */
-#define MAXUNITS 4 /* maximum number of PST units permitted */
-#define PSTDEV "/dev/pst%d" /* device we open. %d is unit number */
-#define NPSTSAMPS 12 /* take 12 PST samples per minute */
-
-/*
- * Other constant stuff
+ * There are no special fudge factors other than the generic.
*/
-#define PSTPRECISION (-9) /* what the heck */
-#define WWVREFID "WWV\0"
-#define WWVHREFID "WWVH"
-#define PSTHSREFID 0x7f7f030a /* 127.127.3.10 refid for hi strata */
/*
- * Parameters for the clock
+ * Interface definitions
*/
-#define SPEED232 B9600
-#define PSTMAGIC2 ('\r' | 0x80) /* HP-UX uses this also now */
-#ifdef CLKLDISC
-#define PSTMAGIC1 '\r'
-#define PSTEOL '\r'
-#else
-#define PSTEOL '\n'
-#endif
+#define DEVICE "/dev/pst%d" /* device name and unit */
+#define SPEED232 B9600 /* uart speed (9600 baud) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define WWVREFID "WWV\0" /* WWV reference ID */
+#define WWVHREFID "WWVH" /* WWVH reference ID */
+#define DESCRIPTION "PSTI/Traconex WWV/WWVH Receiver" /* WRU */
-/*
- * Description of clock. We fill in whether it is a 1010 or 1020,
- * and the firmware revision, using the QV command.
- */
-#define PSTDESCLEN 64
-#define PSTDESCRIPTION "%s %s (%s) WWV/H Receiver"
-#define PSTDEFDESC "PSTI/Traconex 10?0 (V??.??) WWV/H Receiver"
+#define NSAMPLES 3 /* stages of median filter */
+#define LENPST 46 /* min timecode length */
/*
- * Length of the PST time code. This must be the length of the output
- * of the QM command, plus QT, plus QD, plus two spaces. We make it
- * big just on principle.
+ * Imported from ntp_timer module
*/
-#define PSTCODELEN (128)
+extern u_long current_time; /* current time (s) */
/*
- * Minimum and maximum lengths
- */
-#define PSTMINQVLEN (16)
-#define PSTMAXQVLEN (24)
-
-#define PSTMINQMLEN (19)
-#define PSTMAXQMLEN (32)
-
-#define PSTMINQDLEN (12)
-#define PSTMAXQDLEN (12)
-
-#define PSTMINQTLEN (14)
-#define PSTMAXQTLEN (14)
-
-/*
- * It turns out that the QT command does *not* adjust for transmission
- * delays. Since the QT command returns 15 characters at 9600 baud,
- * the adjustment for this should be 15.6 ms. We'll default to this,
- * but don't let this stop you from fiddling with the fudge factors
- * to make things come out right
- */
-#define PSTQTFUDGE 0x04000000 /* about 15.6 ms */
-
-/*
- * Default propagation delays. About right for Toronto
- */
-#define DEFWWVPROP 0x01eb851f /* about 7.5 ms */
-#define DEFWWVHPROP 0x06c8b439 /* about 26.5 ms */
-
-/*
- * Maximum propagation delay we believe. 125 ms as an l_fp fraction
- */
-#define PSTMAXPROP 0x20000000
-
-/*
- * Default minutes since an update.
- */
-#define DEFMAXFREERUN (20)
-
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
+ * Imported from ntpd module
*/
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
+extern int debug; /* global debug flag */
/*
- * PST unit control structure.
+ * Unit control structure
*/
struct pstunit {
- struct peer *peer; /* associated peer structure */
- struct event psttimer; /* timeout timer structure */
- struct refclockio pstio; /* given to the I/O handler */
- l_fp rectimes[NPSTSAMPS]; /* times we received this stuff */
- l_fp reftimes[NPSTSAMPS]; /* times of codes received */
- l_fp lastrec; /* last receive time */
- l_fp lastref; /* last reference time */
- char description[PSTDESCLEN]; /* description of clock */
- char lastcode[PSTCODELEN]; /* last code we received */
- u_char lencode; /* length of the last code */
- u_char nextsample; /* the next offset expected */
- u_char unit; /* unit number for this guy */
- u_char state; /* what we're waiting for */
- s_char station; /* WWV or WWVH? */
- u_char flags; /* flag byte */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char timezone; /* hour offset to time zone */
- u_char errors; /* number of errors detected */
- u_char year; /* year reported by clock */
- u_char month; /* month, from clock */
- u_char monthday; /* day, from clock */
- u_char hour; /* hour of day */
- u_char minute; /* minute of day */
- u_char second; /* second of day */
- u_char leap; /* leap indicators */
- s_char tzoffset; /* time zone offset */
- u_char reason; /* reason for failure */
- u_short millisecond; /* millisecond of day */
- u_short yearday; /* day of the year */
- u_short timesincesync; /* time since radio got sample */
- U_LONG yearstart; /* NTP time at year start */
- U_LONG lastupdate; /* last time data received */
- U_LONG polls; /* number of polls */
- U_LONG noreply; /* number of time outs */
- U_LONG badformat; /* number of bad format responses */
- U_LONG baddata; /* number of invalid time codes */
- U_LONG timestarted; /* time we started this */
-};
+ int pollcnt; /* poll message counter */
-/*
- * States we might be in
- */
-#define STATE_IDLE 0 /* not doing anything in particular */
-#define STATE_QV 1 /* trying to get version */
-#define STATE_QM 2 /* sent QM */
-#define STATE_QD 3 /* sent QD */
-#define STATE_QT 4 /* send QT */
-
-/*
- * Status flags
- */
-#define PST_LEAPYEAR 0x1 /* pst clock thinks it is a leap year */
-#define PST_SIGFAULT 0x2 /* signal fault */
-#define PST_HARDERR 0x4 /* hardware error */
-#define PST_NOTIME 0x8 /* no time available */
-#define PST_WWVH 0x10 /* synchronized to WWVH */
-#define PST_DOQV 0x20 /* get version, reinit delays */
-#define PST_DORESET 0x40 /* reset the clock */
-
-/*
- * The PST often encodes stuff by adding an ASCII '0' to it. The
- * largest range of values encoded this way is 0 through 31, or '0'
- * through 'O'. These macroes manipulate these values.
- */
-#define ISVALIDPST(c) ((c) >= '0' && (c) <= 'O')
-#define PSTTOBIN(c) ((int)(c) - '0')
-#define BINTOPST(c) ((char)((c) + '0'))
-
-/*
- * Status bits. Look at the QM command
- */
-#define SIGFAULT 0x1
-#define HARDFAULT 0x2
-#define OUTOFSPEC 0x4
-#define TIMEAVAILABLE 0x8
-
-/*
- * Module reason codes
- */
-#define QVREASON 20
-#define QMREASON 40
-#define QDREASON 60
-#define QTREASON 80
-
-/*
- * Station i.d. characters in QM output
- */
-#define WWV_CHAR 'C'
-#define WWVH_CHAR 'H'
-
-/*
- * We allow a few errors, but if we get more than 12 seconds behind
- * the schedule we start from sample 0 again. 4 seconds is the minimum
- * time between time out routine executions.
- */
-#define PSTMAXDELAY 12
-#define PSTMINTIMEOUT 4
-
-/*
- * The PST polling schedule. We poll 12 times per 64 seconds (far too
- * many, but what the heck). The polls are scheduled to finish in this
- * time with the assumption that the timer is good for no better than
- * 4 second resolution. If we get too far behind (due to bad samples
- * or no responses) we start over.
- */
-struct pstsched {
- u_short nextinterval;
- u_short tooold;
+ u_char tcswitch; /* timecode switch */
+ char *lastptr; /* pointer to timecode data */
};
-static struct pstsched psttab[NPSTSAMPS] = {
- { 4, PSTMAXDELAY+1 },
- { 4, PSTMAXDELAY+1+4 },
- { 8, PSTMAXDELAY+1+4+4 },
- { 4, PSTMAXDELAY+1+4+4+8 },
- { 8, PSTMAXDELAY+1+4+4+8+4 },
- { 4, PSTMAXDELAY+1+4+4+8+4+8 },
- { 4, PSTMAXDELAY+1+4+4+8+4+8+4 },
- { 8, PSTMAXDELAY+1+4+4+8+4+8+4+4 },
- { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8 },
- { 8, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4 },
- { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8 },
- { 4, PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8+4 }
-};
-
-
-/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct pstunit *pstunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Structure to keep processed propagation data in.
- */
-struct pst_propagate {
- U_LONG remainder; /* left over submillisecond remainder */
- char msbchar; /* character for high order bits */
- char lsbchar; /* character for low order bits */
-};
-
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp wwv_prop_delay[MAXUNITS];
-static l_fp wwvh_prop_delay[MAXUNITS];
-static struct pst_propagate wwv_prop_data[MAXUNITS];
-static struct pst_propagate wwvh_prop_data[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclock[MAXUNITS];
-static u_short freerun[MAXUNITS];
-
-/*
- * Pointer to the default description
- */
-static char *pstdefdesc = PSTDEFDESC;
-
-/*
- * macro for writing to the clock, printing an error if we fail
- */
-#define pst_send(pst, str, len) \
- if (write((pst)->pstio.fd, (str), (len)) < 0) \
- pst_write_error((pst))
-
-/*
- * macro for resetting the clock structure to zero
- */
-#define pst_reset(pst) \
- do { \
- pst->nextsample = 0; \
- pst->station = 0; \
- pst->leap = 0; \
- } while (0)
-
-/*
- * macro for event reporting
- */
-#define pst_event(pst, evnt_code) \
- do { \
- if ((pst)->status != (u_char)(evnt_code)) \
- pst_do_event((pst), (evnt_code)); \
- } while (0)
-
-/*
- * Imported from the timer module
- */
-extern U_LONG current_time;
-extern struct event timerqueue[];
-
-/*
- * Imported from ntp_loopfilter module
- */
-extern int fdpps; /* pps file descriptor */
-
-/*
- * Imported from ntpd module
- */
-extern int debug; /* global debug flag */
-
/*
* Function prototypes
*/
-static void pst_init P((void));
-static int pst_start P((u_int, struct peer *));
-static void pst_shutdown P((int));
+static int pst_start P((int, struct peer *));
+static void pst_shutdown P((int, struct peer *));
static void pst_receive P((struct recvbuf *));
-static void pst_process P((struct pstunit *));
-static void pst_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void pst_buginfo P((int, struct refclockbug *));
-static void pst_write_error P((struct pstunit *));
-static void pst_timeout P((struct peer *));
-static int pst_QV_process P((struct pstunit *, struct recvbuf *));
-static int pst_QM_process P((struct pstunit *, struct recvbuf *));
-static int pst_QD_process P((struct pstunit *, struct recvbuf *));
-static int pst_QT_process P((struct pstunit *, struct recvbuf *, l_fp *, l_fp *));
-static void pst_do_event P((struct pstunit *, int));
-static void pst_compute_delay P((U_LONG, struct pst_propagate *));
+static void pst_poll P((int, struct peer *));
/*
* Transfer vector
*/
struct refclock refclock_pst = {
- pst_start, pst_shutdown, noentry,
- pst_control, pst_init, pst_buginfo, NOFLAGS
+ pst_start, /* start up driver */
+ pst_shutdown, /* shut down driver */
+ pst_poll, /* transmit poll message */
+ noentry, /* not used (old pst_control) */
+ noentry, /* initialize driver */
+ noentry, /* not used (old pst_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * pst_init - initialize internal PST driver data
- */
-static void
-pst_init()
-{
- register int i;
-
- /*
- * Just zero the data arrays
- */
- memset((char *)pstunits, 0, sizeof pstunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- wwv_prop_delay[i].l_ui = 0;
- wwv_prop_delay[i].l_uf = DEFWWVPROP;
- pst_compute_delay(DEFWWVPROP, &wwv_prop_data[i]);
- wwvh_prop_delay[i].l_ui = 0;
- wwvh_prop_delay[i].l_uf = DEFWWVHPROP;
- pst_compute_delay(DEFWWVHPROP, &wwvh_prop_data[i]);
- stratumtouse[i] = 0;
- sloppyclock[i] = 0;
- freerun[i] = DEFMAXFREERUN;
- }
-}
-
/*
- * pst_start - open the PST device and initialize data for processing
+ * pst_start - open the devices and initialize data for processing
*/
static int
pst_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct pstunit *pst;
- register int i;
- int fd232;
- char pstdev[20];
-
- /*
- * Check configuration info
- */
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "pst_start: unit %d invalid", unit);
- return 0;
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "pst_start: unit %d in use", unit);
- return 0;
- }
+ register struct pstunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
/*
- * Open serial port
- */
- (void) sprintf(pstdev, PSTDEV, unit);
- fd232 = open(pstdev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "pst_start: open of %s: %m", pstdev);
- return 0;
- }
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- *
- */
- { struct termio ttyb;
- if (ioctl(fd232, TCGETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, TCGETA): %m", pstdev);
- goto screwed;
- }
- ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyb.c_oflag = 0;
- ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyb.c_lflag = ICANON;
- ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
- if (ioctl(fd232, TCSETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, TCSETA): %m", pstdev);
- goto screwed;
- }
- }
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The PSTCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
- *
- * The PSTPPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
+ * Open serial port. Use CLK line discipline, if available.
*/
- { struct termios ttyb, *ttyp;
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
+ return (0);
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "pst_start: tcgetattr(%s): %m", pstdev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "pst_start: tcsetattr(%s): %m", pstdev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "pst_start: tcflush(%s): %m", pstdev);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#ifdef STREAM
-#if defined(PSTCLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, I_PUSH, clk): %m", pstdev);
- if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, CLK_SETSTR): %m", pstdev);
-#endif /* PSTCLK */
-#if defined(PSTPPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, I_PUSH, ppsclock): %m", pstdev);
- else
- fdpps = fd232;
-#endif /* PSTPPS */
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
/*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The PSTCLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
+ * Allocate and initialize unit structure
*/
- { struct sgttyb ttyb;
-#if defined(PSTCLK)
- int ldisc = CLKLDISC;
-#endif /* PSTCLK */
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, TIOCGETP): %m", pstdev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(PSTCLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
- ttyb.sg_erase = ttyb.sg_kill = '\0';
- ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* PSTCLK */
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, TIOCSETP): %m", pstdev);
- goto screwed;
+ if (!(up = (struct pstunit *)
+ emalloc(sizeof(struct pstunit)))) {
+ (void) close(fd);
+ return (0);
}
-#if defined(PSTCLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "pst_start: ioctl(%s, TIOCSETD): %m",pstdev);
- goto screwed;
- }
-#endif /* PSTCLK */
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (pstunits[unit] != 0) {
- pst = pstunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && pstunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- pst = pstunits[i];
- pstunits[i] = 0;
- } else {
- pst = (struct pstunit *)emalloc(sizeof(struct pstunit));
- }
+ memset((char *)up, 0, sizeof(struct pstunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = pst_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- memset((char *)pst, 0, sizeof(struct pstunit));
- pstunits[unit] = pst;
+ pp->unitptr = (caddr_t)up;
/*
- * Set up the structure
+ * Initialize miscellaneous variables
*/
- pst->peer = peer;
- pst->unit = (u_char)unit;
- pst->state = STATE_IDLE;
- pst->flags |= PST_DOQV;
- pst->timestarted = current_time;
- (void) strcpy(pst->description, pstdefdesc);
-
- pst->psttimer.peer = (struct peer *)pst;
- pst->psttimer.event_handler = pst_timeout;
-
- pst->pstio.clock_recv = pst_receive;
- pst->pstio.srcclock = (caddr_t)pst;
- pst->pstio.datalen = 0;
- pst->pstio.fd = fd232;
- if (!io_addclock(&pst->pstio)) {
- goto screwed;
- }
-
- /*
- * All done. Initialize a few random peer variables, then
- * start the timer and return success.
- */
- peer->precision = PSTPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, WWVREFID, 4);
- else
- peer->refid = htonl(PSTHSREFID);
- pst->psttimer.event_time = current_time + PSTMINTIMEOUT;
- TIMER_ENQUEUE(timerqueue, &pst->psttimer);
- unitinuse[unit] = 1;
- return 1;
-
- /*
- * Something broke; abandon ship.
- */
-screwed:
- (void) close(fd232);
- return (0);
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, WWVREFID, 4);
+ up->pollcnt = 2;
+ return (1);
}
+
/*
- * pst_shutdown - shut down a PST clock
+ * pst_shutdown - shut down the clock
*/
static void
-pst_shutdown(unit)
+pst_shutdown(unit, peer)
int unit;
+ struct peer *peer;
{
- register struct pstunit *pst;
+ register struct pstunit *up;
+ struct refclockproc *pp;
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "pst_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "pst_shutdown: unit %d not in use", unit);
- return;
- }
-
- /*
- * Tell the I/O module to turn us off, and dequeue timer
- * if any. We're history.
- */
- pst = pstunits[unit];
- TIMER_DEQUEUE(&pst->psttimer);
- io_closeclock(&pst->pstio);
- unitinuse[unit] = 0;
+ pp = peer->procptr;
+ up = (struct pstunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
/*
- * pst_write_error - complain about writes to the clock
+ * pst_receive - receive data from the serial interface
*/
static void
-pst_write_error(pst)
- struct pstunit *pst;
-{
- /*
- * This will fill syslog is something is really wrong. Should
- * throttle it back.
- */
- syslog(LOG_ERR, "pst_write_error: unit %d: %m", pst->unit);
-}
-
-
-/*
- * pst_timeout - process a timeout event
- */
-static void
-pst_timeout(fakepeer)
- struct peer *fakepeer;
-{
- register struct pstunit *pst;
- U_LONG poll;
-
- /*
- * The timeout routine always initiates a chain of
- * query-responses from the clock, by sending either
- * a QV command (if we need to (re)set the propagation
- * delays into the clock), a QM command or an SRY
- * command (after a leap second). The pst_receive()
- * routine should complete the set of queries on its own
- * LONG before the next time out is due, so if we see any
- * state in here other than idle it means the clock hasn't
- * responded.
- */
- pst = (struct pstunit *)fakepeer;
- switch(pst->state) {
- case STATE_IDLE:
- poll = (U_LONG)psttab[pst->nextsample].nextinterval;
- break; /* all is well */
-
- case STATE_QV:
- pst->flags |= PST_DOQV; /* no response, do QV again */
- /*FALLSTHROUGH*/
-
- case STATE_QM:
- case STATE_QD:
- case STATE_QT:
- pst->noreply++; /* mark the lack of response */
- poll = PSTMINTIMEOUT; /* minimum time poll */
- break;
-
- default:
- syslog(LOG_ERR, "pst_timeout: unit %d invalid state %d",
- pst->unit, pst->state);
- poll = PSTMINTIMEOUT; /* minimum time poll */
- break;
- }
-
- if (pst->flags & PST_DORESET) {
- /*
- * Do a reset. At the next interrupt, start with
- * a QV command to set in the delays.
- */
- pst->flags &= ~PST_DORESET;
- pst->flags |= PST_DOQV;
- pst->state = STATE_IDLE;
- pst_send(pst, "\003SRY", 4);
- } else if (pst->flags & PST_DOQV) {
- pst->polls++;
- pst->flags &= ~PST_DOQV;
- pst->state = STATE_QV;
- pst_send(pst, "\003QV", 3);
- } else {
- pst->polls++;
- pst->state = STATE_QM;
- pst_send(pst, "\003QM", 3);
- }
-
- pst->psttimer.event_time += poll;
- TIMER_ENQUEUE(timerqueue, &pst->psttimer);
-}
-
-
-/*
- * pst_QV_process - decode the results of a QV poll and insert fudge
- * factors into the clock.
- */
-static int
-pst_QV_process(pst, rbufp)
- register struct pstunit *pst;
- struct recvbuf *rbufp;
-{
- register char *cp;
- register char *bp;
- register int len;
- char *model;
- char *company;
- char buf[20];
- static char wwvdelay[6] = { 'S', 'C', '\0', 'S', 'E', '\0' };
- static char wwvhdelay[6] = { 'S', 'H', '\0', 'S', 'G', '\0' };
-
- /*
- * The output of the QV command looks like:
- *
- * PSTI ITS V04.01.000\r
- *
- * or
- *
- * TRAC ITS V04.01.000\r
- *
- * or
- *
- * TRACONEX TS V05.02.001\r
- *
- * The minimum length of the string is about 16 characters.
- * The maximum length is sort of unbounded, but we get suspicious
- * if it is more than 34.
- */
- len = rbufp->recv_length;
- if (len > PSTMAXQVLEN + 10)
- len = PSTMAXQVLEN + 10;
-
- bp = rbufp->recv_buffer;
- cp = pst->lastcode;
- while (len-- > 0) {
- *cp = (*bp++) & 0x7f; /* strip parity */
- if (!isprint(*cp))
- break;
- cp++;
- }
- pst->lencode = (u_char)(cp - pst->lastcode);
-
- /*
- * Okay, got all printable characters from the string
- * copied. We expect to have been terminated by the
- * EOL character. If not, forget it. If the length
- * is insane, forget it.
- */
-
- if (*cp != PSTEOL
- || pst->lencode < PSTMINQVLEN || pst->lencode > PSTMAXQVLEN) {
- pst->reason = QVREASON + 1;
- return 0;
- }
-
- /*
- * Now, format check what we can. Dump it at the least
- * sign of trouble.
- */
- cp = pst->lastcode;
- model = NULL;
- if (*cp++ != 'P' || *cp++ != 'S' || *cp++ != 'T'
- || *cp++ != 'I' || *cp++ != ' ') {
- cp = pst->lastcode;
- if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A'
- || *cp++ != 'C' || *cp++ != ' ') {
- cp = pst->lastcode;
- if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A'
- || *cp++ != 'C' || *cp++ != 'O' || *cp++ != 'N'
- || *cp++ != 'E' || *cp++ != 'X' || *cp != ' ') {
- pst->reason = QVREASON + 2;
- return 0;
- }
- company = "Traconex";
- model = "1030";
- }
- company = "Traconex";
- } else {
- company = "Precision Standard Time";
- }
-
- if (*cp == 'M')
- model = "1010";
- else if (*cp == 'I')
- model = "1020";
- else if (model == NULL) {
- pst->reason = QVREASON + 3;
- return 0;
- }
- cp++;
-
- if (*cp++ != 'T' || *cp++ != 'S' || *cp++ != ' ') {
- pst->reason = QVREASON + 4;
- return 0;
- }
- if (*cp != 'X' && *cp != 'V') {
- pst->reason = QVREASON + 5;
- return 0;
- }
-
- /*
- * Next is the version. Copy it into the buffer.
- */
- bp = buf;
- *bp++ = *cp++;
- while (isdigit(*cp) || *cp == '.')
- *bp++ = *cp++;
- *bp++ = '\0';
-
- /*
- * Final bit of fluff is to set the description
- */
- (void) sprintf(pst->description, PSTDESCRIPTION, company, model, buf);
-
- /*
- * Now the serious stuff. Since we are now sure that the
- * clock is there, we can be fairly sure that the delay
- * setting commands will take. Send them.
- */
- wwvdelay[2] = wwv_prop_data[pst->unit].msbchar;
- wwvdelay[5] = wwv_prop_data[pst->unit].lsbchar;
- pst_send(pst, wwvdelay, 6);
-
- /*
- * Same thing for WWVH
- */
- wwvhdelay[2] = wwvh_prop_data[pst->unit].msbchar;
- wwvhdelay[5] = wwvh_prop_data[pst->unit].lsbchar;
- pst_send(pst, wwvhdelay, 6);
-
- /*
- * Should be okay. Return positive response.
- */
- return 1;
-}
-
-
-/*
- * pst_QM_process - process the output of a QM command
- */
-static int
-pst_QM_process(pst, rbufp)
- register struct pstunit *pst;
- struct recvbuf *rbufp;
-{
- register char *cp;
- register char *bp;
- register int n;
-
- /*
- * The output of the QM command looks like:
- *
- * O6B532352823C00270322
- *
- * The minimum length of the string is 19 characters.
- * The maximum length is sort of unbounded, but we get suspicious
- * if it is more than 42.
- */
- n = rbufp->recv_length;
- if (n > PSTMAXQMLEN + 10)
- n = PSTMAXQMLEN + 10;
-
- bp = rbufp->recv_buffer;
- cp = pst->lastcode;
- while (n-- > 0) {
- *cp = (*bp++) & 0x7f; /* strip parity */
- if (!isprint(*cp))
- break;
- cp++;
- }
- pst->lencode = (u_char)(cp - pst->lastcode);
-
- /*
- * Okay, got all printable characters from the string
- * copied. We expect to have been terminated by the
- * EOL character. If not, forget it. If the length
- * is insane, forget it.
- */
- if (*cp != PSTEOL
- || pst->lencode < PSTMINQMLEN || pst->lencode > PSTMAXQMLEN) {
- pst->reason = QMREASON + 1;
- return 0;
- }
-
- /*
- * Ensure that the first PSTMINQMLEN characters are valid with
- * respect to the way the clock encodes binary data.
- */
- cp = pst->lastcode;
- n = pst->lencode;
- while (n-- > 0) {
- if (!ISVALIDPST(*cp)) {
- pst->reason = QMREASON + 2;
- return 0;
- }
- cp++;
- }
-
- /*
- * Collect information we are interested in.
- */
- cp = pst->lastcode;
- pst->timezone = PSTTOBIN(cp[3]);
- if (pst->timezone > 23) {
- pst->reason = QMREASON + 3;
- return 0;
- }
-
- pst->flags &=
- ~(PST_LEAPYEAR|PST_SIGFAULT|PST_HARDERR|PST_NOTIME|PST_WWVH);
- n = PSTTOBIN(cp[4]);
- if (n > 15) {
- pst->reason = QMREASON + 4;
- return 0;
- }
- if (((n + 2) & 0x3) == 0)
- pst->flags |= PST_LEAPYEAR;
-
- n = PSTTOBIN(cp[9]);
- if (n > 15) {
- pst->reason = QMREASON + 5;
- return 0;
- }
- if (n & SIGFAULT)
- pst->flags |= PST_SIGFAULT;
- if (n & HARDFAULT)
- pst->flags |= PST_HARDERR;
- if (!(n & TIMEAVAILABLE))
- pst->flags |= PST_NOTIME;
-
- if (cp[12] == 'H') {
- pst->flags |= PST_WWVH;
- } else if (cp[12] == 'C') {
- pst->flags &= ~PST_WWVH;
- } else {
- pst->reason = QMREASON + 6;
- return 0;
- }
-
- if (wwv_prop_data[pst->unit].msbchar != cp[5] ||
- wwv_prop_data[pst->unit].lsbchar != cp[6] ||
- wwvh_prop_data[pst->unit].msbchar != cp[7] ||
- wwvh_prop_data[pst->unit].lsbchar != cp[8])
- pst->flags |= PST_DOQV;
-
- bp = cp + 13;
- pst->timesincesync = 0;
- while (bp < (cp + 17)) {
- if (!isdigit(*bp)) {
- pst->reason = QMREASON + 6;
- return 0;
- }
- pst->timesincesync = MULBY10(pst->timesincesync)
- + PSTTOBIN(*bp);
- bp++;
- }
-
- /*
- * That's about all we can do. Return success.
- */
- return 1;
-}
-
-
-/*
- * pst_QD_process - process the output of a QD command
- */
-static int
-pst_QD_process(pst, rbufp)
- register struct pstunit *pst;
- struct recvbuf *rbufp;
-{
- register char *cp;
- register char *bp;
- register int n;
- char *cpstart;
- int len;
-
- /*
- * The output of the QM command looks like:
- *
- * 88/05/17/138\r
- *
- * The minimum length of the string is 12 characters as is
- * the maximum length.
- */
- n = rbufp->recv_length;
- if (n > PSTMAXQDLEN + 10)
- n = PSTMAXQDLEN + 10;
-
- bp = rbufp->recv_buffer;
- cp = &pst->lastcode[pst->lencode];
- *cp++ = ' ';
- cpstart = cp;
- while (n-- > 0) {
- *cp = (*bp++) & 0x7f; /* strip parity */
- if (!isprint(*cp))
- break;
- cp++;
- }
- len = (cp - cpstart);
- pst->lencode = (u_char)(cp - pst->lastcode);
-
- /*
- * Okay, got all printable characters from the string
- * copied. We expect to have been terminated by the
- * EOL character. If not, forget it. If the length
- * is insane, forget it.
- */
- if (*cp != PSTEOL ||
- len < PSTMINQDLEN || len > PSTMAXQDLEN) {
- pst->reason = QDREASON + 1;
- return 0;
- }
-
- /*
- * Ensure that the characters are formatted validly. They
- * are either digits or '/'s.
- */
- cp = cpstart;
- if (!isdigit(cp[0]) || !isdigit(cp[1]) || cp[2] != '/' ||
- !isdigit(cp[3]) || !isdigit(cp[4]) || cp[5] != '/' ||
- !isdigit(cp[6]) || !isdigit(cp[7]) || cp[8] != '/' ||
- !isdigit(cp[9]) || !isdigit(cp[10]) || !isdigit(cp[11])) {
- pst->reason = QDREASON + 2;
- return 0;
- }
-
- /*
- * Decode into year, month, day and year day
- */
- pst->year = MULBY10(PSTTOBIN(cp[0])) + PSTTOBIN(cp[1]);
- pst->month = MULBY10(PSTTOBIN(cp[3])) + PSTTOBIN(cp[4]);
- pst->monthday = MULBY10(PSTTOBIN(cp[6])) + PSTTOBIN(cp[7]);
- pst->yearday = MULBY10(PSTTOBIN(cp[9])) + PSTTOBIN(cp[10]);
- pst->yearday = MULBY10(pst->yearday) + PSTTOBIN(cp[11]);
-
- /*
- * Format check these.
- */
- if (pst->month > 12 || pst->monthday > 31 || pst->yearday > 366) {
- pst->reason = QDREASON + 3;
- return 0;
- }
- if (!(pst->flags & PST_LEAPYEAR) && pst->yearday > 365) {
- pst->reason = QDREASON + 4;
- return 0;
- }
-
- /*
- * Done all we can.
- */
- return 1;
-}
-
-
-/*
- * pst_QT_process - process the output of a QT command, return the times
- */
-static int
-pst_QT_process(pst, rbufp, tsclk, tsrec)
- register struct pstunit *pst;
+pst_receive(rbufp)
struct recvbuf *rbufp;
- l_fp *tsclk;
- l_fp *tsrec;
{
- register char *cp;
- register char *bp;
- register int n;
- char *cpstart;
- int len;
- int hour;
- int minute;
- int second;
- int msec;
- int tzoff;
+ register struct pstunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp trtmp;
+ u_long ltemp;
+ char ampmchar; /* AM/PM indicator */
+ char daychar; /* standard/daylight indicator */
+ char junque[10]; /* "yy/dd/mm/" discard */
+ char info[14]; /* "frdzycchhSSFT" clock info */
/*
- * The output of the QT command looks like:
- *
- * A09:57:50.263D
- *
- * The minimum length of the string is 14 characters as is
- * the maximum length.
+ * Initialize pointers and read the timecode and timestamp
*/
- n = rbufp->recv_length;
- if (n > PSTMAXQTLEN + 10)
- n = PSTMAXQTLEN + 10;
-
- bp = rbufp->recv_buffer;
- cp = &pst->lastcode[pst->lencode];
- *cp++ = ' ';
- cpstart = cp;
- while (n-- > 0) {
- *cp = (*bp++) & 0x7f; /* strip parity */
- if (!isprint(*cp))
- break;
- cp++;
- }
- len = (cp - cpstart);
- pst->lencode = (u_char)(cp - pst->lastcode);
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct pstunit *)pp->unitptr;
+ up->lastptr += refclock_gtlin(rbufp, up->lastptr, pp->lastcode
+ + BMAX - 2 - up->lastptr, &trtmp);
+ *up->lastptr++ = ' ';
+ *up->lastptr = '\0';
/*
- * Okay, got all printable characters from the string
- * copied. We expect to have been terminated by the
- * EOL character. If not, forget it. If the length
- * is insane, forget it.
- */
- if (*cp != PSTEOL ||
- len < PSTMINQTLEN || len > PSTMAXQTLEN) {
- pst->reason = QTREASON + 1;
- return 0;
- }
- *cp = '\0';
-#ifdef PSTCLK
- /*
- * Receive time stamp should be in buffer after the code.
- * Make sure we have enough characters in there.
- */
- if (&rbufp->recv_buffer[rbufp->recv_length] - bp < 8) {
- pst->reason = QTREASON + 2;
- return 0;
- }
- if (!buftvtots(bp, tsrec)) {
- pst->reason = QTREASON + 3;
- return 0;
- }
-#else
- /*
- * Use the timestamp collected with the input.
+ * Note we get a buffer and timestamp for each <cr>, but only
+ * the first timestamp is retained.
*/
- *tsrec = rbufp->recv_time;
+ if (!up->tcswitch)
+ pp->lastrec = trtmp;
+ up->tcswitch++;
+ pp->lencode = up->lastptr - pp->lastcode;
+ if (up->tcswitch < 3)
+ return;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+#ifdef DEBUG
+ if (debug)
+ printf("pst: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
#endif
/*
- * Ensure that the characters are formatted validly. Mostly
- * digits, but the occasional `:' and `.'.
- */
- cp = cpstart;
- if (!isdigit(cp[1]) || !isdigit(cp[2]) || cp[3] != ':' ||
- !isdigit(cp[4]) || !isdigit(cp[5]) || cp[6] != ':' ||
- !isdigit(cp[7]) || !isdigit(cp[8]) || cp[9] != '.' ||
- !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[12])) {
- pst->reason = QTREASON + 4;
- return 0;
- }
-
- /*
- * Extract the hour, minute, second and millisecond
- */
- hour = MULBY10(PSTTOBIN(cp[1])) + PSTTOBIN(cp[2]);
- minute = MULBY10(PSTTOBIN(cp[4])) + PSTTOBIN(cp[5]);
- second = MULBY10(PSTTOBIN(cp[7])) + PSTTOBIN(cp[8]);
- msec = MULBY10(PSTTOBIN(cp[10])) + PSTTOBIN(cp[11]);
- msec = MULBY10(msec) + PSTTOBIN(cp[12]);
-
- if (minute > 59 || second > 59) {
- pst->reason = QTREASON + 5;
- return 0;
- }
-
- /*
- * Trouble here. Adjust the hours for AM/PM, if this is
- * on, and for daylight saving time.
- */
- if (*cp == 'A') {
- if (hour > 12 || hour == 0) {
- pst->reason = QTREASON + 5;
- return 0;
- }
- if (hour == 12)
- hour = 0;
- } else if (*cp == 'P') {
- if (hour > 12 || hour == 0)
- return 0;
- if (hour < 12)
- hour += 12;
- } else if (*cp != ' ') {
- pst->reason = QTREASON + 6;
- return 0;
- }
-
- if (cp[13] == 'D')
- tzoff = -1;
- else if (cp[13] == ' ')
- tzoff = 0;
- else {
- pst->reason = QTREASON + 7;
- return 0;
- }
-
- /*
- * Adjust for the timezone. The PST manual is screwy here.
- * it says the timezone is an integer in the range 0 to 23,
- * but this doesn't allow us to tell the difference between
- * +12 and -12. Assume the 12 hour timezone is west of
- * GMT.
- */
- if (pst->timezone <= 12)
- tzoff += pst->timezone;
- else
- tzoff -= (24 - pst->timezone);
-
-
- /*
- * Record for posterity
- */
- pst->hour = (u_char)hour;
- pst->minute = (u_char)minute;
- pst->second = (u_char)second;
- pst->millisecond = (u_short)msec;
- pst->tzoffset = (s_char)tzoff;
-
- /*
- * All that to get the day-hour-minute-second. Turn this
- * into the seconds part of a time stamp. Also use the
- * milliseconds part directly as the fractional part.
- */
- MSUTOTSF(msec, tsclk->l_uf);
- if (!clocktime((int)pst->yearday, hour, minute, second, tzoff,
- tsrec->l_ui, &pst->yearstart, &tsclk->l_ui)) {
- pst->reason = QTREASON + 8;
- return 0;
- }
-
- /*
- * Add in the fudge
- */
- if (pst->flags & PST_WWVH)
- L_ADDUF(tsclk, wwvh_prop_data[pst->unit].remainder);
- else
- L_ADDUF(tsclk, wwv_prop_data[pst->unit].remainder);
-
- /*
- * Glad that's over with
- */
- return 1;
-}
-
-
-/*
- * pst_do_event - update our status and report any changes
- */
-static void
-pst_do_event(pst, evnt_code)
- register struct pstunit *pst;
- int evnt_code;
-{
- if (pst->status != (u_char)evnt_code) {
- pst->status = (u_char)evnt_code;
- if (evnt_code != CEVNT_NOMINAL)
- pst->lastevent = (u_char)evnt_code;
- /*
- * Should trap this, but the trap code isn't up to
- * it yet.
- */
- }
-}
-
-
-
-/*
- * pst_process - process the data collected to produce an offset estimate
- */
-static void
-pst_process(pst)
- register struct pstunit *pst;
-{
- register int i;
- register int n;
- register U_LONG tmp_ui;
- register U_LONG tmp_uf;
- register U_LONG date_ui;
- register U_LONG date_uf;
- u_fp dispersion;
- l_fp off[NPSTSAMPS];
-
- /*
- * Compute offsets from the raw data. Sort them into
- * ascending order.
+ * We get down to business, check the timecode format and decode
+ * its contents. If the timecode has invalid length or is not in
+ * proper format, we declare bad format and exit.
*/
- for (i = 0; i < NPSTSAMPS; i++) {
- tmp_ui = pst->reftimes[i].l_ui;
- tmp_uf = pst->reftimes[i].l_uf;
- M_SUB(tmp_ui, tmp_uf, pst->rectimes[i].l_ui,
- pst->rectimes[i].l_uf);
- for (n = i; n > 0; n--) {
- if (M_ISGEQ(tmp_ui, tmp_uf, off[n-1].l_ui,
- off[n-1].l_uf))
- break;
- off[n] = off[n-1];
- }
- off[n].l_ui = tmp_ui;
- off[n].l_uf = tmp_uf;
+ if (pp->lencode < LENPST) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
}
/*
- * Reject the furthest from the median until 8 samples left
+ * Timecode format:
+ * "ahh:mm:ss.fffs yy/dd/mm/ddd frdzycchhSSFTttttuuxx"
*/
- i = 0;
- n = NPSTSAMPS;
- while ((n - i) > 8) {
- tmp_ui = off[n-1].l_ui;
- tmp_uf = off[n-1].l_uf;
- date_ui = off[(n+i)/2].l_ui;
- date_uf = off[(n+i)/2].l_uf;
- M_SUB(tmp_ui, tmp_uf, date_ui, date_uf);
- M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf);
- if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) {
- /*
- * reject low end
- */
- i++;
- } else {
- /*
- * reject high end
- */
- n--;
- }
+ if (sscanf(pp->lastcode, "%c%2d:%2d:%2d.%3d%c %9s%3d%13s%4ld",
+ &ampmchar, &pp->hour, &pp->minute, &pp->second,
+ &pp->msec, &daychar, junque, &pp->day,
+ info, &ltemp) != 10) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
}
/*
- * Compute the dispersion based on the difference between the
- * extremes of the remaining offsets.
+ * Decode synchronization, quality and last update. If
+ * unsynchronized, set the leap bits accordingly and exit. Once
+ * synchronized, the dispersion depends only on when the clock
+ * was last heard, which depends on the time since last update,
+ * as reported by the clock.
*/
- tmp_ui = off[n-1].l_ui;
- tmp_uf = off[n-1].l_uf;
- M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
- dispersion = MFPTOFP(tmp_ui, tmp_uf);
-
- /*
- * Now compute the offset estimate. If the sloppy clock
- * flag is set, average the remainder, otherwise pick the
- * median.
- */
- if (sloppyclock[pst->unit]) {
- tmp_ui = tmp_uf = 0;
- while (i < n) {
- M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
- i++;
- }
- M_RSHIFT(tmp_ui, tmp_uf);
- M_RSHIFT(tmp_ui, tmp_uf);
- M_RSHIFT(tmp_ui, tmp_uf);
- i = 0;
- off[0].l_ui = tmp_ui;
- off[0].l_uf = tmp_uf;
+ if (info[9] != '8') {
+ pp->leap = LEAP_NOTINSYNC;
} else {
- i = (n+i)/2;
- }
-
- /*
- * Add the default PST QT delay into this.
- */
- L_ADDUF(&off[i], PSTQTFUDGE);
-
- /*
- * Set the reference ID to the appropriate station
- */
- if (stratumtouse[pst->unit] <= 1) {
- if (pst->station >= 0)
- memmove((char *)&pst->peer->refid, WWVREFID, 4);
+ pp->leap = 0;
+ pp->lasttime = current_time - ltemp;
+ if (info[12] == 'H')
+ memcpy((char *)&pp->refid, WWVHREFID, 4);
else
- memmove((char *)&pst->peer->refid, WWVHREFID, 4);
+ memcpy((char *)&pp->refid, WWVREFID, 4);
+ if (peer->stratum <= 1)
+ peer->refid = pp->refid;
}
/*
- * Give the data to the reference clock support code
- */
- record_clock_stats(&(pst->peer->srcadr), pst->lastcode);
- refclock_receive(pst->peer, &off[i], 0, dispersion, &pst->reftimes[NPSTSAMPS-1],
- &pst->rectimes[NPSTSAMPS-1], pst->leap);
-
- /*
- * If the don't-sync flag isn't on, we're nominal.
- */
- if (pst->leap == 0)
- pst_event(pst, CEVNT_NOMINAL);
- pst_reset(pst);
-}
-
-
-
-/*
- * pst_receive - receive data from a PST clock, call the appropriate
- * routine to process it, and advance the state.
- */
-static void
-pst_receive(rbufp)
- struct recvbuf *rbufp;
-{
- register struct pstunit *pst;
- register U_LONG tmp;
-
- pst = (struct pstunit *)rbufp->recv_srcclock;
-
- /*
- * Process based on the current state.
- */
- switch(pst->state) {
- case STATE_IDLE:
- return; /* Ignore the input */
-
- case STATE_QV:
- if (!pst_QV_process(pst, rbufp)) {
- /*
- * Set the state to idle, but request another
- * QV poll.
- */
- pst->badformat++;
- pst_event(pst, CEVNT_BADREPLY);
- pst->state = STATE_IDLE;
- pst->flags |= PST_DOQV;
- } else {
- /*
- * This went okay. Advance the state to
- * QM and send the request.
- */
- pst->state = STATE_QM;
- pst_send(pst, "QM", 2);
- }
- return;
-
- case STATE_QM:
- if (!pst_QM_process(pst, rbufp)) {
- /*
- * Idle us and note the error
- */
- pst->badformat++;
- pst_event(pst, CEVNT_BADREPLY);
- pst->state = STATE_IDLE;
- return;
- }
- if (pst->flags & PST_NOTIME) {
- /*
- * Here we aren't getting any time because the
- * clock is still searching. Don't bother
- * looking for anything. Remove any leap
- * second hold, however, since this should
- * ensure the clock is sensible.
- */
- pst_event(pst, CEVNT_FAULT);
- pst->state = STATE_IDLE;
- if (pst->nextsample > 0)
- pst_reset(pst); /* Make sure rate low */
- return;
- }
-
- /*
- * Next is QD. Do it.
- */
- pst->state = STATE_QD;
- pst_send(pst, "QD", 2);
- return;
-
- case STATE_QD:
- if (!pst_QD_process(pst, rbufp)) {
- /*
- * Idle us and note the error
- */
- pst->badformat++;
- pst_event(pst, CEVNT_BADDATE);
- pst->state = STATE_IDLE;
- } else {
- /*
- * Last step is QT.
- */
- pst->state = STATE_QT;
- pst_send(pst, "QT", 2);
- }
- return;
-
- case STATE_QT:
- pst->state = STATE_IDLE;
- if (!pst_QT_process(pst, rbufp, &pst->lastref, &pst->lastrec)) {
- /*
- * Note the error
- */
- pst->baddata++;
- pst_event(pst, CEVNT_BADTIME);
- return;
- }
- break;
-
- default:
- syslog(LOG_ERR,
- "pst_receive: unit %d invalid state %d",
- pst->unit, pst->state);
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
-
-
- /*
- * You may not have noticed this, but the only way we end up
- * out here is if we've completed polling and have a couple of
- * valid time stamps. First see if we should reset the
- * structure.
- */
- if (pst->nextsample > 0) {
- tmp = pst->lastrec.l_ui - pst->rectimes[0].l_ui;
- if (tmp > (U_LONG)psttab[pst->nextsample].tooold)
- pst_reset(pst);
- }
-
- pst->rectimes[pst->nextsample] = pst->lastrec;
- pst->reftimes[pst->nextsample] = pst->lastref;
- pst->nextsample++;
- if (pst->flags & PST_WWVH)
- pst->station--;
- else
- pst->station++;
-
- if (pst->flags & (PST_SIGFAULT|PST_HARDERR)) {
- pst_event(pst, CEVNT_FAULT);
- pst->leap = LEAP_NOTINSYNC;
- } else if (pst->timesincesync > freerun[pst->unit]) {
- pst_event(pst, CEVNT_PROP);
- pst->leap = LEAP_NOTINSYNC;
- }
-
- if (pst->nextsample >= NPSTSAMPS)
- pst_process(pst);
+ trtmp = pp->lastrec;
+ trtmp.l_ui -= ltemp;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion, &trtmp,
+ &pp->lastrec, pp->leap);
}
/*
- * pst_compute_delay - compute appropriate things to tell clock about delays
+ * pst_poll - called by the transmit procedure
*/
static void
-pst_compute_delay(prop_delay, prop_data)
- U_LONG prop_delay;
- struct pst_propagate *prop_data;
+pst_poll(unit, peer)
+ int unit;
+ struct peer *peer;
{
- register int code;
- register U_LONG tsf;
+ register struct pstunit *up;
+ struct refclockproc *pp;
/*
- * Convert (truncate) the delay to milliseconds. Save the
- * characters needed to send this to the clock and compute
- * the remainder to be added in later.
+ * Time to poll the clock. The PSTI/Traconex clock responds to a
+ * "QTQDQMT" by returning a timecode in the format specified
+ * above. If nothing is heard from the clock for two polls,
+ * declare a timeout and keep going.
*/
- code = tsftomsu(prop_delay, 0);
- MSUTOTSF(code, tsf);
- prop_data->remainder = prop_delay - tsf;
- if (prop_data->remainder & 0x80000000)
- prop_data->remainder = 0;
- prop_data->msbchar = BINTOPST((code >> 2) & 0x1f);
- prop_data->lsbchar = BINTOPST(code & 0x3);
-}
-
-
-/*
- * pst_control - set fudge factors, return statistics
- */
-static void
-pst_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct pstunit *pst;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "pst_control: unit %d invalid", unit);
- return;
- }
-
- if (in != 0) {
- int doqv = 0;
-
- if (in->haveflags & CLK_HAVETIME1)
- if (in->fudgetime1.l_ui == 0
- && in->fudgetime1.l_uf <= PSTMAXPROP) {
- wwv_prop_delay[unit] = in->fudgetime1;
- doqv = 1;
- pst_compute_delay(wwv_prop_delay[unit].l_uf,
- &wwv_prop_data[unit]);
- }
- if (in->haveflags & CLK_HAVETIME2)
- if (in->fudgetime2.l_ui == 0
- && in->fudgetime2.l_uf <= PSTMAXPROP) {
- wwvh_prop_delay[unit] = in->fudgetime2;
- doqv = 1;
- pst_compute_delay(wwvh_prop_delay[unit].l_uf,
- &wwvh_prop_data[unit]);
- }
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- }
- if (in->haveflags & CLK_HAVEVAL2) {
- if (in->fudgeval2 > 0 && in->fudgeval2 < 9990)
- freerun[unit] = (u_short)in->fudgeval2;
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- sloppyclock[unit] = in->flags & CLK_FLAG1;
- }
- if (unitinuse[unit]) {
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- if (in->haveflags & CLK_HAVEVAL1) {
- pstunits[unit]->peer->stratum
- = stratumtouse[unit];
- if (stratumtouse[unit] > 1)
- pstunits[unit]->peer->refid
- = htonl(PSTHSREFID);
- }
-
- if ((in->haveflags & CLK_HAVEFLAG3) &&
- (in->flags & CLK_FLAG3)) {
- pstunits[unit]->flags |= PST_DORESET;
- } else if (doqv || ((in->haveflags & CLK_HAVEFLAG2) &&
- (in->flags & CLK_FLAG2))) {
- pstunits[unit]->flags |= PST_DOQV;
- }
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_WWV_PST;
- out->flags = 0;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
- CLK_HAVEVAL2|CLK_HAVEFLAG1;
- out->fudgetime1 = wwv_prop_delay[unit];
- out->fudgetime2 = wwvh_prop_delay[unit];
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = (LONG)freerun[unit];
- out->flags = sloppyclock[unit];
- if (unitinuse[unit]) {
- pst = pstunits[unit];
- out->clockdesc = pst->description;
- out->lencode = pst->lencode;
- out->lastcode = pst->lastcode;
- out->timereset = current_time - pst->timestarted;
- out->polls = pst->polls;
- out->noresponse = pst->noreply;
- out->badformat = pst->badformat;
- out->baddata = pst->baddata;
- out->lastevent = pst->lastevent;
- out->currentstatus = pst->status;
- } else {
- out->clockdesc = pstdefdesc;
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ pp = peer->procptr;
+ up = (struct pstunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ up->tcswitch = 0;
+ up->lastptr = pp->lastcode;
+ if (write(pp->io.fd, "QTQDQMT", 6) != 6) {
+ refclock_report(peer, CEVNT_FAULT);
+ } else
+ pp->polls++;
}
-
-/*
- * pst_buginfo - return clock dependent debugging info
- */
-static void
-pst_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct pstunit *pst;
- register int i;
-
- bug->nvalues = bug->ntimes = 0;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "pst_buginfo: unit %d invalid", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- pst = pstunits[unit];
-
- bug->nvalues = 14;
- bug->svalues = (1<<10);
- bug->values[0] = (U_LONG)pst->nextsample;
- bug->values[1] = (U_LONG)pst->state;
- bug->values[2] = (U_LONG)pst->reason;
- bug->values[3] = (U_LONG)pst->flags;
- bug->values[4] = (U_LONG)pst->yearday;
- bug->values[5] = (U_LONG)pst->hour;
- bug->values[6] = (U_LONG)pst->minute;
- bug->values[7] = (U_LONG)pst->second;
- bug->values[8] = (U_LONG)pst->millisecond;
- bug->values[9] = (U_LONG)pst->timezone;
- bug->values[10] = (U_LONG)((LONG)pst->tzoffset);
- bug->values[11] = (U_LONG)pst->timesincesync;
- bug->values[12] = pst->yearstart;
- bug->ntimes = ((NPSTSAMPS*2)+2) > NCLKBUGTIMES ? NCLKBUGTIMES :
- ((NPSTSAMPS*2)+2);
- bug->stimes = 0;
- for (i = 0; i < (bug->ntimes-2)/2; i++) {
- bug->times[2*i] = pst->rectimes[i];
- bug->times[(2*i) + 1] = pst->reftimes[i];
- }
- bug->times[bug->ntimes - 2] = pst->lastrec;
- bug->times[bug->ntimes - 1] = pst->lastref;
-}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_tpro.c b/usr.sbin/xntpd/xntpd/refclock_tpro.c
index 54d9f3cb5287..388103c7c1c6 100644
--- a/usr.sbin/xntpd/xntpd/refclock_tpro.c
+++ b/usr.sbin/xntpd/xntpd/refclock_tpro.c
@@ -1,7 +1,8 @@
/*
- * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader
+ * refclock_tpro - clock driver for the KSI/Odetics TPRO-S IRIG-B reader
*/
-#if defined(REFCLOCK) && defined(TPRO)
+#if defined(REFCLOCK) && defined(TPRO) && defined(sun)
+
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
@@ -20,31 +21,19 @@
*/
/*
- * Definitions
+ * TPRO interface definitions
*/
-#define MAXUNITS 1 /* max number of TPRO units */
-#define TPROFD "/dev/tpro%d" /* name of driver device */
-#define BMAX 50 /* timecode buffer length */
+#define DEVICE "/dev/tpro%d" /* device name and unit */
+#define PRECISION (-20) /* precision assumed (1 us) */
+#define REFID "IRIG" /* reference ID */
+#define DESCRIPTION "KSI/Odetics TPRO/S IRIG Interface" /* WRU */
-/*
- * TPRO interface parameters. The "IRIG" can be changed to "GPS" for the
- * TPRO-GPS.
- */
-#define TPROPRECISION (-20) /* precision assumed (1 us) */
-#define TPROREFID "IRIG" /* reference id */
-#define TPRODESCRIPTION "KSI/Odetics TPRO-S IRIG-B Reader" /* who we are */
-#define TPROHSREFID 0x7f7f0c0a /* 127.127.12.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
-
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
- */
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
+#define NSAMPLES 3 /* stages of median filter */
/*
* Imported from ntp_timer module
*/
-extern U_LONG current_time; /* current time (s) */
+extern u_long current_time; /* current time (s) */
/*
* Imported from ntpd module
@@ -52,250 +41,106 @@ extern U_LONG current_time; /* current time (s) */
extern int debug; /* global debug flag */
/*
- * TPRO unit control structure.
+ * Unit control structure
*/
struct tprounit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- struct tproval tprodata; /* data returned from tpro read */
- l_fp lastrec; /* last local time */
- l_fp lastref; /* last timecode time */
- char lastcode[BMAX]; /* last timecode received */
- u_char lencode; /* length of last timecode */
- U_LONG lasttime; /* last time clock heard from */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- U_LONG usec; /* microsecond of second */
- U_LONG yearstart; /* start of current year */
- u_char leap; /* leap indicators */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
+ struct tproval tprodata; /* data returned from tpro read */
};
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct tprounit *tprounits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-/*
* Function prototypes
*/
-static void tpro_init P(());
-static int tpro_start P((u_int, struct peer *));
-static void tpro_shutdown P((int));
-static void tpro_report_event P((struct tprounit *, int));
-static void tpro_receive P((struct recvbuf *));
+static int tpro_start P((int, struct peer *));
+static void tpro_shutdown P((int, struct peer *));
static void tpro_poll P((int unit, struct peer *));
-static void tpro_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void tpro_buginfo P((int, struct refclockbug *));
/*
* Transfer vector
*/
-struct refclock refclock_tpro = {
- tpro_start, tpro_shutdown, tpro_poll,
- tpro_control, tpro_init, tpro_buginfo, NOFLAGS
+struct refclock refclock_tpro = {
+ tpro_start, /* start up driver */
+ tpro_shutdown, /* shut down driver */
+ tpro_poll, /* transmit poll message */
+ noentry, /* not used (old tpro_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old tpro_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * tpro_init - initialize internal tpro driver data
- */
-static void
-tpro_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)tprounits, 0, sizeof tprounits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = 0;
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
/*
* tpro_start - open the TPRO device and initialize data for processing
*/
static int
tpro_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct tprounit *tpro;
- register int i;
- char tprodev[20];
- int fd_tpro;
+ register struct tprounit *up;
+ struct refclockproc *pp;
+ char device[20];
+ int fd;
/*
- * Check configuration info.
+ * Open TPRO device
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "tpro_start: unit %d invalid", unit);
- return (0);
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "tpro_start: unit %d in use", unit);
+ (void)sprintf(device, DEVICE, unit);
+ fd = open(device, O_RDONLY | O_NDELAY, 0777);
+ if (fd == -1) {
+ syslog(LOG_ERR, "tpro_start: open of %s: %m", device);
return (0);
}
/*
- * Open TPRO device
+ * Allocate and initialize unit structure
*/
- (void) sprintf(tprodev, TPROFD, unit);
- fd_tpro = open(tprodev, O_RDWR, 0777);
- if (fd_tpro == -1) {
- syslog(LOG_ERR, "tpro_start: open of %s: %m", tprodev);
+ if (!(up = (struct tprounit *)
+ emalloc(sizeof(struct tprounit)))) {
+ (void) close(fd);
return (0);
}
-
- /*
- * Allocate unit structure
- */
- if (tprounits[unit] != 0) {
- tpro = tprounits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && tprounits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- tpro = tprounits[i];
- tprounits[i] = 0;
- } else {
- tpro = (struct tprounit *)
- emalloc(sizeof(struct tprounit));
- }
+ memset((char *)up, 0, sizeof(struct tprounit));
+ pp = peer->procptr;
+ pp->io.clock_recv = noentry;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- memset((char *)tpro, 0, sizeof(struct tprounit));
- tprounits[unit] = tpro;
-
- /*
- * Set up the structures
- */
- tpro->peer = peer;
- tpro->unit = (u_char)unit;
- tpro->timestarted = current_time;
-
- tpro->io.clock_recv = tpro_receive;
- tpro->io.srcclock = (caddr_t)tpro;
- tpro->io.datalen = 0;
- tpro->io.fd = fd_tpro;
+ pp->unitptr = (caddr_t)up;
/*
- * All done. Initialize a few random peer variables, then
- * return success. Note that root delay and root dispersion are
- * always zero for this clock.
+ * Initialize miscellaneous peer variables
*/
- peer->precision = TPROPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, TPROREFID, 4);
- else
- peer->refid = htonl(TPROHSREFID);
- unitinuse[unit] = 1;
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
return (1);
}
/*
- * tpro_shutdown - shut down a TPRO clock
+ * tpro_shutdown - shut down the clock
*/
static void
-tpro_shutdown(unit)
+tpro_shutdown(unit, peer)
int unit;
-{
- register struct tprounit *tpro;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "tpro_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "tpro_shutdown: unit %d not in use", unit);
- return;
- }
-
- /*
- * Tell the I/O module to turn us off. We're history.
- */
- tpro = tprounits[unit];
- io_closeclock(&tpro->io);
- unitinuse[unit] = 0;
-}
-
-/*
- * tpro_report_event - note the occurance of an event
- *
- * This routine presently just remembers the report and logs it, but
- * does nothing heroic for the trap handler.
- */
-static void
-tpro_report_event(tpro, code)
- struct tprounit *tpro;
- int code;
-{
struct peer *peer;
+{
+ register struct tprounit *up;
+ struct refclockproc *pp;
- peer = tpro->peer;
- if (tpro->status != (u_char)code) {
- tpro->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- tpro->lastevent = (u_char)code;
- syslog(LOG_INFO,
- "clock %s event %x", ntoa(&peer->srcadr), code);
- }
+ pp = peer->procptr;
+ up = (struct tprounit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
/*
- * tpro_receive - receive data from the TPRO device.
- *
- * Note: This interface would be interrupt-driven. We don't use that
- * now, but include a dummy routine for possible future adventures.
- */
-static void
-tpro_receive(rbufp)
- struct recvbuf *rbufp;
-{
-}
-
-/*
* tpro_poll - called by the transmit procedure
*/
static void
@@ -303,196 +148,80 @@ tpro_poll(unit, peer)
int unit;
struct peer *peer;
{
- struct tprounit *tpro;
- struct tproval *tptr;
- l_fp tstmp;
+ register struct tprounit *up;
+ struct refclockproc *pp;
+ struct tproval *tp;
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "tpro_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "tpro_poll: unit %d not in use", unit);
- return;
- }
- tpro = tprounits[unit];
- tpro->polls++;
+ /*
+ * This is the main routine. It snatches the time from the TPRO
+ * board and tacks on a local timestamp.
+ */
+ pp = peer->procptr;
+ up = (struct tprounit *)pp->unitptr;
- tptr = &tpro->tprodata;
- if (read(tpro->io.fd, (char *)tptr, sizeof(struct tproval)) < 0) {
- tpro_report_event(tpro, CEVNT_BADREPLY);
+ tp = &up->tprodata;
+ if (read(pp->io.fd, (char *)tp, sizeof(struct tproval)) < 0) {
+ refclock_report(peer, CEVNT_FAULT);
return;
}
- gettstamp(&tpro->lastrec);
- tpro->lasttime = current_time;
+ gettstamp(&pp->lastrec);
+ pp->lasttime = current_time;
+ pp->polls++;
/*
- * Get TPRO time and convert to timestamp format. Note: we
+ * We get down to business, check the timecode format and decode
+ * its contents. If the timecode has invalid length or is not in
+ * proper format, we declare bad format and exit. Note: we
* can't use the sec/usec conversion produced by the driver,
- * since the year may be suspect.
+ * since the year may be suspect. All format error checking is
+ * done by the sprintf() and sscanf() routines.
*/
- sprintf(tpro->lastcode,
+ if (sprintf(pp->lastcode,
"%1x%1x%1x %1x%1x:%1x%1x:%1x%1x.%1x%1x%1x%1x%1x%1x %1x",
- tptr->day100, tptr->day10, tptr->day1, tptr->hour10, tptr->hour1,
- tptr->min10, tptr->min1, tptr->sec10, tptr->sec1,
- tptr->ms100, tptr->ms10, tptr->ms1, tptr->usec100, tptr->usec10,
- tptr->usec1, tptr->status);
- record_clock_stats(&(tpro->peer->srcadr), tpro->lastcode);
- tpro->lencode = strlen(tpro->lastcode);
+ tp->day100, tp->day10, tp->day1, tp->hour10, tp->hour1,
+ tp->min10, tp->min1, tp->sec10, tp->sec1, tp->ms100,
+ tp->ms10, tp->ms1, tp->usec100, tp->usec10, tp->usec1,
+ tp->status)) {
+ refclock_report(peer, CEVNT_BADREPLY);
+ return;
+ }
- tpro->day = MULBY10(MULBY10(tptr->day100) + tptr->day10) + tptr->day1;
- tpro->hour = MULBY10(tptr->hour10) + tptr->hour1;
- tpro->minute = MULBY10(tptr->min10) + tptr->min1;
- tpro->second = MULBY10(tptr->sec10) + tptr->sec1;
- tpro->usec = MULBY10(MULBY10(tptr->ms100) + tptr->ms10) + tptr->ms1;
- tpro->usec = tpro->usec * 10 + tptr->usec100;
- tpro->usec = tpro->usec * 10 + tptr->usec10;
- tpro->usec = tpro->usec * 10 + tptr->usec1;
#ifdef DEBUG
if (debug)
- printf("tpro: %3d %02d:%02d:%02d.%06ld %1x\n",
- tpro->day, tpro->hour, tpro->minute, tpro->second,
- tpro->usec, tptr->status);
+ printf("tpro: time %s timecode %d %s\n",
+ ulfptoa(&pp->lastrec, 6), pp->lencode,
+ pp->lastcode);
#endif
- if (tptr->status != 0xff) {
- tpro_report_event(tpro, CEVNT_BADREPLY);
+ record_clock_stats(&peer->srcadr, pp->lastcode);
+ if (sscanf(pp->lastcode, "%3d %2d:%2d:%2d.%6ld", &pp->day,
+ &pp->hour, &pp->minute, &pp->second, &pp->usec)
+ != 5) {
+ refclock_report(peer, CEVNT_BADTIME);
+ return;
+ }
+ if (tp->status != 0xff) {
+ pp->leap = LEAP_NOTINSYNC;
+ refclock_report(peer, CEVNT_FAULT);
return;
+ } else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
}
/*
- * Now, compute the reference time value. Use the heavy
- * machinery for the seconds and the millisecond field for the
- * fraction when present. If an error in conversion to internal
- * format is found, the program declares bad data and exits.
- * Note that this code does not yet know how to do the years and
- * relies on the clock-calendar chip for sanity.
- */
- if (!clocktime(tpro->day, tpro->hour, tpro->minute,
- tpro->second, GMT, tpro->lastrec.l_ui,
- &tpro->yearstart, &tpro->lastref.l_ui)) {
- tpro->baddata++;
- tpro_report_event(tpro, CEVNT_BADTIME);
- return;
- }
- TVUTOTSF(tpro->usec, tpro->lastref.l_uf);
- tstmp = tpro->lastref;
- L_SUB(&tstmp, &tpro->lastrec);
- tpro->coderecv++;
- L_ADD(&tstmp, &(fudgefactor[tpro->unit]));
- refclock_receive(tpro->peer, &tstmp, GMT, 0,
- &tpro->lastrec, &tpro->lastrec, tpro->leap);
-}
-
-/*
- * tpro_control - set fudge factors, return statistics
- */
-static void
-tpro_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct tprounit *tpro;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "tpro_control: unit %d invalid)", unit);
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
+ */
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- tpro = tprounits[unit];
- peer = tpro->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- TPROREFID, 4);
- else
- peer->refid = htonl(TPROHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG1;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_IRIG_TPRO;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1;
- out->clockdesc = TPRODESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- tpro = tprounits[unit];
- out->lencode = tpro->lencode;
- out->lastcode = tpro->lastcode;
- out->timereset = current_time - tpro->timestarted;
- out->polls = tpro->polls;
- out->noresponse = tpro->noreply;
- out->badformat = tpro->badformat;
- out->baddata = tpro->baddata;
- out->lastevent = tpro->lastevent;
- out->currentstatus = tpro->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
}
-/*
- * tpro_buginfo - return clock dependent debugging info
- */
-static void
-tpro_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct tprounit *tpro;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "tpro_buginfo: unit %d invalid)", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- tpro = tprounits[unit];
-
- bug->nvalues = 11;
- bug->ntimes = 5;
- if (tpro->lasttime != 0)
- bug->values[0] = current_time - tpro->lasttime;
- else
- bug->values[0] = 0;
- bug->values[2] = (U_LONG)tpro->year;
- bug->values[3] = (U_LONG)tpro->day;
- bug->values[4] = (U_LONG)tpro->hour;
- bug->values[5] = (U_LONG)tpro->minute;
- bug->values[6] = (U_LONG)tpro->second;
- bug->values[7] = (U_LONG)tpro->usec;
- bug->values[9] = tpro->yearstart;
- bug->stimes = 0x1c;
- bug->times[0] = tpro->lastref;
- bug->times[1] = tpro->lastrec;
-}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_trak.c b/usr.sbin/xntpd/xntpd/refclock_trak.c
index f2b3eb11fc9d..d10d75234fbd 100644
--- a/usr.sbin/xntpd/xntpd/refclock_trak.c
+++ b/usr.sbin/xntpd/xntpd/refclock_trak.c
@@ -1,11 +1,10 @@
/*
- * refclock_trak.c - clock driver for the TRAK 8810 GPS STATION CLOCK
- * Tsuruoka Tomoaki Oct 30, 1993
- * tsuruoka@nc.fukuoka-u.ac.jp
- * Faculty of Engineering,
- * Fukuoka University, Fukuoka, JAPAN
+ * refclock_trak - clock driver for the TRAK 8820 GPS Station Clock
+ *
+ * Thanks to Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp> for the
+ * previous version from which this one was developed.
*/
-#if defined(REFCLOCK) && (defined(TRAK) || defined(TRAKCLK) || defined(TRAKPPS))
+#if defined(REFCLOCK) && defined(TRAK)
#include <stdio.h>
#include <ctype.h>
@@ -14,494 +13,201 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-
-static void gps_send();
-
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(STREAM)
-#include <termios.h>
-#include <stropts.h>
-#if defined(TRAKCLK)
-#include <sys/clkdefs.h>
-#endif /* TRAKCLK */
-#endif /* STREAM */
-
-#if defined (TRAKPPS)
-#include <sys/ppsclock.h>
-#endif /* TRAKPPS */
-
#include "ntp_stdlib.h"
/*
- * This driver supports the TRAK 8810 GPS Receiver with
- * Buffered RS-232-C Interface Module.
+ * This driver supports the TRAK 8820 GPS Station Clock. The claimed
+ * accuracy at the 1-pps output is 200-300 ns relative to the broadcast
+ * signal; however, in most cases the actual accuracy is limited by the
+ * precision of the timecode and the latencies of the serial interface
+ * and operating system.
*
- * Most of codes are copied from refclock_as2201.c, Thanks a lot.
+ * For best accuracy, this radio requires the LDISC_ACTS line
+ * discipline, which captures a timestamp at the '*' on-time character
+ * of the timecode. Using this discipline the jitter is in the order of
+ * 1 ms and systematic error about 0.5 ms. If unavailable, the buffer
+ * timestamp is used, which is captured at the \r ending the timecode
+ * message. This introduces a systematic error of 23 character times, or
+ * about 24 ms at 9600 bps, together with a jitter well over 8 ms on Sun
+ * IPC-class machines.
*
- * The program expects the radio responses once per seccond
- * ( by "rqts,u" command or panel control )
- * of the form "*RQTS U,ddd:hh:mm:ss.0,Q\r\n for UTC" where
- * ddd= day of year
- * hh= hours
- * mm= minutes
- * ss= seconds
- * Q= Quality byte. Q=0 Phase error > 20 us
- * Q=6 Pahse error < 20 us
- * > 10 us
- * Q=5 Pahse error < 10 us
- * > 1 us
- * Q=4 Pahse error < 1 us
- * > 100 ns
- * Q=3 Pahse error < 100 ns
- * > 10 ns
- * Q=2 Pahse error < 10 ns
- * (note that my clock almost stable at 1 us per 10 hours)
+ * Using the memus, the radio should be set for 9600 bps, one stop bit
+ * and no parity. It should be set to operate in computer (no echo)
+ * mode. The timecode format includes neither the year nor leap-second
+ * warning. No provisions are included in this preliminary version of
+ * the driver to read and record detailed internal radio status.
*
- * Request leap second status - if needed.
- * send: rqls\n
- * reply: RQLS yy,mm,dd
- * where: yy is year
- * mm is month
- * dd is day of month.baud
- * Note: Default data is all zeros
- * i.e. RQLS 00,00,00
- */
-
-/*
- * Definitions
+ * In operation, this driver sends a RQTS\r request to the radio at
+ * initialization in order to put it in continuous time output mode. The
+ * radio then sends the following message once each second:
+ *
+ * *RQTS U,ddd:hh:mm:ss.0,q<cr><lf>
+ *
+ * on-time = '*' * ddd = day of year
+ * hh:mm:ss = hours, minutes, seconds
+ * q = quality indicator (phase error), 0-6:
+ * 0 > 20 us
+ * 6 > 10 us
+ * 5 > 1 us
+ * 4 > 100 ns
+ * 3 > 10 ns
+ * 2 < 10 ns
+ *
+ * The alarm condition is indicated by '0' at Q, which means the radio
+ * has a phase error than 20 usec relative to the broadcast time. The
+ * absence of year, DST and leap-second warning in this format is also
+ * alarming.
+ *
+ * The continuous time mode is disabled using the RQTX<cr> request,
+ * following which the radio sends a RQTX DONE<cr><lf> response. In the
+ * normal mode, other control and status requests are effective,
+ * including the leap-second status request RQLS<cr>. The radio responds
+ * wtih RQLS yy,mm,dd<cr><lf>, where yy,mm,dd are the year, month and
+ * day. Presumably, this gives the epoch of the next leap second,
+ * RQLS 00,00,00 if none is specified in the GPS message. Specified in
+ * this form, the information is generally useless and is ignored by
+ * the driver.
+ *
+ * Fudge Factors
+ *
+ * There are no special fudge factors other than the generic.
*/
-#define MAXUNITS 4 /* max number of GPS units */
-#define GPS232 "/dev/gps%d" /* name of radio device */
-#define SPEED232 B9600 /* uart speed (9600 bps) */
/*
- * Radio interface parameters
+ * Interface definitions
*/
-#define GPSPRECISION (-20) /* precision assumed (about 1 us) */
-#define GPSREFID "GPS" /* reference id */
-#define GPSDESCRIPTION "TRAK 8810 GPS station clock" /* who we are */
-#define GPSHSREFID 0x7f7f020a /* 127.127.2.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
-#define NCODES 3 /* stages of median filter */
-#define LENTOC 25 /* *RQTS U,ddd:hh:mm:ss.0,Q datecode length */
-#define BMAX 100 /* timecode buffer length */
-#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+#define DEVICE "/dev/trak%d" /* device name and unit */
+#define SPEED232 B9600 /* uart speed (9600 baud) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "TRAK" /* reference ID */
+#define DESCRIPTION "TRACK 8810/8820 Station Clock" /* WRU */
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
- */
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
+#define NSAMPLES 3 /* stages of median filter */
+#define LENTRAK 24 /* timecode length */
+#define C_CTO "RQTS\r" /* start continuous time output */
/*
* Imported from ntp_timer module
*/
-extern U_LONG current_time; /* current time (s) */
-
-/*
- * Imported from ntp_loopfilter module
- */
-extern int fdpps; /* pps file descriptor */
+extern u_long current_time; /* current time (s) */
/*
* Imported from ntpd module
*/
-extern int debug; /* global debug flag */
+extern int debug; /* global debug flag */
/*
- * GPS unit control structure.
+ * Unit control structure
*/
-struct gpsunit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp lastrec; /* last data receive time */
- l_fp lastref; /* last timecode time */
- l_fp offset[NCODES]; /* recent sample offsets */
- char lastcode[BMAX]; /* last timecode received */
- u_short polled; /* when polled, means a last sample */
- u_char lencode; /* length of last received ASCII string */
- U_LONG lasttime; /* last time clock heard from */
-#ifdef TRAKPPS
- U_LONG lastev; /* last ppsclock second */
-#endif /* TRAKPPS */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char reason; /* reason for last abort */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- u_short msec; /* milliseconds of second */
- u_char leap; /* leap indicators */
- U_LONG yearstart; /* start of current year */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
-};
-
+struct wwvbunit {
+ int pollcnt; /* poll message counter */
-/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct gpsunit *gpsunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
+ u_char tcswitch; /* timecode switch */
+ char qualchar; /* quality indicator */
+};
/*
* Function prototypes
*/
-static void trak_init P(());
-static int trak_start P((u_int, struct peer *));
-static void trak_shutdown P((int));
-static void trak_report_event P((struct gpsunit *, int));
+static int trak_start P((int, struct peer *));
+static void trak_shutdown P((int, struct peer *));
static void trak_receive P((struct recvbuf *));
-static char trak_process P((struct gpsunit *, l_fp *, u_fp *));
-static void trak_poll P((int unit, struct peer *));
-static void trak_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void trak_buginfo P((int, struct refclockbug *));
+static void trak_poll P((int, struct peer *));
/*
* Transfer vector
*/
-struct refclock refclock_trak = {
- trak_start, trak_shutdown, trak_poll,
- trak_control, trak_init, trak_buginfo, NOFLAGS
+struct refclock refclock_trak = {
+ trak_start, /* start up driver */
+ trak_shutdown, /* shut down driver */
+ trak_poll, /* transmit poll message */
+ noentry, /* not used (old trak_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old trak_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * trak_init - initialize internal gps driver data
- */
-static void
-trak_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)gpsunits, 0, sizeof gpsunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = 0;
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
/*
- * trak_start - open the GPS devices and initialize data for processing
+ * trak_start - open the devices and initialize data for processing
*/
static int
trak_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct gpsunit *gps;
- register int i;
- int fd232;
- char trakdev[20];
-#ifdef TRAKPPS
- struct ppsclockev ev;
-#endif /* TRAKPPS */
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
/*
- * Check configuration info
+ * Open serial port. The LDISC_ACTS line discipline inserts a
+ * timestamp following the "*" on-time character of the
+ * timecode.
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "trak_start: unit %d invalid", unit);
- return (0);
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "trak_start: unit %d in use", unit);
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS)))
return (0);
- }
/*
- * Open serial port
+ * Allocate and initialize unit structure
*/
- (void) sprintf(trakdev, GPS232, unit);
- fd232 = open(trakdev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "trak_start: open of %s: %m", trakdev);
+ if (!(up = (struct wwvbunit *)
+ emalloc(sizeof(struct wwvbunit)))) {
+ (void) close(fd);
return (0);
}
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- *
- */
- { struct termio ttyb;
- if (ioctl(fd232, TCGETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, TCGETA): %m", trakdev);
- goto screwed;
- }
- ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyb.c_oflag = 0;
- ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyb.c_lflag = ICANON;
- ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
- if (ioctl(fd232, TCSETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, TCSETA): %m", trakdev);
- goto screwed;
- }
- }
-#endif /* HAVE_SYSV_TTYS */
-#if defined(STREAM)
- /*
- * POSIX/STREAMS serial line parameters (termios interface)
- *
- * The TRAKCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
- *
- * The TRAKPPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "trak_start: tcgetattr(%s): %m", trakdev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "trak_start: tcsetattr(%s): %m", trakdev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "trak_start: tcflush(%s): %m", trakdev);
- goto screwed;
- }
-#if defined(TRAKCLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, I_PUSH, clk): %m", trakdev);
- if (ioctl(fd232, CLK_SETSTR, "*") < 0)
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, CLK_SETSTR): %m", trakdev);
-#endif /* TRAKCLK */
-#if defined(TRAKPPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, I_PUSH, ppsclock): %m", trakdev);
- else
- fdpps = fd232;
-#endif /* TRAKPPS */
- }
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The TRAKCLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
- */
- { struct sgttyb ttyb;
-#if defined(TRAKCLK)
- int ldisc = CLKLDISC;
-#endif /* TRAKCLK */
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, TIOCGETP): %m", trakdev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(TRAKCLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
- ttyb.sg_erase = ttyb.sg_kill = '\0';
- ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* TRAKCLK */
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, TIOCSETP): %m", trakdev);
- goto screwed;
- }
-#if defined(TRAKCLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, TIOCSETD): %m",trakdev);
- goto screwed;
- }
-#endif /* TRAKCLK */
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (gpsunits[unit] != 0) {
- gps = gpsunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && gpsunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- gps = gpsunits[i];
- gpsunits[i] = 0;
- } else {
- gps = (struct gpsunit *)
- emalloc(sizeof(struct gpsunit));
- }
+ memset((char *)up, 0, sizeof(struct wwvbunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = trak_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- bzero((char *)gps, sizeof(struct gpsunit));
- gpsunits[unit] = gps;
+ pp->unitptr = (caddr_t)up;
/*
- * Set up the structures
+ * Initialize miscellaneous variables
*/
- gps->peer = peer;
- gps->unit = (u_char)unit;
- gps->timestarted = current_time;
-
- gps->io.clock_recv = trak_receive;
- gps->io.srcclock = (caddr_t)gps;
- gps->io.datalen = 0;
- gps->io.fd = fd232;
-#ifdef TRAKPPS
- if (ioctl(fd232, CIOGETEV, (caddr_t)&ev) < 0) {
- syslog(LOG_ERR,
- "trak_start: ioctl(%s, CIOGETEV): %m", trakdev);
- goto screwed;
- } else
- gps->lastev = ev.tv.tv_sec;
-#endif /* TRAKPPS */
- if (!io_addclock(&gps->io)) {
- goto screwed;
- }
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
/*
- * All done. Initialize a few random peer variables, then
- * return success. Note that root delay and root dispersion are
- * always zero for this clock.
- */
- peer->precision = GPSPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- bcopy(GPSREFID, (char *)&peer->refid, 4);
- else
- peer->refid = htonl(GPSHSREFID);
- unitinuse[unit] = 1;
- /*
- * request to give time code
+ * Start continuous time output. If something breaks, fold the
+ * tent and go home.
*/
- {
- void gps_send();
- gps_send(gps,"\rRQTS,U\r");
- gps_send(gps,"SEL 00\r");
+ if (write(pp->io.fd, C_CTO, sizeof(C_CTO)) != sizeof(C_CTO)) {
+ refclock_report(peer, CEVNT_FAULT);
+ (void) close(fd);
+ free(up);
+ return (0);
}
-
return (1);
-
- /*
- * Something broke; abandon ship.
- */
-screwed:
- (void) close(fd232);
- return (0);
-}
-
-/*
- * trak_shutdown - shut down a GPS clock
- */
-static void
-trak_shutdown(unit)
- int unit;
-{
- register struct gpsunit *gps;
- void gps_send();
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "trak_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "trak_shutdown: unit %d not in use", unit);
- return;
- }
- gps = gpsunits[unit];
- /*
- * request not to give time code any more
- */
- gps_send(gps,"RQTX\r");
- /*
- * Tell the I/O module to turn us off. We're history.
- */
- io_closeclock(&gps->io);
-
- unitinuse[unit] = 0;
}
/*
- * trak_report_event - note the occurance of an event
- *
- * This routine presently just remembers the report and logs it, but
- * does nothing heroic for the trap handler.
+ * trak_shutdown - shut down the clock
*/
static void
-trak_report_event(gps, code)
- struct gpsunit *gps;
- int code;
-{
+trak_shutdown(unit, peer)
+ int unit;
struct peer *peer;
+{
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
- peer = gps->peer;
- if (gps->status != (u_char)code) {
- gps->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- gps->lastevent = (u_char)code;
- syslog(LOG_INFO,
- "clock %s event %x\n", ntoa(&peer->srcadr), code);
- }
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
@@ -512,495 +218,122 @@ static void
trak_receive(rbufp)
struct recvbuf *rbufp;
{
- register int i,cmdtype;
- register struct gpsunit *gps;
-
-#if defined(TRAKPPS)
- struct ppsclockev ev;
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
l_fp trtmp;
-#endif /* TRAKPPS */
- register u_char *dpt;
- register u_char *cp;
- register u_char *dpend;
- l_fp tstmp;
- u_fp dispersion;
+ char *dpt, *dpend;
+ char qchar;
/*
- * Get the clock this applies to and pointers to the data.
- * Edit the timecode to remove control chars and trashbits.
+ * Initialize pointers and read the timecode and timestamp. We
+ * then chuck out everything, including runts, except one
+ * message each poll interval.
*/
- gps = (struct gpsunit *)rbufp->recv_srcclock;
- dpt = (u_char *)&rbufp->recv_space;
- dpend = dpt + rbufp->recv_length;
- cp = (u_char *)gps->lastcode;
-
- while (dpt < dpend) {
-#ifdef TRAKCLK /* prior to TRAKPPS due to timestamp */
- if ((*cp = 0x7f & *dpt++) != '*' ) cp++;
- else if (*cp == '*' ) { /* caught magic character */
- if ( dpend - dpt < 8) {
- /* short timestamp */
- if(debug) puts("gps: short timestamp.");
- return;
- }
- if (!buftvtots(dpt,&gps->lastrec)) {
- /* screwy timestamp */
- if(debug) puts("gps: screwy timestamp.");
- return;
- }
- dpt += 8;
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX,
+ &pp->lastrec);
+ if (up->tcswitch || pp->lencode < 9)
+ return;
+ up->tcswitch = 1;
+
+ /*
+ * We get a buffer and timestamp following the '*' on-time
+ * character. If a valid timestamp, we use that in place of the
+ * buffer timestamp and edit out the timestamp for prettyprint
+ * billboards.
+ */
+ dpt = pp->lastcode;
+ dpend = dpt + pp->lencode;
+ if (*dpt == '*' && buftvtots(dpt + 1, &trtmp)) {
+ if (trtmp.l_i == pp->lastrec.l_i || trtmp.l_i ==
+ pp->lastrec.l_i + 1) {
+ pp->lastrec = trtmp;
+ dpt += 9;
+ while (dpt < dpend)
+ *(dpt - 8) = *dpt++;
}
-#else
-#ifdef TRAKPPS
- if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
-#else
- /* both are not specified */
-#endif /* TRAKPPS */
-#endif /* TRAKCLK */
}
- *cp = '\0';
- gps->lencode = cp - (u_char *)gps->lastcode;
- if (gps->lencode == 0) return;
-
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
#ifdef DEBUG
if (debug)
- printf("gps: timecode %d %s\n",
- gps->lencode, gps->lastcode);
+ printf("trak: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
#endif
/*
- * We check the timecode format and decode its contents. The
- * timecode has format *........RQTS U,ddd:hh:mm:ss.0,Q\r\n).
- * 012345678901234567890123
+ * We get down to business, check the timecode format and decode
+ * its contents. If the timecode has invalid length or is not in
+ * proper format, we declare bad format and exit.
*/
-#define RQTS 0
-#define RQLS 1
- cp = (u_char *)gps->lastcode;
- gps->leap = 0;
- cmdtype=0;
- if(strncmp(cp,"*RQTS",5)==0) {
- cmdtype=RQTS;
- cp += 8;
- }
- else if(strncmp(cp,"RQTS",4)==0) {
- cmdtype=RQTS;
- cp += 7;
- }
- else if(strncmp(cp,"RQLS",4)==0) {
- cmdtype=RQLS;
- cp += 5;
- }
- else
- return;
-
- switch( cmdtype ) {
- case RQTS:
- /*
- * Check time code format of TRAK 8810
- */
- if( !isdigit(cp[0]) ||
- !isdigit(cp[1]) ||
- !isdigit(cp[2]) ||
- cp[3] != ':' ||
- !isdigit(cp[4]) ||
- !isdigit(cp[5]) ||
- cp[6] != ':' ||
- !isdigit(cp[7]) ||
- !isdigit(cp[8]) ||
- cp[9] != ':' ||
- !isdigit(cp[10])||
- !isdigit(cp[11])) {
- gps->badformat++;
- trak_report_event(gps, CEVNT_BADREPLY);
- return;
- }
- break;
- case RQLS:
- /*
- * reply for leap second request
- */
- if (cp[0] !='0' || cp[1] != '0' ) gps->leap = LEAP_ADDSECOND;
- return;
- default:
+ if (pp->lencode < LENTRAK) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
-
}
/*
- * Convert date and check values.
- */
- gps->day = cp[0] - '0';
- gps->day = MULBY10(gps->day) + cp[1] - '0';
- gps->day = MULBY10(gps->day) + cp[2] - '0';
- if (gps->day < 1 || gps->day > 366) {
- gps->baddata++;
- trak_report_event(gps, CEVNT_BADDATE);
- return;
- }
- /*
- * Convert time and check values.
- */
- gps->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
- gps->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
- gps->second = MULBY10(cp[10] - '0') + cp[11] - '0';
- gps->msec = 0;
- if (gps->hour > 23 || gps->minute > 59 || gps->second > 59) {
- gps->baddata++;
- trak_report_event(gps, CEVNT_BADTIME);
+ * Timecode format: "*RQTS U,ddd:hh:mm:ss.0,q"
+ */
+ if (sscanf(pp->lastcode, "*RQTS U,%3d:%2d:%2d:%2d.0,%c",
+ &pp->day, &pp->hour, &pp->minute, &pp->second, &qchar) != 5) {
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
- if (!gps->polled) return;
-
/*
- * Test for synchronization Check for quality byte.
+ * Decode quality and leap characters. If unsynchronized, set
+ * the leap bits accordingly and exit.
*/
-/*
- switch( cp[15] ) {
- case '0':
- if(gps->peer->stratum == stratumtouse[gps->unit]) {
- gps->peer->stratum = 10 ;
- bzero(&gps->peer->refid,4);
- }
- break;
- default:
- if(gps->peer->stratum != stratumtouse[gps->unit]) {
- gps->peer->stratum = stratumtouse[gps->unit] ;
- bcopy(GPSREFID,&gps->peer->refid,4);
- }
- break;
+ if (qchar == '0')
+ pp->leap = LEAP_NOTINSYNC;
+ else {
+ pp->leap = 0;
+ pp->lasttime = current_time;
}
-*/
- if( cp[15] == '0') /* TRAK derailed from tracking satellites */
- {
- gps->leap = LEAP_NOTINSYNC;
- gps->noreply++;
- trak_report_event(gps, CEVNT_TIMEOUT);
- }
- else
- {
- gps->lasttime = current_time;
- if( gps->lastevent == CEVNT_TIMEOUT ) {
- gps->status = CEVNT_NOMINAL;
- trak_report_event(gps, CEVNT_NOMINAL);
- }
- }
-
- /*
- * Now, compute the reference time value. Use the heavy
- * machinery for the second, which presumably is the one which
- * occured at the last pps pulse and which was captured by the
- * loop_filter module. All we have to do here is present a
- * reasonable facsimile of the time at that pulse so the clock-
- * filter and selection machinery declares us truechimer. The
- * precision offset within the second is really tuned by the
- * loop_filter module. Note that this code does not yet know how
- * to do the years and relies on the clock-calendar chip for
- * sanity.
- */
-
-#if defined(TRAKPPS)
-
- /*
- * timestamp must be greater than previous one.
- */
- if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
- ev.tv.tv_sec += (U_LONG)JAN_1970;
- TVTOTS(&ev.tv,&gps->lastrec);
- if (gps->lastev < ev.tv.tv_sec) {
- gps->lastev = ev.tv.tv_sec;
- } else { /* in case of 1-pps missing */
- gps->lastev = ev.tv.tv_sec;
- return;
- }
- }
- else
- return; /* failed to get timestamp */
-#endif /* TRAKPPS */
-
- if (!clocktime(gps->day, gps->hour, gps->minute,
- gps->second, GMT, gps->lastrec.l_ui,
- &gps->yearstart, &gps->lastref.l_ui)) {
- gps->baddata++;
- trak_report_event(gps, CEVNT_BADTIME);
-#ifdef DEBUG
- if(debug) printf("gps: bad date \n");
-#endif
- return;
- }
- MSUTOTSF(gps->msec, gps->lastref.l_uf);
- tstmp = gps->lastref;
-
- L_SUB(&tstmp, &gps->lastrec);
- L_ADD(&tstmp, &(fudgefactor[gps->unit]));
- i = ((int)(gps->coderecv)) % NCODES;
- gps->offset[i] = tstmp;
- gps->coderecv++;
-#if DEBUG
- if (debug)
- printf("gps: times %s %s %s\n",
- ulfptoa(&gps->lastref, 6), ulfptoa(&gps->lastrec, 6),
- lfptoa(&tstmp, 6));
-#endif
-/* if( tstmp.l_ui != 0 ) return; something wrong */
/*
- * Process the samples in the median filter, add the fudge
- * factor and pass the offset and dispersion along. We use
- * lastref as both the reference time and receive time in order
- * to avoid being cute, like setting the reference time later
- * than the receive time, which may cause a paranoid protocol
- * module to chuck out the data.
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
*/
- if (gps->coderecv < NCODES)
- return;
- if (!trak_process(gps, &tstmp, &dispersion)) {
- gps->baddata++;
- trak_report_event(gps, CEVNT_BADTIME);
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
- refclock_receive(gps->peer, &tstmp, GMT, dispersion,
- &gps->lastrec, &gps->lastrec, gps->leap);
- /*
- * after all, clear polled flag
- */
- gps->polled = 0;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &pp->lastrec, &pp->lastrec, pp->leap);
}
-/*
- * ==================================================================
- * gps_send(gps,cmd) Sends a command to the GPS receiver.
- * as gps_send(gps,"rqts,u\r");
- * ==================================================================
- */
-static void
-gps_send(gps,cmd)
- struct gpsunit *gps;
- char *cmd;
-{
- if (write(gps->io.fd, cmd, strlen(cmd)) == -1) {
- syslog(LOG_ERR, "gps_send: unit %d: %m", gps->unit);
- trak_report_event(gps,CEVNT_FAULT);
- } else {
- gps->polls++;
- }
-}
-
-/*
- * trak_process - process a pile of samples from the clock
- *
- * This routine uses a three-stage median filter to calculate offset and
- * dispersion and reduce jitter. The dispersion is calculated as the
- * span of the filter (max - min).
- */
-static char
-trak_process(gps, offset, dispersion)
- struct gpsunit *gps;
- l_fp *offset;
- u_fp *dispersion;
-{
- register int i, j;
- register U_LONG tmp_ui, tmp_uf;
- int not_median1 = -1; /* XXX correct? */
- int not_median2 = -1; /* XXX correct? */
- int median;
- u_fp disp_tmp, disp_tmp2;
-
- /*
- * This code implements a three-stage median filter. First, we
- * check if the samples are within 125 ms of each other. If not,
- * dump the sample set. We take the median of the three offsets
- * and use that as the sample offset. There probably is not much
- * to be gained by a longer filter, since the clock filter in
- * ntp_proto should do its thing.
- */
- disp_tmp2 = 0;
- for (i = 0; i < NCODES-1; i++) {
- for (j = i+1; j < NCODES; j++) {
- tmp_ui = gps->offset[i].l_ui;
- tmp_uf = gps->offset[i].l_uf;
- M_SUB(tmp_ui, tmp_uf, gps->offset[j].l_ui,
- gps->offset[j].l_uf);
- if (M_ISNEG(tmp_ui, tmp_uf)) {
- M_NEG(tmp_ui, tmp_uf);
- }
- if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
- return (0);
- }
- disp_tmp = MFPTOFP(0, tmp_uf);
- if (disp_tmp > disp_tmp2) {
- disp_tmp2 = disp_tmp;
- not_median1 = i;
- not_median2 = j;
- }
- }
- }
- if (gps->lasttime == 0)
- disp_tmp2 = NTP_MAXDISPERSE;
- else
- disp_tmp2 = current_time - gps->lasttime;
- if (not_median1 == 0) {
- if (not_median2 == 1)
- median = 2;
- else
- median = 1;
- } else {
- median = 0;
- }
- *offset = gps->offset[median];
- *dispersion = disp_tmp2;
- return (1);
-}
/*
* trak_poll - called by the transmit procedure
- *
- * We go to great pains to avoid changing state here, since there may be
- * more than one eavesdropper receiving the same timecode.
*/
static void
trak_poll(unit, peer)
int unit;
struct peer *peer;
{
- struct gpsunit *gps;
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "trak_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "trak_poll: unit %d not in use", unit);
- return;
- }
- gps = gpsunits[unit];
- if ((current_time - gps->lasttime) > 150)
- trak_report_event(gpsunits[unit], CEVNT_TIMEOUT);
/*
- * usually trak_receive can get a timestamp every second
+ * We don't really do anything here, except arm the receiving
+ * side to capture a sample and check for timeouts.
*/
-#if !defined(TRAKPPS) && !defined(TRAKCLK)
- gettstamp(&gps->lastrec);
-#endif
- gps->polls++;
- /*
- * may be polled every 16 seconds (minpoll 4)
- */
- gps->polled = 1;
-}
-
-/*
- * trak_control - set fudge factors, return statistics
- */
-static void
-trak_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct gpsunit *gps;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "trak_control: unit %d invalid", unit);
- return;
- }
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- gps = gpsunits[unit];
- peer = gps->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- bcopy(GPSREFID, (char *)&peer->refid,
- 4);
- else
- peer->refid = htonl(GPSHSREFID);
- }
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_GPS_TRAK;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2;
- out->clockdesc = GPSDESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- gps = gpsunits[unit];
- out->lencode = gps->lencode; /* LENTOC */;
- out->lastcode = gps->lastcode;
- out->timereset = current_time - gps->timestarted;
- out->polls = gps->polls;
- out->noresponse = gps->noreply;
- out->badformat = gps->badformat;
- out->baddata = gps->baddata;
- out->lastevent = gps->lastevent;
- out->currentstatus = gps->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ up->tcswitch = 0;
+ pp->polls++;
}
-/*
- * trak_buginfo - return clock dependent debugging info
- */
-static void
-trak_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct gpsunit *gps;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "trak_buginfo: unit %d invalid", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- gps = gpsunits[unit];
-
- bug->nvalues = 10;
- bug->ntimes = 5;
- if (gps->lasttime != 0)
- bug->values[0] = current_time - gps->lasttime;
- else
- bug->values[0] = 0;
- bug->values[1] = (U_LONG)gps->reason;
- bug->values[2] = (U_LONG)gps->year;
- bug->values[3] = (U_LONG)gps->day;
- bug->values[4] = (U_LONG)gps->hour;
- bug->values[5] = (U_LONG)gps->minute;
- bug->values[6] = (U_LONG)gps->second;
- bug->values[7] = (U_LONG)gps->msec;
- bug->values[8] = gps->noreply;
- bug->values[9] = gps->yearstart;
- bug->stimes = 0x1c;
- bug->times[0] = gps->lastref;
- bug->times[1] = gps->lastrec;
- bug->times[2] = gps->offset[0];
- bug->times[3] = gps->offset[1];
- bug->times[4] = gps->offset[2];
-}
#endif
diff --git a/usr.sbin/xntpd/xntpd/refclock_wwvb.c b/usr.sbin/xntpd/xntpd/refclock_wwvb.c
index 9b2563a797db..ea0c82e28ec1 100644
--- a/usr.sbin/xntpd/xntpd/refclock_wwvb.c
+++ b/usr.sbin/xntpd/xntpd/refclock_wwvb.c
@@ -1,7 +1,7 @@
/*
- * refclock_wwvb - clock driver for the Spectracom WWVB receivers
+ * refclock_wwvb - clock driver for Spectracom WWVB receivers
*/
-#if defined(REFCLOCK) && (defined(WWVB) || defined(WWVBCLK) || defined(WWVBPPS))
+#if defined(REFCLOCK) && defined(WWVB)
#include <stdio.h>
#include <ctype.h>
@@ -10,62 +10,63 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-
-#if defined(HAVE_TERMIOS)
-#include <termios.h>
-#endif
-#if defined(STREAM)
-#include <stropts.h>
-#if defined(WWVBCLK)
-#include <sys/clkdefs.h>
-#endif /* WWVBCLK */
-#endif /* STREAM */
-
-#if defined (WWVBPPS)
-#include <sys/ppsclock.h>
-#endif /* WWVBPPS */
-
#include "ntp_stdlib.h"
/*
* This driver supports the Spectracom Model 8170 and Netclock/2 WWVB
- * Synchronized Clock under Unix and on a Gizmo board. There are two
- * formats used by these clocks. Format 0 (zero), which is available
- * with both the Netclock/2 and 8170, is in the following format:
+ * Synchronized Clock. This clock has proven a reliable source of time,
+ * except in some cases of high ambient conductive RF interference. The
+ * claimed accuracy of the clock is 100 usec relative to the broadcast
+ * signal; however, in most cases the actual accuracy is limited by the
+ * precision of the timecode and the latencies of the serial interface
+ * and operating system.
+ *
+ * The DIPswitches on this clock should be set to 24-hour display, AUTO
+ * DST off, time zone 0 (UTC), data format 0 or 2 (see below) and baud
+ * rate 9600. If this clock is to used as the source for the IRIG Audio
+ * Decoder (refclock_irig.c in this distribution), set the DIPswitches
+ * for AM IRIG output and IRIG format 1 (IRIG B with signature control).
+ *
+ * There are two timecode formats used by these clocks. Format 0, which
+ * is available with both the Netclock/2 and 8170, and format 2, which
+ * is available only with the Netclock/2 and specially modified 8170.
+ *
+ * Format 0 (22 ASCII printing characters):
+ *
+ * <cr><lf>i ddd hh:mm:ss TZ=zz<cr><lf>
+ *
+ * on-time = first <cr> * hh:mm:ss = hours, minutes, seconds
+ * i = synchronization flag (' ' = in synch, '?' = out of synch)
*
- * <cr><lf>I<sp><sp>ddd<sp>hh:mm:ss<sp><sp>TZ=nn<cr><lf>
+ * The alarm condition is indicated by other than ' ' at A, which occurs
+ * during initial synchronization and when received signal is lost for
+ * about ten hours.
*
- * The ddd, hh, mm and ss fields show the day of year, hours, minutes
- * and seconds, respectively. The nn field shows the local hour offset
- * relative to UTC and should always be set to 00. The I is normally
- * <sp> when the clock is synchronized and '?' when it isn't (it could
- * also be a '*' if we set the time manually, but this is forbidden.
+ * Format 2 (24 ASCII printing characters):
*
- * Format 2 (two), which is available only with the Netclock/2 and
- * specially modified 8170, is in the following format:
+ * <cr><lf>iqyy ddd hh:mm:ss.fff ld
*
- * <cr><lf>IQyy<sp>ddd<sp>hh:mm:ss.mmm<sp>LD
+ * on-time = <cr>
+ * i = synchronization flag (' ' = in synch, '?' = out of synch)
+ * q = quality indicator (' ' = locked, 'A'...'D' = unlocked)
+ * yy = year (as broadcast)
+ * ddd = day of year
+ * hh:mm:ss.fff = hours, minutes, seconds, milliseconds
*
- * The ddd, hh and ss fields and I are as in format 0. The yy field
- * shows the year and mmm the milliseconds, respectively. The Q is
- * normally <sp> when the time error is less than 1 ms and and a
+ * The alarm condition is indicated by other than ' ' at A, which occurs
+ * during initial synchronization and when received signal is lost for
+ * about ten hours. The unlock condition is indicated by other than ' '
+ * at Q.
+ *
+ * The Q is normally ' ' when the time error is less than 1 ms and a
* character in the set 'A'...'D' when the time error is less than 10,
- * 100, 500 and greater than 500 ms respectively. The L is normally
- * <sp>, but is set to 'L' early in the month of an upcoming UTC
- * leap second and reset to <sp> on the first day of the following
- * month. The D is set to 'S' for standard time 'I' on the day
- * preceding a switch to daylight time, 'D' for daylight time and 'O'
- * on the day preceding a switch to standard time. The start bit of the
- * first <cr> is supposed to be synchronized to the on-time second.
+ * 100, 500 and greater than 500 ms respectively. The L is normally ' ',
+ * but is set to 'L' early in the month of an upcoming UTC leap second
+ * and reset to ' ' on the first day of the following month. The D is
+ * set to 'S' for standard time 'I' on the day preceding a switch to
+ * daylight time, 'D' for daylight time and 'O' on the day preceding a
+ * switch to standard time. The start bit of the first <cr> is
+ * synchronized to the indicated time as returned.
*
* This driver does not need to be told which format is in use - it
* figures out which one from the length of the message. A three-stage
@@ -74,485 +75,168 @@
* jitter of the radio itself, which is a known problem with the older
* radios.
*
- * This driver supports the 1-pps signal provided by the radio and
- * connected via a level converted described in the gadget directory.
- * The signal is captured using a separate, dedicated, serial port and
- * the tty_clk line discipline/streams modules described in the kernel
- * directory. For the highest precision, the signal is captured using
- * the carrier-detect line of the same serial port using the ppsclock
- * streams module described in the ppsclock directory.
- *
- * Bugs:
+ * Fudge Factors
*
- * The year indication so carefully provided in format 2 is not used.
+ * This driver can retrieve a table of quality data maintained
+ * internally by the Netclock/2 receiver. If flag4 of the fudge
+ * configuration command is set to 1, the driver will retrieve this
+ * table and write it to the clockstats file on when the first timecode
+ * message of a new day is received.
*/
/*
- * Definitions
+ * Interface definitions
*/
-#define MAXUNITS 4 /* max number of WWVB units */
-#define WWVB232 "/dev/wwvb%d" /* name of radio device */
+#define DEVICE "/dev/wwvb%d" /* device name and unit */
#define SPEED232 B9600 /* uart speed (9600 baud) */
+#define PRECISION (-10) /* precision assumed (about 1 ms) */
+#define REFID "WWVB" /* reference ID */
+#define DESCRIPTION "Spectracom WWVB Receiver" /* WRU */
-/*
- * Radio interface parameters
- */
-#define WWVBPRECISION (-13) /* precision assumed (about 100 us) */
-#define WWVBREFID "WWVB" /* reference id */
-#define WWVBDESCRIPTION "Spectracom WWVB Receiver" /* who we are */
-#define WWVBHSREFID 0x7f7f040a /* 127.127.4.10 refid hi strata */
-#define GMT 0 /* hour offset from Greenwich */
-#define NCODES 3 /* stages of median filter */
+#define NSAMPLES 3 /* stages of median filter */
#define LENWWVB0 22 /* format 0 timecode length */
#define LENWWVB2 24 /* format 2 timecode length */
-#define FMTWWVBU 0 /* unknown format timecode id */
-#define FMTWWVB0 1 /* format 0 timecode id */
-#define FMTWWVB2 2 /* format 2 timecode id */
-#define BMAX 80 /* timecode buffer length */
-#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
#define MONLIN 15 /* number of monitoring lines */
-/*
- * Hack to avoid excercising the multiplier. I have no pride.
- */
-#define MULBY10(x) (((x)<<3) + ((x)<<1))
/*
* Imported from ntp_timer module
*/
-extern U_LONG current_time; /* current time (s) */
-
-/*
- * Imported from ntp_loopfilter module
- */
-extern int fdpps; /* pps file descriptor */
+extern u_long current_time; /* current time (s) */
/*
* Imported from ntpd module
*/
-extern int debug; /* global debug flag */
+extern int debug; /* global debug flag */
/*
* WWVB unit control structure
*/
struct wwvbunit {
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp lastrec; /* last receive time */
- l_fp lastref; /* last timecode time */
- l_fp offset[NCODES]; /* recent sample offsets */
- char lastcode[BMAX]; /* last timecode received */
- u_char format; /* timecode format */
- u_char tcswitch; /* timecode switch */
- u_char pollcnt; /* poll message counter */
- u_char lencode; /* length of last timecode */
- U_LONG lasttime; /* last time clock heard from */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char reason; /* reason for last abort */
- u_char year; /* year of eternity */
- u_short day; /* day of year */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- u_char leap; /* leap indicators */
- u_short msec; /* millisecond of second */
- u_char quality; /* quality char from format 2 */
- U_LONG yearstart; /* start of current year */
- u_char lasthour; /* last hour (for monitor) */
- u_char linect; /* count of ignored lines (for monitor */
+ int pollcnt; /* poll message counter */
- /*
- * Status tallies
- */
- U_LONG polls; /* polls sent */
- U_LONG noreply; /* no replies to polls */
- U_LONG coderecv; /* timecodes received */
- U_LONG badformat; /* bad format */
- U_LONG baddata; /* bad data */
- U_LONG timestarted; /* time we started this */
+ u_char tcswitch; /* timecode switch */
+ l_fp laststamp; /* last receive timestamp */
+ u_char lasthour; /* last hour (for monitor) */
+ u_char linect; /* count ignored lines (for monitor */
};
/*
- * Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back.
- */
-static struct wwvbunit *wwvbunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/*
- * Keep the fudge factors separately so they can be set even
- * when no clock is configured.
- */
-static l_fp fudgefactor[MAXUNITS];
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-/*
* Function prototypes
*/
-static void wwvb_init P((void));
-static int wwvb_start P((u_int, struct peer *));
-static void wwvb_shutdown P((int));
-static void wwvb_report_event P((struct wwvbunit *, int));
+static int wwvb_start P((int, struct peer *));
+static void wwvb_shutdown P((int, struct peer *));
static void wwvb_receive P((struct recvbuf *));
-static char wwvb_process P((struct wwvbunit *, l_fp *, u_fp *));
static void wwvb_poll P((int, struct peer *));
-static void wwvb_control P((u_int, struct refclockstat *, struct refclockstat *));
-static void wwvb_buginfo P((int, struct refclockbug *));
/*
* Transfer vector
*/
struct refclock refclock_wwvb = {
- wwvb_start, wwvb_shutdown, wwvb_poll,
- wwvb_control, wwvb_init, wwvb_buginfo, NOFLAGS
+ wwvb_start, /* start up driver */
+ wwvb_shutdown, /* shut down driver */
+ wwvb_poll, /* transmit poll message */
+ noentry, /* not used (old wwvb_control) */
+ noentry, /* initialize driver (not used) */
+ noentry, /* not used (old wwvb_buginfo) */
+ NOFLAGS /* not used */
};
-/*
- * wwvb_init - initialize internal wwvb driver data
- */
-static void
-wwvb_init()
-{
- register int i;
- /*
- * Just zero the data arrays
- */
- memset((char *)wwvbunits, 0, sizeof wwvbunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- /*
- * Initialize fudge factors to default.
- */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = 0;
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
/*
- * wwvb_start - open the WWVB devices and initialize data for processing
+ * wwvb_start - open the devices and initialize data for processing
*/
static int
wwvb_start(unit, peer)
- u_int unit;
+ int unit;
struct peer *peer;
{
- register struct wwvbunit *wwvb;
- register int i;
- int fd232;
- char wwvbdev[20];
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
+ int fd;
+ char device[20];
/*
- * Check configuration info
+ * Open serial port. Use CLK line discipline, if available.
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "wwvb_start: unit %d invalid", unit);
+ (void)sprintf(device, DEVICE, unit);
+ if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
return (0);
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "wwvb_start: unit %d in use", unit);
- return (0);
- }
/*
- * Open serial port
+ * Allocate and initialize unit structure
*/
- (void) sprintf(wwvbdev, WWVB232, unit);
- fd232 = open(wwvbdev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "wwvb_start: open of %s: %m", wwvbdev);
+ if (!(up = (struct wwvbunit *)
+ emalloc(sizeof(struct wwvbunit)))) {
+ (void) close(fd);
return (0);
}
-
-#if defined(HAVE_SYSV_TTYS)
- /*
- * System V serial line parameters (termio interface)
- *
- */
- { struct termio ttyb;
- if (ioctl(fd232, TCGETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, TCGETA): %m", wwvbdev);
- goto screwed;
- }
- ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyb.c_oflag = 0;
- ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyb.c_lflag = ICANON;
- ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
- if (ioctl(fd232, TCSETA, &ttyb) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, TCSETA): %m", wwvbdev);
- goto screwed;
- }
- }
-#endif /* HAVE_SYSV_TTYS */
-#if defined(HAVE_TERMIOS)
- /*
- * POSIX serial line parameters (termios interface)
- *
- * The WWVBCLK option provides timestamping at the driver level.
- * It requires the tty_clk streams module.
- *
- * The WWVBPPS option provides timestamping at the driver level.
- * It uses a 1-pps signal and level converter (gadget box) and
- * requires the ppsclock streams module and SunOS 4.1.1 or
- * later.
- */
- { struct termios ttyb, *ttyp;
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: tcgetattr(%s): %m", wwvbdev);
- goto screwed;
- }
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_oflag = 0;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: tcsetattr(%s): %m", wwvbdev);
- goto screwed;
- }
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: tcflush(%s): %m", wwvbdev);
- goto screwed;
- }
- }
-#endif /* HAVE_TERMIOS */
-#ifdef STREAM
-#if defined(WWVBCLK)
- if (ioctl(fd232, I_PUSH, "clk") < 0)
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, I_PUSH, clk): %m", wwvbdev);
- if (ioctl(fd232, CLK_SETSTR, "\n") < 0)
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, CLK_SETSTR): %m", wwvbdev);
-#endif /* WWVBCLK */
-#if defined(WWVBPPS)
- if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, I_PUSH, ppsclock): %m", wwvbdev);
- else
- fdpps = fd232;
-#endif /* WWVBPPS */
-#endif /* STREAM */
-#if defined(HAVE_BSD_TTYS)
- /*
- * 4.3bsd serial line parameters (sgttyb interface)
- *
- * The WWVBCLK option provides timestamping at the driver level.
- * It requires the tty_clk line discipline and 4.3bsd or later.
- */
- { struct sgttyb ttyb;
-#if defined(WWVBCLK)
- int ldisc = CLKLDISC;
-#endif /* WWVBCLK */
-
- if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, TIOCGETP): %m", wwvbdev);
- goto screwed;
- }
- ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
-#if defined(WWVBCLK)
- ttyb.sg_erase = ttyb.sg_kill = '\r';
- ttyb.sg_flags = RAW;
-#else
- ttyb.sg_erase = ttyb.sg_kill = '\0';
- ttyb.sg_flags = EVENP|ODDP|CRMOD;
-#endif /* WWVBCLK */
- if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, TIOCSETP): %m", wwvbdev);
- goto screwed;
- }
-#if defined(WWVBCLK)
- if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
- syslog(LOG_ERR,
- "wwvb_start: ioctl(%s, TIOCSETD): %m",wwvbdev);
- goto screwed;
- }
-#endif /* WWVBCLK */
- }
-#endif /* HAVE_BSD_TTYS */
-
- /*
- * Allocate unit structure
- */
- if (wwvbunits[unit] != 0) {
- wwvb = wwvbunits[unit]; /* The one we want is okay */
- } else {
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && wwvbunits[i] != 0)
- break;
- }
- if (i < MAXUNITS) {
- /*
- * Reclaim this one
- */
- wwvb = wwvbunits[i];
- wwvbunits[i] = 0;
- } else {
- wwvb = (struct wwvbunit *)
- emalloc(sizeof(struct wwvbunit));
- }
+ memset((char *)up, 0, sizeof(struct wwvbunit));
+ pp = peer->procptr;
+ pp->io.clock_recv = wwvb_receive;
+ pp->io.srcclock = (caddr_t)peer;
+ pp->io.datalen = 0;
+ pp->io.fd = fd;
+ if (!io_addclock(&pp->io)) {
+ (void) close(fd);
+ free(up);
+ return (0);
}
- memset((char *)wwvb, 0, sizeof(struct wwvbunit));
- wwvbunits[unit] = wwvb;
+ pp->unitptr = (caddr_t)up;
/*
- * Set up the structures
+ * Initialize miscellaneous variables
*/
- wwvb->peer = peer;
- wwvb->unit = (u_char)unit;
- wwvb->timestarted = current_time;
- wwvb->pollcnt = 2;
-
- wwvb->io.clock_recv = wwvb_receive;
- wwvb->io.srcclock = (caddr_t)wwvb;
- wwvb->io.datalen = 0;
- wwvb->io.fd = fd232;
- if (!io_addclock(&wwvb->io))
- goto screwed;
-
- /*
- * All done. Initialize a few random peer variables, then
- * return success. Note that root delay and root dispersion are
- * always zero for this clock.
- */
- peer->precision = WWVBPRECISION;
- peer->rootdelay = 0;
- peer->rootdispersion = 0;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid, WWVBREFID, 4);
- else
- peer->refid = htonl(WWVBHSREFID);
- unitinuse[unit] = 1;
+ peer->precision = PRECISION;
+ pp->clockdesc = DESCRIPTION;
+ memcpy((char *)&pp->refid, REFID, 4);
+ up->pollcnt = 2;
return (1);
-
- /*
- * Something broke; abandon ship.
- */
-screwed:
- (void) close(fd232);
- return (0);
-}
-
-/*
- * wwvb_shutdown - shut down a WWVB clock
- */
-static void
-wwvb_shutdown(unit)
- int unit;
-{
- register struct wwvbunit *wwvb;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "wwvb_shutdown: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "wwvb_shutdown: unit %d not in use", unit);
- return;
- }
-
- /*
- * Tell the I/O module to turn us off. We're history.
- */
- wwvb = wwvbunits[unit];
- io_closeclock(&wwvb->io);
- unitinuse[unit] = 0;
}
/*
- * wwvb_report_event - note the occurance of an event
- *
- * This routine presently just remembers the report and logs it, but
- * does nothing heroic for the trap handler.
+ * wwvb_shutdown - shut down the clock
*/
static void
-wwvb_report_event(wwvb, code)
- struct wwvbunit *wwvb;
- int code;
-{
+wwvb_shutdown(unit, peer)
+ int unit;
struct peer *peer;
+{
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
- peer = wwvb->peer;
- if (wwvb->status != (u_char)code) {
- wwvb->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- wwvb->lastevent = (u_char)code;
- syslog(LOG_INFO,
- "clock %s event %x", ntoa(&peer->srcadr), code);
- }
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ io_closeclock(&pp->io);
+ free(up);
}
/*
- * wwvb_receive - receive data from the serial interface on a Spectracom
- * clock
+ * wwvb_receive - receive data from the serial interface
*/
static void
wwvb_receive(rbufp)
struct recvbuf *rbufp;
{
- register int i;
- register struct wwvbunit *wwvb;
- register char *dpt, *cp, *dp;
- int dpend;
- l_fp tstmp, trtmp;
- u_fp dispersion;
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
+ struct peer *peer;
+ l_fp trtmp;
+ u_long ltemp;
+ int temp;
+ char syncchar; /* synchronization indicator */
+ char qualchar; /* quality indicator */
+ char leapchar; /* leap indicator */
/*
- * Get the clock this applies to and a pointers to the data.
- * Check for the presence of a timestamp left by the tty_clock
- * line discipline/streams module and, if present, use that
- * instead of the timestamp captured by the i/o routines.
+ * Initialize pointers and read the timecode and timestamp
*/
- wwvb = (struct wwvbunit *)rbufp->recv_srcclock;
- dpt = (char *)&rbufp->recv_space;
- dpend = rbufp->recv_length;
- if (dpend > BMAX - 1)
- dpend = BMAX - 1;
- wwvb-> pollcnt = 2;
- trtmp = rbufp->recv_time;
- if (dpend >= 9) {
- dp = dpt + dpend - 9;
- if (*dp == '\n' || *dp == '\r') {
- dpend -= 8;
- if (!buftvtots(dp + 1, &tstmp)) {
-#ifdef DEBUG
- if (debug)
- printf("wwvb_receive: invalid timestamp");
-#endif
- } else {
-#ifdef DEBUG
- if (debug) {
- L_SUB(&trtmp, &tstmp);
- printf("wwvb: delta %s",
- lfptoa(&trtmp, 6));
- gettstamp(&trtmp);
- L_SUB(&trtmp, &tstmp);
- printf(" SIGIO %s\n",
- lfptoa(&trtmp, 6));
- }
-#endif
- trtmp = tstmp;
- }
- }
- }
+ peer = (struct peer *)rbufp->recv_srcclock;
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ temp = refclock_gtlin(rbufp, pp->lastcode, BMAX, &trtmp);
+
/*
* Note we get a buffer and timestamp for both a <cr> and <lf>,
* but only the <cr> timestamp is retained. Note: in format 0 on
@@ -563,38 +247,24 @@ wwvb_receive(rbufp)
* you have a pps gadget and don't have to have the year, format
* 0 provides the lowest jitter.
*/
- if (dpend == 1) {
- if (wwvb->tcswitch == 0) {
- wwvb->tcswitch = 1;
- wwvb->lastrec = trtmp;
+ if (temp == 0) {
+ if (up->tcswitch == 0) {
+ up->tcswitch = 1;
+ up->laststamp = trtmp;
} else
- wwvb->tcswitch = 0;
+ up->tcswitch = 0;
return;
}
- tstmp = wwvb->lastrec;
- wwvb->lastrec = trtmp;
- wwvb->tcswitch = 1;
-
- /*
- * Edit timecode to remove control chars. Note the receive
- * timestamp is determined at the first <cr>; however, we don't
- * get the timecode for that timestamp until the next <cr>. We
- * assume that, if we happen to come up during a timestamp, or
- * other awkward time, the format and data checks will cause the
- * driver to resynchronize after maybe a few false starts.
- */
- if (dpend <= 0)
- return;
- cp = dp = wwvb->lastcode;
- for (i = 0; i < dpend; i++)
- if ((*dp = 0x7f & *dpt++) >= ' ') dp++;
- *dp = '\0';
- wwvb->lencode = dp - cp;
- record_clock_stats(&(wwvb->peer->srcadr), wwvb->lastcode);
+ pp->lencode = temp;
+ pp->lastrec = up->laststamp;
+ up->laststamp = trtmp;
+ up->tcswitch = 1;
+ up->pollcnt = 2;
+ record_clock_stats(&peer->srcadr, pp->lastcode);
#ifdef DEBUG
if (debug)
- printf("wwvb: timecode %d %d %s\n",
- wwvb->linect, wwvb->lencode, wwvb->lastcode);
+ printf("wwvb: timecode %d %s\n", pp->lencode,
+ pp->lastcode);
#endif
/*
@@ -602,279 +272,113 @@ wwvb_receive(rbufp)
* its contents. This code uses the timecode length to determine
* whether format 0 or format 2. If the timecode has invalid
* length or is not in proper format, we declare bad format and
- * exit; if the converted decimal values are out of range, we
- * declare bad data and exit.
+ * exit.
*/
- cp = wwvb->lastcode;
- wwvb->leap = 0;
- wwvb->format = FMTWWVBU;
- if ((cp[0] == ' ' || cp[0] == '?') && wwvb->lencode == LENWWVB0) {
+ switch (pp->lencode) {
+
+ case LENWWVB0:
/*
- * Check timecode format 0
+ * Timecode format 0: "I ddd hh:mm:ss TZ=nn"
*/
- if (cp[1] != ' ' || /* <sp> separator */
- cp[2] != ' ' || /* <sp> separator */
- !isdigit(cp[3]) || /* day of year */
- !isdigit(cp[4]) ||
- !isdigit(cp[5]) ||
- cp[6] != ' ' || /* <sp> separator */
- !isdigit(cp[7]) || /* hours */
- !isdigit(cp[8]) ||
- cp[9] != ':' || /* : separator */
- !isdigit(cp[10]) || /* minutes */
- !isdigit(cp[11]) ||
- cp[12] != ':' || /* : separator */
- !isdigit(cp[13]) || /* seconds */
- !isdigit(cp[14])) {
- wwvb->badformat++;
- wwvb_report_event(wwvb, CEVNT_BADREPLY);
- return;
- }
- else
- wwvb->format = FMTWWVB0;
+ qualchar = leapchar = ' ';
+ if (sscanf(pp->lastcode, "%c %3d %2d:%2d:%2d",
+ &syncchar, &pp->day, &pp->hour, &pp->minute,
+ &pp->second) == 5)
+ break;
- /*
- * Convert format 0 and check values
- */
- wwvb->year = 0; /* fake */
- wwvb->day = cp[3] - '0';
- wwvb->day = MULBY10(wwvb->day) + cp[4] - '0';
- wwvb->day = MULBY10(wwvb->day) + cp[5] - '0';
- wwvb->hour = MULBY10(cp[7] - '0') + cp[8] - '0';
- wwvb->minute = MULBY10(cp[10] - '0') + cp[11] - '0';
- wwvb->second = MULBY10(cp[13] - '0') + cp[14] - '0';
- wwvb->msec = 0;
- if (cp[0] != ' ')
- wwvb->leap = LEAP_NOTINSYNC;
- else
- wwvb->lasttime = current_time;
- if (wwvb->day < 1 || wwvb->day > 366) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADDATE);
- return;
- }
- if (wwvb->hour > 23 || wwvb->minute > 59
- || wwvb->second > 59) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADTIME);
- return;
- }
- } else if ((cp[0] == ' ' || cp[0] == '?') && wwvb->lencode == LENWWVB2) {
+ case LENWWVB2:
/*
- * Check timecode format 2
+ * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD"
*/
- if (!isdigit(cp[2]) || /* year of century */
- !isdigit(cp[3]) ||
- cp[4] != ' ' || /* <sp> separator */
- !isdigit(cp[5]) || /* day of year */
- !isdigit(cp[6]) ||
- !isdigit(cp[7]) ||
- cp[8] != ' ' || /* <sp> separator */
- !isdigit(cp[9]) || /* hour */
- !isdigit(cp[10]) ||
- cp[11] != ':' || /* : separator */
- !isdigit(cp[12]) || /* minute */
- !isdigit(cp[13]) ||
- cp[14] != ':' || /* : separator */
- !isdigit(cp[15]) || /* second */
- !isdigit(cp[16]) ||
- cp[17] != '.' || /* . separator */
- !isdigit(cp[18]) || /* millisecond */
- !isdigit(cp[19]) ||
- !isdigit(cp[20]) ||
- cp[21] != ' ') { /* <sp> separator */
- wwvb->badformat++;
- wwvb_report_event(wwvb, CEVNT_BADREPLY);
- return;
- }
- else
- wwvb->format = FMTWWVB2;
+ if (sscanf(pp->lastcode, "%c%c %2d %3d %2d:%2d:%2d.%3d %c",
+ &syncchar, &qualchar, &pp->year, &pp->day,
+ &pp->hour, &pp->minute, &pp->second, &pp->msec,
+ &leapchar) == 9)
+ break;
- /*
- * Convert format 2 and check values
- */
- wwvb->year = MULBY10(cp[2] - '0') + cp[3] - '0';
- wwvb->day = cp[5] - '0';
- wwvb->day = MULBY10(wwvb->day) + cp[6] - '0';
- wwvb->day = MULBY10(wwvb->day) + cp[7] - '0';
- wwvb->hour = MULBY10(cp[9] - '0') + cp[10] - '0';
- wwvb->minute = MULBY10(cp[12] - '0') + cp[13] - '0';
- wwvb->second = MULBY10(cp[15] - '0') + cp[16] - '0';
- wwvb->msec = cp[18] - '0';
- wwvb->msec = MULBY10(wwvb->msec) + cp[19] - '0';
- wwvb->msec = MULBY10(wwvb->msec) + cp[20] - '0';
- wwvb->quality = cp[1];
- if (cp[0] != ' ')
- wwvb->leap = LEAP_NOTINSYNC;
+ default:
- /*
- * This nonsense adjusts the last time the clock was
- * heard from depending on the quality indicator. Once
- * the clock has been heard, the dispersion depends only
- * on when the clock was last heard. The first time the
- * clock is heard, the time last heard is faked based on
- * the quality indicator. The magic numbers (in seconds)
- * are from the clock specifications.
- */
- if (wwvb->lasttime != 0) {
- if (cp[1] == ' ')
- wwvb->lasttime = current_time;
- } else {
- switch (cp[1]) {
- case ' ':
- wwvb->lasttime = current_time;
- break;
- case 'A':
- wwvb->lasttime = current_time - 800;
- break;
- case 'B':
- wwvb->lasttime = current_time - 5300;
- break;
- case 'C':
- wwvb->lasttime = current_time - 25300;
- break;
- /* Don't believe anything else */
- }
- }
- if (cp[22] == 'L')
- wwvb->leap = LEAP_ADDSECOND;
- if (wwvb->day < 1 || wwvb->day > 366) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADDATE);
- return;
- }
- if (wwvb->hour > 23 || wwvb->minute > 59
- || wwvb->second > 59) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADTIME);
- return;
- }
- } else {
- if (wwvb->linect > 0)
- wwvb->linect--;
- else {
- wwvb->badformat++;
- wwvb_report_event(wwvb, CEVNT_BADREPLY);
- }
+ if (up->linect > 0)
+ up->linect--;
+ else
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
- if (sloppyclockflag[wwvb->unit] & CLK_FLAG4 &&
- wwvb->hour < wwvb->lasthour)
- wwvb->linect = MONLIN;
- wwvb->lasthour = wwvb->hour;
/*
- * Now, compute the reference time value. Use the heavy
- * machinery for the seconds and the millisecond field for the
- * fraction when present. If an error in conversion to internal
- * format is found, the program declares bad data and exits.
- * Note that this code does not yet know how to do the years and
- * relies on the clock-calendar chip for sanity.
+ * Decode synchronization, quality and leap characters. If
+ * unsynchronized, set the leap bits accordingly and exit.
+ * Otherwise, set the leap bits according to the leap character.
+ * Once synchronized, the dispersion depends only on when the
+ * clock was last heard. The first time the clock is heard, the
+ * time last heard is faked based on the quality indicator. The
+ * magic numbers (in seconds) are from the clock specifications.
*/
- if (!clocktime(wwvb->day, wwvb->hour, wwvb->minute,
- wwvb->second, GMT, tstmp.l_ui,
- &wwvb->yearstart, &wwvb->lastref.l_ui)) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADTIME);
+ switch (qualchar) {
+
+ case ' ':
+ ltemp = 0;
+ break;
+
+ case 'A':
+ ltemp = 800;
+ break;
+
+ case 'B':
+ ltemp = 5300;
+ break;
+
+ case 'C':
+ ltemp = 25300;
+ break;
+
+ case 'D':
+ ltemp = NTP_MAXAGE;
+ break;
+
+ default:
+ refclock_report(peer, CEVNT_BADREPLY);
return;
}
- MSUTOTSF(wwvb->msec, wwvb->lastref.l_uf);
- i = ((int)(wwvb->coderecv)) % NCODES;
- wwvb->offset[i] = wwvb->lastref;
- L_SUB(&wwvb->offset[i], &tstmp);
- if (wwvb->coderecv == 0)
- for (i = 1; i < NCODES; i++)
- wwvb->offset[i] = wwvb->offset[0];
- wwvb->coderecv++;
+ if (syncchar != ' ')
+ pp->leap = LEAP_NOTINSYNC;
+ else {
+ if (leapchar == 'L')
+ pp->leap = LEAP_ADDSECOND;
+ else
+ pp->leap = 0;
+ pp->lasttime = current_time - ltemp;
+ }
+
+ /*
+ * If the monitor flag is set (flag4), we dump the internal
+ * quality table at the first timecode beginning the day.
+ */
+ if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour <
+ up->lasthour)
+ up->linect = MONLIN;
+ up->lasthour = pp->hour;
/*
- * Process the samples in the median filter, add the fudge
- * factor and pass the offset and dispersion along. We use
- * lastrec as both the reference time and receive time in order
- * to avoid being cute, like setting the reference time later
- * than the receive time, which may cause a paranoid protocol
- * module to chuck out the data.
+ * Process the new sample in the median filter and determine the
+ * reference clock offset and dispersion. We use lastrec as both
+ * the reference time and receive time in order to avoid being
+ * cute, like setting the reference time later than the receive
+ * time, which may cause a paranoid protocol module to chuck out
+ * the data.
*/
- if (!wwvb_process(wwvb, &tstmp, &dispersion)) {
- wwvb->baddata++;
- wwvb_report_event(wwvb, CEVNT_BADTIME);
+ if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
+ refclock_report(peer, CEVNT_BADTIME);
return;
}
- L_ADD(&tstmp, &(fudgefactor[wwvb->unit]));
- refclock_receive(wwvb->peer, &tstmp, GMT, dispersion,
- &wwvb->lastrec, &wwvb->lastrec, wwvb->leap);
+ trtmp = pp->lastrec;
+ trtmp.l_ui -= ltemp;
+ refclock_receive(peer, &pp->offset, 0, pp->dispersion,
+ &trtmp, &pp->lastrec, pp->leap);
}
-/*
- * wwvb_process - process a pile of samples from the clock
- *
- * This routine uses a three-stage median filter to calculate offset and
- * dispersion. reduce jitter. The dispersion is calculated as the span
- * of the filter (max - min), unless the quality character (format 2) is
- * non-blank, in which case the dispersion is calculated on the basis of
- * the inherent tolerance of the internal radio oscillator, which is
- * +-2e-5 according to the radio specifications.
- */
-static char
-wwvb_process(wwvb, offset, dispersion)
- struct wwvbunit *wwvb;
- l_fp *offset;
- u_fp *dispersion;
-{
- register int i, j;
- register U_LONG tmp_ui, tmp_uf;
- int not_median1 = -1; /* XXX correct? */
- int not_median2 = -1; /* XXX correct? */
- int median;
- u_fp disp_tmp, disp_tmp2;
-
- /*
- * This code implements a three-stage median filter. First, we
- * check if the samples are within 125 ms of each other. If not,
- * dump the sample set. We take the median of the three offsets
- * and use that as the sample offset. There probably is not much
- * to be gained by a longer filter, since the clock filter in
- * ntp_proto should do its thing.
- */
- disp_tmp2 = 0;
- for (i = 0; i < NCODES-1; i++) {
- for (j = i+1; j < NCODES; j++) {
- tmp_ui = wwvb->offset[i].l_ui;
- tmp_uf = wwvb->offset[i].l_uf;
- M_SUB(tmp_ui, tmp_uf, wwvb->offset[j].l_ui,
- wwvb->offset[j].l_uf);
- if (M_ISNEG(tmp_ui, tmp_uf)) {
- M_NEG(tmp_ui, tmp_uf);
- }
- if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
- return (0);
- }
- disp_tmp = MFPTOFP(0, tmp_uf);
- if (disp_tmp > disp_tmp2) {
- disp_tmp2 = disp_tmp;
- not_median1 = i;
- not_median2 = j;
- }
- }
- }
- if (wwvb->lasttime == 0)
- disp_tmp2 = NTP_MAXDISPERSE;
- else if (wwvb->quality != ' ')
- disp_tmp2 = current_time - wwvb->lasttime;
- if (not_median1 == 0) {
- if (not_median2 == 1)
- median = 2;
- else
- median = 1;
- } else {
- median = 0;
- }
- *offset = wwvb->offset[median];
- *dispersion = disp_tmp2;
- return (1);
-}
/*
* wwvb_poll - called by the transmit procedure
@@ -884,162 +388,33 @@ wwvb_poll(unit, peer)
int unit;
struct peer *peer;
{
- struct wwvbunit *wwvb;
+ register struct wwvbunit *up;
+ struct refclockproc *pp;
char poll;
/*
- * Time to request a time code. The Spectracom clock responds
- * to a "T" sent to it by returning a time code as stated in the
- * comments in the header. Note there is no checking on state,
- * since this may not be the only customer reading the clock.
- * Only one customer need poll the clock; all others just listen
- * in. If nothing is heard from the clock for two polls, declare
- * a timeout and keep going.
+ * Time to poll the clock. The Spectracom clock responds to a
+ * 'T' by returning a timecode in the format(s) specified above.
+ * Note there is no checking on state, since this may not be the
+ * only customer reading the clock. Only one customer need poll
+ * the clock; all others just listen in. If nothing is heard
+ * from the clock for two polls, declare a timeout and keep
+ * going.
*/
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "wwvb_poll: unit %d invalid", unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "wwvb_poll: unit %d not in use", unit);
- return;
- }
- wwvb = wwvbunits[unit];
- if (wwvb->pollcnt > 0) {
- wwvb->pollcnt--;
- if (wwvb->pollcnt == 0)
- wwvb_report_event(wwvbunits[unit], CEVNT_TIMEOUT);
- }
- if (wwvb->pollcnt == 0)
- wwvb->noreply++;
- if (wwvb->linect > 0)
+ pp = peer->procptr;
+ up = (struct wwvbunit *)pp->unitptr;
+ if (up->pollcnt == 0)
+ refclock_report(peer, CEVNT_TIMEOUT);
+ else
+ up->pollcnt--;
+ if (up->linect > 0)
poll = 'R';
else
poll = 'T';
- if (write(wwvb->io.fd, &poll, 1) != 1) {
- syslog(LOG_ERR, "wwvb_poll: unit %d: %m", wwvb->unit);
- wwvb_report_event(wwvb, CEVNT_FAULT);
- } else {
- wwvb->polls++;
- }
-}
-
-/*
- * wwvb_control - set fudge factors, return statistics
- */
-static void
-wwvb_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct wwvbunit *wwvb;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "wwvb_control: unit %d invalid", unit);
- return;
- }
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- struct peer *peer;
-
- /*
- * Should actually reselect clock, but
- * will wait for the next timecode
- */
- wwvb = wwvbunits[unit];
- peer = wwvb->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1)
- memmove((char *)&peer->refid,
- WWVBREFID, 4);
- else
- peer->refid = htonl(WWVBHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEFLAG4) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG4;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_WWVB_SPECTRACOM;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG4;
- out->clockdesc = WWVBDESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2.l_ui = 0;
- out->fudgetime2.l_uf = 0;
- out->fudgeval1 = (LONG)stratumtouse[unit];
- out->fudgeval2 = 0;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- wwvb = wwvbunits[unit];
- out->lencode = wwvb->lencode;
- out->lastcode = wwvb->lastcode;
- out->timereset = current_time - wwvb->timestarted;
- out->polls = wwvb->polls;
- out->noresponse = wwvb->noreply;
- out->badformat = wwvb->badformat;
- out->baddata = wwvb->baddata;
- out->lastevent = wwvb->lastevent;
- out->currentstatus = wwvb->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
+ if (write(pp->io.fd, &poll, 1) != 1) {
+ refclock_report(peer, CEVNT_FAULT);
+ } else
+ pp->polls++;
}
-/*
- * wwvb_buginfo - return clock dependent debugging info
- */
-static void
-wwvb_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct wwvbunit *wwvb;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "wwvb_buginfo: unit %d invalid", unit);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- wwvb = wwvbunits[unit];
-
- bug->nvalues = 11;
- bug->ntimes = 5;
- if (wwvb->lasttime != 0)
- bug->values[0] = current_time - wwvb->lasttime;
- else
- bug->values[0] = 0;
- bug->values[1] = (U_LONG)wwvb->reason;
- bug->values[2] = (U_LONG)wwvb->year;
- bug->values[3] = (U_LONG)wwvb->day;
- bug->values[4] = (U_LONG)wwvb->hour;
- bug->values[5] = (U_LONG)wwvb->minute;
- bug->values[6] = (U_LONG)wwvb->second;
- bug->values[7] = (U_LONG)wwvb->msec;
- bug->values[8] = wwvb->noreply;
- bug->values[9] = wwvb->yearstart;
- bug->values[10] = wwvb->quality;
- bug->stimes = 0x1c;
- bug->times[0] = wwvb->lastref;
- bug->times[1] = wwvb->lastrec;
- bug->times[2] = wwvb->offset[0];
- bug->times[3] = wwvb->offset[1];
- bug->times[4] = wwvb->offset[2];
-}
#endif