home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xntp3.zip / xntpd / refclock_chu.c < prev    next >
C/C++ Source or Header  |  1992-07-30  |  27KB  |  996 lines

  1. /*
  2.  * refclock_chu - clock driver for the CHU time code
  3.  */
  4. #include <stdio.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <sys/time.h>
  9. #include <sys/file.h>
  10. #include <sys/ioctl.h>
  11. #include <sgtty.h>
  12.  
  13. #ifdef STREAM
  14. #include <stropts.h>
  15. #endif
  16.  
  17. #include "ntp_syslog.h"
  18. #include "ntp_fp.h"
  19. #include "ntp.h"
  20. #include "ntp_refclock.h"
  21. #include "ntp_unixtime.h"
  22.  
  23. #if defined(REFCLOCK) && defined(CHU)
  24. #include <sys/chudefs.h>
  25.  
  26. /*
  27.  * The CHU time signal includes a time code which is modulated at the
  28.  * standard Bell 103 frequencies (i.e. mark=2225Hz, space=2025Hz).
  29.  * and formatted into 8 bit characters with one start bit and two
  30.  * stop bits.  The time code is sent in the 31st through the 39th
  31.  * second of the minute.  The time code is composed of 10 8-bit
  32.  * characters, with 2 BCD nibbles in each character.  The following
  33.  * BCD is sent
  34.  *
  35.  *     6dddhhmmss6dddhhmmss
  36.  *
  37.  * where ddd is the day of the year, hh is the hour (in UTC), mm is
  38.  * the minute and ss the second.  The 6 is a constant.  Note that
  39.  * the code is repeated twice.
  40.  *
  41.  * It is assumed that you have built or modified a Bell 103 standard
  42.  * modem, attached the input to the output of a radio and cabled the
  43.  * output to a serial port on your computer, i.e. what you are receiving
  44.  * is essentially the output of your radio.  It is also assumed you have
  45.  * installed a special CHU line discipline to condition the output from
  46.  * the terminal driver and take accurate time stamps.
  47.  *
  48.  * The start bit in each character has a precise relationship to
  49.  * the on-time second.  Most often UART's synchronize themselves to the
  50.  * start bit and will post an interrupt at the center of the first stop
  51.  * bit.  Thus each character's interrupt should occur at a fixed offset
  52.  * from the on-time second.  This means that a timestamp taken at the
  53.  * arrival of each character in the code will provide an independent
  54.  * estimate of the offset.  Since there are 10 characters in the time
  55.  * code and the code is sent 9 times per minute, this means you potentially
  56.  * get 90 offset samples per minute.  Much of the code in here is dedicated
  57.  * to producing a single offset estimate from these samples.
  58.  *
  59.  * A note about the line discipline.  It is possible to receive the
  60.  * CHU time code in raw mode, but this has disadvantages.  In particular,
  61.  * this puts a lot of code between the interrupt and the time you freeze
  62.  * a time stamp, decreasing precision.  It is also expensive in terms of
  63.  * context switches, and made even more expensive by the way I do I/O.
  64.  * Worse, since you are listening directly to the output of your radio,
  65.  * CHU is noisy and will make you spend a lot of time receiving noise.
  66.  *
  67.  * The line discipline fixes a lot of this.  It knows that the CHU time
  68.  * code consists of 10 bytes which arrive with an intercharacter
  69.  * spacing of about 37 ms, and that the data is BCD, and filters on this
  70.  * basis.  It delivers block of ten characters plus their associated time
  71.  * stamps all at once.  The time stamps are hence about as accurate as
  72.  * a Unix machine can get them, and much of the noise disappears in the
  73.  * kernel with no context switching cost.
  74.  */
  75.  
  76. /*
  77.  * Definitions
  78.  */
  79. #define    MAXUNITS    4    /* maximum number of CHU units permitted */
  80. #define    CHUDEV    "/dev/chu%d"    /* device we open.  %d is unit number */
  81. #define    NCHUCODES    9    /* expect 9 CHU codes per minute */
  82.  
  83. /*
  84.  * To compute a quality for the estimate (a pseudo dispersion) we add a
  85.  * fixed 10 ms for each missing code in the minute and add to this
  86.  * the sum of the differences between the remaining offsets and the
  87.  * estimated sample offset.
  88.  */
  89. #define    CHUDELAYPENALTY    0x0000028f
  90.  
  91. /*
  92.  * Other constant stuff
  93.  */
  94. #define    CHUPRECISION    (-9)    /* what the heck */
  95. #define    CHUREFID    "CHU\0"
  96. #define    CHUDESCRIPTION    "Direct synchronized to CHU timecode"
  97. #define    CHUHSREFID    0x7f7f070a /* 127.127.7.10 refid for hi strata */
  98.  
  99. /*
  100.  * Default fudge factors
  101.  */
  102. #define    DEFPROPDELAY    0x00624dd3    /* 0.0015 seconds, 1.5 ms */
  103. #define    DEFFILTFUDGE    0x000d1b71    /* 0.0002 seconds, 200 us */
  104.  
  105. /*
  106.  * Hacks to avoid excercising the multiplier.  I have no pride.
  107.  */
  108. #define    MULBY10(x)    (((x)<<3) + ((x)<<1))
  109. #define    MULBY60(x)    (((x)<<6) - ((x)<<2))    /* watch overflow */
  110. #define    MULBY24(x)    (((x)<<4) + ((x)<<3))
  111.  
  112. /*
  113.  * Constants for use when multiplying by 0.1.  ZEROPTONE is 0.1
  114.  * as an l_fp fraction, NZPOBITS is the number of significant bits
  115.  * in ZEROPTONE.
  116.  */
  117. #define    ZEROPTONE    0x1999999a
  118. #define    NZPOBITS    29
  119.  
  120. /*
  121.  * CHU unit control structure.
  122.  */
  123. struct chuunit {
  124.     struct peer *peer;        /* associated peer structure */
  125.     struct event chutimer;        /* timeout timer structure */
  126.     struct refclockio chuio;    /* given to the I/O handler */
  127.     l_fp offsets[NCHUCODES];    /* offsets computed from each code */
  128.     l_fp rectimes[NCHUCODES];    /* times we received this stuff */
  129.     u_long reftimes[NCHUCODES];    /* time of last code received */
  130.     u_char lastcode[2*NCHUCHARS];    /* last code we received */
  131.     u_char expect;            /* the next offset expected */
  132.     u_char unit;            /* unit number for this guy */
  133.     u_short haveoffset;        /* flag word indicating valid offsets */
  134.     u_short flags;            /* operational flags */
  135.     u_char status;            /* clock status */
  136.     u_char lastevent;        /* last clock event */
  137.     u_char unused[2];
  138.     u_long lastupdate;        /* last time data received */
  139.     u_long responses;        /* number of responses */
  140.     u_long badformat;        /* number of bad format responses */
  141.     u_long baddata;            /* number of invalid time codes */
  142.     u_long timestarted;        /* time we started this */
  143. };
  144.  
  145. #define    CHUTIMERSET    0x1        /* timer is set to fire */
  146.  
  147.  
  148. /*
  149.  * The CHU table.  This gives the expected time of arrival of each
  150.  * character after the on-time second and is computed as follows:
  151.  * The CHU time code is sent at 300 bps.  Your average UART will
  152.  * synchronize at the edge of the start bit and will consider the
  153.  * character complete at the middle of the first stop bit, i.e.
  154.  * 0.031667 ms later (some UARTS may complete the character at the
  155.  * end of the stop bit instead of the middle, but you can fudge this).
  156.  * Thus the expected time of each interrupt is the start bit time plus
  157.  * 0.031667 seconds.  These times are in chutable[].  To this we add
  158.  * such things as propagation delay and delay fudge factor.
  159.  */
  160. #define    CHARDELAY    0x081b4e82
  161.  
  162. static u_long chutable[NCHUCHARS] = {
  163.     0x22222222 + CHARDELAY,        /* 0.1333333333 */
  164.     0x2b851eb8 + CHARDELAY,        /* 0.170 (exactly) */
  165.     0x34e81b4e + CHARDELAY,        /* 0.2066666667 */
  166.     0x3f92c5f9 + CHARDELAY,        /* 0.2483333333 */
  167.     0x47ae147b + CHARDELAY,        /* 0.280 (exactly) */
  168.     0x51111111 + CHARDELAY,        /* 0.3166666667 */
  169.     0x5a740da7 + CHARDELAY,        /* 0.3533333333 */
  170.     0x63d70a3d + CHARDELAY,        /* 0.390 (exactly) */
  171.     0x6d3a06d4 + CHARDELAY,        /* 0.4266666667 */
  172.     0x769d0370 + CHARDELAY,        /* 0.4633333333 */
  173. };
  174.  
  175. /*
  176.  * Data space for the unit structures.  Note that we allocate these on
  177.  * the fly, but never give them back.
  178.  */
  179. static struct chuunit *chuunits[MAXUNITS];
  180. static u_char unitinuse[MAXUNITS];
  181.  
  182. /*
  183.  * Keep the fudge factors separately so they can be set even
  184.  * when no clock is configured.
  185.  */
  186. static l_fp propagation_delay[MAXUNITS];
  187. static l_fp fudgefactor[MAXUNITS];
  188. static l_fp offset_fudge[MAXUNITS];
  189. static u_char stratumtouse[MAXUNITS];
  190. static u_char sloppyclockflag[MAXUNITS];
  191.  
  192. /*
  193.  * We keep track of the start of the year, watching for changes.
  194.  * We also keep track of whether the year is a leap year or not.
  195.  * All because stupid CHU doesn't include the year in the time code.
  196.  */
  197. static u_long yearstart;
  198.  
  199. /*
  200.  * Imported from the timer module
  201.  */
  202. extern u_long current_time;
  203. extern struct event timerqueue[];
  204.  
  205. /*
  206.  * Event reporting.  This optimizes things a little.
  207.  */
  208. #define    chu_event(chu, evcode) \
  209.     do { \
  210.         if ((chu)->status != (u_char)(evcode)) \
  211.             chu_report_event((chu), (evcode)); \
  212.     } while (0)
  213.  
  214. /*
  215.  * Time conversion tables imported from the library
  216.  */
  217. extern u_long ustotslo[];
  218. extern u_long ustotsmid[];
  219. extern u_long ustotshi[];
  220.  
  221.  
  222. /*
  223.  * chu_init - initialize internal chu driver data
  224.  */
  225. void
  226. chu_init()
  227. {
  228.     register int i;
  229.     /*
  230.      * Just zero the data arrays
  231.      */
  232.     bzero((char *)chuunits, sizeof chuunits);
  233.     bzero((char *)unitinuse, sizeof unitinuse);
  234.  
  235.     /*
  236.      * Initialize fudge factors to default.
  237.      */
  238.     for (i = 0; i < MAXUNITS; i++) {
  239.         propagation_delay[i].l_ui = 0;
  240.         propagation_delay[i].l_uf = DEFPROPDELAY;
  241.         fudgefactor[i].l_ui = 0;
  242.         fudgefactor[i].l_uf = DEFFILTFUDGE;
  243.         offset_fudge[i] = propagation_delay[i];
  244.         L_ADD(&offset_fudge[i], &fudgefactor[i]);
  245.         stratumtouse[i] = 0;
  246.         sloppyclockflag[i] = 0;
  247.     }
  248. }
  249.  
  250.  
  251. /*
  252.  * chu_start - open the CHU device and initialize data for processing
  253.  */
  254. int
  255. chu_start(unit, peer)
  256.     u_int unit;
  257.     struct peer *peer;
  258. {
  259.     register struct chuunit *chu;
  260.     register int i;
  261.     int fd;
  262.     int ldisc;
  263.     char chudev[20];
  264.     struct sgttyb ttyb;
  265.     l_fp ts;
  266.     void chu_timeout();
  267.     void chu_receive();
  268.     extern int io_addclock();
  269.     extern char *emalloc();
  270.     extern void get_systime();
  271.     extern u_long calyearstart();
  272.  
  273.     if (unit >= MAXUNITS) {
  274.         syslog(LOG_ERR, "chu clock: unit number %d invalid (max 3)",
  275.             unit);
  276.         return 0;
  277.     }
  278.     if (unitinuse[unit]) {
  279.         syslog(LOG_ERR, "chu clock: unit number %d in use", unit);
  280.         return 0;
  281.     }
  282.  
  283.     /*
  284.      * Unit okay, attempt to open the device.
  285.      */
  286.     (void) sprintf(chudev, CHUDEV, unit);
  287.  
  288.     fd = open(chudev, O_RDONLY, 0777);
  289.     if (fd == -1) {
  290.         syslog(LOG_ERR, "chu clock: open of %s failed: %m", chudev);
  291.         return 0;
  292.     }
  293.  
  294.     /*
  295.      * Set for exclusive use
  296.      */
  297.     if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
  298.         syslog(LOG_ERR, "chu clock: ioctl(%s, TIOCEXCL): %m", chudev);
  299.         (void) close(fd);
  300.         return 0;
  301.     }
  302.  
  303.     /*
  304.      * Set to raw mode
  305.      */
  306.     ttyb.sg_ispeed = ttyb.sg_ospeed = B300;
  307.     ttyb.sg_erase = ttyb.sg_kill = 0;
  308.     ttyb.sg_flags = EVENP|ODDP|RAW;
  309.     if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
  310.         syslog(LOG_ERR, "chu clock: ioctl(%s, TIOCSETP): %m", chudev);
  311.         return 0;
  312.     }
  313.  
  314.     /*
  315.      * Looks like this might succeed.  Find memory for the structure.
  316.      * Look to see if there are any unused ones, if not we malloc()
  317.      * one.
  318.      */
  319.     if (chuunits[unit] != 0) {
  320.         chu = chuunits[unit];    /* The one we want is okay */
  321.     } else {
  322.         for (i = 0; i < MAXUNITS; i++) {
  323.             if (!unitinuse[i] && chuunits[i] != 0)
  324.                 break;
  325.         }
  326.         if (i < MAXUNITS) {
  327.             /*
  328.              * Reclaim this one
  329.              */
  330.             chu = chuunits[i];
  331.             chuunits[i] = 0;
  332.         } else {
  333.             chu = (struct chuunit *)emalloc(sizeof(struct chuunit));
  334.         }
  335.     }
  336.     bzero((char *)chu, sizeof(struct chuunit));
  337.     chuunits[unit] = chu;
  338.  
  339.     /*
  340.      * Set up the structure
  341.      */
  342.     chu->peer = peer;
  343.     chu->unit = (u_char)unit;
  344.     chu->timestarted = current_time;
  345.  
  346.     chu->chutimer.peer = (struct peer *)chu;
  347.     chu->chutimer.event_handler = chu_timeout;
  348.  
  349.     chu->chuio.clock_recv = chu_receive;
  350.     chu->chuio.srcclock = (caddr_t)chu;
  351.     chu->chuio.datalen = sizeof(struct chucode);
  352.     chu->chuio.fd = fd;
  353.  
  354.     /*
  355.      * Initialize the year from the system time in case this is the
  356.      * first open.
  357.      */
  358.     get_systime(&ts);
  359.     yearstart = calyearstart(ts.l_ui);
  360.  
  361. #ifdef STREAM
  362.     /*
  363.      * Okay. Push the CHU stream on top of the tty, but get rid of
  364.      * existing trash first.
  365.      */
  366.     while (ioctl(fd, I_POP, 0 ) >= 0) ;
  367.     if (ioctl(fd, I_PUSH, "chu" ) < 0) {
  368.         syslog(LOG_ERR, "chu clock: ioctl(%s, I_PUSH): %m", chudev);
  369.         (void) close(fd);
  370.         return 0;
  371.     }
  372. #else
  373.     /*
  374.      * Okay.  Set the line discipline to the CHU line discipline, then
  375.      * give it to the I/O code to start receiving stuff.  Not the
  376.      * change of line discipline will clear the read buffers, which
  377.      * makes the change clean if done quickly.
  378.      */
  379.     ldisc = CHULDISC;
  380.     if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
  381.         syslog(LOG_ERR, "chu clock: ioctl(%s, TIOCSETD): %m", chudev);
  382.         (void) close(fd);
  383.         return 0;
  384.     }
  385. #endif
  386.     if (!io_addclock(&chu->chuio)) {
  387.         /*
  388.          * Oh shit.  Just close and return.
  389.          */
  390.         (void) close(fd);
  391.         return 0;
  392.     }
  393.  
  394.     /*
  395.      * All done.  Initialize a few random peer variables, then
  396.      * return success.
  397.      */
  398.     peer->precision = CHUPRECISION;
  399.     peer->rootdelay = 0;
  400.     peer->rootdispersion = 0;
  401.     peer->stratum = stratumtouse[unit];
  402.     if (stratumtouse[unit] <= 1)
  403.         bcopy(CHUREFID, (char *)&peer->refid, 4);
  404.     else
  405.         peer->refid = htonl(CHUHSREFID);
  406.     unitinuse[unit] = 1;
  407.     return 1;
  408. }
  409.  
  410.  
  411. /*
  412.  * chu_shutdown - shut down a CHU clock
  413.  */
  414. void
  415. chu_shutdown(unit)
  416.     int unit;
  417. {
  418.     register struct chuunit *chu;
  419.     extern void io_closeclock();
  420.  
  421.     if (unit >= MAXUNITS) {
  422.         syslog(LOG_ERR,
  423.             "chu clock: INTERNAL ERROR, unit number %d invalid (max 3)",
  424.             unit);
  425.         return;
  426.     }
  427.     if (!unitinuse[unit]) {
  428.         syslog(LOG_ERR,
  429.          "chu clock: INTERNAL ERROR, unit number %d not in use", unit);
  430.         return;
  431.     }
  432.  
  433.     /*
  434.      * Tell the I/O module to turn us off, and dequeue timer
  435.      * if any.  We're history.
  436.      */
  437.     chu = chuunits[unit];
  438.     if (chu->flags & CHUTIMERSET)
  439.         TIMER_DEQUEUE(&chu->chutimer);
  440.     io_closeclock(&chu->chuio);
  441.     unitinuse[unit] = 0;
  442. }
  443.  
  444.  
  445. /*
  446.  * chu_report_event - record an event and report it
  447.  */
  448. static void
  449. chu_report_event(chu, code)
  450.     struct chuunit *chu;
  451.     int code;
  452. {
  453.     /*
  454.      * Trap support isn't up to handling this, so just
  455.      * record it.
  456.      */
  457.     if (chu->status != (u_char)code) {
  458.         chu->status = (u_char)code;
  459.         if (code != CEVNT_NOMINAL)
  460.             chu->lastevent = (u_char)code;
  461.     }
  462. }
  463.  
  464.  
  465. /*
  466.  * chu_receive - receive data from a CHU clock, do format checks and compute
  467.  *         an estimate from the sample data
  468.  */
  469. void
  470. chu_receive(rbufp)
  471.     struct recvbuf *rbufp;
  472. {
  473.     register int i;
  474.     register u_long date_ui;
  475.     register u_long tmp;
  476.     register u_char *code;
  477.     register struct chuunit *chu;
  478.     register struct chucode *chuc;
  479.     int isneg;
  480.     u_long reftime;
  481.     l_fp off[NCHUCHARS];
  482.     int day, hour, minute, second;
  483.     void chu_process();
  484.     extern int clocktime();
  485.  
  486.     /*
  487.      * Do a length check on the data.  Should be what we asked for.
  488.      */
  489.     if (rbufp->recv_length != sizeof(struct chucode)) {
  490.         syslog(LOG_ERR,
  491.             "chu clock: received %d bytes, expected %d",
  492.             rbufp->recv_length, sizeof(struct chucode));
  493.         return;
  494.     }
  495.  
  496.     /*
  497.      * Get the clock this applies to and a pointer to the data
  498.      */
  499.     chu = (struct chuunit *)rbufp->recv_srcclock;
  500.     chuc = (struct chucode *)&rbufp->recv_space;
  501.     chu->responses++;
  502.     chu->lastupdate = current_time;
  503.  
  504.     /*
  505.      * We'll skip the checks made in the kernel, but assume they've
  506.      * been done.  This means that all characters are BCD and
  507.      * the intercharacter spacing isn't unreasonable.
  508.      */
  509.  
  510.     /*
  511.      * Break out the code into the BCD nibbles.  Only need to fiddle
  512.      * with the first half since both are identical.  Note the first
  513.      * BCD character is the low order nibble, the second the high order.
  514.      */
  515.     code = chu->lastcode;
  516.     for (i = 0; i < NCHUCHARS; i++) {
  517.         *code++ = chuc->codechars[i] & 0xf;
  518.         *code++ = (chuc->codechars[i] >> 4) & 0xf;
  519.     }
  520.  
  521.     /*
  522.      * Format check.  Make sure the two halves match.
  523.      */
  524.     for (i = 0; i < NCHUCHARS/2; i++)
  525.         if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)]) {
  526.             chu->badformat++;
  527.             chu_event(chu, CEVNT_BADREPLY);
  528.             return;
  529.         }
  530.  
  531.     /*
  532.      * If the first nibble isn't a 6, we're up the creek
  533.      */
  534.     code = chu->lastcode;
  535.     if (*code++ != 6) {
  536.         chu->badformat++;
  537.         chu_event(chu, CEVNT_BADREPLY);
  538.         return;
  539.     }
  540.  
  541.     /*
  542.      * Collect the day, the hour, the minute and the second.
  543.      */
  544.     day = *code++;
  545.     day = MULBY10(day) + *code++;
  546.     day = MULBY10(day) + *code++;
  547.     hour = *code++;
  548.     hour = MULBY10(hour) + *code++;
  549.     minute = *code++;
  550.     minute = MULBY10(minute) + *code++;
  551.     second = *code++;
  552.     second = MULBY10(second) + *code++;
  553.  
  554.     /*
  555.      * Sanity check the day and time.  Note that this
  556.      * only occurs on the 31st through the 39th second
  557.      * of the minute.
  558.      */
  559.     if (day < 1 || day > 366
  560.         || hour > 23 || minute > 59
  561.         || second < 31 || second > 39) {
  562.         chu->baddata++;
  563.         if (day < 1 || day > 366) {
  564.             chu_event(chu, CEVNT_BADDATE);
  565.         } else {
  566.             chu_event(chu, CEVNT_BADTIME);
  567.         }
  568.         return;
  569.     }
  570.  
  571.     /*
  572.      * Compute the NTP date from the input data and the
  573.      * receive timestamp.  If this doesn't work, mark the
  574.      * date as bad and forget it.
  575.      */
  576.     if (!clocktime(day, hour, minute, second, 0,
  577.         rbufp->recv_time.l_ui, &yearstart, &reftime)) {
  578.         chu_event(chu, CEVNT_BADDATE);
  579.         return;
  580.     }
  581.     date_ui = reftime;;
  582.  
  583.     /*
  584.      * We've now got the integral seconds part of the time code (we hope).
  585.      * The fractional part comes from the table.  We next compute
  586.      * the offsets for each character.
  587.      */
  588.     for (i = 0; i < NCHUCHARS; i++) {
  589.         register u_long tmp2;
  590.  
  591.         off[i].l_ui = date_ui;
  592.         off[i].l_uf = chutable[i];
  593.         tmp = chuc->codetimes[i].tv_sec + JAN_1970;
  594.         TVUTOTSF(chuc->codetimes[i].tv_usec, tmp2);
  595.         M_SUB(off[i].l_ui, off[i].l_uf, tmp, tmp2);
  596.     }
  597.  
  598.     if (!sloppyclockflag[chu->unit]) {
  599.         u_short ord[NCHUCHARS];
  600.         /*
  601.          * In here we assume the clock has adequate bits
  602.          * to take timestamps with reasonable accuracy.
  603.          * Note that the time stamps may contain errors
  604.          * for a couple of reasons.  Timing is actually
  605.          * referenced to the start bit in each character
  606.          * in the time code.  If this is obscured by static
  607.          * you can still get a valid character but have the
  608.          * timestamp offset by +-1.5 ms.  Also, we may suffer
  609.          * from interrupt delays if the interrupt is being
  610.          * held off when the character arrives.  Note the
  611.          * latter error is always in the form of a delay.
  612.          *
  613.          * After fiddling I arrived at the following scheme.
  614.          * We sort the times into order by offset.  We then
  615.          * drop the most positive 2 offset values (which may
  616.          * correspond to a character arriving early due to
  617.          * static) and the most negative 4 (which may correspond
  618.          * to delayed characters, either from static or from
  619.          * interrupt latency).  We then take the mean of the
  620.          * remaining 4 offsets as our estimate.
  621.          */
  622.         
  623.         /*
  624.          * Set up the order array.
  625.          */
  626.         for (i = 0; i < NCHUCHARS; i++)
  627.             ord[i] = (u_short)i;
  628.         
  629.         /*
  630.          * Sort them into order.  Reuse variables with abandon.
  631.          */
  632.         for (tmp = 0; tmp < (NCHUCHARS-1); tmp++) {
  633.             for (i = (int)tmp+1; i < NCHUCHARS; i++) {
  634.                 if (!L_ISGEQ(&off[ord[i]], &off[ord[tmp]])) {
  635.                     date_ui = (u_long)ord[i];
  636.                     ord[i] = ord[tmp];
  637.                     ord[tmp] = (u_short)date_ui;
  638.                 }
  639.             }
  640.         }
  641.  
  642.         /*
  643.          * Done the sort.  We drop 0, 1, 2 and 3 at the negative
  644.          * end, and 8 and 9 at the positive.  Take the sum of
  645.          * 4, 5, 6 and 7.
  646.          */
  647.         date_ui = off[ord[4]].l_ui;
  648.         tmp = off[ord[4]].l_uf;
  649.         for (i = 5; i <= 7; i++)
  650.             M_ADD(date_ui, tmp, off[ord[i]].l_ui, off[ord[i]].l_uf);
  651.         
  652.         /*
  653.          * Round properly, then right shift two bits for the
  654.          * divide by four.
  655.          */
  656.         if (tmp & 0x2)
  657.             M_ADDUF(date_ui, tmp, 0x4);
  658.         M_RSHIFT(date_ui, tmp);
  659.         M_RSHIFT(date_ui, tmp);
  660.     } else {
  661.         /*
  662.          * Here is a *big* problem.  On a machine where the
  663.          * low order bit in the clock is on the order of half
  664.          * a millisecond or more we don't really have enough
  665.          * precision to make intelligent choices about which
  666.          * samples might be in error and which aren't.  More
  667.          * than this, in the case of error free data we can
  668.          * pick up a few bits of precision by taking the mean
  669.          * of the whole bunch.  This is what we do.  The problem
  670.          * comes when it comes time to divide the 64 bit sum of
  671.          * the 10 samples by 10, a procedure which really sucks.
  672.          * Oh, well, grin and bear it.  Compute the sum first.
  673.          */
  674.         date_ui = 0;
  675.         tmp = 0;
  676.         for (i = 0; i < NCHUCHARS; i++)
  677.             M_ADD(date_ui, tmp, off[i].l_ui, off[i].l_uf);
  678.         if (M_ISNEG(date_ui, tmp))
  679.             isneg = 1;
  680.         else
  681.             isneg = 0;
  682.  
  683.         /*
  684.          * Here is a multiply-by-0.1 optimization that should apply
  685.          * just about everywhere.  If the magnitude of the sum
  686.          * is less than 9 we don't have to worry about overflow
  687.          * out of a 64 bit product, even after rounding.
  688.          */
  689.         if (date_ui < 9 || date_ui > 0xfffffff7) {
  690.             register u_long prod_ui;
  691.             register u_long prod_uf;
  692.     
  693.             prod_ui = prod_uf = 0;
  694.             /*
  695.              * This code knows the low order bit in 0.1 is zero
  696.              */
  697.             for (i = 1; i < NZPOBITS; i++) {
  698.                 M_LSHIFT(date_ui, tmp);
  699.                 if (ZEROPTONE & (1<<i))
  700.                     M_ADD(prod_ui, prod_uf, date_ui, tmp);
  701.             }
  702.  
  703.             /*
  704.              * Done, round it correctly.  Prod_ui contains the
  705.              * fraction.
  706.              */
  707.             if (prod_uf & 0x80000000)
  708.                 prod_ui++;
  709.             if (isneg)
  710.                 date_ui = 0xffffffff;
  711.             else
  712.                 date_ui = 0;
  713.             tmp = prod_ui;
  714.             /*
  715.              * date_ui is integral part, tmp is fraction.
  716.              */
  717.         } else {
  718.             register u_long prod_ovr;
  719.             register u_long prod_ui;
  720.             register u_long prod_uf;
  721.             register u_long highbits;
  722.  
  723.             prod_ovr = prod_ui = prod_uf = 0;
  724.             if (isneg)
  725.                 highbits = 0xffffffff;    /* sign extend */
  726.             else
  727.                 highbits = 0;
  728.             /*
  729.              * This code knows the low order bit in 0.1 is zero
  730.              */
  731.             for (i = 1; i < NZPOBITS; i++) {
  732.                 M_LSHIFT3(highbits, date_ui, tmp);
  733.                 if (ZEROPTONE & (1<<i))
  734.                     M_ADD3(prod_ovr, prod_uf, prod_ui,
  735.                         highbits, date_ui, tmp);
  736.             }
  737.  
  738.             if (prod_uf & 0x80000000)
  739.                 M_ADDUF(prod_ovr, prod_ui, (u_long)1);
  740.             date_ui = prod_ovr;
  741.             tmp = prod_ui;
  742.         }
  743.     }
  744.     
  745.     /*
  746.      * At this point we have the mean offset, with the integral
  747.      * part in date_ui and the fractional part in tmp.  Store
  748.      * it in the structure.
  749.      */
  750.     i = second - 31;    /* gives a value 0 through 8 */
  751.     if (i < chu->expect) {
  752.         /*
  753.          * This shouldn't actually happen, but might if a single
  754.          * bit error occurred in the code which fooled us.
  755.          * Throw away all previous data.
  756.          */
  757.         chu->expect = 0;
  758.         chu->haveoffset = 0;
  759.         if (chu->flags & CHUTIMERSET) {
  760.             TIMER_DEQUEUE(&chu->chutimer);
  761.             chu->flags &= ~CHUTIMERSET;
  762.         }
  763.     }
  764.  
  765.     /*
  766.      * Add in fudge factor.
  767.      */
  768.     M_ADD(date_ui, tmp, offset_fudge[chu->unit].l_ui,
  769.         offset_fudge[chu->unit].l_uf);
  770.  
  771.     chu->offsets[i].l_ui = date_ui;
  772.     chu->offsets[i].l_uf = tmp;
  773.     chu->rectimes[i] = rbufp->recv_time;
  774.     chu->reftimes[i] = reftime;
  775.  
  776.     chu->expect = i + 1;
  777.     chu->haveoffset |= (1<<i);
  778.  
  779.     if (chu->expect >= NCHUCODES) {
  780.         /*
  781.          * Got a full second's worth.  Dequeue timer and
  782.          * process this.
  783.          */
  784.         if (chu->flags & CHUTIMERSET) {
  785.             TIMER_DEQUEUE(&chu->chutimer);
  786.             chu->flags &= ~CHUTIMERSET;
  787.         }
  788.         chu_process(chu);
  789.     } else if (!(chu->flags & CHUTIMERSET)) {
  790.         /*
  791.          * Try to take an interrupt sometime after the
  792.          * 42 second mark (leaves an extra 2 seconds for
  793.          * slop).  Round it up to an even multiple of
  794.          * 4 seconds.
  795.          */
  796.         chu->chutimer.event_time =
  797.             current_time + (u_long)(10 - i) + (1<<EVENT_TIMEOUT);
  798.         chu->chutimer.event_time &= ~((1<<EVENT_TIMEOUT) - 1);
  799.         TIMER_INSERT(timerqueue, &chu->chutimer);
  800.         chu->flags |= CHUTIMERSET;
  801.     }
  802. }
  803.  
  804.  
  805. /*
  806.  * chu_timeout - process a timeout event
  807.  */
  808. void
  809. chu_timeout(fakepeer)
  810.     struct peer *fakepeer;
  811. {
  812.     void chu_process();
  813.  
  814.     /*
  815.      * If we got here it means we received some time codes
  816.      * but didn't get the one which should have arrived on
  817.      * the 39th second.  Process what we have.
  818.      */
  819.     ((struct chuunit *)fakepeer)->flags &= ~CHUTIMERSET;
  820.     chu_process((struct chuunit *)fakepeer);
  821. }
  822.  
  823.  
  824. /*
  825.  * chu_process - process the raw offset estimates we have and pass
  826.  *         the results on to the NTP clock filters.
  827.  */
  828. void
  829. chu_process(chu)
  830.     register struct chuunit *chu;
  831. {
  832.     register int i;
  833.     register s_fp bestoff;
  834.     register s_fp tmpoff;
  835.     u_fp dispersion;
  836.     int imax;
  837.     l_fp ts;
  838.     extern void refclock_receive();
  839.  
  840.     /*
  841.      * The most positive offset.
  842.      */
  843.     imax = NCHUCODES;
  844.     for (i = 0; i < NCHUCODES; i++)
  845.         if (chu->haveoffset & (1<<i))
  846.             if (i < imax || L_ISGEQ(&chu->offsets[i],
  847.                 &chu->offsets[imax]))
  848.                 imax = i;
  849.  
  850.     /*
  851.      * The most positive estimate is our best bet.  Go through
  852.      * the list again computing the dispersion.
  853.      */
  854.     bestoff = LFPTOFP(&chu->offsets[imax]);
  855.     dispersion = 0;
  856.     for (i = 0; i < NCHUCODES; i++) {
  857.         if (chu->haveoffset & (1<<i)) {
  858.             tmpoff = LFPTOFP(&chu->offsets[i]);
  859.             dispersion += (bestoff - tmpoff);
  860.         } else {
  861.             dispersion += CHUDELAYPENALTY;
  862.         }
  863.     }
  864.  
  865.     /*
  866.      * Make up a reference time stamp, then give it to the
  867.      * reference clock support code for further processing.
  868.      */
  869.     ts.l_ui = chu->reftimes[imax];
  870.     ts.l_uf = chutable[NCHUCHARS-1];
  871.  
  872.     refclock_receive(chu->peer, &chu->offsets[imax], 0,
  873.         dispersion, &ts, &chu->rectimes[imax], 0);
  874.     
  875.     /*
  876.      * Zero out unit for next code series
  877.      */
  878.     chu->haveoffset = 0;
  879.     chu->expect = 0;
  880.     chu_event(chu, CEVNT_NOMINAL);
  881. }
  882.  
  883.  
  884. /*
  885.  * chu_poll - called by the transmit procedure
  886.  */
  887. void
  888. chu_poll(unit, peer)
  889.     int unit;
  890.     char *peer;
  891. {
  892.     if (unit >= MAXUNITS) {
  893.         syslog(LOG_ERR, "chu clock poll: INTERNAL: unit %d invalid",
  894.             unit);
  895.         return;
  896.     }
  897.     if (!unitinuse[unit]) {
  898.         syslog(LOG_ERR, "chu clock poll: INTERNAL: unit %d unused",
  899.             unit);
  900.         return;
  901.     }
  902.  
  903.     if ((current_time - chuunits[unit]->lastupdate) > 150) {
  904.         chu_event(chuunits[unit], CEVNT_PROP);
  905.     }
  906. }
  907.  
  908.  
  909.  
  910. /*
  911.  * chu_control - set fudge factors, return statistics
  912.  */
  913. void
  914. chu_control(unit, in, out)
  915.     u_int unit;
  916.     struct refclockstat *in;
  917.     struct refclockstat *out;
  918. {
  919.     register int i;
  920.     register struct chuunit *chu;
  921.     u_long npolls;
  922.     static char asciicode[NCHUCHARS*2];
  923.  
  924.     if (unit >= MAXUNITS) {
  925.         syslog(LOG_ERR, "chu clock: unit %d invalid (max %d)",
  926.             unit, MAXUNITS-1);
  927.         return;
  928.     }
  929.  
  930.     if (in != 0) {
  931.         if (in->haveflags & CLK_HAVETIME1)
  932.             propagation_delay[unit] = in->fudgetime1;
  933.         if (in->haveflags & CLK_HAVETIME2)
  934.             fudgefactor[unit] = in->fudgetime2;
  935.         offset_fudge[unit] = propagation_delay[unit];
  936.         L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
  937.         if (in->haveflags & CLK_HAVEVAL1) {
  938.             stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
  939.             if (unitinuse[unit]) {
  940.                 struct peer *peer;
  941.  
  942.                 /*
  943.                  * Should actually reselect clock, but
  944.                  * will wait for the next timecode
  945.                  */
  946.                 peer = chuunits[unit]->peer;
  947.                 peer->stratum = stratumtouse[unit];
  948.                 if (stratumtouse[unit] <= 1)
  949.                     bcopy(CHUREFID, (char *)&peer->refid,4);
  950.                 else
  951.                     peer->refid = htonl(CHUHSREFID);
  952.             }
  953.         }
  954.         if (in->haveflags & CLK_HAVEFLAG1) {
  955.             sloppyclockflag[unit] = in->flags & CLK_FLAG1;
  956.         }
  957.     }
  958.  
  959.     if (out != 0) {
  960.         out->type = REFCLK_CHU;
  961.         out->flags = 0;
  962.         out->haveflags
  963.             = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEFLAG1;
  964.         out->clockdesc = CHUDESCRIPTION;
  965.         out->fudgetime1 = propagation_delay[unit];
  966.         out->fudgetime2 = fudgefactor[unit];
  967.         out->fudgeval1 = (long)stratumtouse[unit];
  968.         out->fudgeval2 = 0;
  969.         out->flags = sloppyclockflag[unit];
  970.         if (unitinuse[unit]) {
  971.             chu = chuunits[unit];
  972.             out->lencode = NCHUCHARS*2;
  973.             for (i = 0; i < NCHUCHARS*2; i++) {
  974.                 asciicode[i] = chu->lastcode[i] + '0';
  975.             }
  976.             out->lastcode = asciicode;
  977.             out->timereset = current_time - chu->timestarted;
  978.             npolls = out->timereset / 6;    /* **divide** */
  979.             out->polls = npolls;
  980.             out->noresponse = (npolls - chu->responses);
  981.             out->badformat = chu->badformat;
  982.             out->baddata = chu->baddata;
  983.             out->lastevent = chu->lastevent;
  984.             out->currentstatus = chu->status;
  985.         } else {
  986.             out->lencode = 0;
  987.             out->lastcode = "";
  988.             out->polls = out->noresponse = 0;
  989.             out->badformat = out->baddata = 0;
  990.             out->timereset = 0;
  991.             out->currentstatus = out->lastevent = CEVNT_NOMINAL;
  992.         }
  993.     }
  994. }
  995. #endif
  996.