1/*	$NetBSD: refclock_true.c,v 1.7 2020/05/25 20:47:26 christos Exp $	*/
2
3/*
4 * refclock_true - clock driver for the Kinemetrics/TrueTime receivers
5 *	Receiver Version 3.0C - tested plain, with CLKLDISC
6 *	Development work being done:
7 *      - Support TL-3 WWV TOD receiver
8 */
9
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
14#if defined(REFCLOCK) && defined(CLOCK_TRUETIME)
15
16#include <stdio.h>
17#include <ctype.h>
18
19#include "ntpd.h"
20#include "ntp_io.h"
21#include "ntp_refclock.h"
22#include "ntp_unixtime.h"
23#include "ntp_stdlib.h"
24
25#ifdef SYS_WINNT
26extern int async_write(int, const void *, unsigned int);
27#undef write
28#define write(fd, data, octets)	async_write(fd, data, octets)
29#endif
30
31/* This should be an atom clock but those are very hard to build.
32 *
33 * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch
34 * of TTL input and output pins, all brought out to the back panel.  If you
35 * wire a PPS signal (such as the TTL PPS coming out of a GOES or other
36 * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the
37 * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the
38 * number of uSecs since the last PPS upward swing, mediated by reading OUT0
39 * to find out if the counter has wrapped around (this happens if more than
40 * 65535us (65ms) elapses between the PPS event and our being called.)
41 */
42#ifdef CLOCK_PPS720
43# undef min	/* XXX */
44# undef max	/* XXX */
45# include <machine/inline.h>
46# include <sys/pcl720.h>
47# include <sys/i8253.h>
48# define PCL720_IOB 0x2a0	/* XXX */
49# define PCL720_CTR 0		/* XXX */
50#endif
51
52/*
53 * Support for Kinemetrics Truetime Receivers
54 *	GOES:           (468-DC, usable with GPS->GOES converting antenna)
55 *	GPS/TM-TMD:
56 *	XL-DC:		(a 151-602-210, reported by the driver as a GPS/TM-TMD)
57 *	GPS-800 TCU:	(an 805-957 with the RS232 Talker/Listener module)
58 *      TL-3:           3 channel WWV/H receiver w/ IRIG and RS-232 outputs
59 *	OM-DC:		getting stale ("OMEGA")
60 *
61 * Most of this code is originally from refclock_wwvb.c with thanks.
62 * It has been so mangled that wwvb is not a recognizable ancestor.
63 *
64 * Timcode format: ADDD:HH:MM:SSQCL
65 *	A - control A		(this is stripped before we see it)
66 *	Q - Quality indication	(see below)
67 *	C - Carriage return
68 *	L - Line feed
69 *
70 * Quality codes indicate possible error of
71 *   468-DC GOES Receiver:
72 *   GPS-TM/TMD Receiver: (default quality codes for XL-DC)
73 *       ?     +/- 1  milliseconds	#     +/- 100 microseconds
74 *       *     +/- 10 microseconds	.     +/- 1   microsecond
75 *     space   less than 1 microsecond
76 *   TL-3 Receiver: (default quality codes for TL-3)
77 *       ?     unknown quality (receiver is unlocked)
78 *     space   +/- 5 milliseconds
79 *   OM-DC OMEGA Receiver: (default quality codes for OMEGA)
80 *   WARNING OMEGA navigation system is no longer existent
81 *       >     >+- 5 seconds
82 *       ?     >+/- 500 milliseconds    #     >+/- 50 milliseconds
83 *       *     >+/- 5 milliseconds      .     >+/- 1 millisecond
84 *      A-H    less than 1 millisecond.  Character indicates which station
85 *	       is being received as follows:
86 *	       A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
87 *	       E = La Reunion, F = Argentina, G = Australia, H = Japan.
88 *
89 * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
90 *
91 * Notes on 468-DC and OMEGA receiver:
92 *
93 * Send the clock a 'R' or 'C' and once per second a timestamp will
94 * appear.  Send a 'P' to get the satellite position once (GOES only.)
95 *
96 * Notes on the 468-DC receiver:
97 *
98 * Since the old east/west satellite locations are only historical, you can't
99 * set your clock propagation delay settings correctly and still use
100 * automatic mode. The manual says to use a compromise when setting the
101 * switches. This results in significant errors. The solution; use fudge
102 * time1 and time2 to incorporate corrections. If your clock is set for
103 * 50 and it should be 58 for using the west and 46 for using the east,
104 * use the line
105 *
106 * fudge 127.127.5.0 time1 +0.008 time2 -0.004
107 *
108 * This corrects the 4 milliseconds advance and 8 milliseconds retard
109 * needed. The software will ask the clock which satellite it sees.
110 *
111 * Notes on the TrueTime TimeLink TL-3 WWV TOD receiver:
112 *
113 * This clock may be polled, or send one timecode per second.
114 * That mode may be toggled via the front panel ("C" mode), or controlled
115 * from the RS-232 port.  Send the receiver "ST1" to turn it on, and
116 * "ST0" to turn it off.  Send "QV" to get the firmware revision (useful
117 * for identifying this model.)
118 *
119 * Note that it can take several polling cycles, especially if the receiver
120 * was in the continuous timecode mode.  (It can be slow to leave that mode.)
121 *
122 * ntp.conf parameters:
123 * time1   - offset applied to samples when reading WEST satellite (default = 0)
124 * time2   - offset applied to samples when reading EAST satellite (default = 0)
125 * stratum - stratum to assign to this clock (default = 0)
126 * refid   - refid assigned to this clock (default = "TRUE", see below)
127 * flag1   - will silence the clock side of ntpd, just reading the clock
128 *	     without trying to write to it.  (default = 0)
129 * flag2   - generate a debug file /tmp/true%d.
130 * flag3   - enable ppsclock streams module
131 * flag4   - use the PCL-720 (BSD/OS only)
132 */
133
134
135/*
136 * Definitions
137 */
138#define	DEVICE		"/dev/true%d"
139#define	SPEED232	B9600	/* 9600 baud */
140
141/*
142 * Radio interface parameters
143 */
144#define	PRECISION	(-10)	/* precision assumed (about 1 ms) */
145#define	REFID		"TRUE"	/* reference id */
146#define	DESCRIPTION	"Kinemetrics/TrueTime Receiver"
147
148/*
149 * Tags which station (satellite) we see
150 */
151#define GOES_WEST	0	/* Default to WEST satellite and apply time1 */
152#define GOES_EAST	1	/* until you discover otherwise */
153
154/*
155 * used by the state machine
156 */
157enum true_event	{e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
158		 e_TL3, e_Poll, e_Location, e_TS, e_Max};
159const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
160			"TL3", "Poll", "Location", "TS"};
161#define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
162
163enum true_state	{s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
164		 s_InqTL3, s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
165const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
166			"InqTL3", "Init", "F18", "F50", "Start", "Auto"};
167#define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
168
169enum true_type	{t_unknown, t_goes, t_tm, t_tcu, t_omega, t_tl3, t_Max};
170const char *types[] = {"unknown", "goes", "tm", "tcu", "omega", "tl3"};
171#define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
172
173/*
174 * unit control structure
175 */
176struct true_unit {
177	unsigned int	pollcnt;	/* poll message counter */
178	unsigned int	station;	/* which station we are on */
179	unsigned int	polled;		/* Hand in a time sample? */
180	enum true_state	state;		/* state machine */
181	enum true_type	type;		/* what kind of clock is it? */
182	int		unit;		/* save an extra copy of this */
183	FILE		*debug;		/* debug logging file */
184#ifdef CLOCK_PPS720
185	int		pcl720init;	/* init flag for PCL 720 */
186#endif
187};
188
189/*
190 * Function prototypes
191 */
192static	int	true_start	(int, struct peer *);
193static	void	true_shutdown	(int, struct peer *);
194static	void	true_receive	(struct recvbuf *);
195static	void	true_poll	(int, struct peer *);
196static	void	true_send	(struct peer *, const char *);
197static	void	true_doevent	(struct peer *, enum true_event);
198
199#ifdef CLOCK_PPS720
200static	u_long	true_sample720	(void);
201#endif
202
203/*
204 * Transfer vector
205 */
206struct	refclock refclock_true = {
207	true_start,		/* start up driver */
208	true_shutdown,		/* shut down driver */
209	true_poll,		/* transmit poll message */
210	noentry,		/* not used (old true_control) */
211	noentry,		/* initialize driver (not used) */
212	noentry,		/* not used (old true_buginfo) */
213	NOFLAGS			/* not used */
214};
215
216
217#if !defined(__STDC__)
218# define true_debug (void)
219#else
220NTP_PRINTF(2, 3)
221static void
222true_debug(struct peer *peer, const char *fmt, ...)
223{
224	va_list ap;
225	int want_debugging, now_debugging;
226	struct refclockproc *pp;
227	struct true_unit *up;
228
229	va_start(ap, fmt);
230	pp = peer->procptr;
231	up = pp->unitptr;
232
233	want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
234	now_debugging = (up->debug != NULL);
235	if (want_debugging != now_debugging)
236	{
237		if (want_debugging) {
238			char filename[40];
239			int fd;
240
241			snprintf(filename, sizeof(filename),
242				 "/tmp/true%d.debug", up->unit);
243			fd = open(filename, O_CREAT | O_WRONLY | O_EXCL,
244				  0600);
245			if (fd >= 0 && (up->debug = fdopen(fd, "w"))) {
246#ifdef HAVE_SETVBUF
247				static char buf[BUFSIZ];
248
249				setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
250#else
251				setlinebuf(up->debug);
252#endif
253			}
254		} else {
255			fclose(up->debug);
256			up->debug = NULL;
257		}
258	}
259
260	if (up->debug) {
261		fprintf(up->debug, "true%d: ", up->unit);
262		vfprintf(up->debug, fmt, ap);
263	}
264	va_end(ap);
265}
266#endif /*STDC*/
267
268/*
269 * true_start - open the devices and initialize data for processing
270 */
271static int
272true_start(
273	int unit,
274	struct peer *peer
275	)
276{
277	register struct true_unit *up;
278	struct refclockproc *pp;
279	char device[40];
280	int fd;
281
282	/*
283	 * Open serial port
284	 */
285	snprintf(device, sizeof(device), DEVICE, unit);
286	fd = refclock_open(device, SPEED232, LDISC_CLK);
287	if (fd <= 0)
288		return 0;
289
290	/*
291	 * Allocate and initialize unit structure
292	 */
293	up = emalloc_zero(sizeof(*up));
294	pp = peer->procptr;
295	pp->io.clock_recv = true_receive;
296	pp->io.srcclock = peer;
297	pp->io.datalen = 0;
298	pp->io.fd = fd;
299	if (!io_addclock(&pp->io)) {
300		close(fd);
301		pp->io.fd = -1;
302		free(up);
303		return (0);
304	}
305	pp->unitptr = up;
306
307	/*
308	 * Initialize miscellaneous variables
309	 */
310	peer->precision = PRECISION;
311	pp->clockdesc = DESCRIPTION;
312	memcpy(&pp->refid, REFID, 4);
313	up->pollcnt = 2;
314	up->type = t_unknown;
315	up->state = s_Base;
316
317	/*
318	 * Send a CTRL-C character at the start,
319	 * just in case the clock is already
320	 * sending timecodes
321	 */
322	true_send(peer, "\03\r");
323
324	true_doevent(peer, e_Init);
325
326	return (1);
327}
328
329
330/*
331 * true_shutdown - shut down the clock
332 */
333static void
334true_shutdown(
335	int unit,
336	struct peer *peer
337	)
338{
339	register struct true_unit *up;
340	struct refclockproc *pp;
341
342	pp = peer->procptr;
343	up = pp->unitptr;
344	if (pp->io.fd != -1)
345		io_closeclock(&pp->io);
346	if (up != NULL)
347		free(up);
348}
349
350
351/*
352 * true_receive - receive data from the serial interface on a clock
353 */
354static void
355true_receive(
356	struct recvbuf *rbufp
357	)
358{
359	register struct true_unit *up;
360	struct refclockproc *pp;
361	struct peer *peer;
362	u_short new_station;
363	char synced;
364	int i;
365	int lat, lon, off;	/* GOES Satellite position */
366	/* These variables hold data until we decide to keep it */
367	char	rd_lastcode[BMAX];
368	l_fp	rd_tmp;
369	u_short	rd_lencode;
370
371	/*
372	 * Get the clock this applies to and pointers to the data.
373	 */
374	peer = rbufp->recv_peer;
375	pp = peer->procptr;
376	up = pp->unitptr;
377
378	/*
379	 * Read clock output.  Automatically handles STREAMS, CLKLDISC.
380	 */
381	rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
382	rd_lastcode[rd_lencode] = '\0';
383
384	/*
385	 * There is a case where <cr><lf> generates 2 timestamps.
386	 */
387	if (rd_lencode == 0)
388		return;
389	pp->lencode = rd_lencode;
390	strlcpy(pp->a_lastcode, rd_lastcode, sizeof(pp->a_lastcode));
391	pp->lastrec = rd_tmp;
392	true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode,
393		   pp->lencode);
394
395	up->pollcnt = 2;
396	record_clock_stats(&peer->srcadr, pp->a_lastcode);
397
398	/*
399	 * We get down to business, check the timecode format and decode
400	 * its contents. This code decodes a multitude of different
401	 * clock messages. Timecodes are processed if needed. All replies
402	 * will be run through the state machine to tweak driver options
403	 * and program the clock.
404	 */
405
406	/*
407	 * Clock misunderstood our last command?
408	 */
409	if (pp->a_lastcode[0] == '?' ||
410	    strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
411		true_doevent(peer, e_Huh);
412		return;
413	}
414
415	/*
416	 * Timecode: "nnnnn+nnn-nnn"
417	 * (from GOES clock when asked about satellite position)
418	 */
419	if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
420	    (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
421	    sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
422	    ) {
423		const char *label = "Botch!";
424
425		/*
426		 * This is less than perfect.  Call the (satellite)
427		 * either EAST or WEST and adjust slop accodingly
428		 * Perfectionists would recalculate the exact delay
429		 * and adjust accordingly...
430		 */
431		if (lon > 7000 && lon < 14000) {
432			if (lon < 10000) {
433				new_station = GOES_EAST;
434				label = "EAST";
435			} else {
436				new_station = GOES_WEST;
437				label = "WEST";
438			}
439
440			if (new_station != up->station) {
441				double dtemp;
442
443				dtemp = pp->fudgetime1;
444				pp->fudgetime1 = pp->fudgetime2;
445				pp->fudgetime2 = dtemp;
446				up->station = new_station;
447			}
448		}
449		else {
450			/*refclock_report(peer, CEVNT_BADREPLY);*/
451			label = "UNKNOWN";
452		}
453		true_debug(peer, "GOES: station %s\n", label);
454		true_doevent(peer, e_Satellite);
455		return;
456	}
457
458	/*
459	 * Timecode: "Fnn"
460	 * (from TM/TMD clock when it wants to tell us what it's up to.)
461	 */
462	if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
463		switch (i) {
464		case 50:
465			true_doevent(peer, e_F50);
466			break;
467		case 51:
468			true_doevent(peer, e_F51);
469			break;
470		default:
471			true_debug(peer, "got F%02d - ignoring\n", i);
472			break;
473		}
474		return;
475	}
476
477        /*
478         * Timecode: "VER xx.xx"
479         * (from a TL3 when sent "QV", so id's it during initialization.)
480         */
481        if (pp->a_lastcode[0] == 'V' && pp->a_lastcode[1] == 'E' &&
482            pp->a_lastcode[2] == 'R' && pp->a_lastcode[6] == '.') {
483                true_doevent(peer, e_TL3);
484                NLOG(NLOG_CLOCKSTATUS) {
485                        msyslog(LOG_INFO, "TL3: %s", pp->a_lastcode);
486                }
487                return;
488        }
489
490	/*
491	 * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
492	 * (from a TM/TMD/XL clock during initialization.)
493	 */
494	if (strncmp(pp->a_lastcode, " TRUETIME Mk III ", 17) == 0 ||
495	    strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
496		true_doevent(peer, e_F18);
497		NLOG(NLOG_CLOCKSTATUS) {
498			msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
499		}
500		return;
501	}
502
503	/*
504	 * Timecode: "N03726428W12209421+000033"
505	 *			1	   2
506	 * index      0123456789012345678901234
507	 * (from a TCU during initialization)
508	 */
509	if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
510	    (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
511	    pp->a_lastcode[18] == '+') {
512		true_doevent(peer, e_Location);
513		NLOG(NLOG_CLOCKSTATUS) {
514			msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
515		}
516		return;
517	}
518	/*
519	 * Timecode: "ddd:hh:mm:ssQ"
520	 *			1	   2
521	 * index      0123456789012345678901234
522	 * (from all clocks supported by this driver.)
523	 */
524	if (pp->a_lastcode[3] == ':' &&
525	    pp->a_lastcode[6] == ':' &&
526	    pp->a_lastcode[9] == ':' &&
527	    sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
528		   &pp->day, &pp->hour, &pp->minute,
529		   &pp->second, &synced) == 5) {
530
531		/*
532		 * Adjust the synchronize indicator according to timecode
533		 * say were OK, and then say not if we really are not OK
534		 */
535		if (synced == '>' || synced == '#' || synced == '?'
536		    || synced == 'X')
537			pp->leap = LEAP_NOTINSYNC;
538		else
539			pp->leap = LEAP_NOWARNING;
540
541		true_doevent(peer, e_TS);
542
543#ifdef CLOCK_PPS720
544		/* If it's taken more than 65ms to get here, we'll lose. */
545		if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) {
546			l_fp   off;
547
548#ifdef CLOCK_ATOM
549			/*
550			 * find out what time it really is. Include
551			 * the count from the PCL720
552			 */
553			if (!clocktime(pp->day, pp->hour, pp->minute,
554				       pp->second, GMT, pp->lastrec.l_ui,
555				       &pp->yearstart, &off.l_ui)) {
556				refclock_report(peer, CEVNT_BADTIME);
557				return;
558			}
559			off.l_uf = 0;
560#endif
561
562			pp->usec = true_sample720();
563#ifdef CLOCK_ATOM
564			TVUTOTSF(pp->usec, off.l_uf);
565#endif
566
567			/*
568			 * Stomp all over the timestamp that was pulled out
569			 * of the input stream. It's irrelevant since we've
570			 * adjusted the input time to reflect now (via pp->usec)
571			 * rather than when the data was collected.
572			 */
573			get_systime(&pp->lastrec);
574#ifdef CLOCK_ATOM
575			/*
576			 * Create a true offset for feeding to pps_sample()
577			 */
578			L_SUB(&off, &pp->lastrec);
579
580			pps_sample(peer, &off);
581#endif
582			true_debug(peer, "true_sample720: %luus\n", pp->usec);
583		}
584#endif
585
586		/*
587		 * The clock will blurt a timecode every second but we only
588		 * want one when polled.  If we havn't been polled, bail out.
589		 */
590		if (!up->polled)
591			return;
592
593                /* We only call doevent if additional things need be done
594                 * at poll interval.  Currently, its only for GOES.  We also
595                 * call it for clock unknown so that it gets logged.
596                 */
597                if (up->type == t_goes || up->type == t_unknown)
598                    true_doevent(peer, e_Poll);
599
600		if (!refclock_process(pp)) {
601			refclock_report(peer, CEVNT_BADTIME);
602			return;
603		}
604		/*
605		 * If clock is good we send a NOMINAL message so that
606		 * any previous BAD messages are nullified
607		 */
608		pp->lastref = pp->lastrec;
609		refclock_receive(peer);
610		refclock_report(peer, CEVNT_NOMINAL);
611
612		/*
613		 * We have succedded in answering the poll.
614		 * Turn off the flag and return
615		 */
616		up->polled = 0;
617
618		return;
619	}
620
621	/*
622	 * No match to known timecodes, report failure and return
623	 */
624	refclock_report(peer, CEVNT_BADREPLY);
625	return;
626}
627
628
629/*
630 * true_send - time to send the clock a signal to cough up a time sample
631 */
632static void
633true_send(
634	struct peer *peer,
635	const char *cmd
636	)
637{
638	struct refclockproc *pp;
639
640	pp = peer->procptr;
641	if (!(pp->sloppyclockflag & CLK_FLAG1)) {
642		size_t len = strlen(cmd);
643
644		true_debug(peer, "Send '%s'\n", cmd);
645		if (write(pp->io.fd, cmd, len) != (ssize_t)len)
646			refclock_report(peer, CEVNT_FAULT);
647		else
648			pp->polls++;
649	}
650}
651
652
653/*
654 * state machine for initializing and controlling a clock
655 */
656static void
657true_doevent(
658	struct peer *peer,
659	enum true_event event
660	)
661{
662	struct true_unit *up;
663	struct refclockproc *pp;
664
665	pp = peer->procptr;
666	up = pp->unitptr;
667	if (event != e_TS) {
668		NLOG(NLOG_CLOCKSTATUS) {
669			msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
670				typeStr(up->type),
671				stateStr(up->state),
672				eventStr(event));
673		}
674	}
675	true_debug(peer, "clock %s, state %s, event %s\n",
676		   typeStr(up->type), stateStr(up->state), eventStr(event));
677	switch (up->type) {
678	case t_goes:
679		switch (event) {
680		case e_Init:	/* FALLTHROUGH */
681		case e_Satellite:
682			/*
683			 * Switch back to on-second time codes and return.
684			 */
685			true_send(peer, "C");
686			up->state = s_Start;
687			break;
688		case e_Poll:
689			/*
690			 * After each poll, check the station (satellite).
691			 */
692			true_send(peer, "P");
693			/* No state change needed. */
694			break;
695		default:
696			break;
697		}
698		/* FALLTHROUGH */
699	case t_omega:
700		switch (event) {
701		case e_Init:
702			true_send(peer, "C");
703			up->state = s_Start;
704			break;
705		case e_TS:
706			if (up->state != s_Start && up->state != s_Auto) {
707				true_send(peer, "\03\r");
708				break;
709			}
710			up->state = s_Auto;
711			break;
712		default:
713			break;
714		}
715		break;
716	case t_tm:
717		switch (event) {
718		case e_Init:
719			true_send(peer, "F18\r");
720			up->state = s_Init;
721			break;
722		case e_F18:
723			true_send(peer, "F50\r");
724                        /*
725                         * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
726                         * (from a TM/TMD/XL clock during initialization.)
727                         */
728                        if ( strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
729                            strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
730                                true_doevent(peer, e_F18);
731                                NLOG(NLOG_CLOCKSTATUS) {
732                                    msyslog(LOG_INFO, "TM/TMD/XL: %s",
733                                            pp->a_lastcode);
734                                }
735                                return;
736                        }
737			up->state = s_F18;
738			break;
739		case e_F50:
740			true_send(peer, "F51\r");
741			up->state = s_F50;
742			break;
743		case e_F51:
744			true_send(peer, "F08\r");
745			up->state = s_Start;
746			break;
747		case e_TS:
748			if (up->state != s_Start && up->state != s_Auto) {
749				true_send(peer, "\03\r");
750				break;
751			}
752			up->state = s_Auto;
753			break;
754		default:
755			break;
756		}
757		break;
758	case t_tcu:
759		switch (event) {
760		case e_Init:
761			true_send(peer, "MD3\r");	/* GPS Synch'd Gen. */
762			true_send(peer, "TSU\r");	/* UTC, not GPS. */
763			true_send(peer, "AU\r");	/* Auto Timestamps. */
764			up->state = s_Start;
765			break;
766		case e_TS:
767			if (up->state != s_Start && up->state != s_Auto) {
768				true_send(peer, "\03\r");
769				break;
770			}
771			up->state = s_Auto;
772			break;
773		default:
774			break;
775		}
776		break;
777	case t_tl3:
778                switch (event) {
779                    case e_Init:
780                        true_send(peer, "ST1"); /* Turn on continuous stream */
781                        break;
782                    case e_TS:
783                        up->state = s_Auto;
784                        break;
785                    default:
786                        break;
787                }
788                break;
789	case t_unknown:
790               if (event == e_Poll)
791                   break;
792		switch (up->state) {
793		case s_Base:
794			if (event != e_Init)
795			    abort();
796			true_send(peer, "P\r");
797			up->state = s_InqGOES;
798			break;
799		case s_InqGOES:
800			switch (event) {
801			case e_Satellite:
802				up->type = t_goes;
803				true_doevent(peer, e_Init);
804				break;
805			case e_Init:	/*FALLTHROUGH*/
806			case e_Huh:
807			case e_TS:
808                                true_send(peer, "ST0"); /* turn off TL3 auto */
809                                sleep(1);               /* wait for it */
810                                up->state = s_InqTL3;
811                                true_send(peer, "QV");  /* see if its a TL3 */
812                                break;
813                            default:
814                                abort();
815                        }
816                        break;
817                    case s_InqTL3:
818                        switch (event) {
819                            case e_TL3:
820                                up->type = t_tl3;
821                                up->state = s_Auto;     /* Inq side-effect. */
822                                true_send(peer, "ST1"); /* Turn on 1/sec data */
823                                break;
824                            case e_Init:        /*FALLTHROUGH*/
825                            case e_Huh:
826				up->state = s_InqOmega;
827				true_send(peer, "C\r");
828				break;
829                            case e_TS:
830                                 up->type = t_tl3;    /* Already sending data */
831                                 up->state = s_Auto;
832                                 break;
833			    default:
834                                msyslog(LOG_INFO,
835                                        "TRUE: TL3 init fellthrough! (%d)", event);
836                                break;
837			}
838			break;
839		case s_InqOmega:
840			switch (event) {
841			case e_TS:
842				up->type = t_omega;
843				up->state = s_Auto;	/* Inq side-effect. */
844				break;
845			case e_Init:	/*FALLTHROUGH*/
846			case e_Huh:
847				up->state = s_InqTM;
848				true_send(peer, "F18\r");
849				break;
850			default:
851				abort();
852			}
853			break;
854		case s_InqTM:
855			switch (event) {
856			case e_F18:
857				up->type = t_tm;
858				true_doevent(peer, e_Init);
859				break;
860			case e_Init:	/*FALLTHROUGH*/
861			case e_Huh:
862				true_send(peer, "PO\r");
863				up->state = s_InqTCU;
864				break;
865			default:
866                                msyslog(LOG_INFO,
867                                        "TRUE: TM/TMD init fellthrough!");
868			        break;
869			}
870			break;
871		case s_InqTCU:
872			switch (event) {
873			case e_Location:
874				up->type = t_tcu;
875				true_doevent(peer, e_Init);
876				break;
877			case e_Init:	/*FALLTHROUGH*/
878			case e_Huh:
879				up->state = s_Base;
880				sleep(1);	/* XXX */
881				break;
882			default:
883                                msyslog(LOG_INFO,
884                                        "TRUE: TCU init fellthrough!");
885                                break;
886			}
887			break;
888			/*
889			 * An expedient hack to prevent lint complaints,
890			 * these don't actually need to be used here...
891			 */
892		case s_Init:
893		case s_F18:
894		case s_F50:
895		case s_Start:
896		case s_Auto:
897		case s_Max:
898			msyslog(LOG_INFO, "TRUE: state %s is unexpected!",
899				stateStr(up->state));
900		}
901		break;
902	default:
903                msyslog(LOG_INFO, "TRUE: cannot identify refclock!");
904		abort();
905		/* NOTREACHED */
906	}
907
908#ifdef CLOCK_PPS720
909	if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) {
910		/* Make counter trigger on gate0, count down from 65535. */
911		pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535);
912		/*
913		 * (These constants are OK since
914		 * they represent hardware maximums.)
915		 */
916		NLOG(NLOG_CLOCKINFO) {
917			msyslog(LOG_NOTICE, "PCL-720 initialized");
918		}
919		up->pcl720init++;
920	}
921#endif
922
923
924}
925
926/*
927 * true_poll - called by the transmit procedure
928 */
929static void
930true_poll(
931	int unit,
932	struct peer *peer
933	)
934{
935	struct true_unit *up;
936	struct refclockproc *pp;
937
938	/*
939	 * You don't need to poll this clock.  It puts out timecodes
940	 * once per second.  If asked for a timestamp, take note.
941	 * The next time a timecode comes in, it will be fed back.
942	 */
943	pp = peer->procptr;
944	up = pp->unitptr;
945	if (up->pollcnt > 0) {
946		up->pollcnt--;
947	} else {
948		true_doevent(peer, e_Init);
949		refclock_report(peer, CEVNT_TIMEOUT);
950	}
951
952	/*
953	 * polled every 64 seconds. Ask true_receive to hand in a
954	 * timestamp.
955	 */
956	up->polled = 1;
957	pp->polls++;
958}
959
960#ifdef CLOCK_PPS720
961/*
962 * true_sample720 - sample the PCL-720
963 */
964static u_long
965true_sample720(void)
966{
967	unsigned long f;
968
969	/* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3.
970	 * If it is not being held low now, we did not get called
971	 * within 65535us.
972	 */
973	if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) {
974		NLOG(NLOG_CLOCKINFO) {
975			msyslog(LOG_NOTICE, "PCL-720 out of synch");
976		}
977		return (0);
978	}
979	f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR));
980#ifdef PPS720_DEBUG
981	msyslog(LOG_DEBUG, "PCL-720: %luus", f);
982#endif
983	return (f);
984}
985#endif
986
987#else
988int refclock_true_bs;
989#endif /* REFCLOCK */
990