PageRenderTime 165ms CodeModel.GetById 95ms app.highlight 61ms RepoModel.GetById 2ms app.codeStats 0ms

/contrib/ntp/ntpd/refclock_true.c

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