File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / refclock_atom.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:37 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_atom - clock driver for 1-pps signals
    3:  */
    4: #ifdef HAVE_CONFIG_H
    5: #include <config.h>
    6: #endif
    7: 
    8: #include <stdio.h>
    9: #include <ctype.h>
   10: 
   11: #include "ntpd.h"
   12: #include "ntp_io.h"
   13: #include "ntp_unixtime.h"
   14: #include "ntp_refclock.h"
   15: #include "ntp_stdlib.h"
   16: 
   17: /*
   18:  * This driver requires the PPSAPI interface (RFC 2783)
   19:  */
   20: #if defined(REFCLOCK) && defined(CLOCK_ATOM) && defined(HAVE_PPSAPI)
   21: #include "ppsapi_timepps.h"
   22: #include "refclock_atom.h"
   23: 
   24: /*
   25:  * This driver furnishes an interface for pulse-per-second (PPS) signals
   26:  * produced by a cesium clock, timing receiver or related equipment. It
   27:  * can be used to remove accumulated jitter over a congested link and
   28:  * retime a server before redistributing the time to clients. It can 
   29:  *also be used as a holdover should all other synchronization sources
   30:  * beconme unreachable.
   31:  *
   32:  * Before this driver becomes active, the local clock must be set to
   33:  * within +-0.4 s by another means, such as a radio clock or NTP
   34:  * itself. There are two ways to connect the PPS signal, normally at TTL
   35:  * levels, to the computer. One is to shift to EIA levels and connect to
   36:  * pin 8 (DCD) of a serial port. This requires a level converter and
   37:  * may require a one-shot flipflop to lengthen the pulse. The other is
   38:  * to connect the PPS signal directly to pin 10 (ACK) of a PC paralell
   39:  * port. These methods are architecture dependent.
   40:  *
   41:  * This driver requires the Pulse-per-Second API for Unix-like Operating
   42:  * Systems, Version 1.0, RFC-2783 (PPSAPI). Implementations are
   43:  * available for FreeBSD, Linux, SunOS, Solaris and Tru64. However, at
   44:  * present only the Tru64 implementation provides the full generality of
   45:  * the API with multiple PPS drivers and multiple handles per driver. If
   46:  * the PPSAPI is normally implemented in the /usr/include/sys/timepps.h
   47:  * header file and kernel support specific to each operating system.
   48:  *
   49:  * This driver normally uses the PLL/FLL clock discipline implemented in
   50:  * the ntpd code. Ordinarily, this is the most accurate means, as the
   51:  * median filter in the driver interface is much larger than in the
   52:  * kernel. However, if the systemic clock frequency error is large (tens
   53:  * to hundreds of PPM), it's better to used the kernel support, if
   54:  * available.
   55:  *
   56:  * This deriver is subject to the mitigation rules described in the
   57:  * "mitigation rulse and the prefer peer" page. However, there is an
   58:  * important difference. If this driver becomes the PPS driver according
   59:  * to these rules, it is acrive only if (a) a prefer peer other than
   60:  * this driver is among the survivors or (b) there are no survivors and
   61:  * the minsane option of the tos command is zero. This is intended to
   62:  * support space missions where updates from other spacecraft are
   63:  * infrequent, but a reliable PPS signal, such as from an Ultra Stable
   64:  * Oscillator (USO) is available.
   65:  *
   66:  * Fudge Factors
   67:  *
   68:  * The PPS timestamp is captured on the rising (assert) edge if flag2 is
   69:  * dim (default) and on the falling (clear) edge if lit. If flag3 is dim
   70:  * (default), the kernel PPS support is disabled; if lit it is enabled.
   71:  * If flag4 is lit, each timesampt is copied to the clockstats file for
   72:  * later analysis. This can be useful when constructing Allan deviation
   73:  * plots. The time1 parameter can be used to compensate for
   74:  * miscellaneous device driver and OS delays.
   75:  */
   76: /*
   77:  * Interface definitions
   78:  */
   79: #define DEVICE		"/dev/pps%d" /* device name and unit */
   80: #define	PRECISION	(-20)	/* precision assumed (about 1 us) */
   81: #define	REFID		"PPS\0"	/* reference ID */
   82: #define	DESCRIPTION	"PPS Clock Discipline" /* WRU */
   83: 
   84: /*
   85:  * PPS unit control structure
   86:  */
   87: struct ppsunit {
   88: 	struct refclock_atom atom; /* atom structure pointer */
   89: 	int	fddev;		/* file descriptor */
   90: };
   91: 
   92: /*
   93:  * Function prototypes
   94:  */
   95: static	int	atom_start	(int, struct peer *);
   96: static	void	atom_shutdown	(int, struct peer *);
   97: static	void	atom_poll	(int, struct peer *);
   98: static	void	atom_timer	(int, struct peer *);
   99: 
  100: /*
  101:  * Transfer vector
  102:  */
  103: struct	refclock refclock_atom = {
  104: 	atom_start,		/* start up driver */
  105: 	atom_shutdown,		/* shut down driver */
  106: 	atom_poll,		/* transmit poll message */
  107: 	noentry,		/* control (not used) */
  108: 	noentry,		/* initialize driver (not used) */
  109: 	noentry,		/* buginfo (not used) */
  110: 	atom_timer,		/* called once per second */
  111: };
  112: 
  113: 
  114: /*
  115:  * atom_start - initialize data for processing
  116:  */
  117: static int
  118: atom_start(
  119: 	int unit,		/* unit number (not used) */
  120: 	struct peer *peer	/* peer structure pointer */
  121: 	)
  122: {
  123: 	struct refclockproc *pp;
  124: 	struct ppsunit *up;
  125: 	char	device[80];
  126: 
  127: 	/*
  128: 	 * Allocate and initialize unit structure
  129: 	 */
  130: 	pp = peer->procptr;
  131: 	peer->precision = PRECISION;
  132: 	pp->clockdesc = DESCRIPTION;
  133: 	pp->stratum = STRATUM_UNSPEC;
  134: 	memcpy((char *)&pp->refid, REFID, 4);
  135: 	up = emalloc(sizeof(struct ppsunit));
  136: 	memset(up, 0, sizeof(struct ppsunit));
  137: 	pp->unitptr = (caddr_t)up;
  138: 
  139: 	/*
  140: 	 * Open PPS device. This can be any serial or parallel port and
  141: 	 * not necessarily the port used for the associated radio.
  142: 	 */
  143: 	snprintf(device, sizeof(device), DEVICE, unit);
  144: 	up->fddev = tty_open(device, O_RDWR, 0777);
  145: 	if (up->fddev <= 0) {
  146: 		msyslog(LOG_ERR,
  147: 			"refclock_atom: %s: %m", device);
  148: 		return (0);
  149: 	}
  150: 
  151: 	/*
  152: 	 * Light up the PPSAPI interface.
  153: 	 */
  154: 	return (refclock_ppsapi(up->fddev, &up->atom));
  155: }
  156: 
  157: 
  158: /*
  159:  * atom_shutdown - shut down the clock
  160:  */
  161: static void
  162: atom_shutdown(
  163: 	int unit,		/* unit number (not used) */
  164: 	struct peer *peer	/* peer structure pointer */
  165: 	)
  166: {
  167: 	struct refclockproc *pp;
  168: 	struct ppsunit *up;
  169: 
  170: 	pp = peer->procptr;
  171: 	up = (struct ppsunit *)pp->unitptr;
  172: 	if (up->fddev > 0)
  173: 		close(up->fddev);
  174: 	free(up);
  175: }
  176: 
  177: /*
  178:  * atom_timer - called once per second
  179:  */
  180: void
  181: atom_timer(
  182: 	int	unit,		/* unit pointer (not used) */
  183: 	struct peer *peer	/* peer structure pointer */
  184: 	)
  185: {
  186: 	struct ppsunit *up;
  187: 	struct refclockproc *pp;
  188: 	char	tbuf[80];
  189: 
  190: 	pp = peer->procptr;
  191: 	up = (struct ppsunit *)pp->unitptr;
  192: 	if (refclock_pps(peer, &up->atom, pp->sloppyclockflag) <= 0)
  193: 		return;
  194: 
  195: 	peer->flags |= FLAG_PPS;
  196: 
  197: 	/*
  198: 	 * If flag4 is lit, record each second offset to clockstats.
  199: 	 * That's so we can make awesome Allan deviation plots.
  200: 	 */
  201: 	if (pp->sloppyclockflag & CLK_FLAG4) {
  202: 		snprintf(tbuf, sizeof(tbuf), "%.9f",
  203: 			 pp->filter[pp->coderecv]);
  204: 		record_clock_stats(&peer->srcadr, tbuf);
  205: 	}
  206: }
  207: 
  208: 
  209: /*
  210:  * atom_poll - called by the transmit procedure
  211:  */
  212: static void
  213: atom_poll(
  214: 	int unit,		/* unit number (not used) */
  215: 	struct peer *peer	/* peer structure pointer */
  216: 	)
  217: {
  218: 	struct refclockproc *pp;
  219: 
  220: 	/*
  221: 	 * Don't wiggle the clock until some other driver has numbered
  222: 	 * the seconds.
  223: 	 */
  224: 	if (sys_leap == LEAP_NOTINSYNC)
  225: 		return;
  226: 
  227: 	pp = peer->procptr;
  228: 	pp->polls++;
  229: 	if (pp->codeproc == pp->coderecv) {
  230: 		peer->flags &= ~FLAG_PPS;
  231: 		refclock_report(peer, CEVNT_TIMEOUT);
  232: 		return;
  233: 	}
  234: 	pp->lastref = pp->lastrec;
  235: 	refclock_receive(peer);
  236: }
  237: #else
  238: int refclock_atom_bs;
  239: #endif /* REFCLOCK */

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