Annotation of embedaddon/ntp/ntpd/refclock_atom.c, revision 1.1

1.1     ! misho       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>