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