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>