Annotation of embedaddon/ntp/ntpd/refclock_atom.c, revision 1.1.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>