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

1.1       misho       1: /*
                      2:  * refclock_arbiter - clock driver for Arbiter 1088A/B Satellite
                      3:  *     Controlled Clock
                      4:  */
                      5: 
                      6: #ifdef HAVE_CONFIG_H
                      7: #include <config.h>
                      8: #endif
                      9: 
                     10: #if defined(REFCLOCK) && defined(CLOCK_ARBITER)
                     11: 
                     12: #include "ntpd.h"
                     13: #include "ntp_io.h"
                     14: #include "ntp_refclock.h"
                     15: #include "ntp_stdlib.h"
                     16: 
                     17: #include <stdio.h>
                     18: #include <ctype.h>
                     19: 
                     20: #ifdef SYS_WINNT
                     21: extern int async_write(int, const void *, unsigned int);
                     22: #undef write
                     23: #define write(fd, data, octets)        async_write(fd, data, octets)
                     24: #endif
                     25: 
                     26: /*
                     27:  * This driver supports the Arbiter 1088A/B Satellite Controlled Clock.
                     28:  * The claimed accuracy of this clock is 100 ns relative to the PPS
                     29:  * output when receiving four or more satellites.
                     30:  *
                     31:  * The receiver should be configured before starting the NTP daemon, in
                     32:  * order to establish reliable position and operating conditions. It
                     33:  * does not initiate surveying or hold mode. For use with NTP, the
                     34:  * daylight savings time feature should be disables (D0 command) and the
                     35:  * broadcast mode set to operate in UTC (BU command).
                     36:  *
                     37:  * The timecode format supported by this driver is selected by the poll
                     38:  * sequence "B5", which initiates a line in the following format to be
                     39:  * repeated once per second until turned off by the "B0" poll sequence.
                     40:  *
                     41:  * Format B5 (24 ASCII printing characters):
                     42:  *
                     43:  * <cr><lf>i yy ddd hh:mm:ss.000bbb  
                     44:  *
                     45:  *     on-time = <cr>
                     46:  *     i = synchronization flag (' ' = locked, '?' = unlocked)
                     47:  *     yy = year of century
                     48:  *     ddd = day of year
                     49:  *     hh:mm:ss = hours, minutes, seconds
                     50:  *     .000 = fraction of second (not used)
                     51:  *     bbb = tailing spaces for fill
                     52:  *
                     53:  * The alarm condition is indicated by a '?' at i, which indicates the
                     54:  * receiver is not synchronized. In normal operation, a line consisting
                     55:  * of the timecode followed by the time quality character (TQ) followed
                     56:  * by the receiver status string (SR) is written to the clockstats file.
                     57:  * The time quality character is encoded in IEEE P1344 standard:
                     58:  *
                     59:  * Format TQ (IEEE P1344 estimated worst-case time quality)
                     60:  *
                     61:  *     0       clock locked, maximum accuracy
                     62:  *     F       clock failure, time not reliable
                     63:  *     4       clock unlocked, accuracy < 1 us
                     64:  *     5       clock unlocked, accuracy < 10 us
                     65:  *     6       clock unlocked, accuracy < 100 us
                     66:  *     7       clock unlocked, accuracy < 1 ms
                     67:  *     8       clock unlocked, accuracy < 10 ms
                     68:  *     9       clock unlocked, accuracy < 100 ms
                     69:  *     A       clock unlocked, accuracy < 1 s
                     70:  *     B       clock unlocked, accuracy < 10 s
                     71:  *
                     72:  * The status string is encoded as follows:
                     73:  *
                     74:  * Format SR (25 ASCII printing characters)
                     75:  *
                     76:  *     V=vv S=ss T=t P=pdop E=ee
                     77:  *
                     78:  *     vv = satellites visible
                     79:  *     ss = relative signal strength
                     80:  *     t = satellites tracked
                     81:  *     pdop = position dilution of precision (meters)
                     82:  *     ee = hardware errors
                     83:  *
                     84:  * If flag4 is set, an additional line consisting of the receiver
                     85:  * latitude (LA), longitude (LO), elevation (LH) (meters), and data
                     86:  * buffer (DB) is written to this file. If channel B is enabled for
                     87:  * deviation mode and connected to a 1-PPS signal, the last two numbers
                     88:  * on the line are the deviation and standard deviation averaged over
                     89:  * the last 15 seconds.
                     90:  *
                     91:  * PPS calibration fudge time1 .001240
                     92:  */
                     93: 
                     94: /*
                     95:  * Interface definitions
                     96:  */
                     97: #define        DEVICE          "/dev/gps%d" /* device name and unit */
                     98: #define        SPEED232        B9600   /* uart speed (9600 baud) */
                     99: #define        PRECISION       (-20)   /* precision assumed (about 1 us) */
                    100: #define        REFID           "GPS "  /* reference ID */
                    101: #define        DESCRIPTION     "Arbiter 1088A/B GPS Receiver" /* WRU */
                    102: #define        LENARB          24      /* format B5 timecode length */
                    103: #define MAXSTA         40      /* max length of status string */
                    104: #define MAXPOS         80      /* max length of position string */
                    105: 
                    106: #ifdef PRE_NTP420
                    107: #define MODE ttlmax
                    108: #else
                    109: #define MODE ttl
                    110: #endif
                    111: 
                    112: #define COMMAND_HALT_BCAST ( (peer->MODE % 2) ? "O0" : "B0" )
                    113: #define COMMAND_START_BCAST ( (peer->MODE % 2) ? "O5" : "B5" )
                    114: 
                    115: /*
                    116:  * ARB unit control structure
                    117:  */
                    118: struct arbunit {
                    119:        l_fp    laststamp;      /* last receive timestamp */
                    120:        int     tcswitch;       /* timecode switch/counter */
                    121:        char    qualchar;       /* IEEE P1344 quality (TQ command) */
                    122:        char    status[MAXSTA]; /* receiver status (SR command) */
                    123:        char    latlon[MAXPOS]; /* receiver position (lat/lon/alt) */
                    124: };
                    125: 
                    126: /*
                    127:  * Function prototypes
                    128:  */
                    129: static int     arb_start       (int, struct peer *);
                    130: static void    arb_shutdown    (int, struct peer *);
                    131: static void    arb_receive     (struct recvbuf *);
                    132: static void    arb_poll        (int, struct peer *);
                    133: 
                    134: /*
                    135:  * Transfer vector
                    136:  */
                    137: struct refclock refclock_arbiter = {
                    138:        arb_start,              /* start up driver */
                    139:        arb_shutdown,           /* shut down driver */
                    140:        arb_poll,               /* transmit poll message */
                    141:        noentry,                /* not used (old arb_control) */
                    142:        noentry,                /* initialize driver (not used) */
                    143:        noentry,                /* not used (old arb_buginfo) */
                    144:        NOFLAGS                 /* not used */
                    145: };
                    146: 
                    147: 
                    148: /*
                    149:  * arb_start - open the devices and initialize data for processing
                    150:  */
                    151: static int
                    152: arb_start(
                    153:        int unit,
                    154:        struct peer *peer
                    155:        )
                    156: {
                    157:        register struct arbunit *up;
                    158:        struct refclockproc *pp;
                    159:        int fd;
                    160:        char device[20];
                    161: 
                    162:        /*
                    163:         * Open serial port. Use CLK line discipline, if available.
                    164:         */
                    165:        snprintf(device, sizeof(device), DEVICE, unit);
                    166:        if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
                    167:                return (0);
                    168: 
                    169:        /*
                    170:         * Allocate and initialize unit structure
                    171:         */
                    172:        up = emalloc(sizeof(*up));
                    173:        memset(up, 0, sizeof(*up));
                    174:        pp = peer->procptr;
                    175:        pp->io.clock_recv = arb_receive;
                    176:        pp->io.srcclock = (caddr_t)peer;
                    177:        pp->io.datalen = 0;
                    178:        pp->io.fd = fd;
                    179:        if (!io_addclock(&pp->io)) {
                    180:                close(fd);
                    181:                pp->io.fd = -1;
                    182:                free(up);
                    183:                return (0);
                    184:        }
                    185:        pp->unitptr = (caddr_t)up;
                    186: 
                    187:        /*
                    188:         * Initialize miscellaneous variables
                    189:         */
                    190:        peer->precision = PRECISION;
                    191:        pp->clockdesc = DESCRIPTION;
                    192:        memcpy((char *)&pp->refid, REFID, 4);
                    193:        if (peer->MODE > 1) {
                    194:                msyslog(LOG_NOTICE, "ARBITER: Invalid mode %d", peer->MODE);
                    195:                close(fd);
                    196:                pp->io.fd = -1;
                    197:                free(up);
                    198:                return (0);
                    199:        }
                    200: #ifdef DEBUG
                    201:        if(debug) { printf("arbiter: mode = %d.\n", peer->MODE); }
                    202: #endif
                    203:        write(pp->io.fd, COMMAND_HALT_BCAST, 2);
                    204:        return (1);
                    205: }
                    206: 
                    207: 
                    208: /*
                    209:  * arb_shutdown - shut down the clock
                    210:  */
                    211: static void
                    212: arb_shutdown(
                    213:        int unit,
                    214:        struct peer *peer
                    215:        )
                    216: {
                    217:        register struct arbunit *up;
                    218:        struct refclockproc *pp;
                    219: 
                    220:        pp = peer->procptr;
                    221:        up = (struct arbunit *)pp->unitptr;
                    222:        if (-1 != pp->io.fd)
                    223:                io_closeclock(&pp->io);
                    224:        if (NULL != up)
                    225:                free(up);
                    226: }
                    227: 
                    228: 
                    229: /*
                    230:  * arb_receive - receive data from the serial interface
                    231:  */
                    232: static void
                    233: arb_receive(
                    234:        struct recvbuf *rbufp
                    235:        )
                    236: {
                    237:        register struct arbunit *up;
                    238:        struct refclockproc *pp;
                    239:        struct peer *peer;
                    240:        l_fp trtmp;
                    241:        int temp;
                    242:        u_char  syncchar;               /* synch indicator */
                    243:        char    tbuf[BMAX];             /* temp buffer */
                    244: 
                    245:        /*
                    246:         * Initialize pointers and read the timecode and timestamp
                    247:         */
                    248:        peer = (struct peer *)rbufp->recv_srcclock;
                    249:        pp = peer->procptr;
                    250:        up = (struct arbunit *)pp->unitptr;
                    251:        temp = refclock_gtlin(rbufp, tbuf, BMAX, &trtmp);
                    252: 
                    253:        /*
                    254:         * Note we get a buffer and timestamp for both a <cr> and <lf>,
                    255:         * but only the <cr> timestamp is retained. The program first
                    256:         * sends a TQ and expects the echo followed by the time quality
                    257:         * character. It then sends a B5 starting the timecode broadcast
                    258:         * and expects the echo followed some time later by the on-time
                    259:         * character <cr> and then the <lf> beginning the timecode
                    260:         * itself. Finally, at the <cr> beginning the next timecode at
                    261:         * the next second, the program sends a B0 shutting down the
                    262:         * timecode broadcast.
                    263:         *
                    264:         * If flag4 is set, the program snatches the latitude, longitude
                    265:         * and elevation and writes it to the clockstats file.
                    266:         */
                    267:        if (temp == 0)
                    268:                return;
                    269: 
                    270:        pp->lastrec = up->laststamp;
                    271:        up->laststamp = trtmp;
                    272:        if (temp < 3)
                    273:                return;
                    274: 
                    275:        if (up->tcswitch == 0) {
                    276: 
                    277:                /*
                    278:                 * Collect statistics. If nothing is recogized, just
                    279:                 * ignore; sometimes the clock doesn't stop spewing
                    280:                 * timecodes for awhile after the B0 command.
                    281:                 *
                    282:                 * If flag4 is not set, send TQ, SR, B5. If flag4 is
                    283:                 * sset, send TQ, SR, LA, LO, LH, DB, B5. When the
                    284:                 * median filter is full, send B0.
                    285:                 */
                    286:                if (!strncmp(tbuf, "TQ", 2)) {
                    287:                        up->qualchar = tbuf[2];
                    288:                        write(pp->io.fd, "SR", 2);
                    289:                        return;
                    290: 
                    291:                } else if (!strncmp(tbuf, "SR", 2)) {
                    292:                        strcpy(up->status, tbuf + 2);
                    293:                        if (pp->sloppyclockflag & CLK_FLAG4)
                    294:                                write(pp->io.fd, "LA", 2);
                    295:                        else
                    296:                                write(pp->io.fd, COMMAND_START_BCAST, 2);
                    297:                        return;
                    298: 
                    299:                } else if (!strncmp(tbuf, "LA", 2)) {
                    300:                        strcpy(up->latlon, tbuf + 2);
                    301:                        write(pp->io.fd, "LO", 2);
                    302:                        return;
                    303: 
                    304:                } else if (!strncmp(tbuf, "LO", 2)) {
                    305:                        strcat(up->latlon, " ");
                    306:                        strcat(up->latlon, tbuf + 2);
                    307:                        write(pp->io.fd, "LH", 2);
                    308:                        return;
                    309: 
                    310:                } else if (!strncmp(tbuf, "LH", 2)) {
                    311:                        strcat(up->latlon, " ");
                    312:                        strcat(up->latlon, tbuf + 2);
                    313:                        write(pp->io.fd, "DB", 2);
                    314:                        return;
                    315: 
                    316:                } else if (!strncmp(tbuf, "DB", 2)) {
                    317:                        strcat(up->latlon, " ");
                    318:                        strcat(up->latlon, tbuf + 2);
                    319:                        record_clock_stats(&peer->srcadr, up->latlon);
                    320: #ifdef DEBUG
                    321:                        if (debug)
                    322:                                printf("arbiter: %s\n", up->latlon);
                    323: #endif
                    324:                        write(pp->io.fd, COMMAND_START_BCAST, 2);
                    325:                }
                    326:        }
                    327: 
                    328:        /*
                    329:         * We get down to business, check the timecode format and decode
                    330:         * its contents. If the timecode has valid length, but not in
                    331:         * proper format, we declare bad format and exit. If the
                    332:         * timecode has invalid length, which sometimes occurs when the
                    333:         * B0 amputates the broadcast, we just quietly steal away. Note
                    334:         * that the time quality character and receiver status string is
                    335:         * tacked on the end for clockstats display. 
                    336:         */
                    337:        up->tcswitch++;
                    338:        if (up->tcswitch <= 1 || temp < LENARB)
                    339:                return;
                    340: 
                    341:        /*
                    342:         * Timecode format B5: "i yy ddd hh:mm:ss.000   "
                    343:         */
                    344:        strncpy(pp->a_lastcode, tbuf, BMAX);
                    345:        pp->a_lastcode[LENARB - 2] = up->qualchar;
                    346:        strcat(pp->a_lastcode, up->status);
                    347:        pp->lencode = strlen(pp->a_lastcode);
                    348:        syncchar = ' ';
                    349:        if (sscanf(pp->a_lastcode, "%c%2d %3d %2d:%2d:%2d",
                    350:            &syncchar, &pp->year, &pp->day, &pp->hour,
                    351:            &pp->minute, &pp->second) != 6) {
                    352:                refclock_report(peer, CEVNT_BADREPLY);
                    353:                write(pp->io.fd, COMMAND_HALT_BCAST, 2);
                    354:                return;
                    355:        }
                    356: 
                    357:        /*
                    358:         * We decode the clock dispersion from the time quality
                    359:         * character.
                    360:         */
                    361:        switch (up->qualchar) {
                    362: 
                    363:            case '0':           /* locked, max accuracy */
                    364:                pp->disp = 1e-7;
                    365:                pp->lastref = pp->lastrec;
                    366:                break;
                    367: 
                    368:            case '4':           /* unlock accuracy < 1 us */
                    369:                pp->disp = 1e-6;
                    370:                break;
                    371: 
                    372:            case '5':           /* unlock accuracy < 10 us */
                    373:                pp->disp = 1e-5;
                    374:                break;
                    375: 
                    376:            case '6':           /* unlock accuracy < 100 us */
                    377:                pp->disp = 1e-4;
                    378:                break;
                    379: 
                    380:            case '7':           /* unlock accuracy < 1 ms */
                    381:                pp->disp = .001;
                    382:                break;
                    383: 
                    384:            case '8':           /* unlock accuracy < 10 ms */
                    385:                pp->disp = .01;
                    386:                break;
                    387: 
                    388:            case '9':           /* unlock accuracy < 100 ms */
                    389:                pp->disp = .1;
                    390:                break;
                    391: 
                    392:            case 'A':           /* unlock accuracy < 1 s */
                    393:                pp->disp = 1;
                    394:                break;
                    395: 
                    396:            case 'B':           /* unlock accuracy < 10 s */
                    397:                pp->disp = 10;
                    398:                break;
                    399: 
                    400:            case 'F':           /* clock failure */
                    401:                pp->disp = MAXDISPERSE;
                    402:                refclock_report(peer, CEVNT_FAULT);
                    403:                write(pp->io.fd, COMMAND_HALT_BCAST, 2);
                    404:                return;
                    405: 
                    406:            default:
                    407:                pp->disp = MAXDISPERSE;
                    408:                refclock_report(peer, CEVNT_BADREPLY);
                    409:                write(pp->io.fd, COMMAND_HALT_BCAST, 2);
                    410:                return;
                    411:        }
                    412:        if (syncchar != ' ')
                    413:                pp->leap = LEAP_NOTINSYNC;
                    414:        else
                    415:                pp->leap = LEAP_NOWARNING;
                    416: 
                    417:        /*
                    418:         * Process the new sample in the median filter and determine the
                    419:         * timecode timestamp.
                    420:         */
                    421:        if (!refclock_process(pp))
                    422:                refclock_report(peer, CEVNT_BADTIME);
                    423:        else if (peer->disp > MAXDISTANCE)
                    424:                refclock_receive(peer);
                    425: 
                    426:        /* if (up->tcswitch >= MAXSTAGE) { */
                    427:        write(pp->io.fd, COMMAND_HALT_BCAST, 2);
                    428:        /* } */
                    429: }
                    430: 
                    431: 
                    432: /*
                    433:  * arb_poll - called by the transmit procedure
                    434:  */
                    435: static void
                    436: arb_poll(
                    437:        int unit,
                    438:        struct peer *peer
                    439:        )
                    440: {
                    441:        register struct arbunit *up;
                    442:        struct refclockproc *pp;
                    443: 
                    444:        /*
                    445:         * Time to poll the clock. The Arbiter clock responds to a "B5"
                    446:         * by returning a timecode in the format specified above.
                    447:         * Transmission occurs once per second, unless turned off by a
                    448:         * "B0". Note there is no checking on state, since this may not
                    449:         * be the only customer reading the clock. Only one customer
                    450:         * need poll the clock; all others just listen in.
                    451:         */
                    452:        pp = peer->procptr;
                    453:        up = (struct arbunit *)pp->unitptr;
                    454:        pp->polls++;
                    455:        up->tcswitch = 0;
                    456:        if (write(pp->io.fd, "TQ", 2) != 2)
                    457:                refclock_report(peer, CEVNT_FAULT);
                    458: 
                    459:        /*
                    460:         * Process median filter samples. If none received, declare a
                    461:         * timeout and keep going.
                    462:         */
                    463:        if (pp->coderecv == pp->codeproc) {
                    464:                refclock_report(peer, CEVNT_TIMEOUT);
                    465:                return;
                    466:        }
                    467:        refclock_receive(peer);
                    468:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
                    469: #ifdef DEBUG
                    470:        if (debug)
                    471:                printf("arbiter: timecode %d %s\n",
                    472:                   pp->lencode, pp->a_lastcode);
                    473: #endif
                    474: }
                    475: 
                    476: #else
                    477: int refclock_arbiter_bs;
                    478: #endif /* REFCLOCK */

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