File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_arbiter.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, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
    3:  *	Controlled Clock
    4:  */
    5: 
    6: #ifdef HAVE_CONFIG_H
    7: #include <config.h>
    8: #endif
    9: 
   10: #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
   11: 
   12: #include "ntpd.h"
   13: #include "ntp_io.h"
   14: #include "ntp_refclock.h"
   15: #include "ntp_stdlib.h"
   16: 
   17: #include <stdio.h>
   18: #include <ctype.h>
   19: 
   20: #ifdef SYS_WINNT
   21: extern int async_write(int, const void *, unsigned int);
   22: #undef write
   23: #define write(fd, data, octets)	async_write(fd, data, octets)
   24: #endif
   25: 
   26: /*
   27:  * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
   28:  * The claimed accuracy of this clock is 100 ns relative to the PPS
   29:  * output when receiving four or more satellites.
   30:  *
   31:  * The receiver should be configured before starting the NTP daemon, in
   32:  * order to establish reliable position and operating conditions. It
   33:  * does not initiate surveying or hold mode. For use with NTP, the
   34:  * daylight savings time feature should be disables (D0 command) and the
   35:  * broadcast mode set to operate in UTC (BU command).
   36:  *
   37:  * The timecode format supported by this driver is selected by the poll
   38:  * sequence "B5", which initiates a line in the following format to be
   39:  * repeated once per second until turned off by the "B0" poll sequence.
   40:  *
   41:  * Format B5 (24 ASCII printing characters):
   42:  *
   43:  * <cr><lf>i yy ddd hh:mm:ss.000bbb  
   44:  *
   45:  *	on-time = <cr>
   46:  *	i = synchronization flag (' ' = locked, '?' = unlocked)
   47:  *	yy = year of century
   48:  *	ddd = day of year
   49:  *	hh:mm:ss = hours, minutes, seconds
   50:  *	.000 = fraction of second (not used)
   51:  *	bbb = tailing spaces for fill
   52:  *
   53:  * The alarm condition is indicated by a '?' at i, which indicates the
   54:  * receiver is not synchronized. In normal operation, a line consisting
   55:  * of the timecode followed by the time quality character (TQ) followed
   56:  * by the receiver status string (SR) is written to the clockstats file.
   57:  * The time quality character is encoded in IEEE P1344 standard:
   58:  *
   59:  * Format TQ (IEEE P1344 estimated worst-case time quality)
   60:  *
   61:  *	0	clock locked, maximum accuracy
   62:  *	F	clock failure, time not reliable
   63:  *	4	clock unlocked, accuracy < 1 us
   64:  *	5	clock unlocked, accuracy < 10 us
   65:  *	6	clock unlocked, accuracy < 100 us
   66:  *	7	clock unlocked, accuracy < 1 ms
   67:  *	8	clock unlocked, accuracy < 10 ms
   68:  *	9	clock unlocked, accuracy < 100 ms
   69:  *	A	clock unlocked, accuracy < 1 s
   70:  *	B	clock unlocked, accuracy < 10 s
   71:  *
   72:  * The status string is encoded as follows:
   73:  *
   74:  * Format SR (25 ASCII printing characters)
   75:  *
   76:  *	V=vv S=ss T=t P=pdop E=ee
   77:  *
   78:  *	vv = satellites visible
   79:  *	ss = relative signal strength
   80:  *	t = satellites tracked
   81:  *	pdop = position dilution of precision (meters)
   82:  *	ee = hardware errors
   83:  *
   84:  * If flag4 is set, an additional line consisting of the receiver
   85:  * latitude (LA), longitude (LO), elevation (LH) (meters), and data
   86:  * buffer (DB) is written to this file. If channel B is enabled for
   87:  * deviation mode and connected to a 1-PPS signal, the last two numbers
   88:  * on the line are the deviation and standard deviation averaged over
   89:  * the last 15 seconds.
   90:  *
   91:  * PPS calibration fudge time1 .001240
   92:  */
   93: 
   94: /*
   95:  * Interface definitions
   96:  */
   97: #define	DEVICE		"/dev/gps%d" /* device name and unit */
   98: #define	SPEED232	B9600	/* uart speed (9600 baud) */
   99: #define	PRECISION	(-20)	/* precision assumed (about 1 us) */
  100: #define	REFID		"GPS "	/* reference ID */
  101: #define	DESCRIPTION	"Arbiter 1088A/B GPS Receiver" /* WRU */
  102: #define	LENARB		24	/* format B5 timecode length */
  103: #define MAXSTA		40	/* max length of status string */
  104: #define MAXPOS		80	/* max length of position string */
  105: 
  106: #ifdef PRE_NTP420
  107: #define MODE ttlmax
  108: #else
  109: #define MODE ttl
  110: #endif
  111: 
  112: #define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
  113: #define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
  114: 
  115: /*
  116:  * ARB unit control structure
  117:  */
  118: struct arbunit {
  119: 	l_fp	laststamp;	/* last receive timestamp */
  120: 	int	tcswitch;	/* timecode switch/counter */
  121: 	char	qualchar;	/* IEEE P1344 quality (TQ command) */
  122: 	char	status[MAXSTA];	/* receiver status (SR command) */
  123: 	char	latlon[MAXPOS];	/* receiver position (lat/lon/alt) */
  124: };
  125: 
  126: /*
  127:  * Function prototypes
  128:  */
  129: static	int	arb_start	(int, struct peer *);
  130: static	void	arb_shutdown	(int, struct peer *);
  131: static	void	arb_receive	(struct recvbuf *);
  132: static	void	arb_poll	(int, struct peer *);
  133: 
  134: /*
  135:  * Transfer vector
  136:  */
  137: struct	refclock refclock_arbiter = {
  138: 	arb_start,		/* start up driver */
  139: 	arb_shutdown,		/* shut down driver */
  140: 	arb_poll,		/* transmit poll message */
  141: 	noentry,		/* not used (old arb_control) */
  142: 	noentry,		/* initialize driver (not used) */
  143: 	noentry,		/* not used (old arb_buginfo) */
  144: 	NOFLAGS			/* not used */
  145: };
  146: 
  147: 
  148: /*
  149:  * arb_start - open the devices and initialize data for processing
  150:  */
  151: static int
  152: arb_start(
  153: 	int unit,
  154: 	struct peer *peer
  155: 	)
  156: {
  157: 	register struct arbunit *up;
  158: 	struct refclockproc *pp;
  159: 	int fd;
  160: 	char device[20];
  161: 
  162: 	/*
  163: 	 * Open serial port. Use CLK line discipline, if available.
  164: 	 */
  165: 	snprintf(device, sizeof(device), DEVICE, unit);
  166: 	if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
  167: 		return (0);
  168: 
  169: 	/*
  170: 	 * Allocate and initialize unit structure
  171: 	 */
  172: 	up = emalloc(sizeof(*up));
  173: 	memset(up, 0, sizeof(*up));
  174: 	pp = peer->procptr;
  175: 	pp->io.clock_recv = arb_receive;
  176: 	pp->io.srcclock = (caddr_t)peer;
  177: 	pp->io.datalen = 0;
  178: 	pp->io.fd = fd;
  179: 	if (!io_addclock(&pp->io)) {
  180: 		close(fd);
  181: 		pp->io.fd = -1;
  182: 		free(up);
  183: 		return (0);
  184: 	}
  185: 	pp->unitptr = (caddr_t)up;
  186: 
  187: 	/*
  188: 	 * Initialize miscellaneous variables
  189: 	 */
  190: 	peer->precision = PRECISION;
  191: 	pp->clockdesc = DESCRIPTION;
  192: 	memcpy((char *)&pp->refid, REFID, 4);
  193: 	if (peer->MODE > 1) {
  194: 		msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
  195: 		close(fd);
  196: 		pp->io.fd = -1;
  197: 		free(up);
  198: 		return (0);
  199: 	}
  200: #ifdef DEBUG
  201: 	if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
  202: #endif
  203: 	write(pp->io.fd, COMMAND_HALT_BCAST, 2);
  204: 	return (1);
  205: }
  206: 
  207: 
  208: /*
  209:  * arb_shutdown - shut down the clock
  210:  */
  211: static void
  212: arb_shutdown(
  213: 	int unit,
  214: 	struct peer *peer
  215: 	)
  216: {
  217: 	register struct arbunit *up;
  218: 	struct refclockproc *pp;
  219: 
  220: 	pp = peer->procptr;
  221: 	up = (struct arbunit *)pp->unitptr;
  222: 	if (-1 != pp->io.fd)
  223: 		io_closeclock(&pp->io);
  224: 	if (NULL != up)
  225: 		free(up);
  226: }
  227: 
  228: 
  229: /*
  230:  * arb_receive - receive data from the serial interface
  231:  */
  232: static void
  233: arb_receive(
  234: 	struct recvbuf *rbufp
  235: 	)
  236: {
  237: 	register struct arbunit *up;
  238: 	struct refclockproc *pp;
  239: 	struct peer *peer;
  240: 	l_fp trtmp;
  241: 	int temp;
  242: 	u_char	syncchar;		/* synch indicator */
  243: 	char	tbuf[BMAX];		/* temp buffer */
  244: 
  245: 	/*
  246: 	 * Initialize pointers and read the timecode and timestamp
  247: 	 */
  248: 	peer = (struct peer *)rbufp->recv_srcclock;
  249: 	pp = peer->procptr;
  250: 	up = (struct arbunit *)pp->unitptr;
  251: 	temp = refclock_gtlin(rbufp, tbuf, BMAX, &trtmp);
  252: 
  253: 	/*
  254: 	 * Note we get a buffer and timestamp for both a <cr> and <lf>,
  255: 	 * but only the <cr> timestamp is retained. The program first
  256: 	 * sends a TQ and expects the echo followed by the time quality
  257: 	 * character. It then sends a B5 starting the timecode broadcast
  258: 	 * and expects the echo followed some time later by the on-time
  259: 	 * character <cr> and then the <lf> beginning the timecode
  260: 	 * itself. Finally, at the <cr> beginning the next timecode at
  261: 	 * the next second, the program sends a B0 shutting down the
  262: 	 * timecode broadcast.
  263: 	 *
  264: 	 * If flag4 is set, the program snatches the latitude, longitude
  265: 	 * and elevation and writes it to the clockstats file.
  266: 	 */
  267: 	if (temp == 0)
  268: 		return;
  269: 
  270: 	pp->lastrec = up->laststamp;
  271: 	up->laststamp = trtmp;
  272: 	if (temp < 3)
  273: 		return;
  274: 
  275: 	if (up->tcswitch == 0) {
  276: 
  277: 		/*
  278: 		 * Collect statistics. If nothing is recogized, just
  279: 		 * ignore; sometimes the clock doesn't stop spewing
  280: 		 * timecodes for awhile after the B0 command.
  281: 		 *
  282: 		 * If flag4 is not set, send TQ, SR, B5. If flag4 is
  283: 		 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
  284: 		 * median filter is full, send B0.
  285: 		 */
  286: 		if (!strncmp(tbuf, "TQ", 2)) {
  287: 			up->qualchar = tbuf[2];
  288: 			write(pp->io.fd, "SR", 2);
  289: 			return;
  290: 
  291: 		} else if (!strncmp(tbuf, "SR", 2)) {
  292: 			strcpy(up->status, tbuf + 2);
  293: 			if (pp->sloppyclockflag & CLK_FLAG4)
  294: 				write(pp->io.fd, "LA", 2);
  295: 			else
  296: 				write(pp->io.fd, COMMAND_START_BCAST, 2);
  297: 			return;
  298: 
  299: 		} else if (!strncmp(tbuf, "LA", 2)) {
  300: 			strcpy(up->latlon, tbuf + 2);
  301: 			write(pp->io.fd, "LO", 2);
  302: 			return;
  303: 
  304: 		} else if (!strncmp(tbuf, "LO", 2)) {
  305: 			strcat(up->latlon, " ");
  306: 			strcat(up->latlon, tbuf + 2);
  307: 			write(pp->io.fd, "LH", 2);
  308: 			return;
  309: 
  310: 		} else if (!strncmp(tbuf, "LH", 2)) {
  311: 			strcat(up->latlon, " ");
  312: 			strcat(up->latlon, tbuf + 2);
  313: 			write(pp->io.fd, "DB", 2);
  314: 			return;
  315: 
  316: 		} else if (!strncmp(tbuf, "DB", 2)) {
  317: 			strcat(up->latlon, " ");
  318: 			strcat(up->latlon, tbuf + 2);
  319: 			record_clock_stats(&peer->srcadr, up->latlon);
  320: #ifdef DEBUG
  321: 			if (debug)
  322: 				printf("arbiter: %s\n", up->latlon);
  323: #endif
  324: 			write(pp->io.fd, COMMAND_START_BCAST, 2);
  325: 		}
  326: 	}
  327: 
  328: 	/*
  329: 	 * We get down to business, check the timecode format and decode
  330: 	 * its contents. If the timecode has valid length, but not in
  331: 	 * proper format, we declare bad format and exit. If the
  332: 	 * timecode has invalid length, which sometimes occurs when the
  333: 	 * B0 amputates the broadcast, we just quietly steal away. Note
  334: 	 * that the time quality character and receiver status string is
  335: 	 * tacked on the end for clockstats display. 
  336: 	 */
  337: 	up->tcswitch++;
  338: 	if (up->tcswitch <= 1 || temp < LENARB)
  339: 		return;
  340: 
  341: 	/*
  342: 	 * Timecode format B5: "i yy ddd hh:mm:ss.000   "
  343: 	 */
  344: 	strncpy(pp->a_lastcode, tbuf, BMAX);
  345: 	pp->a_lastcode[LENARB - 2] = up->qualchar;
  346: 	strcat(pp->a_lastcode, up->status);
  347: 	pp->lencode = strlen(pp->a_lastcode);
  348: 	syncchar = ' ';
  349: 	if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
  350: 	    &syncchar, &pp->year, &pp->day, &pp->hour,
  351: 	    &pp->minute, &pp->second) != 6) {
  352: 		refclock_report(peer, CEVNT_BADREPLY);
  353: 		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
  354: 		return;
  355: 	}
  356: 
  357: 	/*
  358: 	 * We decode the clock dispersion from the time quality
  359: 	 * character.
  360: 	 */
  361: 	switch (up->qualchar) {
  362: 
  363: 	    case '0':		/* locked, max accuracy */
  364: 		pp->disp = 1e-7;
  365: 		pp->lastref = pp->lastrec;
  366: 		break;
  367: 
  368: 	    case '4':		/* unlock accuracy < 1 us */
  369: 		pp->disp = 1e-6;
  370: 		break;
  371: 
  372: 	    case '5':		/* unlock accuracy < 10 us */
  373: 		pp->disp = 1e-5;
  374: 		break;
  375: 
  376: 	    case '6':		/* unlock accuracy < 100 us */
  377: 		pp->disp = 1e-4;
  378: 		break;
  379: 
  380: 	    case '7':		/* unlock accuracy < 1 ms */
  381: 		pp->disp = .001;
  382: 		break;
  383: 
  384: 	    case '8':		/* unlock accuracy < 10 ms */
  385: 		pp->disp = .01;
  386: 		break;
  387: 
  388: 	    case '9':		/* unlock accuracy < 100 ms */
  389: 		pp->disp = .1;
  390: 		break;
  391: 
  392: 	    case 'A':		/* unlock accuracy < 1 s */
  393: 		pp->disp = 1;
  394: 		break;
  395: 
  396: 	    case 'B':		/* unlock accuracy < 10 s */
  397: 		pp->disp = 10;
  398: 		break;
  399: 
  400: 	    case 'F':		/* clock failure */
  401: 		pp->disp = MAXDISPERSE;
  402: 		refclock_report(peer, CEVNT_FAULT);
  403: 		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
  404: 		return;
  405: 
  406: 	    default:
  407: 		pp->disp = MAXDISPERSE;
  408: 		refclock_report(peer, CEVNT_BADREPLY);
  409: 		write(pp->io.fd, COMMAND_HALT_BCAST, 2);
  410: 		return;
  411: 	}
  412: 	if (syncchar != ' ')
  413: 		pp->leap = LEAP_NOTINSYNC;
  414: 	else
  415: 		pp->leap = LEAP_NOWARNING;
  416: 
  417: 	/*
  418: 	 * Process the new sample in the median filter and determine the
  419: 	 * timecode timestamp.
  420: 	 */
  421: 	if (!refclock_process(pp))
  422: 		refclock_report(peer, CEVNT_BADTIME);
  423: 	else if (peer->disp > MAXDISTANCE)
  424: 		refclock_receive(peer);
  425: 
  426: 	/* if (up->tcswitch >= MAXSTAGE) { */
  427: 	write(pp->io.fd, COMMAND_HALT_BCAST, 2);
  428: 	/* } */
  429: }
  430: 
  431: 
  432: /*
  433:  * arb_poll - called by the transmit procedure
  434:  */
  435: static void
  436: arb_poll(
  437: 	int unit,
  438: 	struct peer *peer
  439: 	)
  440: {
  441: 	register struct arbunit *up;
  442: 	struct refclockproc *pp;
  443: 
  444: 	/*
  445: 	 * Time to poll the clock. The Arbiter clock responds to a "B5"
  446: 	 * by returning a timecode in the format specified above.
  447: 	 * Transmission occurs once per second, unless turned off by a
  448: 	 * "B0". Note there is no checking on state, since this may not
  449: 	 * be the only customer reading the clock. Only one customer
  450: 	 * need poll the clock; all others just listen in.
  451: 	 */
  452: 	pp = peer->procptr;
  453: 	up = (struct arbunit *)pp->unitptr;
  454: 	pp->polls++;
  455: 	up->tcswitch = 0;
  456: 	if (write(pp->io.fd, "TQ", 2) != 2)
  457: 		refclock_report(peer, CEVNT_FAULT);
  458: 
  459: 	/*
  460: 	 * Process median filter samples. If none received, declare a
  461: 	 * timeout and keep going.
  462: 	 */
  463: 	if (pp->coderecv == pp->codeproc) {
  464: 		refclock_report(peer, CEVNT_TIMEOUT);
  465: 		return;
  466: 	}
  467: 	refclock_receive(peer);
  468: 	record_clock_stats(&peer->srcadr, pp->a_lastcode);
  469: #ifdef DEBUG
  470: 	if (debug)
  471: 		printf("arbiter: timecode %d %s\n",
  472: 		   pp->lencode, pp->a_lastcode);
  473: #endif
  474: }
  475: 
  476: #else
  477: int refclock_arbiter_bs;
  478: #endif /* REFCLOCK */

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