xref: /netbsd-src/external/bsd/ntp/dist/ntpd/refclock_true.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: refclock_true.c,v 1.2 2014/01/02 21:35:50 joerg 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 NTP_PRINTF(2, 3)
207 static void
208 true_debug(struct peer *peer, const char *fmt, ...)
209 {
210 	va_list ap;
211 	int want_debugging, now_debugging;
212 	struct refclockproc *pp;
213 	struct true_unit *up;
214 
215 	va_start(ap, fmt);
216 	pp = peer->procptr;
217 	up = pp->unitptr;
218 
219 	want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
220 	now_debugging = (up->debug != NULL);
221 	if (want_debugging != now_debugging)
222 	{
223 		if (want_debugging) {
224 			char filename[40];
225 			int fd;
226 
227 			snprintf(filename, sizeof(filename),
228 				 "/tmp/true%d.debug", up->unit);
229 			fd = open(filename, O_CREAT | O_WRONLY | O_EXCL,
230 				  0600);
231 			if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) {
232 #ifdef HAVE_SETVBUF
233 				static char buf[BUFSIZ];
234 
235 				setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
236 #else
237 				setlinebuf(up->debug);
238 #endif
239 			}
240 		} else {
241 			fclose(up->debug);
242 			up->debug = NULL;
243 		}
244 	}
245 
246 	if (up->debug) {
247 		fprintf(up->debug, "true%d: ", up->unit);
248 		vfprintf(up->debug, fmt, ap);
249 	}
250 	va_end(ap);
251 }
252 #endif /*STDC*/
253 
254 /*
255  * true_start - open the devices and initialize data for processing
256  */
257 static int
258 true_start(
259 	int unit,
260 	struct peer *peer
261 	)
262 {
263 	register struct true_unit *up;
264 	struct refclockproc *pp;
265 	char device[40];
266 	int fd;
267 
268 	/*
269 	 * Open serial port
270 	 */
271 	snprintf(device, sizeof(device), DEVICE, unit);
272 	fd = refclock_open(device, SPEED232, LDISC_CLK);
273 	if (fd <= 0)
274 		return 0;
275 
276 	/*
277 	 * Allocate and initialize unit structure
278 	 */
279 	up = emalloc_zero(sizeof(*up));
280 	pp = peer->procptr;
281 	pp->io.clock_recv = true_receive;
282 	pp->io.srcclock = peer;
283 	pp->io.datalen = 0;
284 	pp->io.fd = fd;
285 	if (!io_addclock(&pp->io)) {
286 		close(fd);
287 		pp->io.fd = -1;
288 		free(up);
289 		return (0);
290 	}
291 	pp->unitptr = up;
292 
293 	/*
294 	 * Initialize miscellaneous variables
295 	 */
296 	peer->precision = PRECISION;
297 	pp->clockdesc = DESCRIPTION;
298 	memcpy(&pp->refid, REFID, 4);
299 	up->pollcnt = 2;
300 	up->type = t_unknown;
301 	up->state = s_Base;
302 
303 	/*
304 	 * Send a CTRL-C character at the start,
305 	 * just in case the clock is already
306 	 * sending timecodes
307 	 */
308 	true_send(peer, "\03\r");
309 
310 	true_doevent(peer, e_Init);
311 
312 	return (1);
313 }
314 
315 
316 /*
317  * true_shutdown - shut down the clock
318  */
319 static void
320 true_shutdown(
321 	int unit,
322 	struct peer *peer
323 	)
324 {
325 	register struct true_unit *up;
326 	struct refclockproc *pp;
327 
328 	pp = peer->procptr;
329 	up = pp->unitptr;
330 	if (pp->io.fd != -1)
331 		io_closeclock(&pp->io);
332 	if (up != NULL)
333 		free(up);
334 }
335 
336 
337 /*
338  * true_receive - receive data from the serial interface on a clock
339  */
340 static void
341 true_receive(
342 	struct recvbuf *rbufp
343 	)
344 {
345 	register struct true_unit *up;
346 	struct refclockproc *pp;
347 	struct peer *peer;
348 	u_short new_station;
349 	char synced;
350 	int i;
351 	int lat, lon, off;	/* GOES Satellite position */
352 	/* These variables hold data until we decide to keep it */
353 	char	rd_lastcode[BMAX];
354 	l_fp	rd_tmp;
355 	u_short	rd_lencode;
356 
357 	/*
358 	 * Get the clock this applies to and pointers to the data.
359 	 */
360 	peer = rbufp->recv_peer;
361 	pp = peer->procptr;
362 	up = pp->unitptr;
363 
364 	/*
365 	 * Read clock output.  Automatically handles STREAMS, CLKLDISC.
366 	 */
367 	rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
368 	rd_lastcode[rd_lencode] = '\0';
369 
370 	/*
371 	 * There is a case where <cr><lf> generates 2 timestamps.
372 	 */
373 	if (rd_lencode == 0)
374 		return;
375 	pp->lencode = rd_lencode;
376 	strlcpy(pp->a_lastcode, rd_lastcode, sizeof(pp->a_lastcode));
377 	pp->lastrec = rd_tmp;
378 	true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode,
379 		   pp->lencode);
380 
381 	up->pollcnt = 2;
382 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
383 
384 	/*
385 	 * We get down to business, check the timecode format and decode
386 	 * its contents. This code decodes a multitude of different
387 	 * clock messages. Timecodes are processed if needed. All replies
388 	 * will be run through the state machine to tweak driver options
389 	 * and program the clock.
390 	 */
391 
392 	/*
393 	 * Clock misunderstood our last command?
394 	 */
395 	if (pp->a_lastcode[0] == '?' ||
396 	    strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
397 		true_doevent(peer, e_Huh);
398 		return;
399 	}
400 
401 	/*
402 	 * Timecode: "nnnnn+nnn-nnn"
403 	 * (from GOES clock when asked about satellite position)
404 	 */
405 	if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
406 	    (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
407 	    sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
408 	    ) {
409 		const char *label = "Botch!";
410 
411 		/*
412 		 * This is less than perfect.  Call the (satellite)
413 		 * either EAST or WEST and adjust slop accodingly
414 		 * Perfectionists would recalculate the exact delay
415 		 * and adjust accordingly...
416 		 */
417 		if (lon > 7000 && lon < 14000) {
418 			if (lon < 10000) {
419 				new_station = GOES_EAST;
420 				label = "EAST";
421 			} else {
422 				new_station = GOES_WEST;
423 				label = "WEST";
424 			}
425 
426 			if (new_station != up->station) {
427 				double dtemp;
428 
429 				dtemp = pp->fudgetime1;
430 				pp->fudgetime1 = pp->fudgetime2;
431 				pp->fudgetime2 = dtemp;
432 				up->station = new_station;
433 			}
434 		}
435 		else {
436 			/*refclock_report(peer, CEVNT_BADREPLY);*/
437 			label = "UNKNOWN";
438 		}
439 		true_debug(peer, "GOES: station %s\n", label);
440 		true_doevent(peer, e_Satellite);
441 		return;
442 	}
443 
444 	/*
445 	 * Timecode: "Fnn"
446 	 * (from TM/TMD clock when it wants to tell us what it's up to.)
447 	 */
448 	if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
449 		switch (i) {
450 		case 50:
451 			true_doevent(peer, e_F50);
452 			break;
453 		case 51:
454 			true_doevent(peer, e_F51);
455 			break;
456 		default:
457 			true_debug(peer, "got F%02d - ignoring\n", i);
458 			break;
459 		}
460 		return;
461 	}
462 
463 	/*
464 	 * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
465 	 * (from a TM/TMD/XL clock during initialization.)
466 	 */
467 	if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
468 	    strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
469 		true_doevent(peer, e_F18);
470 		NLOG(NLOG_CLOCKSTATUS) {
471 			msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
472 		}
473 		return;
474 	}
475 
476 	/*
477 	 * Timecode: "N03726428W12209421+000033"
478 	 *			1	   2
479 	 * index      0123456789012345678901234
480 	 * (from a TCU during initialization)
481 	 */
482 	if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
483 	    (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
484 	    pp->a_lastcode[18] == '+') {
485 		true_doevent(peer, e_Location);
486 		NLOG(NLOG_CLOCKSTATUS) {
487 			msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
488 		}
489 		return;
490 	}
491 	/*
492 	 * Timecode: "ddd:hh:mm:ssQ"
493 	 *			1	   2
494 	 * index      0123456789012345678901234
495 	 * (from all clocks supported by this driver.)
496 	 */
497 	if (pp->a_lastcode[3] == ':' &&
498 	    pp->a_lastcode[6] == ':' &&
499 	    pp->a_lastcode[9] == ':' &&
500 	    sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
501 		   &pp->day, &pp->hour, &pp->minute,
502 		   &pp->second, &synced) == 5) {
503 
504 		/*
505 		 * Adjust the synchronize indicator according to timecode
506 		 * say were OK, and then say not if we really are not OK
507 		 */
508 		if (synced == '>' || synced == '#' || synced == '?'
509 		    || synced == 'X')
510 			pp->leap = LEAP_NOTINSYNC;
511 		else
512 			pp->leap = LEAP_NOWARNING;
513 
514 		true_doevent(peer, e_TS);
515 
516 #ifdef CLOCK_PPS720
517 		/* If it's taken more than 65ms to get here, we'll lose. */
518 		if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) {
519 			l_fp   off;
520 
521 #ifdef CLOCK_ATOM
522 			/*
523 			 * find out what time it really is. Include
524 			 * the count from the PCL720
525 			 */
526 			if (!clocktime(pp->day, pp->hour, pp->minute,
527 				       pp->second, GMT, pp->lastrec.l_ui,
528 				       &pp->yearstart, &off.l_ui)) {
529 				refclock_report(peer, CEVNT_BADTIME);
530 				return;
531 			}
532 			off.l_uf = 0;
533 #endif
534 
535 			pp->usec = true_sample720();
536 #ifdef CLOCK_ATOM
537 			TVUTOTSF(pp->usec, off.l_uf);
538 #endif
539 
540 			/*
541 			 * Stomp all over the timestamp that was pulled out
542 			 * of the input stream. It's irrelevant since we've
543 			 * adjusted the input time to reflect now (via pp->usec)
544 			 * rather than when the data was collected.
545 			 */
546 			get_systime(&pp->lastrec);
547 #ifdef CLOCK_ATOM
548 			/*
549 			 * Create a true offset for feeding to pps_sample()
550 			 */
551 			L_SUB(&off, &pp->lastrec);
552 
553 			pps_sample(peer, &off);
554 #endif
555 			true_debug(peer, "true_sample720: %luus\n", pp->usec);
556 		}
557 #endif
558 
559 		/*
560 		 * The clock will blurt a timecode every second but we only
561 		 * want one when polled.  If we havn't been polled, bail out.
562 		 */
563 		if (!up->polled)
564 			return;
565 
566 		true_doevent(peer, e_Poll);
567 		if (!refclock_process(pp)) {
568 			refclock_report(peer, CEVNT_BADTIME);
569 			return;
570 		}
571 		/*
572 		 * If clock is good we send a NOMINAL message so that
573 		 * any previous BAD messages are nullified
574 		 */
575 		pp->lastref = pp->lastrec;
576 		refclock_receive(peer);
577 		refclock_report(peer, CEVNT_NOMINAL);
578 
579 		/*
580 		 * We have succedded in answering the poll.
581 		 * Turn off the flag and return
582 		 */
583 		up->polled = 0;
584 
585 		return;
586 	}
587 
588 	/*
589 	 * No match to known timecodes, report failure and return
590 	 */
591 	refclock_report(peer, CEVNT_BADREPLY);
592 	return;
593 }
594 
595 
596 /*
597  * true_send - time to send the clock a signal to cough up a time sample
598  */
599 static void
600 true_send(
601 	struct peer *peer,
602 	const char *cmd
603 	)
604 {
605 	struct refclockproc *pp;
606 
607 	pp = peer->procptr;
608 	if (!(pp->sloppyclockflag & CLK_FLAG1)) {
609 		int len = strlen(cmd);
610 
611 		true_debug(peer, "Send '%s'\n", cmd);
612 		if (write(pp->io.fd, cmd, (unsigned)len) != len)
613 			refclock_report(peer, CEVNT_FAULT);
614 		else
615 			pp->polls++;
616 	}
617 }
618 
619 
620 /*
621  * state machine for initializing and controlling a clock
622  */
623 static void
624 true_doevent(
625 	struct peer *peer,
626 	enum true_event event
627 	)
628 {
629 	struct true_unit *up;
630 	struct refclockproc *pp;
631 
632 	pp = peer->procptr;
633 	up = pp->unitptr;
634 	if (event != e_TS) {
635 		NLOG(NLOG_CLOCKSTATUS) {
636 			msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
637 				typeStr(up->type),
638 				stateStr(up->state),
639 				eventStr(event));
640 		}
641 	}
642 	true_debug(peer, "clock %s, state %s, event %s\n",
643 		   typeStr(up->type), stateStr(up->state), eventStr(event));
644 	switch (up->type) {
645 	case t_goes:
646 		switch (event) {
647 		case e_Init:	/* FALLTHROUGH */
648 		case e_Satellite:
649 			/*
650 			 * Switch back to on-second time codes and return.
651 			 */
652 			true_send(peer, "C");
653 			up->state = s_Start;
654 			break;
655 		case e_Poll:
656 			/*
657 			 * After each poll, check the station (satellite).
658 			 */
659 			true_send(peer, "P");
660 			/* No state change needed. */
661 			break;
662 		default:
663 			break;
664 		}
665 		/* FALLTHROUGH */
666 	case t_omega:
667 		switch (event) {
668 		case e_Init:
669 			true_send(peer, "C");
670 			up->state = s_Start;
671 			break;
672 		case e_TS:
673 			if (up->state != s_Start && up->state != s_Auto) {
674 				true_send(peer, "\03\r");
675 				break;
676 			}
677 			up->state = s_Auto;
678 			break;
679 		default:
680 			break;
681 		}
682 		break;
683 	case t_tm:
684 		switch (event) {
685 		case e_Init:
686 			true_send(peer, "F18\r");
687 			up->state = s_Init;
688 			break;
689 		case e_F18:
690 			true_send(peer, "F50\r");
691 			up->state = s_F18;
692 			break;
693 		case e_F50:
694 			true_send(peer, "F51\r");
695 			up->state = s_F50;
696 			break;
697 		case e_F51:
698 			true_send(peer, "F08\r");
699 			up->state = s_Start;
700 			break;
701 		case e_TS:
702 			if (up->state != s_Start && up->state != s_Auto) {
703 				true_send(peer, "\03\r");
704 				break;
705 			}
706 			up->state = s_Auto;
707 			break;
708 		default:
709 			break;
710 		}
711 		break;
712 	case t_tcu:
713 		switch (event) {
714 		case e_Init:
715 			true_send(peer, "MD3\r");	/* GPS Synch'd Gen. */
716 			true_send(peer, "TSU\r");	/* UTC, not GPS. */
717 			true_send(peer, "AU\r");	/* Auto Timestamps. */
718 			up->state = s_Start;
719 			break;
720 		case e_TS:
721 			if (up->state != s_Start && up->state != s_Auto) {
722 				true_send(peer, "\03\r");
723 				break;
724 			}
725 			up->state = s_Auto;
726 			break;
727 		default:
728 			break;
729 		}
730 		break;
731 	case t_unknown:
732 		switch (up->state) {
733 		case s_Base:
734 			if (event != e_Init)
735 			    abort();
736 			true_send(peer, "P\r");
737 			up->state = s_InqGOES;
738 			break;
739 		case s_InqGOES:
740 			switch (event) {
741 			case e_Satellite:
742 				up->type = t_goes;
743 				true_doevent(peer, e_Init);
744 				break;
745 			case e_Init:	/*FALLTHROUGH*/
746 			case e_Huh:	/*FALLTHROUGH*/
747 			case e_TS:
748 				up->state = s_InqOmega;
749 				true_send(peer, "C\r");
750 				break;
751 			default:
752 				abort();
753 			}
754 			break;
755 		case s_InqOmega:
756 			switch (event) {
757 			case e_TS:
758 				up->type = t_omega;
759 				up->state = s_Auto;	/* Inq side-effect. */
760 				break;
761 			case e_Init:	/*FALLTHROUGH*/
762 			case e_Huh:
763 				up->state = s_InqTM;
764 				true_send(peer, "F18\r");
765 				break;
766 			default:
767 				abort();
768 			}
769 			break;
770 		case s_InqTM:
771 			switch (event) {
772 			case e_F18:
773 				up->type = t_tm;
774 				true_doevent(peer, e_Init);
775 				break;
776 			case e_Init:	/*FALLTHROUGH*/
777 			case e_Huh:
778 				true_send(peer, "PO\r");
779 				up->state = s_InqTCU;
780 				break;
781 			default:
782 				abort();
783 			}
784 			break;
785 		case s_InqTCU:
786 			switch (event) {
787 			case e_Location:
788 				up->type = t_tcu;
789 				true_doevent(peer, e_Init);
790 				break;
791 			case e_Init:	/*FALLTHROUGH*/
792 			case e_Huh:
793 				up->state = s_Base;
794 				sleep(1);	/* XXX */
795 				break;
796 			default:
797 				abort();
798 			}
799 			break;
800 			/*
801 			 * An expedient hack to prevent lint complaints,
802 			 * these don't actually need to be used here...
803 			 */
804 		case s_Init:
805 		case s_F18:
806 		case s_F50:
807 		case s_Start:
808 		case s_Auto:
809 		case s_Max:
810 			msyslog(LOG_INFO, "TRUE: state %s is unexpected!",
811 				stateStr(up->state));
812 		}
813 		break;
814 	default:
815 		abort();
816 		/* NOTREACHED */
817 	}
818 
819 #ifdef CLOCK_PPS720
820 	if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) {
821 		/* Make counter trigger on gate0, count down from 65535. */
822 		pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535);
823 		/*
824 		 * (These constants are OK since
825 		 * they represent hardware maximums.)
826 		 */
827 		NLOG(NLOG_CLOCKINFO) {
828 			msyslog(LOG_NOTICE, "PCL-720 initialized");
829 		}
830 		up->pcl720init++;
831 	}
832 #endif
833 
834 
835 }
836 
837 /*
838  * true_poll - called by the transmit procedure
839  */
840 static void
841 true_poll(
842 	int unit,
843 	struct peer *peer
844 	)
845 {
846 	struct true_unit *up;
847 	struct refclockproc *pp;
848 
849 	/*
850 	 * You don't need to poll this clock.  It puts out timecodes
851 	 * once per second.  If asked for a timestamp, take note.
852 	 * The next time a timecode comes in, it will be fed back.
853 	 */
854 	pp = peer->procptr;
855 	up = pp->unitptr;
856 	if (up->pollcnt > 0) {
857 		up->pollcnt--;
858 	} else {
859 		true_doevent(peer, e_Init);
860 		refclock_report(peer, CEVNT_TIMEOUT);
861 	}
862 
863 	/*
864 	 * polled every 64 seconds. Ask true_receive to hand in a
865 	 * timestamp.
866 	 */
867 	up->polled = 1;
868 	pp->polls++;
869 }
870 
871 #ifdef CLOCK_PPS720
872 /*
873  * true_sample720 - sample the PCL-720
874  */
875 static u_long
876 true_sample720(void)
877 {
878 	unsigned long f;
879 
880 	/* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3.
881 	 * If it is not being held low now, we did not get called
882 	 * within 65535us.
883 	 */
884 	if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) {
885 		NLOG(NLOG_CLOCKINFO) {
886 			msyslog(LOG_NOTICE, "PCL-720 out of synch");
887 		}
888 		return (0);
889 	}
890 	f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR));
891 #ifdef PPS720_DEBUG
892 	msyslog(LOG_DEBUG, "PCL-720: %luus", f);
893 #endif
894 	return (f);
895 }
896 #endif
897 
898 #else
899 int refclock_true_bs;
900 #endif /* REFCLOCK */
901