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