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