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