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