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