Annotation of embedaddon/ntp/ntpd/ntp_refclock.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * ntp_refclock - processing support for reference clocks
                      3:  */
                      4: #ifdef HAVE_CONFIG_H
                      5: # include <config.h>
                      6: #endif
                      7: 
                      8: #include "ntpd.h"
                      9: #include "ntp_io.h"
                     10: #include "ntp_unixtime.h"
                     11: #include "ntp_tty.h"
                     12: #include "ntp_refclock.h"
                     13: #include "ntp_stdlib.h"
                     14: #include "ntp_assert.h"
                     15: 
                     16: #include <stdio.h>
                     17: 
                     18: #ifdef HAVE_SYS_IOCTL_H
                     19: # include <sys/ioctl.h>
                     20: #endif /* HAVE_SYS_IOCTL_H */
                     21: 
                     22: #ifdef REFCLOCK
                     23: 
                     24: #ifdef TTYCLK
                     25: # ifdef HAVE_SYS_CLKDEFS_H
                     26: #  include <sys/clkdefs.h>
                     27: #  include <stropts.h>
                     28: # endif
                     29: # ifdef HAVE_SYS_SIO_H
                     30: #  include <sys/sio.h>
                     31: # endif
                     32: #endif /* TTYCLK */
                     33: 
                     34: #ifdef KERNEL_PLL
                     35: #include "ntp_syscall.h"
                     36: #endif /* KERNEL_PLL */
                     37: 
                     38: #ifdef HAVE_PPSAPI
                     39: #include "ppsapi_timepps.h"
                     40: #include "refclock_atom.h"
                     41: #endif /* HAVE_PPSAPI */
                     42: 
                     43: /*
                     44:  * Reference clock support is provided here by maintaining the fiction
                     45:  * that the clock is actually a peer.  As no packets are exchanged with
                     46:  * a reference clock, however, we replace the transmit, receive and
                     47:  * packet procedures with separate code to simulate them.  Routines
                     48:  * refclock_transmit() and refclock_receive() maintain the peer
                     49:  * variables in a state analogous to an actual peer and pass reference
                     50:  * clock data on through the filters.  Routines refclock_peer() and
                     51:  * refclock_unpeer() are called to initialize and terminate reference
                     52:  * clock associations.  A set of utility routines is included to open
                     53:  * serial devices, process sample data, edit input lines to extract
                     54:  * embedded timestamps and to perform various debugging functions.
                     55:  *
                     56:  * The main interface used by these routines is the refclockproc
                     57:  * structure, which contains for most drivers the decimal equivalants
                     58:  * of the year, day, month, hour, second and millisecond/microsecond
                     59:  * decoded from the ASCII timecode.  Additional information includes
                     60:  * the receive timestamp, exception report, statistics tallies, etc. 
                     61:  * In addition, there may be a driver-specific unit structure used for
                     62:  * local control of the device.
                     63:  *
                     64:  * The support routines are passed a pointer to the peer structure,
                     65:  * which is used for all peer-specific processing and contains a
                     66:  * pointer to the refclockproc structure, which in turn contains a
                     67:  * pointer to the unit structure, if used.  The peer structure is 
                     68:  * identified by an interface address in the dotted quad form 
                     69:  * 127.127.t.u, where t is the clock type and u the unit.
                     70:  */
                     71: #define FUDGEFAC       .1      /* fudge correction factor */
                     72: #define LF             0x0a    /* ASCII LF */
                     73: 
                     74: #ifdef PPS
                     75: int    fdpps;                  /* ppsclock legacy */
                     76: #endif /* PPS */
                     77: 
                     78: int    cal_enable;             /* enable refclock calibrate */
                     79: 
                     80: /*
                     81:  * Forward declarations
                     82:  */
                     83: #ifdef QSORT_USES_VOID_P
                     84: static int refclock_cmpl_fp (const void *, const void *);
                     85: #else
                     86: static int refclock_cmpl_fp (const double *, const double *);
                     87: #endif /* QSORT_USES_VOID_P */
                     88: static int refclock_sample (struct refclockproc *);
                     89: 
                     90: 
                     91: /*
                     92:  * refclock_report - note the occurance of an event
                     93:  *
                     94:  * This routine presently just remembers the report and logs it, but
                     95:  * does nothing heroic for the trap handler. It tries to be a good
                     96:  * citizen and bothers the system log only if things change.
                     97:  */
                     98: void
                     99: refclock_report(
                    100:        struct peer *peer,
                    101:        int code
                    102:        )
                    103: {
                    104:        struct refclockproc *pp;
                    105: 
                    106:        pp = peer->procptr;
                    107:        if (pp == NULL)
                    108:                return;
                    109: 
                    110:        switch (code) {
                    111: 
                    112:        case CEVNT_TIMEOUT:
                    113:                pp->noreply++;
                    114:                break;
                    115: 
                    116:        case CEVNT_BADREPLY:
                    117:                pp->badformat++;
                    118:                break;
                    119: 
                    120:        case CEVNT_FAULT:
                    121:                break;
                    122: 
                    123:        case CEVNT_BADDATE:
                    124:        case CEVNT_BADTIME:
                    125:                pp->baddata++;
                    126:                break;
                    127: 
                    128:        default:
                    129:                /* ignore others */
                    130:                break;
                    131:        }
                    132:        if (pp->lastevent < 15)
                    133:                pp->lastevent++;
                    134:        if (pp->currentstatus != code) {
                    135:                pp->currentstatus = (u_char)code;
                    136:                report_event(PEVNT_CLOCK, peer, ceventstr(code));
                    137:        }
                    138: }
                    139: 
                    140: 
                    141: /*
                    142:  * init_refclock - initialize the reference clock drivers
                    143:  *
                    144:  * This routine calls each of the drivers in turn to initialize internal
                    145:  * variables, if necessary. Most drivers have nothing to say at this
                    146:  * point.
                    147:  */
                    148: void
                    149: init_refclock(void)
                    150: {
                    151:        int i;
                    152: 
                    153:        for (i = 0; i < (int)num_refclock_conf; i++)
                    154:                if (refclock_conf[i]->clock_init != noentry)
                    155:                        (refclock_conf[i]->clock_init)();
                    156: }
                    157: 
                    158: 
                    159: /*
                    160:  * refclock_newpeer - initialize and start a reference clock
                    161:  *
                    162:  * This routine allocates and initializes the interface structure which
                    163:  * supports a reference clock in the form of an ordinary NTP peer. A
                    164:  * driver-specific support routine completes the initialization, if
                    165:  * used. Default peer variables which identify the clock and establish
                    166:  * its reference ID and stratum are set here. It returns one if success
                    167:  * and zero if the clock address is invalid or already running,
                    168:  * insufficient resources are available or the driver declares a bum
                    169:  * rap.
                    170:  */
                    171: int
                    172: refclock_newpeer(
                    173:        struct peer *peer       /* peer structure pointer */
                    174:        )
                    175: {
                    176:        struct refclockproc *pp;
                    177:        u_char clktype;
                    178:        int unit;
                    179: 
                    180:        /*
                    181:         * Check for valid clock address. If already running, shut it
                    182:         * down first.
                    183:         */
                    184:        if (!ISREFCLOCKADR(&peer->srcadr)) {
                    185:                msyslog(LOG_ERR,
                    186:                        "refclock_newpeer: clock address %s invalid",
                    187:                        stoa(&peer->srcadr));
                    188:                return (0);
                    189:        }
                    190:        clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
                    191:        unit = REFCLOCKUNIT(&peer->srcadr);
                    192:        if (clktype >= num_refclock_conf ||
                    193:                refclock_conf[clktype]->clock_start == noentry) {
                    194:                msyslog(LOG_ERR,
                    195:                        "refclock_newpeer: clock type %d invalid\n",
                    196:                        clktype);
                    197:                return (0);
                    198:        }
                    199: 
                    200:        /*
                    201:         * Allocate and initialize interface structure
                    202:         */
                    203:        pp = emalloc(sizeof(*pp));
                    204:        memset(pp, 0, sizeof(*pp));
                    205:        peer->procptr = pp;
                    206: 
                    207:        /*
                    208:         * Initialize structures
                    209:         */
                    210:        peer->refclktype = clktype;
                    211:        peer->refclkunit = (u_char)unit;
                    212:        peer->flags |= FLAG_REFCLOCK;
                    213:        peer->leap = LEAP_NOTINSYNC;
                    214:        peer->stratum = STRATUM_REFCLOCK;
                    215:        peer->ppoll = peer->maxpoll;
                    216:        pp->type = clktype;
                    217:        pp->timestarted = current_time;
                    218: 
                    219:        /*
                    220:         * Set peer.pmode based on the hmode. For appearances only.
                    221:         */
                    222:        switch (peer->hmode) {
                    223:        case MODE_ACTIVE:
                    224:                peer->pmode = MODE_PASSIVE;
                    225:                break;
                    226: 
                    227:        default:
                    228:                peer->pmode = MODE_SERVER;
                    229:                break;
                    230:        }
                    231: 
                    232:        /*
                    233:         * Do driver dependent initialization. The above defaults
                    234:         * can be wiggled, then finish up for consistency.
                    235:         */
                    236:        if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
                    237:                refclock_unpeer(peer);
                    238:                return (0);
                    239:        }
                    240:        peer->refid = pp->refid;
                    241:        return (1);
                    242: }
                    243: 
                    244: 
                    245: /*
                    246:  * refclock_unpeer - shut down a clock
                    247:  */
                    248: void
                    249: refclock_unpeer(
                    250:        struct peer *peer       /* peer structure pointer */
                    251:        )
                    252: {
                    253:        u_char clktype;
                    254:        int unit;
                    255: 
                    256:        /*
                    257:         * Wiggle the driver to release its resources, then give back
                    258:         * the interface structure.
                    259:         */
                    260:        if (NULL == peer->procptr)
                    261:                return;
                    262: 
                    263:        clktype = peer->refclktype;
                    264:        unit = peer->refclkunit;
                    265:        if (refclock_conf[clktype]->clock_shutdown != noentry)
                    266:                (refclock_conf[clktype]->clock_shutdown)(unit, peer);
                    267:        free(peer->procptr);
                    268:        peer->procptr = NULL;
                    269: }
                    270: 
                    271: 
                    272: /*
                    273:  * refclock_timer - called once per second for housekeeping.
                    274:  */
                    275: void
                    276: refclock_timer(
                    277:        struct peer *peer       /* peer structure pointer */
                    278:        )
                    279: {
                    280:        u_char clktype;
                    281:        int unit;
                    282: 
                    283:        clktype = peer->refclktype;
                    284:        unit = peer->refclkunit;
                    285:        if (refclock_conf[clktype]->clock_timer != noentry)
                    286:                (refclock_conf[clktype]->clock_timer)(unit, peer);
                    287: }
                    288:        
                    289: 
                    290: /*
                    291:  * refclock_transmit - simulate the transmit procedure
                    292:  *
                    293:  * This routine implements the NTP transmit procedure for a reference
                    294:  * clock. This provides a mechanism to call the driver at the NTP poll
                    295:  * interval, as well as provides a reachability mechanism to detect a
                    296:  * broken radio or other madness.
                    297:  */
                    298: void
                    299: refclock_transmit(
                    300:        struct peer *peer       /* peer structure pointer */
                    301:        )
                    302: {
                    303:        u_char clktype;
                    304:        int unit;
                    305: 
                    306:        clktype = peer->refclktype;
                    307:        unit = peer->refclkunit;
                    308:        peer->sent++;
                    309:        get_systime(&peer->xmt);
                    310: 
                    311:        /*
                    312:         * This is a ripoff of the peer transmit routine, but
                    313:         * specialized for reference clocks. We do a little less
                    314:         * protocol here and call the driver-specific transmit routine.
                    315:         */
                    316:        if (peer->burst == 0) {
                    317:                u_char oreach;
                    318: #ifdef DEBUG
                    319:                if (debug)
                    320:                        printf("refclock_transmit: at %ld %s\n",
                    321:                            current_time, stoa(&(peer->srcadr)));
                    322: #endif
                    323: 
                    324:                /*
                    325:                 * Update reachability and poll variables like the
                    326:                 * network code.
                    327:                 */
                    328:                oreach = peer->reach & 0xfe;
                    329:                peer->reach <<= 1;
                    330:                if (!(peer->reach & 0x0f))
                    331:                        clock_filter(peer, 0., 0., MAXDISPERSE);
                    332:                peer->outdate = current_time;
                    333:                if (!peer->reach) {
                    334:                        if (oreach) {
                    335:                                report_event(PEVNT_UNREACH, peer, NULL);
                    336:                                peer->timereachable = current_time;
                    337:                        }
                    338:                } else {
                    339:                        if (peer->flags & FLAG_BURST)
                    340:                                peer->burst = NSTAGE;
                    341:                }
                    342:        } else {
                    343:                peer->burst--;
                    344:        }
                    345:        if (refclock_conf[clktype]->clock_poll != noentry)
                    346:                (refclock_conf[clktype]->clock_poll)(unit, peer);
                    347:        poll_update(peer, peer->hpoll);
                    348: }
                    349: 
                    350: 
                    351: /*
                    352:  * Compare two doubles - used with qsort()
                    353:  */
                    354: static int
                    355: refclock_cmpl_fp(
                    356:        const void *p1,
                    357:        const void *p2
                    358:        )
                    359: {
                    360:        const double *dp1 = (const double *)p1;
                    361:        const double *dp2 = (const double *)p2;
                    362: 
                    363:        if (*dp1 < *dp2)
                    364:                return -1;
                    365:        if (*dp1 > *dp2)
                    366:                return 1;
                    367:        return 0;
                    368: }
                    369: 
                    370: 
                    371: /*
                    372:  * refclock_process_offset - update median filter
                    373:  *
                    374:  * This routine uses the given offset and timestamps to construct a new
                    375:  * entry in the median filter circular buffer. Samples that overflow the
                    376:  * filter are quietly discarded.
                    377:  */
                    378: void
                    379: refclock_process_offset(
                    380:        struct refclockproc *pp,        /* refclock structure pointer */
                    381:        l_fp lasttim,                   /* last timecode timestamp */
                    382:        l_fp lastrec,                   /* last receive timestamp */
                    383:        double fudge
                    384:        )
                    385: {
                    386:        l_fp lftemp;
                    387:        double doffset;
                    388: 
                    389:        pp->lastrec = lastrec;
                    390:        lftemp = lasttim;
                    391:        L_SUB(&lftemp, &lastrec);
                    392:        LFPTOD(&lftemp, doffset);
                    393:        SAMPLE(doffset + fudge);
                    394: }
                    395: 
                    396: 
                    397: /*
                    398:  * refclock_process - process a sample from the clock
                    399:  * refclock_process_f - refclock_process with other than time1 fudge
                    400:  *
                    401:  * This routine converts the timecode in the form days, hours, minutes,
                    402:  * seconds and milliseconds/microseconds to internal timestamp format,
                    403:  * then constructs a new entry in the median filter circular buffer.
                    404:  * Return success (1) if the data are correct and consistent with the
                    405:  * converntional calendar.
                    406:  *
                    407:  * Important for PPS users: Normally, the pp->lastrec is set to the
                    408:  * system time when the on-time character is received and the pp->year,
                    409:  * ..., pp->second decoded and the seconds fraction pp->nsec in
                    410:  * nanoseconds). When a PPS offset is available, pp->nsec is forced to
                    411:  * zero and the fraction for pp->lastrec is set to the PPS offset.
                    412:  */
                    413: int
                    414: refclock_process_f(
                    415:        struct refclockproc *pp,        /* refclock structure pointer */
                    416:        double fudge
                    417:        )
                    418: {
                    419:        l_fp offset, ltemp;
                    420: 
                    421:        /*
                    422:         * Compute the timecode timestamp from the days, hours, minutes,
                    423:         * seconds and milliseconds/microseconds of the timecode. Use
                    424:         * clocktime() for the aggregate seconds and the msec/usec for
                    425:         * the fraction, when present. Note that this code relies on the
                    426:         * filesystem time for the years and does not use the years of
                    427:         * the timecode.
                    428:         */
                    429:        if (!clocktime(pp->day, pp->hour, pp->minute, pp->second, GMT,
                    430:                pp->lastrec.l_ui, &pp->yearstart, &offset.l_ui))
                    431:                return (0);
                    432: 
                    433:        offset.l_uf = 0;
                    434:        DTOLFP(pp->nsec / 1e9, &ltemp);
                    435:        L_ADD(&offset, &ltemp);
                    436:        refclock_process_offset(pp, offset, pp->lastrec, fudge);
                    437:        return (1);
                    438: }
                    439: 
                    440: 
                    441: int
                    442: refclock_process(
                    443:        struct refclockproc *pp         /* refclock structure pointer */
                    444: )
                    445: {
                    446:        return refclock_process_f(pp, pp->fudgetime1);
                    447: }
                    448: 
                    449: 
                    450: /*
                    451:  * refclock_sample - process a pile of samples from the clock
                    452:  *
                    453:  * This routine implements a recursive median filter to suppress spikes
                    454:  * in the data, as well as determine a performance statistic. It
                    455:  * calculates the mean offset and RMS jitter. A time adjustment
                    456:  * fudgetime1 can be added to the final offset to compensate for various
                    457:  * systematic errors. The routine returns the number of samples
                    458:  * processed, which could be zero.
                    459:  */
                    460: static int
                    461: refclock_sample(
                    462:        struct refclockproc *pp         /* refclock structure pointer */
                    463:        )
                    464: {
                    465:        size_t  i, j, k, m, n;
                    466:        double  off[MAXSTAGE];
                    467:        double  offset;
                    468: 
                    469:        /*
                    470:         * Copy the raw offsets and sort into ascending order. Don't do
                    471:         * anything if the buffer is empty.
                    472:         */
                    473:        n = 0;
                    474:        while (pp->codeproc != pp->coderecv) {
                    475:                pp->codeproc = (pp->codeproc + 1) % MAXSTAGE;
                    476:                off[n] = pp->filter[pp->codeproc];
                    477:                n++;
                    478:        }
                    479:        if (n == 0)
                    480:                return (0);
                    481: 
                    482:        if (n > 1)
                    483:                qsort((void *)off, n, sizeof(off[0]), refclock_cmpl_fp);
                    484: 
                    485:        /*
                    486:         * Reject the furthest from the median of the samples until
                    487:         * approximately 60 percent of the samples remain.
                    488:         */
                    489:        i = 0; j = n;
                    490:        m = n - (n * 4) / 10;
                    491:        while ((j - i) > m) {
                    492:                offset = off[(j + i) / 2];
                    493:                if (off[j - 1] - offset < offset - off[i])
                    494:                        i++;    /* reject low end */
                    495:                else
                    496:                        j--;    /* reject high end */
                    497:        }
                    498: 
                    499:        /*
                    500:         * Determine the offset and jitter.
                    501:         */
                    502:        pp->offset = 0;
                    503:        pp->jitter = 0;
                    504:        for (k = i; k < j; k++) {
                    505:                pp->offset += off[k];
                    506:                if (k > i)
                    507:                        pp->jitter += SQUARE(off[k] - off[k - 1]);
                    508:        }
                    509:        pp->offset /= m;
                    510:        pp->jitter = max(SQRT(pp->jitter / m), LOGTOD(sys_precision));
                    511: #ifdef DEBUG
                    512:        if (debug)
                    513:                printf(
                    514:                    "refclock_sample: n %d offset %.6f disp %.6f jitter %.6f\n",
                    515:                    n, pp->offset, pp->disp, pp->jitter);
                    516: #endif
                    517:        return (int)n;
                    518: }
                    519: 
                    520: 
                    521: /*
                    522:  * refclock_receive - simulate the receive and packet procedures
                    523:  *
                    524:  * This routine simulates the NTP receive and packet procedures for a
                    525:  * reference clock. This provides a mechanism in which the ordinary NTP
                    526:  * filter, selection and combining algorithms can be used to suppress
                    527:  * misbehaving radios and to mitigate between them when more than one is
                    528:  * available for backup.
                    529:  */
                    530: void
                    531: refclock_receive(
                    532:        struct peer *peer       /* peer structure pointer */
                    533:        )
                    534: {
                    535:        struct refclockproc *pp;
                    536: 
                    537: #ifdef DEBUG
                    538:        if (debug)
                    539:                printf("refclock_receive: at %lu %s\n",
                    540:                    current_time, stoa(&peer->srcadr));
                    541: #endif
                    542: 
                    543:        /*
                    544:         * Do a little sanity dance and update the peer structure. Groom
                    545:         * the median filter samples and give the data to the clock
                    546:         * filter.
                    547:         */
                    548:        pp = peer->procptr;
                    549:        peer->leap = pp->leap;
                    550:        if (peer->leap == LEAP_NOTINSYNC)
                    551:                return;
                    552: 
                    553:        peer->received++;
                    554:        peer->timereceived = current_time;
                    555:        if (!peer->reach) {
                    556:                report_event(PEVNT_REACH, peer, NULL);
                    557:                peer->timereachable = current_time;
                    558:        }
                    559:        peer->reach |= 1;
                    560:        peer->reftime = pp->lastref;
                    561:        peer->aorg = pp->lastrec;
                    562:        peer->rootdisp = pp->disp;
                    563:        get_systime(&peer->dst);
                    564:        if (!refclock_sample(pp))
                    565:                return;
                    566: 
                    567:        clock_filter(peer, pp->offset, 0., pp->jitter);
                    568:        if (cal_enable && fabs(last_offset) < sys_mindisp && sys_peer !=
                    569:            NULL) {
                    570:                if (sys_peer->refclktype == REFCLK_ATOM_PPS &&
                    571:                    peer->refclktype != REFCLK_ATOM_PPS)
                    572:                        pp->fudgetime1 -= pp->offset * FUDGEFAC;
                    573:        }
                    574: }
                    575: 
                    576: 
                    577: /*
                    578:  * refclock_gtlin - groom next input line and extract timestamp
                    579:  *
                    580:  * This routine processes the timecode received from the clock and
                    581:  * strips the parity bit and control characters. It returns the number
                    582:  * of characters in the line followed by a NULL character ('\0'), which
                    583:  * is not included in the count. In case of an empty line, the previous
                    584:  * line is preserved.
                    585:  */
                    586: int
                    587: refclock_gtlin(
                    588:        struct recvbuf *rbufp,  /* receive buffer pointer */
                    589:        char    *lineptr,       /* current line pointer */
                    590:        int     bmax,           /* remaining characters in line */
                    591:        l_fp    *tsptr          /* pointer to timestamp returned */
                    592:        )
                    593: {
                    594:        char    s[BMAX];
                    595:        char    *dpt, *dpend, *dp;
                    596: 
                    597:        dpt = s;
                    598:        dpend = s + refclock_gtraw(rbufp, s, BMAX - 1, tsptr);
                    599:        if (dpend - dpt > bmax - 1)
                    600:                dpend = dpt + bmax - 1;
                    601:        for (dp = lineptr; dpt < dpend; dpt++) {
                    602:                char    c;
                    603: 
                    604:                c = *dpt & 0x7f;
                    605:                if (c >= 0x20 && c < 0x7f)
                    606:                        *dp++ = c;
                    607:        }
                    608:        if (dp == lineptr)
                    609:                return (0);
                    610: 
                    611:        *dp = '\0';
                    612:        return (dp - lineptr);
                    613: }
                    614: 
                    615: 
                    616: /*
                    617:  * refclock_gtraw - get next line/chunk of data
                    618:  *
                    619:  * This routine returns the raw data received from the clock in both
                    620:  * canonical or raw modes. The terminal interface routines map CR to LF.
                    621:  * In canonical mode this results in two lines, one containing data
                    622:  * followed by LF and another containing only LF. In raw mode the
                    623:  * interface routines can deliver arbitraty chunks of data from one
                    624:  * character to a maximum specified by the calling routine. In either
                    625:  * mode the routine returns the number of characters in the line
                    626:  * followed by a NULL character ('\0'), which is not included in the
                    627:  * count.
                    628:  *
                    629:  * If a timestamp is present in the timecode, as produced by the tty_clk
                    630:  * STREAMS module, it returns that as the timestamp; otherwise, it
                    631:  * returns the buffer timestamp.
                    632:  */
                    633: int
                    634: refclock_gtraw(
                    635:        struct recvbuf *rbufp,  /* receive buffer pointer */
                    636:        char    *lineptr,       /* current line pointer */
                    637:        int     bmax,           /* remaining characters in line */
                    638:        l_fp    *tsptr          /* pointer to timestamp returned */
                    639:        )
                    640: {
                    641:        char    *dpt, *dpend, *dp;
                    642:        l_fp    trtmp, tstmp;
                    643:        int     i;
                    644: 
                    645:        /*
                    646:         * Check for the presence of a timestamp left by the tty_clock
                    647:         * module and, if present, use that instead of the buffer
                    648:         * timestamp captured by the I/O routines. We recognize a
                    649:         * timestamp by noting its value is earlier than the buffer
                    650:         * timestamp, but not more than one second earlier.
                    651:         */
                    652:        dpt = (char *)rbufp->recv_buffer;
                    653:        dpend = dpt + rbufp->recv_length;
                    654:        trtmp = rbufp->recv_time;
                    655:        if (dpend >= dpt + 8) {
                    656:                if (buftvtots(dpend - 8, &tstmp)) {
                    657:                        L_SUB(&trtmp, &tstmp);
                    658:                        if (trtmp.l_ui == 0) {
                    659: #ifdef DEBUG
                    660:                                if (debug > 1) {
                    661:                                        printf(
                    662:                                            "refclock_gtlin: fd %d ldisc %s",
                    663:                                            rbufp->fd, lfptoa(&trtmp,
                    664:                                            6));
                    665:                                        get_systime(&trtmp);
                    666:                                        L_SUB(&trtmp, &tstmp);
                    667:                                        printf(" sigio %s\n",
                    668:                                            lfptoa(&trtmp, 6));
                    669:                                }
                    670: #endif
                    671:                                dpend -= 8;
                    672:                                trtmp = tstmp;
                    673:                        } else
                    674:                                trtmp = rbufp->recv_time;
                    675:                }
                    676:        }
                    677: 
                    678:        /*
                    679:         * Copy the raw buffer to the user string. The string is padded
                    680:         * with a NULL, which is not included in the character count.
                    681:         */
                    682:        if (dpend - dpt > bmax - 1)
                    683:                dpend = dpt + bmax - 1;
                    684:        for (dp = lineptr; dpt < dpend; dpt++)
                    685:                *dp++ = *dpt;
                    686:        *dp = '\0';
                    687:        i = dp - lineptr;
                    688: #ifdef DEBUG
                    689:        if (debug > 1)
                    690:                printf("refclock_gtraw: fd %d time %s timecode %d %s\n",
                    691:                    rbufp->fd, ulfptoa(&trtmp, 6), i, lineptr);
                    692: #endif
                    693:        *tsptr = trtmp;
                    694:        return (i);
                    695: }
                    696: 
                    697: 
                    698: /*
                    699:  * The following code does not apply to WINNT & VMS ...
                    700:  */
                    701: #if !defined SYS_VXWORKS && !defined SYS_WINNT
                    702: #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
                    703: 
                    704: /*
                    705:  * refclock_open - open serial port for reference clock
                    706:  *
                    707:  * This routine opens a serial port for I/O and sets default options. It
                    708:  * returns the file descriptor if success and zero if failure.
                    709:  */
                    710: int
                    711: refclock_open(
                    712:        char    *dev,           /* device name pointer */
                    713:        u_int   speed,          /* serial port speed (code) */
                    714:        u_int   lflags          /* line discipline flags */
                    715:        )
                    716: {
                    717:        int     fd;
                    718:        int     omode;
                    719: #ifdef O_NONBLOCK
                    720:        char    trash[128];     /* litter bin for old input data */
                    721: #endif
                    722: 
                    723:        /*
                    724:         * Open serial port and set default options
                    725:         */
                    726:        omode = O_RDWR;
                    727: #ifdef O_NONBLOCK
                    728:        omode |= O_NONBLOCK;
                    729: #endif
                    730: #ifdef O_NOCTTY
                    731:        omode |= O_NOCTTY;
                    732: #endif
                    733: 
                    734:        fd = open(dev, omode, 0777);
                    735:        if (fd < 0) {
                    736:                msyslog(LOG_ERR, "refclock_open %s: %m", dev);
                    737:                return (0);
                    738:        }
                    739:        NTP_INSIST(fd != 0);
                    740:        if (!refclock_setup(fd, speed, lflags)) {
                    741:                close(fd);
                    742:                return (0);
                    743:        }
                    744:        if (!refclock_ioctl(fd, lflags)) {
                    745:                close(fd);
                    746:                return (0);
                    747:        }
                    748: #ifdef O_NONBLOCK
                    749:        /*
                    750:         * We want to make sure there is no pending trash in the input
                    751:         * buffer. Since we have non-blocking IO available, this is a
                    752:         * good moment to read and dump all available outdated stuff
                    753:         * that might have become toxic for the driver.
                    754:         */
                    755:        while (read(fd, trash, sizeof(trash)) > 0 || errno == EINTR)
                    756:                /*NOP*/;
                    757: #endif
                    758:        return (fd);
                    759: }
                    760: 
                    761: 
                    762: /*
                    763:  * refclock_setup - initialize terminal interface structure
                    764:  */
                    765: int
                    766: refclock_setup(
                    767:        int     fd,             /* file descriptor */
                    768:        u_int   speed,          /* serial port speed (code) */
                    769:        u_int   lflags          /* line discipline flags */
                    770:        )
                    771: {
                    772:        int     i;
                    773:        TTY     ttyb, *ttyp;
                    774: #ifdef PPS
                    775:        fdpps = fd;             /* ppsclock legacy */
                    776: #endif /* PPS */
                    777: 
                    778:        /*
                    779:         * By default, the serial line port is initialized in canonical
                    780:         * (line-oriented) mode at specified line speed, 8 bits and no
                    781:         * parity. LF ends the line and CR is mapped to LF. The break,
                    782:         * erase and kill functions are disabled. There is a different
                    783:         * section for each terminal interface, as selected at compile
                    784:         * time. The flag bits can be used to set raw mode and echo.
                    785:         */
                    786:        ttyp = &ttyb;
                    787: #ifdef HAVE_TERMIOS
                    788: 
                    789:        /*
                    790:         * POSIX serial line parameters (termios interface)
                    791:         */
                    792:        if (tcgetattr(fd, ttyp) < 0) {
                    793:                msyslog(LOG_ERR,
                    794:                        "refclock_setup fd %d tcgetattr: %m", fd);
                    795:                return (0);
                    796:        }
                    797: 
                    798:        /*
                    799:         * Set canonical mode and local connection; set specified speed,
                    800:         * 8 bits and no parity; map CR to NL; ignore break.
                    801:         */
                    802:        if (speed) {
                    803:                u_int   ltemp = 0;
                    804: 
                    805:                ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
                    806:                ttyp->c_oflag = 0;
                    807:                ttyp->c_cflag = CS8 | CLOCAL | CREAD;
                    808:                if (lflags & LDISC_7O1) {
                    809:                        /* HP Z3801A needs 7-bit, odd parity */
                    810:                        ttyp->c_cflag = CS7 | PARENB | PARODD | CLOCAL | CREAD;
                    811:                }
                    812:                cfsetispeed(&ttyb, speed);
                    813:                cfsetospeed(&ttyb, speed);
                    814:                for (i = 0; i < NCCS; ++i)
                    815:                        ttyp->c_cc[i] = '\0';
                    816: 
                    817: #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
                    818: 
                    819:                /*
                    820:                 * If we have modem control, check to see if modem leads
                    821:                 * are active; if so, set remote connection. This is
                    822:                 * necessary for the kernel pps mods to work.
                    823:                 */
                    824:                if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
                    825:                        msyslog(LOG_ERR,
                    826:                            "refclock_setup fd %d TIOCMGET: %m", fd);
                    827: #ifdef DEBUG
                    828:                if (debug)
                    829:                        printf("refclock_setup fd %d modem status: 0x%x\n",
                    830:                            fd, ltemp);
                    831: #endif
                    832:                if (ltemp & TIOCM_DSR && lflags & LDISC_REMOTE)
                    833:                        ttyp->c_cflag &= ~CLOCAL;
                    834: #endif /* TIOCMGET */
                    835:        }
                    836: 
                    837:        /*
                    838:         * Set raw and echo modes. These can be changed on-fly.
                    839:         */
                    840:        ttyp->c_lflag = ICANON;
                    841:        if (lflags & LDISC_RAW) {
                    842:                ttyp->c_lflag = 0;
                    843:                ttyp->c_iflag = 0;
                    844:                ttyp->c_cc[VMIN] = 1;
                    845:        }
                    846:        if (lflags & LDISC_ECHO)
                    847:                ttyp->c_lflag |= ECHO;
                    848:        if (tcsetattr(fd, TCSANOW, ttyp) < 0) {
                    849:                msyslog(LOG_ERR,
                    850:                    "refclock_setup fd %d TCSANOW: %m", fd);
                    851:                return (0);
                    852:        }
                    853: 
                    854:        /*
                    855:         * flush input and output buffers to discard any outdated stuff
                    856:         * that might have become toxic for the driver. Failing to do so
                    857:         * is logged, but we keep our fingers crossed otherwise.
                    858:         */
                    859:        if (tcflush(fd, TCIOFLUSH) < 0)
                    860:                msyslog(LOG_ERR, "refclock_setup fd %d tcflush(): %m", fd);
                    861: #endif /* HAVE_TERMIOS */
                    862: 
                    863: #ifdef HAVE_SYSV_TTYS
                    864: 
                    865:        /*
                    866:         * System V serial line parameters (termio interface)
                    867:         *
                    868:         */
                    869:        if (ioctl(fd, TCGETA, ttyp) < 0) {
                    870:                msyslog(LOG_ERR,
                    871:                    "refclock_setup fd %d TCGETA: %m", fd);
                    872:                return (0);
                    873:        }
                    874: 
                    875:        /*
                    876:         * Set canonical mode and local connection; set specified speed,
                    877:         * 8 bits and no parity; map CR to NL; ignore break.
                    878:         */
                    879:        if (speed) {
                    880:                u_int   ltemp = 0;
                    881: 
                    882:                ttyp->c_iflag = IGNBRK | IGNPAR | ICRNL;
                    883:                ttyp->c_oflag = 0;
                    884:                ttyp->c_cflag = speed | CS8 | CLOCAL | CREAD;
                    885:                for (i = 0; i < NCCS; ++i)
                    886:                        ttyp->c_cc[i] = '\0';
                    887: 
                    888: #if defined(TIOCMGET) && !defined(SCO5_CLOCK)
                    889: 
                    890:                /*
                    891:                 * If we have modem control, check to see if modem leads
                    892:                 * are active; if so, set remote connection. This is
                    893:                 * necessary for the kernel pps mods to work.
                    894:                 */
                    895:                if (ioctl(fd, TIOCMGET, (char *)&ltemp) < 0)
                    896:                        msyslog(LOG_ERR,
                    897:                            "refclock_setup fd %d TIOCMGET: %m", fd);
                    898: #ifdef DEBUG
                    899:                if (debug)
                    900:                        printf("refclock_setup fd %d modem status: %x\n",
                    901:                            fd, ltemp);
                    902: #endif
                    903:                if (ltemp & TIOCM_DSR)
                    904:                        ttyp->c_cflag &= ~CLOCAL;
                    905: #endif /* TIOCMGET */
                    906:        }
                    907: 
                    908:        /*
                    909:         * Set raw and echo modes. These can be changed on-fly.
                    910:         */
                    911:        ttyp->c_lflag = ICANON;
                    912:        if (lflags & LDISC_RAW) {
                    913:                ttyp->c_lflag = 0;
                    914:                ttyp->c_iflag = 0;
                    915:                ttyp->c_cc[VMIN] = 1;
                    916:        }
                    917:        if (ioctl(fd, TCSETA, ttyp) < 0) {
                    918:                msyslog(LOG_ERR,
                    919:                    "refclock_setup fd %d TCSETA: %m", fd);
                    920:                return (0);
                    921:        }
                    922: #endif /* HAVE_SYSV_TTYS */
                    923: 
                    924: #ifdef HAVE_BSD_TTYS
                    925: 
                    926:        /*
                    927:         * 4.3bsd serial line parameters (sgttyb interface)
                    928:         */
                    929:        if (ioctl(fd, TIOCGETP, (char *)ttyp) < 0) {
                    930:                msyslog(LOG_ERR,
                    931:                    "refclock_setup fd %d TIOCGETP: %m", fd);
                    932:                return (0);
                    933:        }
                    934:        if (speed)
                    935:                ttyp->sg_ispeed = ttyp->sg_ospeed = speed;
                    936:        ttyp->sg_flags = EVENP | ODDP | CRMOD;
                    937:        if (ioctl(fd, TIOCSETP, (char *)ttyp) < 0) {
                    938:                msyslog(LOG_ERR,
                    939:                    "refclock_setup TIOCSETP: %m");
                    940:                return (0);
                    941:        }
                    942: #endif /* HAVE_BSD_TTYS */
                    943:        return(1);
                    944: }
                    945: #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
                    946: #endif /* SYS_VXWORKS SYS_WINNT */
                    947: 
                    948: 
                    949: /*
                    950:  * refclock_ioctl - set serial port control functions
                    951:  *
                    952:  * This routine attempts to hide the internal, system-specific details
                    953:  * of serial ports. It can handle POSIX (termios), SYSV (termio) and BSD
                    954:  * (sgtty) interfaces with varying degrees of success. The routine sets
                    955:  * up optional features such as tty_clk. The routine returns 1 if
                    956:  * success and 0 if failure.
                    957:  */
                    958: int
                    959: refclock_ioctl(
                    960:        int     fd,             /* file descriptor */
                    961:        u_int   lflags          /* line discipline flags */
                    962:        )
                    963: {
                    964:        /*
                    965:         * simply return 1 if no UNIX line discipline is supported
                    966:         */
                    967: #if !defined SYS_VXWORKS && !defined SYS_WINNT
                    968: #if defined(HAVE_TERMIOS) || defined(HAVE_SYSV_TTYS) || defined(HAVE_BSD_TTYS)
                    969: 
                    970: #ifdef DEBUG
                    971:        if (debug)
                    972:                printf("refclock_ioctl: fd %d flags 0x%x\n", fd,
                    973:                    lflags);
                    974: #endif
                    975: #ifdef TTYCLK
                    976: 
                    977:        /*
                    978:         * The TTYCLK option provides timestamping at the driver level.
                    979:         * It requires the tty_clk streams module and System V STREAMS
                    980:         * support. If not available, don't complain.
                    981:         */
                    982:        if (lflags & (LDISC_CLK | LDISC_CLKPPS | LDISC_ACTS)) {
                    983:                int rval = 0;
                    984: 
                    985:                if (ioctl(fd, I_PUSH, "clk") < 0) {
                    986:                        msyslog(LOG_NOTICE,
                    987:                            "refclock_ioctl fd %d I_PUSH: %m", fd);
                    988:                        return (0);
                    989: #ifdef CLK_SETSTR
                    990:                } else {
                    991:                        char *str;
                    992: 
                    993:                        if (lflags & LDISC_CLKPPS)
                    994:                                str = "\377";
                    995:                        else if (lflags & LDISC_ACTS)
                    996:                                str = "*";
                    997:                        else
                    998:                                str = "\n";
                    999:                        if (ioctl(fd, CLK_SETSTR, str) < 0) {
                   1000:                                msyslog(LOG_ERR,
                   1001:                                    "refclock_ioctl fd %d CLK_SETSTR: %m", fd);
                   1002:                                return (0);
                   1003:                        }
                   1004: #endif /*CLK_SETSTR */
                   1005:                }
                   1006:        }
                   1007: #endif /* TTYCLK */
                   1008: #endif /* HAVE_TERMIOS || HAVE_SYSV_TTYS || HAVE_BSD_TTYS */
                   1009: #endif /* SYS_VXWORKS SYS_WINNT */
                   1010:        return (1);
                   1011: }
                   1012: 
                   1013: 
                   1014: /*
                   1015:  * refclock_control - set and/or return clock values
                   1016:  *
                   1017:  * This routine is used mainly for debugging. It returns designated
                   1018:  * values from the interface structure that can be displayed using
                   1019:  * ntpdc and the clockstat command. It can also be used to initialize
                   1020:  * configuration variables, such as fudgetimes, fudgevalues, reference
                   1021:  * ID and stratum.
                   1022:  */
                   1023: void
                   1024: refclock_control(
                   1025:        sockaddr_u *srcadr,
                   1026:        struct refclockstat *in,
                   1027:        struct refclockstat *out
                   1028:        )
                   1029: {
                   1030:        struct peer *peer;
                   1031:        struct refclockproc *pp;
                   1032:        u_char clktype;
                   1033:        int unit;
                   1034: 
                   1035:        /*
                   1036:         * Check for valid address and running peer
                   1037:         */
                   1038:        if (!ISREFCLOCKADR(srcadr))
                   1039:                return;
                   1040: 
                   1041:        clktype = (u_char)REFCLOCKTYPE(srcadr);
                   1042:        unit = REFCLOCKUNIT(srcadr);
                   1043: 
                   1044:        peer = findexistingpeer(srcadr, NULL, -1, 0);
                   1045: 
                   1046:        if (NULL == peer || NULL == peer->procptr)
                   1047:                return;
                   1048: 
                   1049:        pp = peer->procptr;
                   1050: 
                   1051:        /*
                   1052:         * Initialize requested data
                   1053:         */
                   1054:        if (in != 0) {
                   1055:                if (in->haveflags & CLK_HAVETIME1)
                   1056:                        pp->fudgetime1 = in->fudgetime1;
                   1057:                if (in->haveflags & CLK_HAVETIME2)
                   1058:                        pp->fudgetime2 = in->fudgetime2;
                   1059:                if (in->haveflags & CLK_HAVEVAL1)
                   1060:                        peer->stratum = pp->stratum = (u_char)in->fudgeval1;
                   1061:                if (in->haveflags & CLK_HAVEVAL2)
                   1062:                        peer->refid = pp->refid = in->fudgeval2;
                   1063:                if (in->haveflags & CLK_HAVEFLAG1) {
                   1064:                        pp->sloppyclockflag &= ~CLK_FLAG1;
                   1065:                        pp->sloppyclockflag |= in->flags & CLK_FLAG1;
                   1066:                }
                   1067:                if (in->haveflags & CLK_HAVEFLAG2) {
                   1068:                        pp->sloppyclockflag &= ~CLK_FLAG2;
                   1069:                        pp->sloppyclockflag |= in->flags & CLK_FLAG2;
                   1070:                }
                   1071:                if (in->haveflags & CLK_HAVEFLAG3) {
                   1072:                        pp->sloppyclockflag &= ~CLK_FLAG3;
                   1073:                        pp->sloppyclockflag |= in->flags & CLK_FLAG3;
                   1074:                }
                   1075:                if (in->haveflags & CLK_HAVEFLAG4) {
                   1076:                        pp->sloppyclockflag &= ~CLK_FLAG4;
                   1077:                        pp->sloppyclockflag |= in->flags & CLK_FLAG4;
                   1078:                }
                   1079:        }
                   1080: 
                   1081:        /*
                   1082:         * Readback requested data
                   1083:         */
                   1084:        if (out != 0) {
                   1085:                out->haveflags = CLK_HAVETIME1 | CLK_HAVEVAL1 |
                   1086:                        CLK_HAVEVAL2 | CLK_HAVEFLAG4;
                   1087:                out->fudgetime1 = pp->fudgetime1;
                   1088:                out->fudgetime2 = pp->fudgetime2;
                   1089:                out->fudgeval1 = pp->stratum;
                   1090:                out->fudgeval2 = pp->refid;
                   1091:                out->flags = (u_char) pp->sloppyclockflag;
                   1092: 
                   1093:                out->timereset = current_time - pp->timestarted;
                   1094:                out->polls = pp->polls;
                   1095:                out->noresponse = pp->noreply;
                   1096:                out->badformat = pp->badformat;
                   1097:                out->baddata = pp->baddata;
                   1098: 
                   1099:                out->lastevent = pp->lastevent;
                   1100:                out->currentstatus = pp->currentstatus;
                   1101:                out->type = pp->type;
                   1102:                out->clockdesc = pp->clockdesc;
                   1103:                out->lencode = (u_short)pp->lencode;
                   1104:                out->p_lastcode = pp->a_lastcode;
                   1105:        }
                   1106: 
                   1107:        /*
                   1108:         * Give the stuff to the clock
                   1109:         */
                   1110:        if (refclock_conf[clktype]->clock_control != noentry)
                   1111:                (refclock_conf[clktype]->clock_control)(unit, in, out, peer);
                   1112: }
                   1113: 
                   1114: 
                   1115: /*
                   1116:  * refclock_buginfo - return debugging info
                   1117:  *
                   1118:  * This routine is used mainly for debugging. It returns designated
                   1119:  * values from the interface structure that can be displayed using
                   1120:  * ntpdc and the clkbug command.
                   1121:  */
                   1122: void
                   1123: refclock_buginfo(
                   1124:        sockaddr_u *srcadr,     /* clock address */
                   1125:        struct refclockbug *bug /* output structure */
                   1126:        )
                   1127: {
                   1128:        struct peer *peer;
                   1129:        struct refclockproc *pp;
                   1130:        int clktype;
                   1131:        int unit;
                   1132:        unsigned u;
                   1133: 
                   1134:        /*
                   1135:         * Check for valid address and peer structure
                   1136:         */
                   1137:        if (!ISREFCLOCKADR(srcadr))
                   1138:                return;
                   1139: 
                   1140:        clktype = (u_char) REFCLOCKTYPE(srcadr);
                   1141:        unit = REFCLOCKUNIT(srcadr);
                   1142: 
                   1143:        peer = findexistingpeer(srcadr, NULL, -1, 0);
                   1144: 
                   1145:        if (NULL == peer || NULL == peer->procptr)
                   1146:                return;
                   1147: 
                   1148:        pp = peer->procptr;
                   1149: 
                   1150:        /*
                   1151:         * Copy structure values
                   1152:         */
                   1153:        bug->nvalues = 8;
                   1154:        bug->svalues = 0x0000003f;
                   1155:        bug->values[0] = pp->year;
                   1156:        bug->values[1] = pp->day;
                   1157:        bug->values[2] = pp->hour;
                   1158:        bug->values[3] = pp->minute;
                   1159:        bug->values[4] = pp->second;
                   1160:        bug->values[5] = pp->nsec;
                   1161:        bug->values[6] = pp->yearstart;
                   1162:        bug->values[7] = pp->coderecv;
                   1163:        bug->stimes = 0xfffffffc;
                   1164:        bug->times[0] = pp->lastref;
                   1165:        bug->times[1] = pp->lastrec;
                   1166:        for (u = 2; u < bug->ntimes; u++)
                   1167:                DTOLFP(pp->filter[u - 2], &bug->times[u]);
                   1168: 
                   1169:        /*
                   1170:         * Give the stuff to the clock
                   1171:         */
                   1172:        if (refclock_conf[clktype]->clock_buginfo != noentry)
                   1173:                (refclock_conf[clktype]->clock_buginfo)(unit, bug, peer);
                   1174: }
                   1175: 
                   1176: 
                   1177: #ifdef HAVE_PPSAPI
                   1178: /*
                   1179:  * refclock_ppsapi - initialize/update ppsapi
                   1180:  *
                   1181:  * This routine is called after the fudge command to open the PPSAPI
                   1182:  * interface for later parameter setting after the fudge command.
                   1183:  */
                   1184: int
                   1185: refclock_ppsapi(
                   1186:        int     fddev,                  /* fd device */
                   1187:        struct refclock_atom *ap        /* atom structure pointer */
                   1188:        )
                   1189: {
                   1190:        if (ap->handle == 0) {
                   1191:                if (time_pps_create(fddev, &ap->handle) < 0) {
                   1192:                        msyslog(LOG_ERR,
                   1193:                            "refclock_ppsapi: time_pps_create: %m");
                   1194:                        return (0);
                   1195:                }
                   1196:        }
                   1197:        return (1);
                   1198: }
                   1199: 
                   1200: 
                   1201: /*
                   1202:  * refclock_params - set ppsapi parameters
                   1203:  *
                   1204:  * This routine is called to set the PPSAPI parameters after the fudge
                   1205:  * command.
                   1206:  */
                   1207: int
                   1208: refclock_params(
                   1209:        int     mode,                   /* mode bits */
                   1210:        struct refclock_atom *ap        /* atom structure pointer */
                   1211:        )
                   1212: {
                   1213:        memset(&ap->pps_params, 0, sizeof(pps_params_t));
                   1214:        ap->pps_params.api_version = PPS_API_VERS_1;
                   1215: 
                   1216:        /*
                   1217:         * Solaris serial ports provide PPS pulse capture only on the
                   1218:         * assert edge. FreeBSD serial ports provide capture on the
                   1219:         * clear edge, while FreeBSD parallel ports provide capture
                   1220:         * on the assert edge. Your mileage may vary.
                   1221:         */
                   1222:        if (mode & CLK_FLAG2)
                   1223:                ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTURECLEAR;
                   1224:        else
                   1225:                ap->pps_params.mode = PPS_TSFMT_TSPEC | PPS_CAPTUREASSERT;
                   1226:        if (time_pps_setparams(ap->handle, &ap->pps_params) < 0) {
                   1227:                msyslog(LOG_ERR,
                   1228:                    "refclock_params: time_pps_setparams: %m");
                   1229:                return (0);
                   1230:        }
                   1231: 
                   1232:        /*
                   1233:         * If flag3 is lit, select the kernel PPS.
                   1234:         */
                   1235:        if (mode & CLK_FLAG3) {
                   1236:                if (time_pps_kcbind(ap->handle, PPS_KC_HARDPPS,
                   1237:                    ap->pps_params.mode & ~PPS_TSFMT_TSPEC,
                   1238:                    PPS_TSFMT_TSPEC) < 0) {
                   1239:                        if (errno != EOPNOTSUPP) { 
                   1240:                                msyslog(LOG_ERR,
                   1241:                                    "refclock_params: time_pps_kcbind: %m");
                   1242:                                return (0);
                   1243:                        }
                   1244:                }
                   1245:                pps_enable = 1;
                   1246:        }
                   1247:        return (1);
                   1248: }
                   1249: 
                   1250: 
                   1251: /*
                   1252:  * refclock_pps - called once per second
                   1253:  *
                   1254:  * This routine is called once per second. It snatches the PPS
                   1255:  * timestamp from the kernel and saves the sign-extended fraction in
                   1256:  * a circular buffer for processing at the next poll event.
                   1257:  */
                   1258: int
                   1259: refclock_pps(
                   1260:        struct peer *peer,              /* peer structure pointer */
                   1261:        struct refclock_atom *ap,       /* atom structure pointer */
                   1262:        int     mode                    /* mode bits */ 
                   1263:        )
                   1264: {
                   1265:        struct refclockproc *pp;
                   1266:        pps_info_t pps_info;
                   1267:        struct timespec timeout;
                   1268:        double  dtemp;
                   1269: 
                   1270:        /*
                   1271:         * We require the clock to be synchronized before setting the
                   1272:         * parameters. When the parameters have been set, fetch the
                   1273:         * most recent PPS timestamp.
                   1274:         */ 
                   1275:        pp = peer->procptr;
                   1276:        if (ap->handle == 0)
                   1277:                return (0);
                   1278: 
                   1279:        if (ap->pps_params.mode == 0 && sys_leap != LEAP_NOTINSYNC) {
                   1280:                if (refclock_params(pp->sloppyclockflag, ap) < 1)
                   1281:                        return (0);
                   1282:        }
                   1283:        timeout.tv_sec = 0;
                   1284:        timeout.tv_nsec = 0;
                   1285:        memset(&pps_info, 0, sizeof(pps_info_t));
                   1286:        if (time_pps_fetch(ap->handle, PPS_TSFMT_TSPEC, &pps_info,
                   1287:            &timeout) < 0) {
                   1288:                refclock_report(peer, CEVNT_FAULT);
                   1289:                return (0);
                   1290:        }
                   1291:        timeout = ap->ts;
                   1292:        if (ap->pps_params.mode & PPS_CAPTUREASSERT)
                   1293:                ap->ts = pps_info.assert_timestamp;
                   1294:        else if (ap->pps_params.mode & PPS_CAPTURECLEAR)
                   1295:                ap->ts = pps_info.clear_timestamp;
                   1296:        else
                   1297:                return (0);
                   1298:        
                   1299:        /*
                   1300:         * There can be zero, one or two PPS pulses between polls,
                   1301:         * depending on the poll interval relative to the PPS interval.
                   1302:         * The pulse must be newer and within the range gate relative
                   1303:         * to the last pulse.
                   1304:         */
                   1305:        if (ap->ts.tv_sec <= timeout.tv_sec || abs(ap->ts.tv_nsec -
                   1306:            timeout.tv_nsec) > RANGEGATE)
                   1307:                return (0);
                   1308: 
                   1309:        /*
                   1310:         * Convert to signed fraction offset and stuff in median filter.
                   1311:         */
                   1312:        pp->lastrec.l_ui = (u_int32)ap->ts.tv_sec + JAN_1970;
                   1313:        dtemp = ap->ts.tv_nsec / 1e9;
                   1314:        pp->lastrec.l_uf = (u_int32)(dtemp * FRAC);
                   1315:        if (dtemp > .5)
                   1316:                dtemp -= 1.;
                   1317:        SAMPLE(-dtemp + pp->fudgetime1);
                   1318: #ifdef DEBUG
                   1319:        if (debug > 1)
                   1320:                printf("refclock_pps: %lu %f %f\n", current_time,
                   1321:                    dtemp, pp->fudgetime1);
                   1322: #endif
                   1323:        return (1);
                   1324: }
                   1325: #endif /* HAVE_PPSAPI */
                   1326: #endif /* REFCLOCK */

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