Annotation of embedaddon/ntp/clockstuff/chutest.c, revision 1.1

1.1     ! misho       1: /* chutest.c,v 3.1 1993/07/06 01:05:21 jbj Exp
        !             2:  * chutest - test the CHU clock
        !             3:  */
        !             4: 
        !             5: #include <stdio.h>
        !             6: #include <sys/types.h>
        !             7: #include <sys/socket.h>
        !             8: #include <netinet/in.h>
        !             9: #include <sys/ioctl.h>
        !            10: #include <sys/time.h>
        !            11: #include <sys/file.h>
        !            12: #include <sgtty.h>
        !            13: 
        !            14: #include "../include/ntp_fp.h"
        !            15: #include "../include/ntp.h"
        !            16: #include "../include/ntp_unixtime.h"
        !            17: 
        !            18: #ifdef CHULDISC
        !            19: #ifdef STREAM
        !            20: # ifdef HAVE_SYS_CHUDEFS_H
        !            21: #include <sys/chudefs.h>
        !            22: #endif
        !            23: #include <stropts.h>
        !            24: #endif
        !            25: #endif
        !            26: 
        !            27: #ifdef CHULDISC
        !            28: # ifdef HAVE_SYS_CHUDEFS_H
        !            29: #include <sys/chudefs.h>
        !            30: #endif
        !            31: #endif
        !            32: 
        !            33: #ifndef CHULDISC
        !            34: #ifndef STREAM
        !            35: #define        NCHUCHARS       (10)
        !            36: 
        !            37: struct chucode {
        !            38:        u_char codechars[NCHUCHARS];    /* code characters */
        !            39:        u_char ncodechars;              /* number of code characters */
        !            40:        u_char chustatus;               /* not used currently */
        !            41:        struct timeval codetimes[NCHUCHARS];    /* arrival times */
        !            42: };
        !            43: #endif
        !            44: #endif
        !            45: 
        !            46: #define        STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
        !            47: 
        !            48: char *progname;
        !            49: int debug;
        !            50: 
        !            51: int dofilter = 0;      /* set to 1 when we should run filter algorithm */
        !            52: int showtimes = 0;     /* set to 1 when we should show char arrival times */
        !            53: int doprocess = 0;     /* set to 1 when we do processing analogous to driver */
        !            54: #ifdef CHULDISC
        !            55: int usechuldisc = 0;   /* set to 1 when CHU line discipline should be used */
        !            56: #endif
        !            57: #ifdef STREAM
        !            58: int usechuldisc = 0;   /* set to 1 when CHU line discipline should be used */
        !            59: #endif
        !            60: 
        !            61: struct timeval lasttv;
        !            62: struct chucode chudata;
        !            63: 
        !            64: extern u_long ustotslo[];
        !            65: extern u_long ustotsmid[];
        !            66: extern u_long ustotshi[];
        !            67: 
        !            68: /*
        !            69:  * main - parse arguments and handle options
        !            70:  */
        !            71: int
        !            72: main(
        !            73:        int argc,
        !            74:        char *argv[]
        !            75:        )
        !            76: {
        !            77:        int c;
        !            78:        int errflg = 0;
        !            79:        extern int ntp_optind;
        !            80:        extern char *ntp_optarg;
        !            81:        void init_chu();
        !            82: 
        !            83:        progname = argv[0];
        !            84:        while ((c = ntp_getopt(argc, argv, "cdfpt")) != EOF)
        !            85:            switch (c) {
        !            86:                case 'c':
        !            87: #ifdef STREAM
        !            88:                    usechuldisc = 1;
        !            89:                    break;
        !            90: #endif
        !            91: #ifdef CHULDISC
        !            92:                    usechuldisc = 1;
        !            93:                    break;
        !            94: #endif
        !            95: #ifndef STREAM
        !            96: #ifndef CHULDISC
        !            97:                    (void) fprintf(stderr,
        !            98:                                   "%s: CHU line discipline not available on this machine\n",
        !            99:                                   progname);
        !           100:                    exit(2);
        !           101: #endif
        !           102: #endif
        !           103:                case 'd':
        !           104:                    ++debug;
        !           105:                    break;
        !           106:                case 'f':
        !           107:                    dofilter = 1;
        !           108:                    break;
        !           109:                case 'p':
        !           110:                    doprocess = 1;
        !           111:                case 't':
        !           112:                    showtimes = 1;
        !           113:                    break;
        !           114:                default:
        !           115:                    errflg++;
        !           116:                    break;
        !           117:            }
        !           118:        if (errflg || ntp_optind+1 != argc) {
        !           119: #ifdef STREAM
        !           120:                (void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
        !           121:                               progname);
        !           122: #endif
        !           123: #ifdef CHULDISC
        !           124:                (void) fprintf(stderr, "usage: %s [-dft] tty_device\n",
        !           125:                               progname);
        !           126: #endif
        !           127: #ifndef STREAM
        !           128: #ifndef CHULDISC
        !           129:                (void) fprintf(stderr, "usage: %s [-cdft] tty_device\n",
        !           130:                               progname);
        !           131: #endif
        !           132: #endif
        !           133:                exit(2);
        !           134:        }
        !           135: 
        !           136:        (void) gettimeofday(&lasttv, (struct timezone *)0);
        !           137:        c = openterm(argv[ntp_optind]);
        !           138:        init_chu();
        !           139: #ifdef STREAM
        !           140:        if (usechuldisc)
        !           141:            process_ldisc(c);
        !           142:        else
        !           143: #endif
        !           144: #ifdef CHULDISC
        !           145:            if (usechuldisc)
        !           146:                process_ldisc(c);
        !           147:            else
        !           148: #endif
        !           149:                process_raw(c);
        !           150:        /*NOTREACHED*/
        !           151: }
        !           152: 
        !           153: 
        !           154: /*
        !           155:  * openterm - open a port to the CHU clock
        !           156:  */
        !           157: int
        !           158: openterm(
        !           159:        char *dev
        !           160:        )
        !           161: {
        !           162:        int s;
        !           163:        struct sgttyb ttyb;
        !           164: 
        !           165:        if (debug)
        !           166:            (void) fprintf(stderr, "Doing open...");
        !           167:        if ((s = open(dev, O_RDONLY, 0777)) < 0)
        !           168:            error("open(%s)", dev, "");
        !           169:        if (debug)
        !           170:            (void) fprintf(stderr, "open okay\n");
        !           171: 
        !           172:        if (debug)
        !           173:            (void) fprintf(stderr, "Setting exclusive use...");
        !           174:        if (ioctl(s, TIOCEXCL, (char *)0) < 0)
        !           175:            error("ioctl(TIOCEXCL)", "", "");
        !           176:        if (debug)
        !           177:            (void) fprintf(stderr, "done\n");
        !           178:        
        !           179:        ttyb.sg_ispeed = ttyb.sg_ospeed = B300;
        !           180:        ttyb.sg_erase = ttyb.sg_kill = 0;
        !           181:        ttyb.sg_flags = EVENP|ODDP|RAW;
        !           182:        if (debug)
        !           183:            (void) fprintf(stderr, "Setting baud rate et al...");
        !           184:        if (ioctl(s, TIOCSETP, (char *)&ttyb) < 0)
        !           185:            error("ioctl(TIOCSETP, raw)", "", "");
        !           186:        if (debug)
        !           187:            (void) fprintf(stderr, "done\n");
        !           188: 
        !           189: #ifdef CHULDISC
        !           190:        if (usechuldisc) {
        !           191:                int ldisc;
        !           192: 
        !           193:                if (debug)
        !           194:                    (void) fprintf(stderr, "Switching to CHU ldisc...");
        !           195:                ldisc = CHULDISC;
        !           196:                if (ioctl(s, TIOCSETD, (char *)&ldisc) < 0)
        !           197:                    error("ioctl(TIOCSETD, CHULDISC)", "", "");
        !           198:                if (debug)
        !           199:                    (void) fprintf(stderr, "okay\n");
        !           200:        }
        !           201: #endif
        !           202: #ifdef STREAM
        !           203:        if (usechuldisc) {
        !           204: 
        !           205:                if (debug)
        !           206:                    (void) fprintf(stderr, "Poping off streams...");
        !           207:                while (ioctl(s, I_POP, 0) >=0) ;
        !           208:                if (debug)
        !           209:                    (void) fprintf(stderr, "okay\n");
        !           210:                if (debug)
        !           211:                    (void) fprintf(stderr, "Pushing CHU stream...");
        !           212:                if (ioctl(s, I_PUSH, "chu") < 0)
        !           213:                    error("ioctl(I_PUSH, \"chu\")", "", "");
        !           214:                if (debug)
        !           215:                    (void) fprintf(stderr, "okay\n");
        !           216:        }
        !           217: #endif
        !           218:        return s;
        !           219: }
        !           220: 
        !           221: 
        !           222: /*
        !           223:  * process_raw - process characters in raw mode
        !           224:  */
        !           225: int
        !           226: process_raw(
        !           227:        int s
        !           228:        )
        !           229: {
        !           230:        u_char c;
        !           231:        int n;
        !           232:        struct timeval tv;
        !           233:        struct timeval difftv;
        !           234: 
        !           235:        while ((n = read(s, &c, sizeof(char))) > 0) {
        !           236:                (void) gettimeofday(&tv, (struct timezone *)0);
        !           237:                if (dofilter)
        !           238:                    raw_filter((unsigned int)c, &tv);
        !           239:                else {
        !           240:                        difftv.tv_sec = tv.tv_sec - lasttv.tv_sec;
        !           241:                        difftv.tv_usec = tv.tv_usec - lasttv.tv_usec;
        !           242:                        if (difftv.tv_usec < 0) {
        !           243:                                difftv.tv_sec--;
        !           244:                                difftv.tv_usec += 1000000;
        !           245:                        }
        !           246:                        (void) printf("%02x\t%lu.%06lu\t%lu.%06lu\n",
        !           247:                                      c, tv.tv_sec, tv.tv_usec, difftv.tv_sec,
        !           248:                                      difftv.tv_usec);
        !           249:                        lasttv = tv;
        !           250:                }
        !           251:        }
        !           252: 
        !           253:        if (n == 0) {
        !           254:                (void) fprintf(stderr, "%s: zero returned on read\n", progname);
        !           255:                exit(1);
        !           256:        } else
        !           257:            error("read()", "", "");
        !           258: }
        !           259: 
        !           260: 
        !           261: /*
        !           262:  * raw_filter - run the line discipline filter over raw data
        !           263:  */
        !           264: int
        !           265: raw_filter(
        !           266:        unsigned int c,
        !           267:        struct timeval *tv
        !           268:        )
        !           269: {
        !           270:        static struct timeval diffs[10] = { 0 };
        !           271:        struct timeval diff;
        !           272:        l_fp ts;
        !           273:        void chufilter();
        !           274: 
        !           275:        if ((c & 0xf) > 9 || ((c>>4)&0xf) > 9) {
        !           276:                if (debug)
        !           277:                    (void) fprintf(stderr,
        !           278:                                   "character %02x failed BCD test\n");
        !           279:                chudata.ncodechars = 0;
        !           280:                return;
        !           281:        }
        !           282: 
        !           283:        if (chudata.ncodechars > 0) {
        !           284:                diff.tv_sec = tv->tv_sec
        !           285:                        - chudata.codetimes[chudata.ncodechars].tv_sec;
        !           286:                diff.tv_usec = tv->tv_usec
        !           287:                        - chudata.codetimes[chudata.ncodechars].tv_usec;
        !           288:                if (diff.tv_usec < 0) {
        !           289:                        diff.tv_sec--;
        !           290:                        diff.tv_usec += 1000000;
        !           291:                } /*
        !           292:                    if (diff.tv_sec != 0 || diff.tv_usec > 900000) {
        !           293:                    if (debug)
        !           294:                    (void) fprintf(stderr,
        !           295:                    "character %02x failed time test\n");
        !           296:                    chudata.ncodechars = 0;
        !           297:                    return;
        !           298:                    } */
        !           299:        }
        !           300: 
        !           301:        chudata.codechars[chudata.ncodechars] = c;
        !           302:        chudata.codetimes[chudata.ncodechars] = *tv;
        !           303:        if (chudata.ncodechars > 0)
        !           304:            diffs[chudata.ncodechars] = diff;
        !           305:        if (++chudata.ncodechars == 10) {
        !           306:                if (doprocess) {
        !           307:                        TVTOTS(&chudata.codetimes[NCHUCHARS-1], &ts);
        !           308:                        ts.l_ui += JAN_1970;
        !           309:                        chufilter(&chudata, &chudata.codetimes[NCHUCHARS-1]);
        !           310:                } else {
        !           311:                        register int i;
        !           312: 
        !           313:                        for (i = 0; i < chudata.ncodechars; i++) {
        !           314:                                (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
        !           315:                                              chudata.codechars[i] & 0xf,
        !           316:                                              (chudata.codechars[i] >>4 ) & 0xf,
        !           317:                                              chudata.codetimes[i].tv_sec,
        !           318:                                              chudata.codetimes[i].tv_usec,
        !           319:                                              diffs[i].tv_sec, diffs[i].tv_usec);
        !           320:                        }
        !           321:                }
        !           322:                chudata.ncodechars = 0;
        !           323:        }
        !           324: }
        !           325: 
        !           326: 
        !           327: /* #ifdef CHULDISC*/
        !           328: /*
        !           329:  * process_ldisc - process line discipline
        !           330:  */
        !           331: int
        !           332: process_ldisc(
        !           333:        int s
        !           334:        )
        !           335: {
        !           336:        struct chucode chu;
        !           337:        int n;
        !           338:        register int i;
        !           339:        struct timeval diff;
        !           340:        l_fp ts;
        !           341:        void chufilter();
        !           342: 
        !           343:        while ((n = read(s, (char *)&chu, sizeof chu)) > 0) {
        !           344:                if (n != sizeof chu) {
        !           345:                        (void) fprintf(stderr, "Expected %d, got %d\n",
        !           346:                                       sizeof chu, n);
        !           347:                        continue;
        !           348:                }
        !           349: 
        !           350:                if (doprocess) {
        !           351:                        TVTOTS(&chu.codetimes[NCHUCHARS-1], &ts);
        !           352:                        ts.l_ui += JAN_1970;
        !           353:                        chufilter(&chu, &ts);
        !           354:                } else {
        !           355:                        for (i = 0; i < NCHUCHARS; i++) {
        !           356:                                if (i == 0)
        !           357:                                    diff.tv_sec = diff.tv_usec = 0;
        !           358:                                else {
        !           359:                                        diff.tv_sec = chu.codetimes[i].tv_sec
        !           360:                                                - chu.codetimes[i-1].tv_sec;
        !           361:                                        diff.tv_usec = chu.codetimes[i].tv_usec
        !           362:                                                - chu.codetimes[i-1].tv_usec;
        !           363:                                        if (diff.tv_usec < 0) {
        !           364:                                                diff.tv_sec--;
        !           365:                                                diff.tv_usec += 1000000;
        !           366:                                        }
        !           367:                                }
        !           368:                                (void) printf("%x%x\t%lu.%06lu\t%lu.%06lu\n",
        !           369:                                              chu.codechars[i] & 0xf, (chu.codechars[i]>>4)&0xf,
        !           370:                                              chu.codetimes[i].tv_sec, chu.codetimes[i].tv_usec,
        !           371:                                              diff.tv_sec, diff.tv_usec);
        !           372:                        }
        !           373:                }
        !           374:        }
        !           375:        if (n == 0) {
        !           376:                (void) fprintf(stderr, "%s: zero returned on read\n", progname);
        !           377:                exit(1);
        !           378:        } else
        !           379:            error("read()", "", "");
        !           380: }
        !           381: /*#endif*/
        !           382: 
        !           383: 
        !           384: /*
        !           385:  * error - print an error message
        !           386:  */
        !           387: void
        !           388: error(
        !           389:        char *fmt,
        !           390:        char *s1,
        !           391:        char *s2
        !           392:        )
        !           393: {
        !           394:        (void) fprintf(stderr, "%s: ", progname);
        !           395:        (void) fprintf(stderr, fmt, s1, s2);
        !           396:        (void) fprintf(stderr, ": ");
        !           397:        perror("");
        !           398:        exit(1);
        !           399: }
        !           400: 
        !           401: /*
        !           402:  * Definitions
        !           403:  */
        !           404: #define        MAXUNITS        4       /* maximum number of CHU units permitted */
        !           405: #define        CHUDEV  "/dev/chu%d"    /* device we open.  %d is unit number */
        !           406: #define        NCHUCODES       9       /* expect 9 CHU codes per minute */
        !           407: 
        !           408: /*
        !           409:  * When CHU is operating optimally we want the primary clock distance
        !           410:  * to come out at 300 ms.  Thus, peer.distance in the CHU peer structure
        !           411:  * is set to 290 ms and we compute delays which are at least 10 ms long.
        !           412:  * The following are 290 ms and 10 ms expressed in u_fp format
        !           413:  */
        !           414: #define        CHUDISTANCE     0x00004a3d
        !           415: #define        CHUBASEDELAY    0x0000028f
        !           416: 
        !           417: /*
        !           418:  * To compute a quality for the estimate (a pseudo delay) we add a
        !           419:  * fixed 10 ms for each missing code in the minute and add to this
        !           420:  * the sum of the differences between the remaining offsets and the
        !           421:  * estimated sample offset.
        !           422:  */
        !           423: #define        CHUDELAYPENALTY 0x0000028f
        !           424: 
        !           425: /*
        !           426:  * Other constant stuff
        !           427:  */
        !           428: #define        CHUPRECISION    (-9)            /* what the heck */
        !           429: #define        CHUREFID        "CHU\0"
        !           430: 
        !           431: /*
        !           432:  * Default fudge factors
        !           433:  */
        !           434: #define        DEFPROPDELAY    0x00624dd3      /* 0.0015 seconds, 1.5 ms */
        !           435: #define        DEFFILTFUDGE    0x000d1b71      /* 0.0002 seconds, 200 us */
        !           436: 
        !           437: /*
        !           438:  * Hacks to avoid excercising the multiplier.  I have no pride.
        !           439:  */
        !           440: #define        MULBY10(x)      (((x)<<3) + ((x)<<1))
        !           441: #define        MULBY60(x)      (((x)<<6) - ((x)<<2))   /* watch overflow */
        !           442: #define        MULBY24(x)      (((x)<<4) + ((x)<<3))
        !           443: 
        !           444: /*
        !           445:  * Constants for use when multiplying by 0.1.  ZEROPTONE is 0.1
        !           446:  * as an l_fp fraction, NZPOBITS is the number of significant bits
        !           447:  * in ZEROPTONE.
        !           448:  */
        !           449: #define        ZEROPTONE       0x1999999a
        !           450: #define        NZPOBITS        29
        !           451: 
        !           452: /*
        !           453:  * The CHU table.  This gives the expected time of arrival of each
        !           454:  * character after the on-time second and is computed as follows:
        !           455:  * The CHU time code is sent at 300 bps.  Your average UART will
        !           456:  * synchronize at the edge of the start bit and will consider the
        !           457:  * character complete at the center of the first stop bit, i.e.
        !           458:  * 0.031667 ms later.  Thus the expected time of each interrupt
        !           459:  * is the start bit time plus 0.031667 seconds.  These times are
        !           460:  * in chutable[].  To this we add such things as propagation delay
        !           461:  * and delay fudge factor.
        !           462:  */
        !           463: #define        CHARDELAY       0x081b4e80
        !           464: 
        !           465: static u_long chutable[NCHUCHARS] = {
        !           466:        0x2147ae14 + CHARDELAY,         /* 0.130 (exactly) */
        !           467:        0x2ac08312 + CHARDELAY,         /* 0.167 (exactly) */
        !           468:        0x34395810 + CHARDELAY,         /* 0.204 (exactly) */
        !           469:        0x3db22d0e + CHARDELAY,         /* 0.241 (exactly) */
        !           470:        0x472b020c + CHARDELAY,         /* 0.278 (exactly) */
        !           471:        0x50a3d70a + CHARDELAY,         /* 0.315 (exactly) */
        !           472:        0x5a1cac08 + CHARDELAY,         /* 0.352 (exactly) */
        !           473:        0x63958106 + CHARDELAY,         /* 0.389 (exactly) */
        !           474:        0x6d0e5604 + CHARDELAY,         /* 0.426 (exactly) */
        !           475:        0x76872b02 + CHARDELAY,         /* 0.463 (exactly) */
        !           476: };
        !           477: 
        !           478: /*
        !           479:  * Keep the fudge factors separately so they can be set even
        !           480:  * when no clock is configured.
        !           481:  */
        !           482: static l_fp propagation_delay;
        !           483: static l_fp fudgefactor;
        !           484: static l_fp offset_fudge;
        !           485: 
        !           486: /*
        !           487:  * We keep track of the start of the year, watching for changes.
        !           488:  * We also keep track of whether the year is a leap year or not.
        !           489:  * All because stupid CHU doesn't include the year in the time code.
        !           490:  */
        !           491: static u_long yearstart;
        !           492: 
        !           493: /*
        !           494:  * Imported from the timer module
        !           495:  */
        !           496: extern u_long current_time;
        !           497: extern struct event timerqueue[];
        !           498: 
        !           499: /*
        !           500:  * Time conversion tables imported from the library
        !           501:  */
        !           502: extern u_long ustotslo[];
        !           503: extern u_long ustotsmid[];
        !           504: extern u_long ustotshi[];
        !           505: 
        !           506: 
        !           507: /*
        !           508:  * init_chu - initialize internal chu driver data
        !           509:  */
        !           510: void
        !           511: init_chu(void)
        !           512: {
        !           513: 
        !           514:        /*
        !           515:         * Initialize fudge factors to default.
        !           516:         */
        !           517:        propagation_delay.l_ui = 0;
        !           518:        propagation_delay.l_uf = DEFPROPDELAY;
        !           519:        fudgefactor.l_ui = 0;
        !           520:        fudgefactor.l_uf = DEFFILTFUDGE;
        !           521:        offset_fudge = propagation_delay;
        !           522:        L_ADD(&offset_fudge, &fudgefactor);
        !           523: 
        !           524:        yearstart = 0;
        !           525: }
        !           526: 
        !           527: 
        !           528: void
        !           529: chufilter(
        !           530:        struct chucode *chuc,
        !           531:        l_fp *rtime
        !           532:        )
        !           533: {
        !           534:        register int i;
        !           535:        register u_long date_ui;
        !           536:        register u_long tmp;
        !           537:        register u_char *code;
        !           538:        int isneg;
        !           539:        int imin;
        !           540:        int imax;
        !           541:        u_long reftime;
        !           542:        l_fp off[NCHUCHARS];
        !           543:        l_fp ts;
        !           544:        int day, hour, minute, second;
        !           545:        static u_char lastcode[NCHUCHARS];
        !           546:        extern u_long calyearstart();
        !           547:        extern char *mfptoa();
        !           548:        void chu_process();
        !           549:        extern char *prettydate();
        !           550: 
        !           551:        /*
        !           552:         * We'll skip the checks made in the kernel, but assume they've
        !           553:         * been done.  This means that all characters are BCD and
        !           554:         * the intercharacter spacing isn't unreasonable.
        !           555:         */
        !           556: 
        !           557:        /*
        !           558:         * print the code
        !           559:         */
        !           560:        for (i = 0; i < NCHUCHARS; i++)
        !           561:            printf("%c%c", (chuc->codechars[i] & 0xf) + '0',
        !           562:                   ((chuc->codechars[i]>>4) & 0xf) + '0');
        !           563:        printf("\n");
        !           564: 
        !           565:        /*
        !           566:         * Format check.  Make sure the two halves match.
        !           567:         */
        !           568:        for (i = 0; i < NCHUCHARS/2; i++)
        !           569:            if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
        !           570:                    (void) printf("Bad format, halves don't match\n");
        !           571:                    return;
        !           572:            }
        !           573:        
        !           574:        /*
        !           575:         * Break out the code into the BCD nibbles.  Only need to fiddle
        !           576:         * with the first half since both are identical.  Note the first
        !           577:         * BCD character is the low order nibble, the second the high order.
        !           578:         */
        !           579:        code = lastcode;
        !           580:        for (i = 0; i < NCHUCHARS/2; i++) {
        !           581:                *code++ = chuc->codechars[i] & 0xf;
        !           582:                *code++ = (chuc->codechars[i] >> 4) & 0xf;
        !           583:        }
        !           584: 
        !           585:        /*
        !           586:         * If the first nibble isn't a 6, we're up the creek
        !           587:         */
        !           588:        code = lastcode;
        !           589:        if (*code++ != 6) {
        !           590:                (void) printf("Bad format, no 6 at start\n");
        !           591:                return;
        !           592:        }
        !           593: 
        !           594:        /*
        !           595:         * Collect the day, the hour, the minute and the second.
        !           596:         */
        !           597:        day = *code++;
        !           598:        day = MULBY10(day) + *code++;
        !           599:        day = MULBY10(day) + *code++;
        !           600:        hour = *code++;
        !           601:        hour = MULBY10(hour) + *code++;
        !           602:        minute = *code++;
        !           603:        minute = MULBY10(minute) + *code++;
        !           604:        second = *code++;
        !           605:        second = MULBY10(second) + *code++;
        !           606: 
        !           607:        /*
        !           608:         * Sanity check the day and time.  Note that this
        !           609:         * only occurs on the 31st through the 39th second
        !           610:         * of the minute.
        !           611:         */
        !           612:        if (day < 1 || day > 366
        !           613:            || hour > 23 || minute > 59
        !           614:            || second < 31 || second > 39) {
        !           615:                (void) printf("Failed date sanity check: %d %d %d %d\n",
        !           616:                              day, hour, minute, second);
        !           617:                return;
        !           618:        }
        !           619: 
        !           620:        /*
        !           621:         * Compute seconds into the year.
        !           622:         */
        !           623:        tmp = (u_long)(MULBY24((day-1)) + hour);        /* hours */
        !           624:        tmp = MULBY60(tmp) + (u_long)minute;            /* minutes */
        !           625:        tmp = MULBY60(tmp) + (u_long)second;            /* seconds */
        !           626: 
        !           627:        /*
        !           628:         * Now the fun begins.  We demand that the received time code
        !           629:         * be within CLOCK_WAYTOOBIG of the receive timestamp, but
        !           630:         * there is uncertainty about the year the timestamp is in.
        !           631:         * Use the current year start for the first check, this should
        !           632:         * work most of the time.
        !           633:         */
        !           634:        date_ui = tmp + yearstart;
        !           635:        if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
        !           636:            && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
        !           637:            goto codeokay;      /* looks good */
        !           638: 
        !           639:        /*
        !           640:         * Trouble.  Next check is to see if the year rolled over and, if
        !           641:         * so, try again with the new year's start.
        !           642:         */
        !           643:        date_ui = calyearstart(rtime->l_ui);
        !           644:        if (date_ui != yearstart) {
        !           645:                yearstart = date_ui;
        !           646:                date_ui += tmp;
        !           647:                (void) printf("time %u, code %u, difference %d\n",
        !           648:                              date_ui, rtime->l_ui, (long)date_ui-(long)rtime->l_ui);
        !           649:                if (date_ui < (rtime->l_ui + CLOCK_WAYTOOBIG)
        !           650:                    && date_ui > (rtime->l_ui - CLOCK_WAYTOOBIG))
        !           651:                    goto codeokay;      /* okay this time */
        !           652:        }
        !           653: 
        !           654:        ts.l_uf = 0;
        !           655:        ts.l_ui = yearstart;
        !           656:        printf("yearstart %s\n", prettydate(&ts));
        !           657:        printf("received %s\n", prettydate(rtime));
        !           658:        ts.l_ui = date_ui;
        !           659:        printf("date_ui %s\n", prettydate(&ts));
        !           660: 
        !           661:        /*
        !           662:         * Here we know the year start matches the current system
        !           663:         * time.  One remaining possibility is that the time code
        !           664:         * is in the year previous to that of the system time.  This
        !           665:         * is only worth checking if the receive timestamp is less
        !           666:         * than CLOCK_WAYTOOBIG seconds into the new year.
        !           667:         */
        !           668:        if ((rtime->l_ui - yearstart) < CLOCK_WAYTOOBIG) {
        !           669:                date_ui = tmp + calyearstart(yearstart - CLOCK_WAYTOOBIG);
        !           670:                if ((rtime->l_ui - date_ui) < CLOCK_WAYTOOBIG)
        !           671:                    goto codeokay;
        !           672:        }
        !           673: 
        !           674:        /*
        !           675:         * One last possibility is that the time stamp is in the year
        !           676:         * following the year the system is in.  Try this one before
        !           677:         * giving up.
        !           678:         */
        !           679:        date_ui = tmp + calyearstart(yearstart + (400*24*60*60)); /* 400 days */
        !           680:        if ((date_ui - rtime->l_ui) >= CLOCK_WAYTOOBIG) {
        !           681:                printf("Date hopelessly off\n");
        !           682:                return;         /* hopeless, let it sync to other peers */
        !           683:        }
        !           684: 
        !           685:     codeokay:
        !           686:        reftime = date_ui;
        !           687:        /*
        !           688:         * We've now got the integral seconds part of the time code (we hope).
        !           689:         * The fractional part comes from the table.  We next compute
        !           690:         * the offsets for each character.
        !           691:         */
        !           692:        for (i = 0; i < NCHUCHARS; i++) {
        !           693:                register u_long tmp2;
        !           694: 
        !           695:                off[i].l_ui = date_ui;
        !           696:                off[i].l_uf = chutable[i];
        !           697:                tmp = chuc->codetimes[i].tv_sec + JAN_1970;
        !           698:                TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2);
        !           699:                M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
        !           700:        }
        !           701: 
        !           702:        /*
        !           703:         * Here is a *big* problem.  What one would normally
        !           704:         * do here on a machine with lots of clock bits (say
        !           705:         * a Vax or the gizmo board) is pick the most positive
        !           706:         * offset and the estimate, since this is the one that
        !           707:         * is most likely suffered the smallest interrupt delay.
        !           708:         * The trouble is that the low order clock bit on an IBM
        !           709:         * RT, which is the machine I had in mind when doing this,
        !           710:         * ticks at just under the millisecond mark.  This isn't
        !           711:         * precise enough.  What we can do to improve this is to
        !           712:         * average all 10 samples and rely on the second level
        !           713:         * filtering to pick the least delayed estimate.  Trouble
        !           714:         * is, this means we have to divide a 64 bit fixed point
        !           715:         * number by 10, a procedure which really sucks.  Oh, well.
        !           716:         * First compute the sum.
        !           717:         */
        !           718:        date_ui = 0;
        !           719:        tmp = 0;
        !           720:        for (i = 0; i < NCHUCHARS; i++)
        !           721:            M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf);
        !           722:        if (M_ISNEG(date_ui, tmp))
        !           723:            isneg = 1;
        !           724:        else
        !           725:            isneg = 0;
        !           726:        
        !           727:        /*
        !           728:         * Here is a multiply-by-0.1 optimization that should apply
        !           729:         * just about everywhere.  If the magnitude of the sum
        !           730:         * is less than 9 we don't have to worry about overflow
        !           731:         * out of a 64 bit product, even after rounding.
        !           732:         */
        !           733:        if (date_ui < 9 || date_ui > 0xfffffff7) {
        !           734:                register u_long prod_ui;
        !           735:                register u_long prod_uf;
        !           736: 
        !           737:                prod_ui = prod_uf = 0;
        !           738:                /*
        !           739:                 * This code knows the low order bit in 0.1 is zero
        !           740:                 */
        !           741:                for (i = 1; i < NZPOBITS; i++) {
        !           742:                        M_LSHIFT(date_ui, tmp);
        !           743:                        if (ZEROPTONE & (1<<i))
        !           744:                            M_ADD(prod_ui, prod_uf, date_ui, tmp);
        !           745:                }
        !           746: 
        !           747:                /*
        !           748:                 * Done, round it correctly.  Prod_ui contains the
        !           749:                 * fraction.
        !           750:                 */
        !           751:                if (prod_uf & 0x80000000)
        !           752:                    prod_ui++;
        !           753:                if (isneg)
        !           754:                    date_ui = 0xffffffff;
        !           755:                else
        !           756:                    date_ui = 0;
        !           757:                tmp = prod_ui;
        !           758:                /*
        !           759:                 * date_ui is integral part, tmp is fraction.
        !           760:                 */
        !           761:        } else {
        !           762:                register u_long prod_ovr;
        !           763:                register u_long prod_ui;
        !           764:                register u_long prod_uf;
        !           765:                register u_long highbits;
        !           766: 
        !           767:                prod_ovr = prod_ui = prod_uf = 0;
        !           768:                if (isneg)
        !           769:                    highbits = 0xffffffff;      /* sign extend */
        !           770:                else
        !           771:                    highbits = 0;
        !           772:                /*
        !           773:                 * This code knows the low order bit in 0.1 is zero
        !           774:                 */
        !           775:                for (i = 1; i < NZPOBITS; i++) {
        !           776:                        M_LSHIFT3(highbits, date_ui, tmp);
        !           777:                        if (ZEROPTONE & (1<<i))
        !           778:                            M_ADD3(prod_ovr, prod_uf, prod_ui,
        !           779:                                   highbits, date_ui, tmp);
        !           780:                }
        !           781: 
        !           782:                if (prod_uf & 0x80000000)
        !           783:                    M_ADDUF(prod_ovr, prod_ui, (u_long)1);
        !           784:                date_ui = prod_ovr;
        !           785:                tmp = prod_ui;
        !           786:        }
        !           787: 
        !           788:        /*
        !           789:         * At this point we have the mean offset, with the integral
        !           790:         * part in date_ui and the fractional part in tmp.  Store
        !           791:         * it in the structure.
        !           792:         */
        !           793:        /*
        !           794:         * Add in fudge factor.
        !           795:         */
        !           796:        M_ADD(date_ui, tmp, offset_fudge.l_ui, offset_fudge.l_uf);
        !           797: 
        !           798:        /*
        !           799:         * Find the minimun and maximum offset
        !           800:         */
        !           801:        imin = imax = 0;
        !           802:        for (i = 1; i < NCHUCHARS; i++) {
        !           803:                if (L_ISGEQ(&off[i], &off[imax])) {
        !           804:                        imax = i;
        !           805:                } else if (L_ISGEQ(&off[imin], &off[i])) {
        !           806:                        imin = i;
        !           807:                }
        !           808:        }
        !           809: 
        !           810:        L_ADD(&off[imin], &offset_fudge);
        !           811:        if (imin != imax)
        !           812:            L_ADD(&off[imax], &offset_fudge);
        !           813:        (void) printf("mean %s, min %s, max %s\n",
        !           814:                      mfptoa(date_ui, tmp, 8), lfptoa(&off[imin], 8),
        !           815:                      lfptoa(&off[imax], 8));
        !           816: }

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