home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / clockstuff / chutest.c next >
C/C++ Source or Header  |  1991-05-20  |  19KB  |  800 lines

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