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

1.1     ! misho       1: /*
        !             2:  * refclock_true - clock driver for the Kinemetrics Truetime receivers
        !             3:  *     Receiver Version 3.0C - tested plain, with CLKLDISC
        !             4:  *     Developement work being done:
        !             5:  *     - Properly handle varying satellite positions (more acurately)
        !             6:  *     - Integrate GPSTM and/or OMEGA and/or TRAK and/or ??? drivers
        !             7:  */
        !             8: 
        !             9: #ifdef HAVE_CONFIG_H
        !            10: #include <config.h>
        !            11: #endif
        !            12: 
        !            13: #if defined(REFCLOCK) && defined(CLOCK_TRUETIME)
        !            14: 
        !            15: #include "ntpd.h"
        !            16: #include "ntp_io.h"
        !            17: #include "ntp_refclock.h"
        !            18: #include "ntp_unixtime.h"
        !            19: #include "ntp_stdlib.h"
        !            20: 
        !            21: #include <stdio.h>
        !            22: #include <ctype.h>
        !            23: 
        !            24: #ifdef SYS_WINNT
        !            25: extern int async_write(int, const void *, unsigned int);
        !            26: #undef write
        !            27: #define write(fd, data, octets)        async_write(fd, data, octets)
        !            28: #endif
        !            29: 
        !            30: /* This should be an atom clock but those are very hard to build.
        !            31:  *
        !            32:  * The PCL720 from P C Labs has an Intel 8253 lookalike, as well as a bunch
        !            33:  * of TTL input and output pins, all brought out to the back panel.  If you
        !            34:  * wire a PPS signal (such as the TTL PPS coming out of a GOES or other
        !            35:  * Kinemetrics/Truetime clock) to the 8253's GATE0, and then also wire the
        !            36:  * 8253's OUT0 to the PCL720's INPUT3.BIT0, then we can read CTR0 to get the
        !            37:  * number of uSecs since the last PPS upward swing, mediated by reading OUT0
        !            38:  * to find out if the counter has wrapped around (this happens if more than
        !            39:  * 65535us (65ms) elapses between the PPS event and our being called.)
        !            40:  */
        !            41: #ifdef CLOCK_PPS720
        !            42: # undef min    /* XXX */
        !            43: # undef max    /* XXX */
        !            44: # include <machine/inline.h>
        !            45: # include <sys/pcl720.h>
        !            46: # include <sys/i8253.h>
        !            47: # define PCL720_IOB 0x2a0      /* XXX */
        !            48: # define PCL720_CTR 0          /* XXX */
        !            49: #endif
        !            50: 
        !            51: /*
        !            52:  * Support for Kinemetrics Truetime Receivers
        !            53:  *     GOES
        !            54:  *     GPS/TM-TMD
        !            55:  *     XL-DC           (a 151-602-210, reported by the driver as a GPS/TM-TMD)
        !            56:  *     GPS-800 TCU     (an 805-957 with the RS232 Talker/Listener module)
        !            57:  *     OM-DC:          getting stale ("OMEGA")
        !            58:  *
        !            59:  * Most of this code is originally from refclock_wwvb.c with thanks.
        !            60:  * It has been so mangled that wwvb is not a recognizable ancestor.
        !            61:  *
        !            62:  * Timcode format: ADDD:HH:MM:SSQCL
        !            63:  *     A - control A           (this is stripped before we see it)
        !            64:  *     Q - Quality indication  (see below)
        !            65:  *     C - Carriage return
        !            66:  *     L - Line feed
        !            67:  *
        !            68:  * Quality codes indicate possible error of
        !            69:  *   468-DC GOES Receiver:
        !            70:  *   GPS-TM/TMD Receiver: (default quality codes for XL-DC)
        !            71:  *       ?     +/- 1  milliseconds     #     +/- 100 microseconds
        !            72:  *       *     +/- 10 microseconds     .     +/- 1   microsecond
        !            73:  *     space   less than 1 microsecond
        !            74:  *   OM-DC OMEGA Receiver: (default quality codes for OMEGA)
        !            75:  *   WARNING OMEGA navigation system is no longer existent
        !            76:  *       >     >+- 5 seconds
        !            77:  *       ?     >+/- 500 milliseconds    #     >+/- 50 milliseconds
        !            78:  *       *     >+/- 5 milliseconds      .     >+/- 1 millisecond
        !            79:  *      A-H    less than 1 millisecond.  Character indicates which station
        !            80:  *             is being received as follows:
        !            81:  *             A = Norway, B = Liberia, C = Hawaii, D = North Dakota,
        !            82:  *             E = La Reunion, F = Argentina, G = Australia, H = Japan.
        !            83:  *
        !            84:  * The carriage return start bit begins on 0 seconds and extends to 1 bit time.
        !            85:  *
        !            86:  * Notes on 468-DC and OMEGA receiver:
        !            87:  *
        !            88:  * Send the clock a 'R' or 'C' and once per second a timestamp will
        !            89:  * appear.  Send a 'P' to get the satellite position once (GOES only.)
        !            90:  *
        !            91:  * Notes on the 468-DC receiver:
        !            92:  *
        !            93:  * Since the old east/west satellite locations are only historical, you can't
        !            94:  * set your clock propagation delay settings correctly and still use
        !            95:  * automatic mode. The manual says to use a compromise when setting the
        !            96:  * switches. This results in significant errors. The solution; use fudge
        !            97:  * time1 and time2 to incorporate corrections. If your clock is set for
        !            98:  * 50 and it should be 58 for using the west and 46 for using the east,
        !            99:  * use the line
        !           100:  *
        !           101:  * fudge 127.127.5.0 time1 +0.008 time2 -0.004
        !           102:  *
        !           103:  * This corrects the 4 milliseconds advance and 8 milliseconds retard
        !           104:  * needed. The software will ask the clock which satellite it sees.
        !           105:  *
        !           106:  * Ntp.conf parameters:
        !           107:  * time1 - offset applied to samples when reading WEST satellite (default = 0)
        !           108:  * time2 - offset applied to samples when reading EAST satellite (default = 0)
        !           109:  * val1  - stratum to assign to this clock (default = 0)
        !           110:  * val2  - refid assigned to this clock (default = "TRUE", see below)
        !           111:  * flag1 - will silence the clock side of ntpd, just reading the clock
        !           112:  *         without trying to write to it.  (default = 0)
        !           113:  * flag2 - generate a debug file /tmp/true%d.
        !           114:  * flag3 - enable ppsclock streams module
        !           115:  * flag4 - use the PCL-720 (BSD/OS only)
        !           116:  */
        !           117: 
        !           118: 
        !           119: /*
        !           120:  * Definitions
        !           121:  */
        !           122: #define        DEVICE          "/dev/true%d"
        !           123: #define        SPEED232        B9600   /* 9600 baud */
        !           124: 
        !           125: /*
        !           126:  * Radio interface parameters
        !           127:  */
        !           128: #define        PRECISION       (-10)   /* precision assumed (about 1 ms) */
        !           129: #define        REFID           "TRUE"  /* reference id */
        !           130: #define        DESCRIPTION     "Kinemetrics/TrueTime Receiver"
        !           131: 
        !           132: /*
        !           133:  * Tags which station (satellite) we see
        !           134:  */
        !           135: #define GOES_WEST      0       /* Default to WEST satellite and apply time1 */
        !           136: #define GOES_EAST      1       /* until you discover otherwise */
        !           137: 
        !           138: /*
        !           139:  * used by the state machine
        !           140:  */
        !           141: enum true_event        {e_Init, e_Huh, e_F18, e_F50, e_F51, e_Satellite,
        !           142:                 e_Poll, e_Location, e_TS, e_Max};
        !           143: const char *events[] = {"Init", "Huh", "F18", "F50", "F51", "Satellite",
        !           144:                        "Poll", "Location", "TS"};
        !           145: #define eventStr(x) (((int)x<(int)e_Max) ? events[(int)x] : "?")
        !           146: 
        !           147: enum true_state        {s_Base, s_InqTM, s_InqTCU, s_InqOmega, s_InqGOES,
        !           148:                 s_Init, s_F18, s_F50, s_Start, s_Auto, s_Max};
        !           149: const char *states[] = {"Base", "InqTM", "InqTCU", "InqOmega", "InqGOES",
        !           150:                        "Init", "F18", "F50", "Start", "Auto"};
        !           151: #define stateStr(x) (((int)x<(int)s_Max) ? states[(int)x] : "?")
        !           152: 
        !           153: enum true_type {t_unknown, t_goes, t_tm, t_tcu, t_omega, t_Max};
        !           154: const char *types[] = {"unknown", "goes", "tm", "tcu", "omega"};
        !           155: #define typeStr(x) (((int)x<(int)t_Max) ? types[(int)x] : "?")
        !           156: 
        !           157: /*
        !           158:  * unit control structure
        !           159:  */
        !           160: struct true_unit {
        !           161:        unsigned int    pollcnt;        /* poll message counter */
        !           162:        unsigned int    station;        /* which station we are on */
        !           163:        unsigned int    polled;         /* Hand in a time sample? */
        !           164:        enum true_state state;          /* state machine */
        !           165:        enum true_type  type;           /* what kind of clock is it? */
        !           166:        int             unit;           /* save an extra copy of this */
        !           167:        FILE            *debug;         /* debug logging file */
        !           168: #ifdef CLOCK_PPS720
        !           169:        int             pcl720init;     /* init flag for PCL 720 */
        !           170: #endif
        !           171: };
        !           172: 
        !           173: /*
        !           174:  * Function prototypes
        !           175:  */
        !           176: static int     true_start      (int, struct peer *);
        !           177: static void    true_shutdown   (int, struct peer *);
        !           178: static void    true_receive    (struct recvbuf *);
        !           179: static void    true_poll       (int, struct peer *);
        !           180: static void    true_send       (struct peer *, const char *);
        !           181: static void    true_doevent    (struct peer *, enum true_event);
        !           182: 
        !           183: #ifdef CLOCK_PPS720
        !           184: static u_long  true_sample720  (void);
        !           185: #endif
        !           186: 
        !           187: /*
        !           188:  * Transfer vector
        !           189:  */
        !           190: struct refclock refclock_true = {
        !           191:        true_start,             /* start up driver */
        !           192:        true_shutdown,          /* shut down driver */
        !           193:        true_poll,              /* transmit poll message */
        !           194:        noentry,                /* not used (old true_control) */
        !           195:        noentry,                /* initialize driver (not used) */
        !           196:        noentry,                /* not used (old true_buginfo) */
        !           197:        NOFLAGS                 /* not used */
        !           198: };
        !           199: 
        !           200: 
        !           201: #if !defined(__STDC__)
        !           202: # define true_debug (void)
        !           203: #else
        !           204: static void
        !           205: true_debug(struct peer *peer, const char *fmt, ...)
        !           206: {
        !           207:        va_list ap;
        !           208:        int want_debugging, now_debugging;
        !           209:        struct refclockproc *pp;
        !           210:        struct true_unit *up;
        !           211: 
        !           212:        va_start(ap, fmt);
        !           213:        pp = peer->procptr;
        !           214:        up = (struct true_unit *)pp->unitptr;
        !           215: 
        !           216:        want_debugging = (pp->sloppyclockflag & CLK_FLAG2) != 0;
        !           217:        now_debugging = (up->debug != NULL);
        !           218:        if (want_debugging != now_debugging)
        !           219:        {
        !           220:                if (want_debugging) {
        !           221:                    char filename[40];
        !           222:                    int fd;
        !           223: 
        !           224:                    snprintf(filename, sizeof(filename), "/tmp/true%d.debug", up->unit);
        !           225:                    fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0600);
        !           226:                    if (fd >= 0 && (up->debug = fdopen(fd, "r+"))) {
        !           227: #ifdef HAVE_SETVBUF
        !           228:                            static char buf[BUFSIZ];
        !           229:                            setvbuf(up->debug, buf, _IOLBF, BUFSIZ);
        !           230: #else
        !           231:                            setlinebuf(up->debug);
        !           232: #endif
        !           233:                    }
        !           234:            } else {
        !           235:                    fclose(up->debug);
        !           236:                    up->debug = NULL;
        !           237:            }
        !           238:        }
        !           239: 
        !           240:        if (up->debug) {
        !           241:                fprintf(up->debug, "true%d: ", up->unit);
        !           242:                vfprintf(up->debug, fmt, ap);
        !           243:        }
        !           244:        va_end(ap);
        !           245: }
        !           246: #endif /*STDC*/
        !           247: 
        !           248: /*
        !           249:  * true_start - open the devices and initialize data for processing
        !           250:  */
        !           251: static int
        !           252: true_start(
        !           253:        int unit,
        !           254:        struct peer *peer
        !           255:        )
        !           256: {
        !           257:        register struct true_unit *up;
        !           258:        struct refclockproc *pp;
        !           259:        char device[40];
        !           260:        int fd;
        !           261: 
        !           262:        /*
        !           263:         * Open serial port
        !           264:         */
        !           265:        (void)snprintf(device, sizeof(device), DEVICE, unit);
        !           266:        if (!(fd = refclock_open(device, SPEED232, LDISC_CLK)))
        !           267:            return (0);
        !           268: 
        !           269:        /*
        !           270:         * Allocate and initialize unit structure
        !           271:         */
        !           272:        if (!(up = (struct true_unit *)
        !           273:              emalloc(sizeof(struct true_unit)))) {
        !           274:                (void) close(fd);
        !           275:                return (0);
        !           276:        }
        !           277:        memset((char *)up, 0, sizeof(struct true_unit));
        !           278:        pp = peer->procptr;
        !           279:        pp->io.clock_recv = true_receive;
        !           280:        pp->io.srcclock = (caddr_t)peer;
        !           281:        pp->io.datalen = 0;
        !           282:        pp->io.fd = fd;
        !           283:        if (!io_addclock(&pp->io)) {
        !           284:                (void) close(fd);
        !           285:                free(up);
        !           286:                return (0);
        !           287:        }
        !           288:        pp->unitptr = (caddr_t)up;
        !           289: 
        !           290:        /*
        !           291:         * Initialize miscellaneous variables
        !           292:         */
        !           293:        peer->precision = PRECISION;
        !           294:        pp->clockdesc = DESCRIPTION;
        !           295:        memcpy((char *)&pp->refid, REFID, 4);
        !           296:        up->pollcnt = 2;
        !           297:        up->type = t_unknown;
        !           298:        up->state = s_Base;
        !           299: 
        !           300:        /*
        !           301:         * Send a CTRL-C character at the start,
        !           302:         * just in case the clock is already
        !           303:         * sending timecodes
        !           304:         */
        !           305:        true_send(peer, "\03\r");
        !           306:        
        !           307:        true_doevent(peer, e_Init);
        !           308: 
        !           309:        return (1);
        !           310: }
        !           311: 
        !           312: /*
        !           313:  * true_shutdown - shut down the clock
        !           314:  */
        !           315: static void
        !           316: true_shutdown(
        !           317:        int unit,
        !           318:        struct peer *peer
        !           319:        )
        !           320: {
        !           321:        register struct true_unit *up;
        !           322:        struct refclockproc *pp;
        !           323: 
        !           324:        pp = peer->procptr;
        !           325:        up = (struct true_unit *)pp->unitptr;
        !           326:        io_closeclock(&pp->io);
        !           327:        free(up);
        !           328: }
        !           329: 
        !           330: 
        !           331: /*
        !           332:  * true_receive - receive data from the serial interface on a clock
        !           333:  */
        !           334: static void
        !           335: true_receive(
        !           336:        struct recvbuf *rbufp
        !           337:        )
        !           338: {
        !           339:        register struct true_unit *up;
        !           340:        struct refclockproc *pp;
        !           341:        struct peer *peer;
        !           342:        u_short new_station;
        !           343:        char synced;
        !           344:        int i;
        !           345:        int lat, lon, off;      /* GOES Satellite position */
        !           346:         /* Use these variable to hold data until we decide its worth keeping */
        !           347:         char    rd_lastcode[BMAX];
        !           348:         l_fp    rd_tmp;
        !           349:         u_short rd_lencode;
        !           350: 
        !           351:        /*
        !           352:         * Get the clock this applies to and pointers to the data.
        !           353:         */
        !           354:        peer = (struct peer *)rbufp->recv_srcclock;
        !           355:        pp = peer->procptr;
        !           356:        up = (struct true_unit *)pp->unitptr;
        !           357: 
        !           358:        /*
        !           359:         * Read clock output.  Automatically handles STREAMS, CLKLDISC.
        !           360:         */
        !           361:         rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
        !           362:         rd_lastcode[rd_lencode] = '\0';
        !           363: 
        !           364:        /*
        !           365:         * There is a case where <cr><lf> generates 2 timestamps.
        !           366:         */
        !           367:         if (rd_lencode == 0)
        !           368:             return;
        !           369:         pp->lencode = rd_lencode;
        !           370:         strcpy(pp->a_lastcode, rd_lastcode);
        !           371:         pp->lastrec = rd_tmp;
        !           372:        true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode);
        !           373: 
        !           374:        up->pollcnt = 2;
        !           375:        record_clock_stats(&peer->srcadr, pp->a_lastcode);
        !           376: 
        !           377:        /*
        !           378:         * We get down to business, check the timecode format and decode
        !           379:         * its contents. This code decodes a multitude of different
        !           380:         * clock messages. Timecodes are processed if needed. All replies
        !           381:         * will be run through the state machine to tweak driver options
        !           382:         * and program the clock.
        !           383:         */
        !           384: 
        !           385:        /*
        !           386:         * Clock misunderstood our last command?
        !           387:         */
        !           388:        if (pp->a_lastcode[0] == '?' ||
        !           389:            strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
        !           390:                true_doevent(peer, e_Huh);
        !           391:                return;
        !           392:        }
        !           393: 
        !           394:        /*
        !           395:         * Timecode: "nnnnn+nnn-nnn"
        !           396:         * (from GOES clock when asked about satellite position)
        !           397:         */
        !           398:        if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
        !           399:            (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
        !           400:            sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
        !           401:            ) {
        !           402:                const char *label = "Botch!";
        !           403: 
        !           404:                /*
        !           405:                 * This is less than perfect.  Call the (satellite)
        !           406:                 * either EAST or WEST and adjust slop accodingly
        !           407:                 * Perfectionists would recalculate the exact delay
        !           408:                 * and adjust accordingly...
        !           409:                 */
        !           410:                if (lon > 7000 && lon < 14000) {
        !           411:                        if (lon < 10000) {
        !           412:                                new_station = GOES_EAST;
        !           413:                                label = "EAST";
        !           414:                        } else {
        !           415:                                new_station = GOES_WEST;
        !           416:                                label = "WEST";
        !           417:                        }
        !           418:                                
        !           419:                        if (new_station != up->station) {
        !           420:                                double dtemp;
        !           421: 
        !           422:                                dtemp = pp->fudgetime1;
        !           423:                                pp->fudgetime1 = pp->fudgetime2;
        !           424:                                pp->fudgetime2 = dtemp;
        !           425:                                up->station = new_station;
        !           426:                        }
        !           427:                }
        !           428:                else {
        !           429:                        /*refclock_report(peer, CEVNT_BADREPLY);*/
        !           430:                        label = "UNKNOWN";
        !           431:                }
        !           432:                true_debug(peer, "GOES: station %s\n", label);
        !           433:                true_doevent(peer, e_Satellite);
        !           434:                return;
        !           435:        }
        !           436: 
        !           437:        /*
        !           438:         * Timecode: "Fnn"
        !           439:         * (from TM/TMD clock when it wants to tell us what it's up to.)
        !           440:         */
        !           441:        if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
        !           442:                switch (i) {
        !           443:                    case 50:
        !           444:                        true_doevent(peer, e_F50);
        !           445:                        break;
        !           446:                    case 51:
        !           447:                        true_doevent(peer, e_F51);
        !           448:                        break;
        !           449:                    default:
        !           450:                        true_debug(peer, "got F%02d - ignoring\n", i);
        !           451:                        break;
        !           452:                }
        !           453:                return;
        !           454:        }
        !           455: 
        !           456:        /*
        !           457:         * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
        !           458:         * (from a TM/TMD/XL clock during initialization.)
        !           459:         */
        !           460:        if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
        !           461:            strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
        !           462:                true_doevent(peer, e_F18);
        !           463:                NLOG(NLOG_CLOCKSTATUS) {
        !           464:                        msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
        !           465:                }
        !           466:                return;
        !           467:        }
        !           468: 
        !           469:        /*
        !           470:         * Timecode: "N03726428W12209421+000033"
        !           471:         *                      1         2
        !           472:         *            0123456789012345678901234
        !           473:         * (from a TCU during initialization)
        !           474:         */
        !           475:        if ((pp->a_lastcode[0] == 'N' || pp->a_lastcode[0] == 'S') &&
        !           476:            (pp->a_lastcode[9] == 'W' || pp->a_lastcode[9] == 'E') &&
        !           477:            pp->a_lastcode[18] == '+') {
        !           478:                true_doevent(peer, e_Location);
        !           479:                NLOG(NLOG_CLOCKSTATUS) {
        !           480:                        msyslog(LOG_INFO, "TCU-800: %s", pp->a_lastcode);
        !           481:                }
        !           482:                return;
        !           483:        }
        !           484:        /*
        !           485:         * Timecode: "ddd:hh:mm:ssQ"
        !           486:         * (from all clocks supported by this driver.)
        !           487:         */
        !           488:        if (pp->a_lastcode[3] == ':' &&
        !           489:            pp->a_lastcode[6] == ':' &&
        !           490:            pp->a_lastcode[9] == ':' &&
        !           491:            sscanf(pp->a_lastcode, "%3d:%2d:%2d:%2d%c",
        !           492:                   &pp->day, &pp->hour, &pp->minute,
        !           493:                   &pp->second, &synced) == 5) {
        !           494: 
        !           495:                /*
        !           496:                 * Adjust the synchronize indicator according to timecode
        !           497:                 * say were OK, and then say not if we really are not OK
        !           498:                 */
        !           499:                if (synced == '>' || synced == '#' || synced == '?'
        !           500:                    || synced == 'X')
        !           501:                    pp->leap = LEAP_NOTINSYNC;
        !           502:                else
        !           503:                     pp->leap = LEAP_NOWARNING;
        !           504: 
        !           505:                true_doevent(peer, e_TS);
        !           506: 
        !           507: #ifdef CLOCK_PPS720
        !           508:                /* If it's taken more than 65ms to get here, we'll lose. */
        !           509:                if ((pp->sloppyclockflag & CLK_FLAG4) && up->pcl720init) {
        !           510:                        l_fp   off;
        !           511: 
        !           512: #ifdef CLOCK_ATOM
        !           513:                        /*
        !           514:                         * find out what time it really is. Include
        !           515:                         * the count from the PCL720
        !           516:                         */
        !           517:                        if (!clocktime(pp->day, pp->hour, pp->minute, 
        !           518:                                       pp->second, GMT, pp->lastrec.l_ui, 
        !           519:                                       &pp->yearstart, &off.l_ui)) {
        !           520:                                refclock_report(peer, CEVNT_BADTIME);
        !           521:                                return;
        !           522:                        }
        !           523:                        off.l_uf = 0;
        !           524: #endif
        !           525: 
        !           526:                        pp->usec = true_sample720();
        !           527: #ifdef CLOCK_ATOM
        !           528:                        TVUTOTSF(pp->usec, off.l_uf);
        !           529: #endif
        !           530: 
        !           531:                        /*
        !           532:                         * Stomp all over the timestamp that was pulled out
        !           533:                         * of the input stream. It's irrelevant since we've
        !           534:                         * adjusted the input time to reflect now (via pp->usec)
        !           535:                         * rather than when the data was collected.
        !           536:                         */
        !           537:                        get_systime(&pp->lastrec);
        !           538: #ifdef CLOCK_ATOM
        !           539:                        /*
        !           540:                         * Create a true offset for feeding to pps_sample()
        !           541:                         */
        !           542:                        L_SUB(&off, &pp->lastrec);
        !           543: 
        !           544:                        pps_sample(peer, &off);
        !           545: #endif
        !           546:                        true_debug(peer, "true_sample720: %luus\n", pp->usec);
        !           547:                }
        !           548: #endif
        !           549: 
        !           550:                /*
        !           551:                 * The clock will blurt a timecode every second but we only
        !           552:                 * want one when polled.  If we havn't been polled, bail out.
        !           553:                 */
        !           554:                if (!up->polled)
        !           555:                    return;
        !           556: 
        !           557:                true_doevent(peer, e_Poll);
        !           558:                if (!refclock_process(pp)) {
        !           559:                        refclock_report(peer, CEVNT_BADTIME);
        !           560:                        return;
        !           561:                }
        !           562:                /*
        !           563:                 * If clock is good we send a NOMINAL message so that
        !           564:                 * any previous BAD messages are nullified
        !           565:                 */
        !           566:                 pp->lastref = pp->lastrec;
        !           567:                refclock_receive(peer);
        !           568:                refclock_report(peer, CEVNT_NOMINAL);
        !           569: 
        !           570:                /*
        !           571:                 * We have succedded in answering the poll.
        !           572:                 * Turn off the flag and return
        !           573:                 */
        !           574:                up->polled = 0;
        !           575: 
        !           576:                return;
        !           577:        }
        !           578: 
        !           579:        /*
        !           580:         * No match to known timecodes, report failure and return
        !           581:         */
        !           582:        refclock_report(peer, CEVNT_BADREPLY);
        !           583:        return;
        !           584: }
        !           585: 
        !           586: 
        !           587: /*
        !           588:  * true_send - time to send the clock a signal to cough up a time sample
        !           589:  */
        !           590: static void
        !           591: true_send(
        !           592:        struct peer *peer,
        !           593:        const char *cmd
        !           594:        )
        !           595: {
        !           596:        struct refclockproc *pp;
        !           597: 
        !           598:        pp = peer->procptr;
        !           599:        if (!(pp->sloppyclockflag & CLK_FLAG1)) {
        !           600:                register int len = strlen(cmd);
        !           601: 
        !           602:                true_debug(peer, "Send '%s'\n", cmd);
        !           603:                if (write(pp->io.fd, cmd, (unsigned)len) != len)
        !           604:                    refclock_report(peer, CEVNT_FAULT);
        !           605:                else
        !           606:                    pp->polls++;
        !           607:        }
        !           608: }
        !           609: 
        !           610: 
        !           611: /*
        !           612:  * state machine for initializing and controlling a clock
        !           613:  */
        !           614: static void
        !           615: true_doevent(
        !           616:        struct peer *peer,
        !           617:        enum true_event event
        !           618:        )
        !           619: {
        !           620:        struct true_unit *up;
        !           621:        struct refclockproc *pp;
        !           622: 
        !           623:        pp = peer->procptr;
        !           624:        up = (struct true_unit *)pp->unitptr;
        !           625:        if (event != e_TS) {
        !           626:                NLOG(NLOG_CLOCKSTATUS) {
        !           627:                        msyslog(LOG_INFO, "TRUE: clock %s, state %s, event %s",
        !           628:                                typeStr(up->type),
        !           629:                                stateStr(up->state),
        !           630:                                eventStr(event));
        !           631:                }
        !           632:        }
        !           633:        true_debug(peer, "clock %s, state %s, event %s\n",
        !           634:                   typeStr(up->type), stateStr(up->state), eventStr(event));
        !           635:        switch (up->type) {
        !           636:            case t_goes:
        !           637:                switch (event) {
        !           638:                    case e_Init:        /* FALLTHROUGH */
        !           639:                    case e_Satellite:
        !           640:                        /*
        !           641:                         * Switch back to on-second time codes and return.
        !           642:                         */
        !           643:                        true_send(peer, "C");
        !           644:                        up->state = s_Start;
        !           645:                        break;
        !           646:                    case e_Poll:
        !           647:                        /*
        !           648:                         * After each poll, check the station (satellite).
        !           649:                         */
        !           650:                        true_send(peer, "P");
        !           651:                        /* No state change needed. */
        !           652:                        break;
        !           653:                    default:
        !           654:                        break;
        !           655:                }
        !           656:                /* FALLTHROUGH */
        !           657:            case t_omega:
        !           658:                switch (event) {
        !           659:                    case e_Init:
        !           660:                        true_send(peer, "C");
        !           661:                        up->state = s_Start;
        !           662:                        break;
        !           663:                    case e_TS:
        !           664:                        if (up->state != s_Start && up->state != s_Auto) {
        !           665:                                true_send(peer, "\03\r");
        !           666:                                break;
        !           667:                        }
        !           668:                        up->state = s_Auto;
        !           669:                        break;
        !           670:                    default:
        !           671:                        break;
        !           672:                }
        !           673:                break;
        !           674:            case t_tm:
        !           675:                switch (event) {
        !           676:                    case e_Init:
        !           677:                        true_send(peer, "F18\r");
        !           678:                        up->state = s_Init;
        !           679:                        break;
        !           680:                    case e_F18:
        !           681:                        true_send(peer, "F50\r");
        !           682:                        up->state = s_F18;
        !           683:                        break;
        !           684:                    case e_F50:
        !           685:                        true_send(peer, "F51\r");
        !           686:                        up->state = s_F50;
        !           687:                        break;
        !           688:                    case e_F51:
        !           689:                        true_send(peer, "F08\r");
        !           690:                        up->state = s_Start;
        !           691:                        break;
        !           692:                    case e_TS:
        !           693:                        if (up->state != s_Start && up->state != s_Auto) {
        !           694:                                true_send(peer, "\03\r");
        !           695:                                break;
        !           696:                        }
        !           697:                        up->state = s_Auto;
        !           698:                        break;
        !           699:                    default:
        !           700:                        break;
        !           701:                }
        !           702:                break;
        !           703:            case t_tcu:
        !           704:                switch (event) {
        !           705:                    case e_Init:
        !           706:                        true_send(peer, "MD3\r");       /* GPS Synch'd Gen. */
        !           707:                        true_send(peer, "TSU\r");       /* UTC, not GPS. */
        !           708:                        true_send(peer, "AU\r");        /* Auto Timestamps. */
        !           709:                        up->state = s_Start;
        !           710:                        break;
        !           711:                    case e_TS:
        !           712:                        if (up->state != s_Start && up->state != s_Auto) {
        !           713:                                true_send(peer, "\03\r");
        !           714:                                break;
        !           715:                        }
        !           716:                        up->state = s_Auto;
        !           717:                        break;
        !           718:                    default:
        !           719:                        break;
        !           720:                }
        !           721:                break;
        !           722:            case t_unknown:
        !           723:                switch (up->state) {
        !           724:                    case s_Base:
        !           725:                        if (event != e_Init)
        !           726:                            abort();
        !           727:                        true_send(peer, "P\r");
        !           728:                        up->state = s_InqGOES;
        !           729:                        break;
        !           730:                    case s_InqGOES:
        !           731:                        switch (event) {
        !           732:                            case e_Satellite:
        !           733:                                up->type = t_goes;
        !           734:                                true_doevent(peer, e_Init);
        !           735:                                break;
        !           736:                            case e_Init:        /*FALLTHROUGH*/
        !           737:                            case e_Huh: /*FALLTHROUGH*/
        !           738:                            case e_TS:
        !           739:                                up->state = s_InqOmega;
        !           740:                                true_send(peer, "C\r");
        !           741:                                break;
        !           742:                            default:
        !           743:                                abort();
        !           744:                        }
        !           745:                        break;
        !           746:                    case s_InqOmega:
        !           747:                        switch (event) {
        !           748:                            case e_TS:
        !           749:                                up->type = t_omega;
        !           750:                                up->state = s_Auto;     /* Inq side-effect. */
        !           751:                                break;
        !           752:                            case e_Init:        /*FALLTHROUGH*/
        !           753:                            case e_Huh:
        !           754:                                up->state = s_InqTM;
        !           755:                                true_send(peer, "F18\r");
        !           756:                                break;
        !           757:                            default:
        !           758:                                abort();
        !           759:                        }
        !           760:                        break;
        !           761:                    case s_InqTM:
        !           762:                        switch (event) {
        !           763:                            case e_F18:
        !           764:                                up->type = t_tm;
        !           765:                                true_doevent(peer, e_Init);
        !           766:                                break;
        !           767:                            case e_Init:        /*FALLTHROUGH*/
        !           768:                            case e_Huh:
        !           769:                                true_send(peer, "PO\r");
        !           770:                                up->state = s_InqTCU;
        !           771:                                break;
        !           772:                            default:
        !           773:                                abort();
        !           774:                        }
        !           775:                        break;
        !           776:                    case s_InqTCU:
        !           777:                        switch (event) {
        !           778:                            case e_Location:
        !           779:                                up->type = t_tcu;
        !           780:                                true_doevent(peer, e_Init);
        !           781:                                break;
        !           782:                            case e_Init:        /*FALLTHROUGH*/
        !           783:                            case e_Huh:
        !           784:                                up->state = s_Base;
        !           785:                                sleep(1);       /* XXX */
        !           786:                                break;
        !           787:                            default:
        !           788:                                abort();
        !           789:                        }
        !           790:                        break;
        !           791:                        /*
        !           792:                         * An expedient hack to prevent lint complaints,
        !           793:                         * these don't actually need to be used here...
        !           794:                         */
        !           795:                    case s_Init:
        !           796:                    case s_F18:
        !           797:                    case s_F50:
        !           798:                    case s_Start:
        !           799:                    case s_Auto:
        !           800:                    case s_Max:
        !           801:                        msyslog(LOG_INFO, "TRUE: state %s is unexpected!", stateStr(up->state));
        !           802:                }
        !           803:                break;
        !           804:            default:
        !           805:                abort();
        !           806:                /* NOTREACHED */
        !           807:        }
        !           808: 
        !           809: #ifdef CLOCK_PPS720
        !           810:        if ((pp->sloppyclockflag & CLK_FLAG4) && !up->pcl720init) {
        !           811:                /* Make counter trigger on gate0, count down from 65535. */
        !           812:                pcl720_load(PCL720_IOB, PCL720_CTR, i8253_oneshot, 65535);
        !           813:                /*
        !           814:                 * (These constants are OK since
        !           815:                 * they represent hardware maximums.)
        !           816:                 */
        !           817:                NLOG(NLOG_CLOCKINFO) {
        !           818:                        msyslog(LOG_NOTICE, "PCL-720 initialized");
        !           819:                }
        !           820:                up->pcl720init++;
        !           821:        }
        !           822: #endif
        !           823: 
        !           824: 
        !           825: }
        !           826: 
        !           827: /*
        !           828:  * true_poll - called by the transmit procedure
        !           829:  */
        !           830: static void
        !           831: true_poll(
        !           832:        int unit,
        !           833:        struct peer *peer
        !           834:        )
        !           835: {
        !           836:        struct true_unit *up;
        !           837:        struct refclockproc *pp;
        !           838: 
        !           839:        /*
        !           840:         * You don't need to poll this clock.  It puts out timecodes
        !           841:         * once per second.  If asked for a timestamp, take note.
        !           842:         * The next time a timecode comes in, it will be fed back.
        !           843:         */
        !           844:        pp = peer->procptr;
        !           845:        up = (struct true_unit *)pp->unitptr;
        !           846:        if (up->pollcnt > 0)
        !           847:            up->pollcnt--;
        !           848:        else {
        !           849:                true_doevent(peer, e_Init);
        !           850:                refclock_report(peer, CEVNT_TIMEOUT);
        !           851:        }
        !           852: 
        !           853:        /*
        !           854:         * polled every 64 seconds. Ask true_receive to hand in a
        !           855:         * timestamp.
        !           856:         */
        !           857:        up->polled = 1;
        !           858:        pp->polls++;
        !           859: }
        !           860: 
        !           861: #ifdef CLOCK_PPS720
        !           862: /*
        !           863:  * true_sample720 - sample the PCL-720
        !           864:  */
        !           865: static u_long
        !           866: true_sample720(void)
        !           867: {
        !           868:        unsigned long f;
        !           869: 
        !           870:        /* We wire the PCL-720's 8253.OUT0 to bit 0 of connector 3.
        !           871:         * If it is not being held low now, we did not get called
        !           872:         * within 65535us.
        !           873:         */
        !           874:        if (inb(pcl720_data_16_23(PCL720_IOB)) & 0x01) {
        !           875:                NLOG(NLOG_CLOCKINFO) {
        !           876:                        msyslog(LOG_NOTICE, "PCL-720 out of synch");
        !           877:                }
        !           878:                return (0);
        !           879:        }
        !           880:        f = (65536 - pcl720_read(PCL720_IOB, PCL720_CTR));
        !           881: #ifdef PPS720_DEBUG
        !           882:        msyslog(LOG_DEBUG, "PCL-720: %luus", f);
        !           883: #endif
        !           884:        return (f);
        !           885: }
        !           886: #endif
        !           887: 
        !           888: #else
        !           889: int refclock_true_bs;
        !           890: #endif /* REFCLOCK */

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