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