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

1.1     ! misho       1: /*
        !             2:  * refclock_wwvb - clock driver for Spectracom WWVB and GPS receivers
        !             3:  */
        !             4: 
        !             5: #ifdef HAVE_CONFIG_H
        !             6: #include <config.h>
        !             7: #endif
        !             8: 
        !             9: #if defined(REFCLOCK) && defined(CLOCK_SPECTRACOM)
        !            10: 
        !            11: #include "ntpd.h"
        !            12: #include "ntp_io.h"
        !            13: #include "ntp_refclock.h"
        !            14: #include "ntp_calendar.h"
        !            15: #include "ntp_stdlib.h"
        !            16: 
        !            17: #include <stdio.h>
        !            18: #include <ctype.h>
        !            19: 
        !            20: #ifdef HAVE_PPSAPI
        !            21: #include "ppsapi_timepps.h"
        !            22: #include "refclock_atom.h"
        !            23: #endif /* HAVE_PPSAPI */
        !            24: 
        !            25: /*
        !            26:  * This driver supports the Spectracom Model 8170 and Netclock/2 WWVB
        !            27:  * Synchronized Clocks and the Netclock/GPS Master Clock. Both the WWVB
        !            28:  * and GPS clocks have proven reliable sources of time; however, the
        !            29:  * WWVB clocks have proven vulnerable to high ambient conductive RF
        !            30:  * interference. The claimed accuracy of the WWVB clocks is 100 us
        !            31:  * relative to the broadcast signal, while the claimed accuracy of the
        !            32:  * GPS clock is 50 ns; however, in most cases the actual accuracy is
        !            33:  * limited by the resolution of the timecode and the latencies of the
        !            34:  * serial interface and operating system.
        !            35:  *
        !            36:  * The WWVB and GPS clocks should be configured for 24-hour display,
        !            37:  * AUTO DST off, time zone 0 (UTC), data format 0 or 2 (see below) and
        !            38:  * baud rate 9600. If the clock is to used as the source for the IRIG
        !            39:  * Audio Decoder (refclock_irig.c in this distribution), it should be
        !            40:  * configured for AM IRIG output and IRIG format 1 (IRIG B with
        !            41:  * signature control). The GPS clock can be configured either to respond
        !            42:  * to a 'T' poll character or left running continuously. 
        !            43:  *
        !            44:  * There are two timecode formats used by these clocks. Format 0, which
        !            45:  * is available with both the Netclock/2 and 8170, and format 2, which
        !            46:  * is available only with the Netclock/2, specially modified 8170 and
        !            47:  * GPS.
        !            48:  *
        !            49:  * Format 0 (22 ASCII printing characters):
        !            50:  *
        !            51:  * <cr><lf>i  ddd hh:mm:ss TZ=zz<cr><lf>
        !            52:  *
        !            53:  *     on-time = first <cr>
        !            54:  *     hh:mm:ss = hours, minutes, seconds
        !            55:  *     i = synchronization flag (' ' = in synch, '?' = out of synch)
        !            56:  *
        !            57:  * The alarm condition is indicated by other than ' ' at i, which occurs
        !            58:  * during initial synchronization and when received signal is lost for
        !            59:  * about ten hours.
        !            60:  *
        !            61:  * Format 2 (24 ASCII printing characters):
        !            62:  *
        !            63:  * <cr><lf>iqyy ddd hh:mm:ss.fff ld
        !            64:  *
        !            65:  *     on-time = <cr>
        !            66:  *     i = synchronization flag (' ' = in synch, '?' = out of synch)
        !            67:  *     q = quality indicator (' ' = locked, 'A'...'D' = unlocked)
        !            68:  *     yy = year (as broadcast)
        !            69:  *     ddd = day of year
        !            70:  *     hh:mm:ss.fff = hours, minutes, seconds, milliseconds
        !            71:  *
        !            72:  * The alarm condition is indicated by other than ' ' at i, which occurs
        !            73:  * during initial synchronization and when received signal is lost for
        !            74:  * about ten hours. The unlock condition is indicated by other than ' '
        !            75:  * at q.
        !            76:  *
        !            77:  * The q is normally ' ' when the time error is less than 1 ms and a
        !            78:  * character in the set 'A'...'D' when the time error is less than 10,
        !            79:  * 100, 500 and greater than 500 ms respectively. The l is normally ' ',
        !            80:  * but is set to 'L' early in the month of an upcoming UTC leap second
        !            81:  * and reset to ' ' on the first day of the following month. The d is
        !            82:  * set to 'S' for standard time 'I' on the day preceding a switch to
        !            83:  * daylight time, 'D' for daylight time and 'O' on the day preceding a
        !            84:  * switch to standard time. The start bit of the first <cr> is
        !            85:  * synchronized to the indicated time as returned.
        !            86:  *
        !            87:  * This driver does not need to be told which format is in use - it
        !            88:  * figures out which one from the length of the message. The driver
        !            89:  * makes no attempt to correct for the intrinsic jitter of the radio
        !            90:  * itself, which is a known problem with the older radios.
        !            91:  *
        !            92:  * PPS Signal Processing
        !            93:  *
        !            94:  * When PPS signal processing is enabled, and when the system clock has
        !            95:  * been set by this or another driver and the PPS signal offset is
        !            96:  * within 0.4 s of the system clock offset, the PPS signal replaces the
        !            97:  * timecode for as long as the PPS signal is active. If for some reason
        !            98:  * the PPS signal fails for one or more poll intervals, the driver
        !            99:  * reverts to the timecode. If the timecode fails for one or more poll
        !           100:  * intervals, the PPS signal is disconnected.
        !           101:  *
        !           102:  * Fudge Factors
        !           103:  *
        !           104:  * This driver can retrieve a table of quality data maintained
        !           105:  * internally by the Netclock/2 clock. If flag4 of the fudge
        !           106:  * configuration command is set to 1, the driver will retrieve this
        !           107:  * table and write it to the clockstats file when the first timecode
        !           108:  * message of a new day is received.
        !           109:  *
        !           110:  * PPS calibration fudge time 1: format 0 .003134, format 2 .004034
        !           111:  */
        !           112: /*
        !           113:  * Interface definitions
        !           114:  */
        !           115: #define        DEVICE          "/dev/wwvb%d" /* device name and unit */
        !           116: #define        SPEED232        B9600   /* uart speed (9600 baud) */
        !           117: #define        PRECISION       (-13)   /* precision assumed (about 100 us) */
        !           118: #define        PPS_PRECISION   (-13)   /* precision assumed (about 100 us) */
        !           119: #define        REFID           "WWVB"  /* reference ID */
        !           120: #define        DESCRIPTION     "Spectracom WWVB/GPS Receiver" /* WRU */
        !           121: 
        !           122: #define        LENWWVB0        22      /* format 0 timecode length */
        !           123: #define        LENWWVB2        24      /* format 2 timecode length */
        !           124: #define LENWWVB3       29      /* format 3 timecode length */
        !           125: #define MONLIN         15      /* number of monitoring lines */
        !           126: 
        !           127: /*
        !           128:  * WWVB unit control structure
        !           129:  */
        !           130: struct wwvbunit {
        !           131: #ifdef HAVE_PPSAPI
        !           132:        struct refclock_atom atom; /* PPSAPI structure */
        !           133:        int     ppsapi_tried;   /* attempt PPSAPI once */
        !           134:        int     ppsapi_lit;     /* time_pps_create() worked */
        !           135:        int     tcount;         /* timecode sample counter */
        !           136:        int     pcount;         /* PPS sample counter */
        !           137: #endif /* HAVE_PPSAPI */
        !           138:        l_fp    laststamp;      /* last <CR> timestamp */
        !           139:        int     prev_eol_cr;    /* was last EOL <CR> (not <LF>)? */
        !           140:        u_char  lasthour;       /* last hour (for monitor) */
        !           141:        u_char  linect;         /* count ignored lines (for monitor */
        !           142: };
        !           143: 
        !           144: /*
        !           145:  * Function prototypes
        !           146:  */
        !           147: static int     wwvb_start      (int, struct peer *);
        !           148: static void    wwvb_shutdown   (int, struct peer *);
        !           149: static void    wwvb_receive    (struct recvbuf *);
        !           150: static void    wwvb_poll       (int, struct peer *);
        !           151: static void    wwvb_timer      (int, struct peer *);
        !           152: #ifdef HAVE_PPSAPI
        !           153: static void    wwvb_control    (int, const struct refclockstat *,
        !           154:                                 struct refclockstat *, struct peer *);
        !           155: #define                WWVB_CONTROL    wwvb_control
        !           156: #else
        !           157: #define                WWVB_CONTROL    noentry
        !           158: #endif /* HAVE_PPSAPI */
        !           159: 
        !           160: /*
        !           161:  * Transfer vector
        !           162:  */
        !           163: struct refclock refclock_wwvb = {
        !           164:        wwvb_start,             /* start up driver */
        !           165:        wwvb_shutdown,          /* shut down driver */
        !           166:        wwvb_poll,              /* transmit poll message */
        !           167:        WWVB_CONTROL,           /* fudge set/change notification */
        !           168:        noentry,                /* initialize driver (not used) */
        !           169:        noentry,                /* not used (old wwvb_buginfo) */
        !           170:        wwvb_timer              /* called once per second */
        !           171: };
        !           172: 
        !           173: 
        !           174: /*
        !           175:  * wwvb_start - open the devices and initialize data for processing
        !           176:  */
        !           177: static int
        !           178: wwvb_start(
        !           179:        int unit,
        !           180:        struct peer *peer
        !           181:        )
        !           182: {
        !           183:        register struct wwvbunit *up;
        !           184:        struct refclockproc *pp;
        !           185:        int fd;
        !           186:        char device[20];
        !           187: 
        !           188:        /*
        !           189:         * Open serial port. Use CLK line discipline, if available.
        !           190:         */
        !           191:        snprintf(device, sizeof(device), DEVICE, unit);
        !           192:        fd = refclock_open(device, SPEED232, LDISC_CLK);
        !           193:        if (fd <= 0)
        !           194:                return (0);
        !           195: 
        !           196:        /*
        !           197:         * Allocate and initialize unit structure
        !           198:         */
        !           199:        up = emalloc_zero(sizeof(*up));
        !           200:        pp = peer->procptr;
        !           201:        pp->io.clock_recv = wwvb_receive;
        !           202:        pp->io.srcclock = (void *)peer;
        !           203:        pp->io.datalen = 0;
        !           204:        pp->io.fd = fd;
        !           205:        if (!io_addclock(&pp->io)) {
        !           206:                close(fd);
        !           207:                pp->io.fd = -1;
        !           208:                free(up);
        !           209:                return (0);
        !           210:        }
        !           211:        pp->unitptr = up;
        !           212: 
        !           213:        /*
        !           214:         * Initialize miscellaneous variables
        !           215:         */
        !           216:        peer->precision = PRECISION;
        !           217:        pp->clockdesc = DESCRIPTION;
        !           218:        memcpy(&pp->refid, REFID, 4);
        !           219:        return (1);
        !           220: }
        !           221: 
        !           222: 
        !           223: /*
        !           224:  * wwvb_shutdown - shut down the clock
        !           225:  */
        !           226: static void
        !           227: wwvb_shutdown(
        !           228:        int unit,
        !           229:        struct peer *peer
        !           230:        )
        !           231: {
        !           232:        register struct wwvbunit *up;
        !           233:        struct refclockproc *pp;
        !           234: 
        !           235:        pp = peer->procptr;
        !           236:        up = pp->unitptr;
        !           237:        if (-1 != pp->io.fd)
        !           238:                io_closeclock(&pp->io);
        !           239:        if (NULL != up)
        !           240:                free(up);
        !           241: }
        !           242: 
        !           243: 
        !           244: /*
        !           245:  * wwvb_receive - receive data from the serial interface
        !           246:  */
        !           247: static void
        !           248: wwvb_receive(
        !           249:        struct recvbuf *rbufp
        !           250:        )
        !           251: {
        !           252:        struct wwvbunit *up;
        !           253:        struct refclockproc *pp;
        !           254:        struct peer *peer;
        !           255: 
        !           256:        l_fp    trtmp;          /* arrival timestamp */
        !           257:        int     tz;             /* time zone */
        !           258:        int     day, month;     /* ddd conversion */
        !           259:        int     temp;           /* int temp */
        !           260:        char    syncchar;       /* synchronization indicator */
        !           261:        char    qualchar;       /* quality indicator */
        !           262:        char    leapchar;       /* leap indicator */
        !           263:        char    dstchar;        /* daylight/standard indicator */
        !           264:        char    tmpchar;        /* trashbin */
        !           265: 
        !           266:        /*
        !           267:         * Initialize pointers and read the timecode and timestamp
        !           268:         */
        !           269:        peer = rbufp->recv_peer;
        !           270:        pp = peer->procptr;
        !           271:        up = pp->unitptr;
        !           272:        temp = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &trtmp);
        !           273: 
        !           274:        /*
        !           275:         * Note we get a buffer and timestamp for both a <cr> and <lf>,
        !           276:         * but only the <cr> timestamp is retained. Note: in format 0 on
        !           277:         * a Netclock/2 or upgraded 8170 the start bit is delayed 100
        !           278:         * +-50 us relative to the pps; however, on an unmodified 8170
        !           279:         * the start bit can be delayed up to 10 ms. In format 2 the
        !           280:         * reading precision is only to the millisecond. Thus, unless
        !           281:         * you have a PPS gadget and don't have to have the year, format
        !           282:         * 0 provides the lowest jitter.
        !           283:         * Save the timestamp of each <CR> in up->laststamp.  Lines with
        !           284:         * no characters occur for every <LF>, and for some <CR>s when
        !           285:         * format 0 is used. Format 0 starts and ends each cycle with a
        !           286:         * <CR><LF> pair, format 2 starts each cycle with its only pair.
        !           287:         * The preceding <CR> is the on-time character for both formats.
        !           288:         * The timestamp provided with non-empty lines corresponds to
        !           289:         * the <CR> following the timecode, which is ultimately not used
        !           290:         * with format 0 and is used for the following timecode for
        !           291:         * format 2.
        !           292:         */
        !           293:        if (temp == 0) {
        !           294:                if (up->prev_eol_cr) {
        !           295:                        DPRINTF(2, ("wwvb: <LF> @ %s\n",
        !           296:                                    prettydate(&trtmp)));
        !           297:                } else {
        !           298:                        up->laststamp = trtmp;
        !           299:                        DPRINTF(2, ("wwvb: <CR> @ %s\n", 
        !           300:                                    prettydate(&trtmp)));
        !           301:                }
        !           302:                up->prev_eol_cr = !up->prev_eol_cr;
        !           303:                return;
        !           304:        }
        !           305:        pp->lencode = temp;
        !           306:        pp->lastrec = up->laststamp;
        !           307:        up->laststamp = trtmp;
        !           308:        up->prev_eol_cr = TRUE;
        !           309:        DPRINTF(2, ("wwvb: code @ %s\n"
        !           310:                    "       using %s minus one char\n",
        !           311:                    prettydate(&trtmp), prettydate(&pp->lastrec)));
        !           312:        if (L_ISZERO(&pp->lastrec))
        !           313:                return;
        !           314: 
        !           315:        /*
        !           316:         * We get down to business, check the timecode format and decode
        !           317:         * its contents. This code uses the timecode length to determine
        !           318:         * format 0, 2 or 3. If the timecode has invalid length or is
        !           319:         * not in proper format, we declare bad format and exit.
        !           320:         */
        !           321:        syncchar = qualchar = leapchar = dstchar = ' ';
        !           322:        tz = 0;
        !           323:        switch (pp->lencode) {
        !           324: 
        !           325:        case LENWWVB0:
        !           326: 
        !           327:                /*
        !           328:                 * Timecode format 0: "I  ddd hh:mm:ss DTZ=nn"
        !           329:                 */
        !           330:                if (sscanf(pp->a_lastcode,
        !           331:                    "%c %3d %2d:%2d:%2d%c%cTZ=%2d",
        !           332:                    &syncchar, &pp->day, &pp->hour, &pp->minute,
        !           333:                    &pp->second, &tmpchar, &dstchar, &tz) == 8) {
        !           334:                        pp->nsec = 0;
        !           335:                        break;
        !           336:                }
        !           337:                goto bad_format;
        !           338: 
        !           339:        case LENWWVB2:
        !           340: 
        !           341:                /*
        !           342:                 * Timecode format 2: "IQyy ddd hh:mm:ss.mmm LD" */
        !           343:                if (sscanf(pp->a_lastcode,
        !           344:                    "%c%c %2d %3d %2d:%2d:%2d.%3ld %c",
        !           345:                    &syncchar, &qualchar, &pp->year, &pp->day,
        !           346:                    &pp->hour, &pp->minute, &pp->second, &pp->nsec,
        !           347:                    &leapchar) == 9) {
        !           348:                        pp->nsec *= 1000000;
        !           349:                        break;
        !           350:                }
        !           351:                goto bad_format;
        !           352: 
        !           353:        case LENWWVB3:
        !           354: 
        !           355:                /*
        !           356:                 * Timecode format 3: "0003I yyyymmdd hhmmss+0000SL#"
        !           357:                 * WARNING: Undocumented, and the on-time character # is
        !           358:                 * not yet handled correctly by this driver.  It may be
        !           359:                 * as simple as compensating for an additional 1/960 s.
        !           360:                 */
        !           361:                if (sscanf(pp->a_lastcode,
        !           362:                    "0003%c %4d%2d%2d %2d%2d%2d+0000%c%c",
        !           363:                    &syncchar, &pp->year, &month, &day, &pp->hour,
        !           364:                    &pp->minute, &pp->second, &dstchar, &leapchar) == 8)
        !           365:                    {
        !           366:                        pp->day = ymd2yd(pp->year, month, day);
        !           367:                        pp->nsec = 0;
        !           368:                        break;
        !           369:                }
        !           370:                goto bad_format;
        !           371: 
        !           372:        default:
        !           373:        bad_format:
        !           374: 
        !           375:                /*
        !           376:                 * Unknown format: If dumping internal table, record
        !           377:                 * stats; otherwise, declare bad format.
        !           378:                 */
        !           379:                if (up->linect > 0) {
        !           380:                        up->linect--;
        !           381:                        record_clock_stats(&peer->srcadr,
        !           382:                            pp->a_lastcode);
        !           383:                } else {
        !           384:                        refclock_report(peer, CEVNT_BADREPLY);
        !           385:                }
        !           386:                return;
        !           387:        }
        !           388: 
        !           389:        /*
        !           390:         * Decode synchronization, quality and leap characters. If
        !           391:         * unsynchronized, set the leap bits accordingly and exit.
        !           392:         * Otherwise, set the leap bits according to the leap character.
        !           393:         * Once synchronized, the dispersion depends only on the
        !           394:         * quality character.
        !           395:         */
        !           396:        switch (qualchar) {
        !           397: 
        !           398:            case ' ':
        !           399:                pp->disp = .001;
        !           400:                pp->lastref = pp->lastrec;
        !           401:                break;
        !           402: 
        !           403:            case 'A':
        !           404:                pp->disp = .01;
        !           405:                break;
        !           406: 
        !           407:            case 'B':
        !           408:                pp->disp = .1;
        !           409:                break;
        !           410: 
        !           411:            case 'C':
        !           412:                pp->disp = .5;
        !           413:                break;
        !           414: 
        !           415:            case 'D':
        !           416:                pp->disp = MAXDISPERSE;
        !           417:                break;
        !           418: 
        !           419:            default:
        !           420:                pp->disp = MAXDISPERSE;
        !           421:                refclock_report(peer, CEVNT_BADREPLY);
        !           422:                break;
        !           423:        }
        !           424:        if (syncchar != ' ')
        !           425:                pp->leap = LEAP_NOTINSYNC;
        !           426:        else if (leapchar == 'L')
        !           427:                pp->leap = LEAP_ADDSECOND;
        !           428:        else
        !           429:                pp->leap = LEAP_NOWARNING;
        !           430: 
        !           431:        /*
        !           432:         * Process the new sample in the median filter and determine the
        !           433:         * timecode timestamp, but only if the PPS is not in control.
        !           434:         */
        !           435: #ifdef HAVE_PPSAPI
        !           436:        up->tcount++;
        !           437:        if (peer->flags & FLAG_PPS)
        !           438:                return;
        !           439: 
        !           440: #endif /* HAVE_PPSAPI */
        !           441:        if (!refclock_process_f(pp, pp->fudgetime2))
        !           442:                refclock_report(peer, CEVNT_BADTIME);
        !           443: }
        !           444: 
        !           445: 
        !           446: /*
        !           447:  * wwvb_timer - called once per second by the transmit procedure
        !           448:  */
        !           449: static void
        !           450: wwvb_timer(
        !           451:        int unit,
        !           452:        struct peer *peer
        !           453:        )
        !           454: {
        !           455:        register struct wwvbunit *up;
        !           456:        struct refclockproc *pp;
        !           457:        char    pollchar;       /* character sent to clock */
        !           458:        l_fp    now;
        !           459: 
        !           460:        /*
        !           461:         * Time to poll the clock. The Spectracom clock responds to a
        !           462:         * 'T' by returning a timecode in the format(s) specified above.
        !           463:         * Note there is no checking on state, since this may not be the
        !           464:         * only customer reading the clock. Only one customer need poll
        !           465:         * the clock; all others just listen in.
        !           466:         */
        !           467:        pp = peer->procptr;
        !           468:        up = pp->unitptr;
        !           469:        if (up->linect > 0)
        !           470:                pollchar = 'R';
        !           471:        else
        !           472:                pollchar = 'T';
        !           473:        if (write(pp->io.fd, &pollchar, 1) != 1)
        !           474:                refclock_report(peer, CEVNT_FAULT);
        !           475: #ifdef DEBUG
        !           476:        get_systime(&now);
        !           477:        if (debug)
        !           478:                printf("%c poll at %s\n", pollchar, prettydate(&now));
        !           479: #endif
        !           480: #ifdef HAVE_PPSAPI
        !           481:        if (up->ppsapi_lit &&
        !           482:            refclock_pps(peer, &up->atom, pp->sloppyclockflag) > 0) {
        !           483:                up->pcount++,
        !           484:                peer->flags |= FLAG_PPS;
        !           485:                peer->precision = PPS_PRECISION;
        !           486:        }
        !           487: #endif /* HAVE_PPSAPI */
        !           488: }
        !           489: 
        !           490: 
        !           491: /*
        !           492:  * wwvb_poll - called by the transmit procedure
        !           493:  */
        !           494: static void
        !           495: wwvb_poll(
        !           496:        int unit,
        !           497:        struct peer *peer
        !           498:        )
        !           499: {
        !           500:        register struct wwvbunit *up;
        !           501:        struct refclockproc *pp;
        !           502: 
        !           503:        /*
        !           504:         * Sweep up the samples received since the last poll. If none
        !           505:         * are received, declare a timeout and keep going.
        !           506:         */
        !           507:        pp = peer->procptr;
        !           508:        up = pp->unitptr;
        !           509:        pp->polls++;
        !           510: 
        !           511:        /*
        !           512:         * If the monitor flag is set (flag4), we dump the internal
        !           513:         * quality table at the first timecode beginning the day.
        !           514:         */
        !           515:        if (pp->sloppyclockflag & CLK_FLAG4 && pp->hour <
        !           516:            (int)up->lasthour)
        !           517:                up->linect = MONLIN;
        !           518:        up->lasthour = (u_char)pp->hour;
        !           519: 
        !           520:        /*
        !           521:         * Process median filter samples. If none received, declare a
        !           522:         * timeout and keep going.
        !           523:         */
        !           524: #ifdef HAVE_PPSAPI
        !           525:        if (up->pcount == 0) {
        !           526:                peer->flags &= ~FLAG_PPS;
        !           527:                peer->precision = PRECISION;
        !           528:        }
        !           529:        if (up->tcount == 0) {
        !           530:                pp->coderecv = pp->codeproc;
        !           531:                refclock_report(peer, CEVNT_TIMEOUT);
        !           532:                return;
        !           533:        }
        !           534:        up->pcount = up->tcount = 0;
        !           535: #else /* HAVE_PPSAPI */
        !           536:        if (pp->coderecv == pp->codeproc) {
        !           537:                refclock_report(peer, CEVNT_TIMEOUT);
        !           538:                return;
        !           539:        }
        !           540: #endif /* HAVE_PPSAPI */
        !           541:        refclock_receive(peer);
        !           542:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
        !           543: #ifdef DEBUG
        !           544:        if (debug)
        !           545:                printf("wwvb: timecode %d %s\n", pp->lencode,
        !           546:                    pp->a_lastcode);
        !           547: #endif
        !           548: }
        !           549: 
        !           550: 
        !           551: /*
        !           552:  * wwvb_control - fudge parameters have been set or changed
        !           553:  */
        !           554: #ifdef HAVE_PPSAPI
        !           555: static void
        !           556: wwvb_control(
        !           557:        int unit,
        !           558:        const struct refclockstat *in_st,
        !           559:        struct refclockstat *out_st,
        !           560:        struct peer *peer
        !           561:        )
        !           562: {
        !           563:        register struct wwvbunit *up;
        !           564:        struct refclockproc *pp;
        !           565:        
        !           566:        pp = peer->procptr;
        !           567:        up = pp->unitptr;
        !           568: 
        !           569:        if (!(pp->sloppyclockflag & CLK_FLAG1)) {
        !           570:                if (!up->ppsapi_tried)
        !           571:                        return;
        !           572:                up->ppsapi_tried = 0;
        !           573:                if (!up->ppsapi_lit)
        !           574:                        return;
        !           575:                peer->flags &= ~FLAG_PPS;
        !           576:                peer->precision = PRECISION;
        !           577:                time_pps_destroy(up->atom.handle);
        !           578:                up->atom.handle = 0;
        !           579:                up->ppsapi_lit = 0;
        !           580:                return;
        !           581:        }
        !           582: 
        !           583:        if (up->ppsapi_tried)
        !           584:                return;
        !           585:        /*
        !           586:         * Light up the PPSAPI interface.
        !           587:         */
        !           588:        up->ppsapi_tried = 1;
        !           589:        if (refclock_ppsapi(pp->io.fd, &up->atom)) {
        !           590:                up->ppsapi_lit = 1;
        !           591:                return;
        !           592:        }
        !           593: 
        !           594:        NLOG(NLOG_CLOCKINFO)
        !           595:                msyslog(LOG_WARNING, "%s flag1 1 but PPSAPI fails",
        !           596:                        refnumtoa(&peer->srcadr));
        !           597: }
        !           598: #endif /* HAVE_PPSAPI */
        !           599: 
        !           600: #else
        !           601: int refclock_wwvb_bs;
        !           602: #endif /* REFCLOCK */

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