File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_true.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>