1/*	$NetBSD$	*/
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
27extern 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 */
143enum true_event	{e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
144		 e_Poll, e_Location, e_TS, e_Max};
145const 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
149enum 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};
151const 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
155enum true_type	{t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
156const 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 */
162struct 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 */
178static	int	true_start	(int, struct peer *);
179static	void	true_shutdown	(int, struct peer *);
180static	void	true_receive	(struct recvbuf *);
181static	void	true_poll	(int, struct peer *);
182static	void	true_send	(struct peer *, const char *);
183static	void	true_doevent	(struct peer *, enum true_event);
184
185#ifdef CLOCK_PPS720
186static	u_long	true_sample720	(void);
187#endif
188
189/*
190 * Transfer vector
191 */
192struct	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
206static void
207true_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 */
253static int
254true_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 */
317static void
318true_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 */
336static void
337true_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 */
592static void
593true_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 */
616static void
617true_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 */
832static void
833true_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 */
867static u_long
868true_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
891int refclock_true_bs;
892#endif /* REFCLOCK */
893