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