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