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_pst.c < prev    next >
C/C++ Source or Header  |  1992-08-29  |  42KB  |  1,741 lines

  1. /*
  2.  * refclock_pst - driver for the PSTI 1010/1020 WWV clock
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <sys/time.h>
  10. #include <sys/file.h>
  11. #include <sys/ioctl.h>
  12. #if defined(HPUX)
  13. #include <termio.h>
  14. #else
  15. #include <sgtty.h>
  16. #endif
  17.  
  18. #include "ntp_syslog.h"
  19. #include "ntp_fp.h"
  20. #include "ntp.h"
  21. #include "ntp_refclock.h"
  22. #include "ntp_unixtime.h"
  23.  
  24. #if defined(REFCLOCK) && defined(PST)
  25. /*
  26.  * This driver is in good measure due to David Schachter, who wrote
  27.  * the firmware for the PST clock.  Not that he is to blame for
  28.  * any of this, but he kindly loaned me a clock to allow me to
  29.  * debug this.
  30.  *
  31.  * Postscript:
  32.  *
  33.  * The strategy in here is actually pretty good, especially if
  34.  * you try to support the clock on something lacking low order
  35.  * clock bits like a Sun, since all the business which is done
  36.  * before taking a time stamp tends to randomize the taking of
  37.  * the stamp with respect to the timer interrupt.  It is, however,
  38.  * a big cpu hog, and in some ways is a bit of a waste since, as
  39.  * it turns out, the PST clock can give you no better than a
  40.  * millisecond precision and it doesn't pay to try to push it
  41.  * harder.
  42.  *
  43.  * In any event, like the first waffle off the iron, this one
  44.  * should probably be tossed.  My current preference would be
  45.  * to retain the 12-a-minute schedule, but to use the QU command
  46.  * instead of the QD and QT, and to only send a QM command with
  47.  * the 12th poll of the minute to get the minutes-since-sync
  48.  * and the station.  Need to get a clock which supports QU,
  49.  * however.
  50.  *
  51.  * End postscript
  52.  *
  53.  * This driver polls the clock using the QM, QT and QD commands.
  54.  * Ntpd actually uses QU instead of the last two, something I would
  55.  * like to have done as well since it gives you the day and time
  56.  * atom, but the firmware in the clock I had (X04.01.999) didn't know
  57.  * about this command.
  58.  *
  59.  * The QM command produces output like:
  60.  *
  61.  *    O6B532352823C00270322
  62.  *       b     c  deeee
  63.  *
  64.  * We use (b) for the time zone, (c) to see whether time is available,
  65.  * (d) to tell whether we are sync'd to WWV or WWVH, and (e) to determine
  66.  * the number of minutes since the last signal was received.  We
  67.  * don't trust the clock for more than about 20 minutes on its own.
  68.  * After this, we keep taking the time but mark the clock unsynchronized.
  69.  *
  70.  * The QT command returns something that looks like this:
  71.  *
  72.  *    18:57:50.263D
  73.  *
  74.  * Note that this particular sample is in 24 hour format, local time
  75.  * (daylight savings time even).  We allow just about anything for
  76.  * this (sigh) since this leaves the clock owner free to set the
  77.  * display mode in whatever way he finds convenient for setting
  78.  * his watch.
  79.  *
  80.  * The QD command returns:
  81.  *
  82.  *    89/10/19/292
  83.  *
  84.  * We actually only use the day-of-the-year here.  We use the year
  85.  * only to determine whether the PST clock thinks the current year
  86.  * has 365 or 366 days in it.
  87.  *
  88.  * At the current writing, this code expects to be using a BSD-style
  89.  * terminal driver.  It will compile code which uses the CLKLDISC
  90.  * line discipline if it thinks this is available, but use cooked
  91.  * mode otherwise.  The cooked mode stuff may not have been tested.
  92.  */
  93.  
  94. /*
  95.  * Definitions
  96.  */
  97. #define    MAXUNITS    4    /* maximum number of PST units permitted */
  98. #define    PSTDEV    "/dev/pst%d"    /* device we open.  %d is unit number */
  99. #define    NPSTSAMPS    12    /* take 12 PST samples per minute */
  100.  
  101. /*
  102.  * Other constant stuff
  103.  */
  104. #define    PSTPRECISION    (-9)        /* what the heck */
  105. #define    WWVREFID    "WWV\0"
  106. #define    WWVHREFID    "WWVH"
  107. #define    PSTHSREFID    0x7f7f030a    /* 127.127.3.10 refid for hi strata */
  108.  
  109. /*
  110.  * Parameters for the clock
  111.  */
  112. #define    PSTBAUD        B9600
  113. #define    PSTMAGIC2    ('\r' | 0x80)    /* HP-UX uses this also now */
  114. #ifdef CLKLDISC
  115. #define    PSTMAGIC1    '\r'
  116. #define    PSTEOL        '\r'
  117. #else
  118. #define    PSTEOL        '\n'
  119. #endif
  120.  
  121. /*
  122.  * Description of clock.  We fill in whether it is a 1010 or 1020,
  123.  * and the firmware revision, using the QV command.
  124.  */
  125. #define    PSTDESCLEN    64
  126. #define    PSTDESCRIPTION    "%s %s (%s) WWV/H Receiver"
  127. #define    PSTDEFDESC    "PSTI/Traconex 10?0 (V??.??) WWV/H Receiver"
  128.  
  129. /*
  130.  * Length of the PST time code.  This must be the length of the output
  131.  * of the QM command, plus QT, plus QD, plus two spaces.  We make it
  132.  * big just on principle.
  133.  */
  134. #define    PSTCODELEN    (128)
  135.  
  136. /*
  137.  * Minimum and maximum lengths
  138.  */
  139. #define    PSTMINQVLEN    (16)
  140. #define    PSTMAXQVLEN    (24)
  141.  
  142. #define    PSTMINQMLEN    (19)
  143. #define    PSTMAXQMLEN    (32)
  144.  
  145. #define    PSTMINQDLEN    (12)
  146. #define    PSTMAXQDLEN    (12)
  147.  
  148. #define    PSTMINQTLEN    (14)
  149. #define    PSTMAXQTLEN    (14)
  150.  
  151. /*
  152.  * It turns out that the QT command does *not* adjust for transmission
  153.  * delays.  Since the QT command returns 15 characters at 9600 baud,
  154.  * the adjustment for this should be 15.6 ms.  We'll default to this,
  155.  * but don't let this stop you from fiddling with the fudge factors
  156.  * to make things come out right
  157.  */
  158. #define    PSTQTFUDGE    0x04000000    /* about 15.6 ms */
  159.  
  160. /*
  161.  * Default propagation delays.  About right for Toronto
  162.  */
  163. #define    DEFWWVPROP    0x01eb851f    /* about 7.5 ms */
  164. #define    DEFWWVHPROP    0x06c8b439    /* about 26.5 ms */
  165.  
  166. /*
  167.  * Maximum propagation delay we believe.  125 ms as an l_fp fraction
  168.  */
  169. #define    PSTMAXPROP    0x20000000
  170.  
  171. /*
  172.  * Default minutes since an update.
  173.  */
  174. #define    DEFMAXFREERUN    (20)
  175.  
  176. /*
  177.  * Hack to avoid excercising the multiplier.  I have no pride.
  178.  */
  179. #define    MULBY10(x)    (((x)<<3) + ((x)<<1))
  180.  
  181. /*
  182.  * PST unit control structure.
  183.  */
  184. struct pstunit {
  185.     struct peer *peer;        /* associated peer structure */
  186.     struct event psttimer;        /* timeout timer structure */
  187.     struct refclockio pstio;    /* given to the I/O handler */
  188.     l_fp rectimes[NPSTSAMPS];    /* times we received this stuff */
  189.     l_fp reftimes[NPSTSAMPS];    /* times of codes received */
  190.     l_fp lastrec;            /* last receive time */
  191.     l_fp lastref;            /* last reference time */
  192.     char description[PSTDESCLEN];    /* description of clock */
  193.     char lastcode[PSTCODELEN];    /* last code we received */
  194.     u_char lencode;            /* length of the last code */
  195.     u_char nextsample;        /* the next offset expected */
  196.     u_char unit;            /* unit number for this guy */
  197.     u_char state;            /* what we're waiting for */
  198.     s_char station;            /* WWV or WWVH? */
  199.     u_char flags;            /* flag byte */
  200.     u_char status;            /* clock status */
  201.     u_char lastevent;        /* last clock event */
  202.     u_char timezone;        /* hour offset to time zone */
  203.     u_char errors;            /* number of errors detected */
  204.     u_char year;            /* year reported by clock */
  205.     u_char month;            /* month, from clock */
  206.     u_char monthday;        /* day, from clock */
  207.     u_char hour;            /* hour of day */
  208.     u_char minute;            /* minute of day */
  209.     u_char second;            /* second of day */
  210.     u_char leap;            /* leap indicators */
  211.     s_char tzoffset;        /* time zone offset */
  212.     u_char reason;            /* reason for failure */
  213.     u_short millisecond;        /* millisecond of day */
  214.     u_short yearday;        /* day of the year */
  215.     u_short timesincesync;        /* time since radio got sample */
  216.     u_long yearstart;        /* NTP time at year start */
  217.     u_long lastupdate;        /* last time data received */
  218.     u_long polls;            /* number of polls */
  219.     u_long noreply;            /* number of time outs */
  220.     u_long badformat;        /* number of bad format responses */
  221.     u_long baddata;            /* number of invalid time codes */
  222.     u_long timestarted;        /* time we started this */
  223. };
  224.  
  225. /*
  226.  * States we might be in
  227.  */
  228. #define    STATE_IDLE    0        /* not doing anything in particular */
  229. #define    STATE_QV    1        /* trying to get version */
  230. #define    STATE_QM    2        /* sent QM */
  231. #define    STATE_QD    3        /* sent QD */
  232. #define    STATE_QT    4        /* send QT */
  233.  
  234. /*
  235.  * Status flags
  236.  */
  237. #define    PST_LEAPYEAR    0x1        /* pst clock thinks it is a leap year */
  238. #define    PST_SIGFAULT    0x2        /* signal fault */
  239. #define    PST_HARDERR    0x4        /* hardware error */
  240. #define    PST_NOTIME    0x8        /* no time available */
  241. #define    PST_WWVH    0x10        /* synchronized to WWVH */
  242. #define    PST_DOQV    0x20        /* get version, reinit delays */
  243. #define    PST_DORESET    0x40        /* reset the clock */
  244.  
  245. /*
  246.  * The PST often encodes stuff by adding an ASCII '0' to it.  The
  247.  * largest range of values encoded this way is 0 through 31, or '0'
  248.  * through 'O'.  These macroes manipulate these values.
  249.  */
  250. #define    ISVALIDPST(c)    ((c) >= '0' && (c) <= 'O')
  251. #define    PSTTOBIN(c)    ((int)(c) - '0')
  252. #define    BINTOPST(c)    ((char)((c) + '0'))
  253.  
  254. /*
  255.  * Status bits.  Look at the QM command
  256.  */
  257. #define    SIGFAULT    0x1
  258. #define    HARDFAULT    0x2
  259. #define    OUTOFSPEC    0x4
  260. #define    TIMEAVAILABLE    0x8
  261.  
  262. /*
  263.  * Module reason codes
  264.  */
  265. #define    QVREASON    20
  266. #define    QMREASON    40
  267. #define    QDREASON    60
  268. #define    QTREASON    80
  269.  
  270. /*
  271.  * Station i.d. characters in QM output
  272.  */
  273. #define    WWV_CHAR    'C'
  274. #define    WWVH_CHAR    'H'
  275.  
  276. /*
  277.  * We allow a few errors, but if we get more than 12 seconds behind
  278.  * the schedule we start from sample 0 again.  4 seconds is the minimum
  279.  * time between time out routine executions.
  280.  */
  281. #define    PSTMAXDELAY    12
  282. #define    PSTMINTIMEOUT    4
  283.  
  284. /*
  285.  * The PST polling schedule.  We poll 12 times per 64 seconds (far too
  286.  * many, but what the heck).  The polls are scheduled to finish in this
  287.  * time with the assumption that the timer is good for no better than
  288.  * 4 second resolution.  If we get too far behind (due to bad samples
  289.  * or no responses) we start over.
  290.  */
  291. struct pstsched {
  292.     u_short nextinterval;
  293.     u_short tooold;
  294. };
  295.  
  296. static struct pstsched psttab[NPSTSAMPS] = {
  297.     { 4,    PSTMAXDELAY+1 },
  298.     { 4,    PSTMAXDELAY+1+4 },
  299.     { 8,    PSTMAXDELAY+1+4+4 },
  300.     { 4,    PSTMAXDELAY+1+4+4+8 },
  301.     { 8,    PSTMAXDELAY+1+4+4+8+4 },
  302.     { 4,    PSTMAXDELAY+1+4+4+8+4+8 },
  303.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4 },
  304.     { 8,    PSTMAXDELAY+1+4+4+8+4+8+4+4 },
  305.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8 },
  306.     { 8,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4 },
  307.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8 },
  308.     { 4,    PSTMAXDELAY+1+4+4+8+4+8+4+4+8+4+8+4 }
  309. };
  310.  
  311.  
  312. /*
  313.  * Data space for the unit structures.  Note that we allocate these on
  314.  * the fly, but never give them back.
  315.  */
  316. static struct pstunit *pstunits[MAXUNITS];
  317. static u_char unitinuse[MAXUNITS];
  318.  
  319. /*
  320.  * Structure to keep processed propagation data in.
  321.  */
  322. struct pst_propagate {
  323.     u_long remainder;    /* left over submillisecond remainder */
  324.     char msbchar;        /* character for high order bits */
  325.     char lsbchar;        /* character for low order bits */
  326. };
  327.  
  328.  
  329. /*
  330.  * Keep the fudge factors separately so they can be set even
  331.  * when no clock is configured.
  332.  */
  333. static l_fp wwv_prop_delay[MAXUNITS];
  334. static l_fp wwvh_prop_delay[MAXUNITS];
  335. static struct pst_propagate wwv_prop_data[MAXUNITS];
  336. static struct pst_propagate wwvh_prop_data[MAXUNITS];
  337. static u_char stratumtouse[MAXUNITS];
  338. static u_char sloppyclock[MAXUNITS];
  339. static u_short freerun[MAXUNITS];
  340.  
  341. /*
  342.  * Pointer to the default description
  343.  */
  344. static char *pstdefdesc = PSTDEFDESC;
  345.  
  346. /*
  347.  * macro for writing to the clock, printing an error if we fail
  348.  */
  349. #define    pst_send(pst, str, len)        \
  350.     if (write((pst)->pstio.fd, (str), (len)) < 0) \
  351.         pst_write_error((pst))
  352.  
  353. /*
  354.  * macro for resetting the clock structure to zero
  355.  */
  356. #define    pst_reset(pst) \
  357.     do { \
  358.         pst->nextsample = 0; \
  359.         pst->station = 0; \
  360.         pst->leap = 0; \
  361.     } while (0)
  362.  
  363. /*
  364.  * macro for event reporting
  365.  */
  366. #define    pst_event(pst, evnt_code) \
  367.     do { \
  368.         if ((pst)->status != (u_char)(evnt_code)) \
  369.             pst_do_event((pst), (evnt_code)); \
  370.     } while (0)
  371.  
  372. /*
  373.  * Imported from the timer module
  374.  */
  375. extern u_long current_time;
  376. extern struct event timerqueue[];
  377.  
  378. /*
  379.  * Time conversion tables imported from the library
  380.  */
  381. extern u_long msutotsflo[];
  382. extern u_long msutotsfhi[];
  383.  
  384.  
  385. /*
  386.  * pst_init - initialize internal PST driver data
  387.  */
  388. void
  389. pst_init()
  390. {
  391.     register int i;
  392.     void pst_compute_delay();
  393.  
  394.     /*
  395.      * Just zero the data arrays
  396.      */
  397.     bzero((char *)pstunits, sizeof pstunits);
  398.     bzero((char *)unitinuse, sizeof unitinuse);
  399.  
  400.     /*
  401.      * Initialize fudge factors to default.
  402.      */
  403.     for (i = 0; i < MAXUNITS; i++) {
  404.         wwv_prop_delay[i].l_ui = 0;
  405.         wwv_prop_delay[i].l_uf = DEFWWVPROP;
  406.         pst_compute_delay(DEFWWVPROP, &wwv_prop_data[i]);
  407.         wwvh_prop_delay[i].l_ui = 0;
  408.         wwvh_prop_delay[i].l_uf = DEFWWVHPROP;
  409.         pst_compute_delay(DEFWWVHPROP, &wwvh_prop_data[i]);
  410.         stratumtouse[i] = 0;
  411.         sloppyclock[i] = 0;
  412.         freerun[i] = DEFMAXFREERUN;
  413.     }
  414. }
  415.  
  416.  
  417. /*
  418.  * pst_start - open the PST device and initialize data for processing
  419.  */
  420. int
  421. pst_start(unit, peer)
  422.     u_int unit;
  423.     struct peer *peer;
  424. {
  425.     register struct pstunit *pst;
  426.     register int i;
  427.     int fd;
  428.     int ldisc;
  429.     char pstdev[20];
  430. #if defined(TCSETA) && !defined(ultrix)
  431.     struct termio ttyb;
  432. #else
  433.     struct sgttyb ttyb;
  434. #endif
  435.     void pst_timeout();
  436.     void pst_receive();
  437.     extern int io_addclock();
  438.     extern char *emalloc();
  439.  
  440.     if (unit >= MAXUNITS) {
  441.         syslog(LOG_ERR, "pst clock: unit number %d invalid (max %d)",
  442.             unit, MAXUNITS-1);
  443.         return 0;
  444.     }
  445.     if (unitinuse[unit]) {
  446.         syslog(LOG_ERR, "pst clock: unit number %d in use", unit);
  447.         return 0;
  448.     }
  449.  
  450.     /*
  451.      * Unit okay, attempt to open the device.
  452.      */
  453.     (void) sprintf(pstdev, PSTDEV, unit);
  454.  
  455.     fd = open(pstdev, O_RDWR, 0777);
  456.     if (fd == -1) {
  457.         syslog(LOG_ERR, "pst clock: open of %s failed: %m", pstdev);
  458.         return 0;
  459.     }
  460.  
  461. #if !defined(HPUX)
  462.     /*
  463.      * Set for exclusive use
  464.      */
  465.     if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
  466.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCEXCL): %m", pstdev);
  467.         (void) close(fd);
  468.         return 0;
  469.     }
  470. #endif
  471.  
  472.     /*
  473.      * Set up file descriptor
  474.      *   -> Those of us without CLKLDISC will have to do it cooked
  475.      */
  476. #if defined(HPUX)
  477.     if (ioctl(fd, TCGETA, (char *)&ttyb) < 0) {
  478.         syslog(LOG_ERR, "pst clock: ioctl(%s, TCGETA): %m", pstdev);
  479.         return 0;
  480.     }
  481.     ttyb.c_cflag = (PSTBAUD|CS8|CLOCAL|CREAD);
  482.     ttyb.c_iflag = ICRNL;
  483.     ttyb.c_oflag = 0;
  484.     ttyb.c_lflag = ICANON;
  485.     ttyb.c_cc[VINTR] = '\000';
  486.     ttyb.c_cc[VQUIT] = '\000';
  487.     ttyb.c_cc[VERASE] = '\000';
  488.     ttyb.c_cc[VKILL] = '\000';
  489.     ttyb.c_cc[VEOF] = '\000';
  490.     ttyb.c_cc[VEOL] = PSTMAGIC2;
  491.     ttyb.c_cc[VSWTCH] = '\000';
  492.     if (ioctl(fd, TCSETA, (char *)&ttyb) < 0) {
  493.         syslog(LOG_ERR, "pst clock: ioctl(%s, TCSETA): %m", pstdev);
  494.         return 0;
  495.     }
  496. #else
  497.     ttyb.sg_ispeed = ttyb.sg_ospeed = PSTBAUD;
  498. #ifdef CLKLDISC
  499.     /*
  500.      * Set to raw mode
  501.      */
  502.     ttyb.sg_erase = PSTMAGIC1;
  503.     ttyb.sg_kill = PSTMAGIC2;
  504.     ttyb.sg_flags = EVENP|ODDP|RAW|CRMOD;
  505. #else
  506.     /*
  507.      * Does this really work ?
  508.      */
  509.     ttyb.sg_erase = ttyb.sg_kill = 0;
  510.     ttyb.sg_flags = EVENP|ODDP|CRMOD;
  511. #endif
  512.     if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
  513.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCSETP): %m", pstdev);
  514.         return 0;
  515.     }
  516. #endif
  517.  
  518.     /*
  519.      * Looks like this might succeed.  Find memory for the structure.
  520.      * Look to see if there are any unused ones, if not we malloc()
  521.      * one.
  522.      */
  523.     if (pstunits[unit] != 0) {
  524.         pst = pstunits[unit];    /* The one we want is okay */
  525.     } else {
  526.         for (i = 0; i < MAXUNITS; i++) {
  527.             if (!unitinuse[i] && pstunits[i] != 0)
  528.                 break;
  529.         }
  530.         if (i < MAXUNITS) {
  531.             /*
  532.              * Reclaim this one
  533.              */
  534.             pst = pstunits[i];
  535.             pstunits[i] = 0;
  536.         } else {
  537.             pst = (struct pstunit *)emalloc(sizeof(struct pstunit));
  538.         }
  539.     }
  540.     bzero((char *)pst, sizeof(struct pstunit));
  541.     pstunits[unit] = pst;
  542.  
  543.     /*
  544.      * Set up the structure
  545.      */
  546.     pst->peer = peer;
  547.     pst->unit = (u_char)unit;
  548.     pst->state = STATE_IDLE;
  549.     pst->flags |= PST_DOQV;
  550.     pst->timestarted = current_time;
  551.     (void) strcpy(pst->description, pstdefdesc);
  552.  
  553.     pst->psttimer.peer = (struct peer *)pst;
  554.     pst->psttimer.event_handler = pst_timeout;
  555.  
  556.     pst->pstio.clock_recv = pst_receive;
  557.     pst->pstio.srcclock = (caddr_t)pst;
  558.     pst->pstio.datalen = 0;
  559.     pst->pstio.fd = fd;
  560.  
  561.     /*
  562.      * Okay.  Set the line discipline to the clock line discipline,
  563.      * if we have it, then give it to the I/O code to start receiving
  564.      * stuff.
  565.      */
  566. #ifdef CLKLDISC
  567.     ldisc = CLKLDISC;
  568.     if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
  569.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCSETD): %m", pstdev);
  570.         (void) close(fd);
  571.         return 0;
  572.     }
  573. #else
  574. #if defined(HPUX)
  575.     if (ioctl(fd, TCFLSH, 2) < 0) {
  576.         syslog(LOG_ERR, "pst clock: ioctl(%s, TCFLSH): %m", pstdev);
  577.         (void) close(fd);
  578.         return 0;
  579.     }
  580. #else
  581.     ldisc = 0;
  582.     if (ioctl(fd, TIOCFLUSH, (char *)&ldisc) < 0) {
  583.         syslog(LOG_ERR, "pst clock: ioctl(%s, TIOCFLUSH): %m", pstdev);
  584.         (void) close(fd);
  585.         return 0;
  586.     }
  587. #endif
  588. #endif
  589.     if (!io_addclock(&pst->pstio)) {
  590.         /*
  591.          * Oh shit.  Just close and return.
  592.          */
  593.         (void) close(fd);
  594.         return 0;
  595.     }
  596.  
  597.     /*
  598.      * All done.  Initialize a few random peer variables, then
  599.      * start the timer and return success.
  600.      */
  601.     peer->precision = PSTPRECISION;
  602.     peer->rootdelay = 0;
  603.     peer->rootdispersion = 0;
  604.     peer->stratum = stratumtouse[unit];
  605.     if (stratumtouse[unit] <= 1)
  606.         bcopy(WWVREFID, (char *)&peer->refid, 4);
  607.     else
  608.         peer->refid = htonl(PSTHSREFID);
  609.     pst->psttimer.event_time = current_time + PSTMINTIMEOUT;
  610.     TIMER_ENQUEUE(timerqueue, &pst->psttimer);
  611.     unitinuse[unit] = 1;
  612.     return 1;
  613. }
  614.  
  615.  
  616. /*
  617.  * pst_shutdown - shut down a PST clock
  618.  */
  619. void
  620. pst_shutdown(unit)
  621.     int unit;
  622. {
  623.     register struct pstunit *pst;
  624.     extern void io_closeclock();
  625.  
  626.     if (unit >= MAXUNITS) {
  627.         syslog(LOG_ERR,
  628.           "pst clock: INTERNAL ERROR, unit number %d invalid (max %d)",
  629.             unit, MAXUNITS-1);
  630.         return;
  631.     }
  632.     if (!unitinuse[unit]) {
  633.         syslog(LOG_ERR,
  634.          "pst clock: INTERNAL ERROR, unit number %d not in use", unit);
  635.         return;
  636.     }
  637.  
  638.     /*
  639.      * Tell the I/O module to turn us off, and dequeue timer
  640.      * if any.  We're history.
  641.      */
  642.     pst = pstunits[unit];
  643.     TIMER_DEQUEUE(&pst->psttimer);
  644.     io_closeclock(&pst->pstio);
  645.     unitinuse[unit] = 0;
  646. }
  647.  
  648.  
  649. /*
  650.  * pst_write_error - complain about writes to the clock
  651.  */
  652. static void
  653. pst_write_error(pst)
  654.     struct pstunit *pst;
  655. {
  656.     /*
  657.      * This will fill syslog is something is really wrong.  Should
  658.      * throttle it back.
  659.      */
  660.     syslog(LOG_ERR, "pst clock: write error on unit %d: %m",
  661.         pst->unit);
  662. }
  663.  
  664.  
  665. /*
  666.  * pst_timeout - process a timeout event
  667.  */
  668. void
  669. pst_timeout(fakepeer)
  670.     struct peer *fakepeer;
  671. {
  672.     register struct pstunit *pst;
  673.     u_long poll;
  674.  
  675.     /*
  676.      * The timeout routine always initiates a chain of
  677.      * query-responses from the clock, by sending either
  678.      * a QV command (if we need to (re)set the propagation
  679.      * delays into the clock), a QM command or an SRY
  680.      * command (after a leap second).  The pst_receive()
  681.      * routine should complete the set of queries on its own
  682.      * long before the next time out is due, so if we see any
  683.      * state in here other than idle it means the clock hasn't
  684.      * responded.
  685.      */
  686.     pst = (struct pstunit *)fakepeer;
  687.     switch(pst->state) {
  688.     case STATE_IDLE:
  689.         poll = (u_long)psttab[pst->nextsample].nextinterval;
  690.         break;                /* all is well */
  691.  
  692.     case STATE_QV:
  693.         pst->flags |= PST_DOQV;        /* no response, do QV again */
  694.         /*FALLSTHROUGH*/
  695.  
  696.     case STATE_QM:
  697.     case STATE_QD:
  698.     case STATE_QT:
  699.         pst->noreply++;            /* mark the lack of response */
  700.         poll = PSTMINTIMEOUT;        /* minimum time poll */
  701.         break;
  702.  
  703.     default:
  704.         syslog(LOG_ERR,
  705.             "pst clock: INTERNAL ERROR unit %d invalid state %d",
  706.             pst->unit, pst->state);
  707.         poll = PSTMINTIMEOUT;        /* minimum time poll */
  708.         break;
  709.     }
  710.  
  711.     if (pst->flags & PST_DORESET) {
  712.         /*
  713.          * Do a reset.  At the next interrupt, start with
  714.          * a QV command to set in the delays.
  715.          */
  716.         pst->flags &= ~PST_DORESET;
  717.         pst->flags |= PST_DOQV;
  718.         pst->state = STATE_IDLE;
  719.         pst_send(pst, "\003SRY", 4);
  720.     } else if (pst->flags & PST_DOQV) {
  721.         pst->polls++;
  722.         pst->flags &= ~PST_DOQV;
  723.         pst->state = STATE_QV;
  724.         pst_send(pst, "\003QV", 3);
  725.     } else {
  726.         pst->polls++;
  727.         pst->state = STATE_QM;
  728.         pst_send(pst, "\003QM", 3);
  729.     }
  730.  
  731.     pst->psttimer.event_time += poll;
  732.     TIMER_ENQUEUE(timerqueue, &pst->psttimer);
  733. }
  734.  
  735.  
  736. /*
  737.  * pst_QV_process - decode the results of a QV poll and insert fudge
  738.  *            factors into the clock.
  739.  */
  740. static int
  741. pst_QV_process(pst, rbufp)
  742.     register struct pstunit *pst;
  743.     struct recvbuf *rbufp;
  744. {
  745.     register char *cp;
  746.     register char *bp;
  747.     register int len;
  748.     char *model;
  749.     char *company;
  750.     char buf[20];
  751.     static char wwvdelay[6] = { 'S', 'C', '\0', 'S', 'E', '\0' };
  752.     static char wwvhdelay[6] = { 'S', 'H', '\0', 'S', 'G', '\0' };
  753.  
  754.     /*
  755.      * The output of the QV command looks like:
  756.      *
  757.      * PSTI ITS V04.01.000\r
  758.      *
  759.      * or
  760.      *
  761.      * TRAC ITS V04.01.000\r
  762.      *
  763.      * The minimum length of the string is about 16 characters.
  764.      * The maximum length is sort of unbounded, but we get suspicious
  765.      * if it is more than 34.
  766.      */
  767.     len = rbufp->recv_length;
  768.     if (len > PSTMAXQVLEN + 10)
  769.         len = PSTMAXQVLEN + 10;
  770.     
  771.     bp = rbufp->recv_buffer;
  772.     cp = pst->lastcode;
  773.     while (len-- > 0) {
  774.         *cp = (*bp++) & 0x7f;    /* strip parity */
  775.         if (!isprint(*cp))
  776.             break;
  777.         cp++;
  778.     }
  779.     pst->lencode = (u_char)(cp - pst->lastcode);
  780.  
  781.     /*
  782.      * Okay, got all printable characters from the string
  783.      * copied.  We expect to have been terminated by the
  784.      * EOL character.  If not, forget it.  If the length
  785.      * is insane, forget it.
  786.      */
  787.  
  788.     if (*cp != PSTEOL
  789.         || pst->lencode < PSTMINQVLEN || pst->lencode > PSTMAXQVLEN) {
  790.         pst->reason = QVREASON + 1;
  791.         return 0;
  792.     }
  793.  
  794.     /*
  795.      * Now, format check what we can.  Dump it at the least
  796.      * sign of trouble.
  797.      */
  798.     cp = pst->lastcode;
  799.     if (*cp++ != 'P' || *cp++ != 'S' || *cp++ != 'T'
  800.         || *cp++ != 'I' || *cp++ != ' ') {
  801.         cp = pst->lastcode;
  802.         if (*cp++ != 'T' || *cp++ != 'R' || *cp++ != 'A'
  803.             || *cp++ != 'C' || *cp++ != ' ') {
  804.             pst->reason = QVREASON + 2;
  805.             return 0;
  806.         }
  807.         company = "Traconex";
  808.     } else {
  809.         company = "Precision Standard Time";
  810.     }
  811.  
  812.     if (*cp == 'M')
  813.         model = "1010";
  814.     else if (*cp == 'I')
  815.         model = "1020";
  816.     else {
  817.         pst->reason = QVREASON + 3;
  818.         return 0;
  819.     }
  820.     cp++;
  821.  
  822.     if (*cp++ != 'T' || *cp++ != 'S' || *cp++ != ' ') {
  823.         pst->reason = QVREASON + 4;
  824.         return 0;
  825.     }
  826.     if (*cp != 'X' && *cp != 'V') {
  827.         pst->reason = QVREASON + 5;
  828.         return 0;
  829.     }
  830.     
  831.     /*
  832.      * Next is the version.  Copy it into the buffer.
  833.      */
  834.     bp = buf;
  835.     *bp++ = *cp++;
  836.     while (isdigit(*cp) || *cp == '.')
  837.         *bp++ = *cp++;
  838.     *bp++ = '\0';
  839.  
  840.     /*
  841.      * Final bit of fluff is to set the description
  842.      */
  843.     (void) sprintf(pst->description, PSTDESCRIPTION, company, model, buf);
  844.  
  845.     /*
  846.      * Now the serious stuff.  Since we are now sure that the
  847.      * clock is there, we can be fairly sure that the delay
  848.      * setting commands will take.  Send them.
  849.      */
  850.     wwvdelay[2] = wwv_prop_data[pst->unit].msbchar;
  851.     wwvdelay[5] = wwv_prop_data[pst->unit].lsbchar;
  852.     pst_send(pst, wwvdelay, 6);
  853.  
  854.     /*
  855.      * Same thing for WWVH
  856.      */
  857.     wwvhdelay[2] = wwvh_prop_data[pst->unit].msbchar;
  858.     wwvhdelay[5] = wwvh_prop_data[pst->unit].lsbchar;
  859.     pst_send(pst, wwvhdelay, 6);
  860.  
  861.     /*
  862.      * Should be okay.  Return positive response.
  863.      */
  864.     return 1;
  865. }
  866.  
  867.  
  868. /*
  869.  * pst_QM_process - process the output of a QM command
  870.  */
  871. static int
  872. pst_QM_process(pst, rbufp)
  873.     register struct pstunit *pst;
  874.     struct recvbuf *rbufp;
  875. {
  876.     register char *cp;
  877.     register char *bp;
  878.     register int n;
  879.  
  880.     /*
  881.      * The output of the QM command looks like:
  882.      *
  883.       * O6B532352823C00270322
  884.      *
  885.      * The minimum length of the string is 19 characters.
  886.      * The maximum length is sort of unbounded, but we get suspicious
  887.      * if it is more than 42.
  888.      */
  889.     n = rbufp->recv_length;
  890.     if (n > PSTMAXQMLEN + 10)
  891.         n = PSTMAXQMLEN + 10;
  892.     
  893.     bp = rbufp->recv_buffer;
  894.     cp = pst->lastcode;
  895.     while (n-- > 0) {
  896.         *cp = (*bp++) & 0x7f;    /* strip parity */
  897.         if (!isprint(*cp))
  898.             break;
  899.         cp++;
  900.     }
  901.     pst->lencode = (u_char)(cp - pst->lastcode);
  902.  
  903.     /*
  904.      * Okay, got all printable characters from the string
  905.      * copied.  We expect to have been terminated by the
  906.      * EOL character.  If not, forget it.  If the length
  907.      * is insane, forget it.
  908.      */
  909.     if (*cp != PSTEOL
  910.         || pst->lencode < PSTMINQMLEN || pst->lencode > PSTMAXQMLEN) {
  911.         pst->reason = QMREASON + 1;
  912.         return 0;
  913.     }
  914.  
  915.     /*
  916.      * Ensure that the first PSTMINQMLEN characters are valid with
  917.      * respect to the way the clock encodes binary data.
  918.      */
  919.     cp = pst->lastcode;
  920.     n = pst->lencode;
  921.     while (n-- > 0) {
  922.         if (!ISVALIDPST(*cp)) {
  923.             pst->reason = QMREASON + 2;
  924.             return 0;
  925.         }
  926.         cp++;
  927.     }
  928.  
  929.     /*
  930.      * Collect information we are interested in.
  931.      */
  932.     cp = pst->lastcode;
  933.     pst->timezone = PSTTOBIN(cp[3]);
  934.     if (pst->timezone > 23) {
  935.         pst->reason = QMREASON + 3;
  936.         return 0;
  937.     }
  938.  
  939.     pst->flags &=
  940.         ~(PST_LEAPYEAR|PST_SIGFAULT|PST_HARDERR|PST_NOTIME|PST_WWVH);
  941.     n = PSTTOBIN(cp[4]);
  942.     if (n > 15) {
  943.         pst->reason = QMREASON + 4;
  944.         return 0;
  945.     }
  946.     if (((n + 2) & 0x3) == 0)
  947.         pst->flags |= PST_LEAPYEAR;
  948.  
  949.     n = PSTTOBIN(cp[9]);
  950.     if (n > 15) {
  951.         pst->reason = QMREASON + 5;
  952.         return 0;
  953.     }
  954.     if (n & SIGFAULT)
  955.         pst->flags |= PST_SIGFAULT;
  956.     if (n & HARDFAULT)
  957.         pst->flags |= PST_HARDERR;
  958.     if (!(n & TIMEAVAILABLE))
  959.         pst->flags |= PST_NOTIME;
  960.  
  961.     if (cp[12] == 'H') {
  962.         pst->flags |= PST_WWVH;
  963.     } else if (cp[12] == 'C') {
  964.         pst->flags &= ~PST_WWVH;
  965.     } else {
  966.         pst->reason = QMREASON + 6;
  967.         return 0;
  968.     }
  969.  
  970.     if (wwv_prop_data[pst->unit].msbchar != cp[5] ||
  971.         wwv_prop_data[pst->unit].lsbchar != cp[6] ||
  972.         wwvh_prop_data[pst->unit].msbchar != cp[7] ||
  973.         wwvh_prop_data[pst->unit].lsbchar != cp[8])
  974.         pst->flags |= PST_DOQV;
  975.  
  976.     bp = cp + 13;
  977.     pst->timesincesync = 0;
  978.     while (bp < (cp + 17)) {
  979.         if (!isdigit(*bp)) {
  980.             pst->reason = QMREASON + 6;
  981.             return 0;
  982.         }
  983.         pst->timesincesync = MULBY10(pst->timesincesync)
  984.             + PSTTOBIN(*bp);
  985.         bp++;
  986.     }
  987.  
  988.     /*
  989.      * That's about all we can do.  Return success.
  990.      */
  991.     return 1;
  992. }
  993.  
  994.  
  995. /*
  996.  * pst_QD_process - process the output of a QD command
  997.  */
  998. static int
  999. pst_QD_process(pst, rbufp)
  1000.     register struct pstunit *pst;
  1001.     struct recvbuf *rbufp;
  1002. {
  1003.     register char *cp;
  1004.     register char *bp;
  1005.     register int n;
  1006.     char *cpstart;
  1007.     int len;
  1008.  
  1009.     /*
  1010.      * The output of the QM command looks like:
  1011.      *
  1012.       * 88/05/17/138\r
  1013.      *
  1014.      * The minimum length of the string is 12 characters as is
  1015.      * the maximum length.
  1016.      */
  1017.     n = rbufp->recv_length;
  1018.     if (n > PSTMAXQDLEN + 10)
  1019.         n = PSTMAXQDLEN + 10;
  1020.     
  1021.     bp = rbufp->recv_buffer;
  1022.     cp = &pst->lastcode[pst->lencode];
  1023.     *cp++ = ' ';
  1024.     cpstart = cp;
  1025.     while (n-- > 0) {
  1026.         *cp = (*bp++) & 0x7f;    /* strip parity */
  1027.         if (!isprint(*cp))
  1028.             break;
  1029.         cp++;
  1030.     }
  1031.     len = (cp - cpstart);
  1032.     pst->lencode = (u_char)(cp - pst->lastcode);
  1033.  
  1034.     /*
  1035.      * Okay, got all printable characters from the string
  1036.      * copied.  We expect to have been terminated by the
  1037.      * EOL character.  If not, forget it.  If the length
  1038.      * is insane, forget it.
  1039.      */
  1040.     if (*cp != PSTEOL ||
  1041.         len < PSTMINQDLEN || len > PSTMAXQDLEN) {
  1042.         pst->reason = QDREASON + 1;
  1043.         return 0;
  1044.     }
  1045.  
  1046.     /*
  1047.      * Ensure that the characters are formatted validly.  They
  1048.      * are either digits or '/'s.
  1049.      */
  1050.     cp = cpstart;
  1051.     if (!isdigit(cp[0]) || !isdigit(cp[1]) || cp[2] != '/' ||
  1052.         !isdigit(cp[3]) || !isdigit(cp[4]) || cp[5] != '/' ||
  1053.         !isdigit(cp[6]) || !isdigit(cp[7]) || cp[8] != '/' ||
  1054.         !isdigit(cp[9]) || !isdigit(cp[10]) || !isdigit(cp[11])) {
  1055.         pst->reason = QDREASON + 2;
  1056.         return 0;
  1057.     }
  1058.  
  1059.     /*
  1060.      * Decode into year, month, day and year day
  1061.      */
  1062.     pst->year = MULBY10(PSTTOBIN(cp[0])) + PSTTOBIN(cp[1]);
  1063.     pst->month = MULBY10(PSTTOBIN(cp[3])) + PSTTOBIN(cp[4]);
  1064.     pst->monthday = MULBY10(PSTTOBIN(cp[6])) + PSTTOBIN(cp[7]);
  1065.     pst->yearday = MULBY10(PSTTOBIN(cp[9])) + PSTTOBIN(cp[10]);
  1066.     pst->yearday = MULBY10(pst->yearday) + PSTTOBIN(cp[11]);
  1067.  
  1068.     /*
  1069.      * Format check these.
  1070.      */
  1071.     if (pst->month > 12 || pst->monthday > 31 || pst->yearday > 366) {
  1072.         pst->reason = QDREASON + 3;
  1073.         return 0;
  1074.     }
  1075.     if (!(pst->flags & PST_LEAPYEAR) && pst->yearday > 365) {
  1076.         pst->reason = QDREASON + 4;
  1077.         return 0;
  1078.     }
  1079.  
  1080.     /*
  1081.      * Done all we can.
  1082.      */
  1083.     return 1;
  1084. }
  1085.  
  1086.  
  1087. /*
  1088.  * pst_QT_process - process the output of a QT command, return the times
  1089.  */
  1090. static int
  1091. pst_QT_process(pst, rbufp, tsclk, tsrec)
  1092.     register struct pstunit *pst;
  1093.     struct recvbuf *rbufp;
  1094.     l_fp *tsclk;
  1095.     l_fp *tsrec;
  1096. {
  1097.     register char *cp;
  1098.     register char *bp;
  1099.     register int n;
  1100.     char *cpstart;
  1101.     int len;
  1102.     int hour;
  1103.     int minute;
  1104.     int second;
  1105.     int msec;
  1106.     int tzoff;
  1107.     extern int buftvtots();
  1108.  
  1109.     /*
  1110.      * The output of the QT command looks like:
  1111.      *
  1112.       * A09:57:50.263D
  1113.       * 
  1114.      * The minimum length of the string is 14 characters as is
  1115.      * the maximum length.
  1116.      */
  1117.     n = rbufp->recv_length;
  1118.     if (n > PSTMAXQTLEN + 10)
  1119.         n = PSTMAXQTLEN + 10;
  1120.     
  1121.     bp = rbufp->recv_buffer;
  1122.     cp = &pst->lastcode[pst->lencode];
  1123.     *cp++ = ' ';
  1124.     cpstart = cp;
  1125.     while (n-- > 0) {
  1126.         *cp = (*bp++) & 0x7f;    /* strip parity */
  1127.         if (!isprint(*cp))
  1128.             break;
  1129.         cp++;
  1130.     }
  1131.     len = (cp - cpstart);
  1132.     pst->lencode = (u_char)(cp - pst->lastcode);
  1133.  
  1134.     /*
  1135.      * Okay, got all printable characters from the string
  1136.      * copied.  We expect to have been terminated by the
  1137.      * EOL character.  If not, forget it.  If the length
  1138.      * is insane, forget it.
  1139.      */
  1140.     if (*cp != PSTEOL ||
  1141.         len < PSTMINQTLEN || len > PSTMAXQTLEN) {
  1142.         pst->reason = QTREASON + 1;
  1143.         return 0;
  1144.     }
  1145. #ifdef CLKLDISC
  1146.     /*
  1147.      * Receive time stamp should be in buffer after the code.
  1148.      * Make sure we have enough characters in there.
  1149.      */
  1150.     if (&rbufp->recv_buffer[rbufp->recv_length] - bp < 8) {
  1151.         pst->reason = QTREASON + 2;
  1152.         return 0;
  1153.     }
  1154.     if (!buftvtots(bp, tsrec)) {
  1155.         pst->reason = QTREASON + 3;
  1156.         return 0;
  1157.     }
  1158. #else
  1159.     /*
  1160.      * Use the timestamp collected with the input.
  1161.      */
  1162.     *tsrec = rbufp->recv_time;
  1163. #endif
  1164.  
  1165.     /*
  1166.      * Ensure that the characters are formatted validly.  Mostly
  1167.      * digits, but the occasional `:' and `.'.
  1168.      */
  1169.     cp = cpstart;
  1170.     if (!isdigit(cp[1]) || !isdigit(cp[2]) || cp[3] != ':' ||
  1171.         !isdigit(cp[4]) || !isdigit(cp[5]) || cp[6] != ':' ||
  1172.         !isdigit(cp[7]) || !isdigit(cp[8]) || cp[9] != '.' ||
  1173.         !isdigit(cp[10]) || !isdigit(cp[11]) || !isdigit(cp[12])) {
  1174.         pst->reason = QTREASON + 4;
  1175.         return 0;
  1176.     }
  1177.  
  1178.     /*
  1179.      * Extract the hour, minute, second and millisecond
  1180.      */
  1181.     hour = MULBY10(PSTTOBIN(cp[1])) + PSTTOBIN(cp[2]);
  1182.     minute = MULBY10(PSTTOBIN(cp[4])) + PSTTOBIN(cp[5]);
  1183.     second = MULBY10(PSTTOBIN(cp[7])) + PSTTOBIN(cp[8]);
  1184.     msec = MULBY10(PSTTOBIN(cp[10])) + PSTTOBIN(cp[11]);
  1185.     msec = MULBY10(msec) + PSTTOBIN(cp[12]);
  1186.  
  1187.     if (minute > 59 || second > 59) {
  1188.         pst->reason = QTREASON + 5;
  1189.         return 0;
  1190.     }
  1191.  
  1192.     /*
  1193.      * Trouble here.  Adjust the hours for AM/PM, if this is
  1194.      * on, and for daylight saving time.
  1195.      */
  1196.     if (*cp == 'A') {
  1197.         if (hour > 12 || hour == 0) {
  1198.             pst->reason = QTREASON + 5;
  1199.             return 0;
  1200.         }
  1201.         if (hour == 12)
  1202.             hour = 0;
  1203.     } else if (*cp == 'P') {
  1204.         if (hour > 12 || hour == 0)
  1205.             return 0;
  1206.         if (hour < 12)
  1207.             hour += 12;
  1208.     } else if (*cp != ' ') {
  1209.         pst->reason = QTREASON + 6;
  1210.         return 0;
  1211.     }
  1212.  
  1213.     if (cp[13] == 'D')
  1214.         tzoff = -1;
  1215.     else if (cp[13] == ' ')
  1216.         tzoff = 0;
  1217.     else {
  1218.         pst->reason = QTREASON + 7;
  1219.         return 0;
  1220.     }
  1221.  
  1222.     /*
  1223.      * Adjust for the timezone.  The PST manual is screwy here.
  1224.      * it says the timezone is an integer in the range 0 to 23,
  1225.      * but this doesn't allow us to tell the difference between
  1226.      * +12 and -12.  Assume the 12 hour timezone is west of
  1227.      * GMT.
  1228.      */
  1229.     if (pst->timezone <= 12)
  1230.         tzoff += pst->timezone;
  1231.     else
  1232.         tzoff -= (24 - pst->timezone);
  1233.  
  1234.  
  1235.     /*
  1236.      * Record for posterity
  1237.      */
  1238.     pst->hour = (u_char)hour;
  1239.     pst->minute = (u_char)minute;
  1240.     pst->second = (u_char)second;
  1241.     pst->millisecond = (u_short)msec;
  1242.     pst->tzoffset = (s_char)tzoff;
  1243.  
  1244.     /*
  1245.      * All that to get the day-hour-minute-second.  Turn this
  1246.      * into the seconds part of a time stamp.  Also use the
  1247.      * milliseconds part directly as the fractional part.
  1248.      */
  1249.     MSUTOTSF(msec, tsclk->l_uf);
  1250.     if (!clocktime((int)pst->yearday, hour, minute, second, tzoff,
  1251.         tsrec->l_ui, &pst->yearstart, &tsclk->l_ui)) {
  1252.         pst->reason = QTREASON + 8;
  1253.         return 0;
  1254.     }
  1255.  
  1256.     /*
  1257.      * Add in the fudge
  1258.      */
  1259.     if (pst->flags & PST_WWVH)
  1260.         L_ADDUF(tsclk, wwvh_prop_data[pst->unit].remainder);
  1261.     else
  1262.         L_ADDUF(tsclk, wwv_prop_data[pst->unit].remainder);
  1263.  
  1264.     /*
  1265.      * Glad that's over with
  1266.      */
  1267.     return 1;
  1268. }
  1269.  
  1270.  
  1271. /*
  1272.  * pst_do_event - update our status and report any changes
  1273.  */
  1274. static void
  1275. pst_do_event(pst, evnt_code)
  1276.     register struct pstunit *pst;
  1277.     int evnt_code;
  1278. {
  1279.     if (pst->status != (u_char)evnt_code) {
  1280.         pst->status = (u_char)evnt_code;
  1281.         if (evnt_code != CEVNT_NOMINAL)
  1282.             pst->lastevent = (u_char)evnt_code;
  1283.         /*
  1284.          * Should trap this, but the trap code isn't up to
  1285.          * it yet.
  1286.          */
  1287.     }
  1288. }
  1289.  
  1290.  
  1291.  
  1292. /*
  1293.  * pst_process - process the data collected to produce an offset estimate
  1294.  */
  1295. static void
  1296. pst_process(pst)
  1297.     register struct pstunit *pst;
  1298. {
  1299.     register int i;
  1300.     register int n;
  1301.     register u_long tmp_ui;
  1302.     register u_long tmp_uf;
  1303.     register u_long date_ui;
  1304.     register u_long date_uf;
  1305.     s_fp delay;
  1306.     u_fp dispersion;
  1307.     int leap;
  1308.     l_fp off[NPSTSAMPS];
  1309.     extern void refclock_receive();
  1310.  
  1311.     /*
  1312.      * Compute offsets from the raw data.  Sort them into
  1313.      * ascending order.
  1314.      */
  1315.     for (i = 0; i < NPSTSAMPS; i++) {
  1316.         tmp_ui = pst->reftimes[i].l_ui;
  1317.         tmp_uf = pst->reftimes[i].l_uf;
  1318.         M_SUB(tmp_ui, tmp_uf, pst->rectimes[i].l_ui,
  1319.             pst->rectimes[i].l_uf);
  1320.         for (n = i; n > 0; n--) {
  1321.             if (M_ISGEQ(tmp_ui, tmp_uf, off[n-1].l_ui,
  1322.                 off[n-1].l_uf))
  1323.                 break;
  1324.             off[n] = off[n-1];
  1325.         }
  1326.         off[n].l_ui = tmp_ui;
  1327.         off[n].l_uf = tmp_uf;
  1328.     }
  1329.  
  1330.     /*
  1331.      * Reject the furthest from the median until 8 samples left
  1332.      */
  1333.     i = 0;
  1334.     n = NPSTSAMPS;
  1335.     while ((n - i) > 8) {
  1336.         tmp_ui = off[n-1].l_ui;
  1337.         tmp_uf = off[n-1].l_uf;
  1338.         date_ui = off[(n+i)/2].l_ui;
  1339.         date_uf = off[(n+i)/2].l_uf;
  1340.         M_SUB(tmp_ui, tmp_uf, date_ui, date_uf);
  1341.         M_SUB(date_ui, date_uf, off[i].l_ui, off[i].l_uf);
  1342.         if (M_ISHIS(date_ui, date_uf, tmp_ui, tmp_uf)) {
  1343.             /*
  1344.              * reject low end
  1345.              */
  1346.             i++;
  1347.         } else {
  1348.             /*
  1349.              * reject high end
  1350.              */
  1351.             n--;
  1352.         }
  1353.     }
  1354.  
  1355.     /*
  1356.      * Compute the dispersion based on the difference between the
  1357.      * extremes of the remaining offsets.
  1358.      */
  1359.     tmp_ui = off[n-1].l_ui;
  1360.     tmp_uf = off[n-1].l_uf;
  1361.     M_SUB(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
  1362.     dispersion = MFPTOFP(tmp_ui, tmp_uf);
  1363.  
  1364.     /*
  1365.      * Now compute the offset estimate.  If the sloppy clock
  1366.      * flag is set, average the remainder, otherwise pick the
  1367.      * median.
  1368.      */
  1369.     if (sloppyclock[pst->unit]) {
  1370.         tmp_ui = tmp_uf = 0;
  1371.         while (i < n) {
  1372.             M_ADD(tmp_ui, tmp_uf, off[i].l_ui, off[i].l_uf);
  1373.             i++;
  1374.         }
  1375.         M_RSHIFT(tmp_ui, tmp_uf);
  1376.         M_RSHIFT(tmp_ui, tmp_uf);
  1377.         M_RSHIFT(tmp_ui, tmp_uf);
  1378.         i = 0;
  1379.         off[0].l_ui = tmp_ui;
  1380.         off[0].l_uf = tmp_uf;
  1381.     } else {
  1382.         i = (n+i)/2;
  1383.     }
  1384.  
  1385.     /*
  1386.      * Add the default PST QT delay into this.
  1387.      */
  1388.     L_ADDUF(&off[i], PSTQTFUDGE);
  1389.  
  1390.     /*
  1391.      * Set the reference ID to the appropriate station
  1392.      */
  1393.     if (stratumtouse[pst->unit] <= 1) {
  1394.         if (pst->station >= 0)
  1395.             bcopy(WWVREFID, (char *)&pst->peer->refid, 4);
  1396.         else
  1397.             bcopy(WWVHREFID, (char *)&pst->peer->refid, 4);
  1398.     }
  1399.  
  1400.     /*
  1401.      * Give the data to the reference clock support code
  1402.      */
  1403.     refclock_receive(pst->peer, &off[i], 0, dispersion, &pst->reftimes[NPSTSAMPS-1],
  1404.         &pst->rectimes[NPSTSAMPS-1], pst->leap);
  1405.  
  1406.     /*
  1407.      * If the don't-sync flag isn't on, we're nominal.
  1408.      */
  1409.     if (pst->leap == 0)
  1410.         pst_event(pst, CEVNT_NOMINAL);
  1411.     pst_reset(pst);
  1412. }
  1413.  
  1414.  
  1415.  
  1416. /*
  1417.  * pst_receive - receive data from a PST clock, call the appropriate
  1418.  *         routine to process it, and advance the state.
  1419.  */
  1420. void
  1421. pst_receive(rbufp)
  1422.     struct recvbuf *rbufp;
  1423. {
  1424.     register struct pstunit *pst;
  1425.     register u_long tmp;
  1426.     void pst_process();
  1427.  
  1428.     pst = (struct pstunit *)rbufp->recv_srcclock;
  1429.  
  1430.     /*
  1431.      * Process based on the current state.
  1432.      */
  1433.     switch(pst->state) {
  1434.     case STATE_IDLE:
  1435.         return;            /* Ignore the input */
  1436.  
  1437.     case STATE_QV:
  1438.         if (!pst_QV_process(pst, rbufp)) {
  1439.             /*
  1440.              * Set the state to idle, but request another
  1441.              * QV poll.
  1442.              */
  1443.             pst->badformat++;
  1444.             pst_event(pst, CEVNT_BADREPLY);
  1445.             pst->state = STATE_IDLE;
  1446.             pst->flags |= PST_DOQV;
  1447.         } else {
  1448.             /*
  1449.              * This went okay.  Advance the state to
  1450.              * QM and send the request.
  1451.              */
  1452.             pst->state = STATE_QM;
  1453.             pst_send(pst, "QM", 2);
  1454.         }
  1455.         return;
  1456.  
  1457.     case STATE_QM:
  1458.         if (!pst_QM_process(pst, rbufp)) {
  1459.             /*
  1460.              * Idle us and note the error
  1461.              */
  1462.             pst->badformat++;
  1463.             pst_event(pst, CEVNT_BADREPLY);
  1464.             pst->state = STATE_IDLE;
  1465.             return;
  1466.         }
  1467.         if (pst->flags & PST_NOTIME) {
  1468.             /*
  1469.              * Here we aren't getting any time because the
  1470.              * clock is still searching.  Don't bother
  1471.              * looking for anything.  Remove any leap
  1472.              * second hold, however, since this should
  1473.              * ensure the clock is sensible.
  1474.              */
  1475.             pst_event(pst, CEVNT_FAULT);
  1476.             pst->state = STATE_IDLE;
  1477.             if (pst->nextsample > 0)
  1478.                 pst_reset(pst);        /* Make sure rate low */
  1479.             return;
  1480.         }
  1481.  
  1482.         /*
  1483.          * Next is QD.  Do it.
  1484.          */
  1485.         pst->state = STATE_QD;
  1486.         pst_send(pst, "QD", 2);
  1487.         return;
  1488.  
  1489.     case STATE_QD:
  1490.         if (!pst_QD_process(pst, rbufp)) {
  1491.             /*
  1492.              * Idle us and note the error
  1493.              */
  1494.             pst->badformat++;
  1495.             pst_event(pst, CEVNT_BADDATE);
  1496.             pst->state = STATE_IDLE;
  1497.         } else {
  1498.             /*
  1499.              * Last step is QT.
  1500.              */
  1501.             pst->state = STATE_QT;
  1502.             pst_send(pst, "QT", 2);
  1503.         }
  1504.         return;
  1505.  
  1506.     case STATE_QT:
  1507.         pst->state = STATE_IDLE;
  1508.         if (!pst_QT_process(pst, rbufp, &pst->lastref, &pst->lastrec)) {
  1509.             /*
  1510.              * Note the error
  1511.              */
  1512.             pst->baddata++;
  1513.             pst_event(pst, CEVNT_BADTIME);
  1514.             return;
  1515.         }
  1516.         break;
  1517.  
  1518.     default:
  1519.         syslog(LOG_ERR,
  1520.     "pst clock: INTERNAL ERROR invalid state %d, unit %d, in receive",
  1521.             pst->state, pst->unit);
  1522.         return;
  1523.     }
  1524.  
  1525.  
  1526.     /*
  1527.      * You may not have noticed this, but the only way we end up
  1528.      * out here is if we've completed polling and have a couple of
  1529.      * valid time stamps.  First see if we should reset the
  1530.      * structure.
  1531.      */
  1532.     if (pst->nextsample > 0) {
  1533.         tmp = pst->lastrec.l_ui - pst->rectimes[0].l_ui;
  1534.         if (tmp > (u_long)psttab[pst->nextsample].tooold)
  1535.             pst_reset(pst);
  1536.     }
  1537.  
  1538.     pst->rectimes[pst->nextsample] = pst->lastrec;
  1539.     pst->reftimes[pst->nextsample] = pst->lastref;
  1540.     pst->nextsample++;
  1541.     if (pst->flags & PST_WWVH)
  1542.         pst->station--;
  1543.     else
  1544.         pst->station++;
  1545.  
  1546.     if (pst->flags & (PST_SIGFAULT|PST_HARDERR)) {
  1547.         pst_event(pst, CEVNT_FAULT);
  1548.         pst->leap = LEAP_NOTINSYNC;
  1549.     } else if (pst->timesincesync > freerun[pst->unit]) {
  1550.         pst_event(pst, CEVNT_PROP);
  1551.         pst->leap = LEAP_NOTINSYNC;
  1552.     }
  1553.  
  1554.     if (pst->nextsample >= NPSTSAMPS)
  1555.         pst_process(pst);
  1556. }
  1557.  
  1558.  
  1559. /*
  1560.  * pst_compute_delay - compute appropriate things to tell clock about delays
  1561.  */
  1562. void
  1563. pst_compute_delay(prop_delay, prop_data)
  1564.     u_long prop_delay;
  1565.     struct pst_propagate *prop_data;
  1566. {
  1567.     register int code;
  1568.     register u_long tsf;
  1569.     extern int tsftomsu();
  1570.  
  1571.     /*
  1572.      * Convert (truncate) the delay to milliseconds.  Save the
  1573.      * characters needed to send this to the clock and compute
  1574.      * the remainder to be added in later.
  1575.      */
  1576.     code = tsftomsu(prop_delay, 0);
  1577.     MSUTOTSF(code, tsf);
  1578.     prop_data->remainder = prop_delay - tsf;
  1579.     if (prop_data->remainder & 0x80000000)
  1580.         prop_data->remainder = 0;
  1581.     prop_data->msbchar = BINTOPST((code >> 2) & 0x1f);
  1582.     prop_data->lsbchar = BINTOPST(code & 0x3);
  1583. }
  1584.  
  1585.  
  1586. /*
  1587.  * pst_control - set fudge factors, return statistics
  1588.  */
  1589. void
  1590. pst_control(unit, in, out)
  1591.     u_int unit;
  1592.     struct refclockstat *in;
  1593.     struct refclockstat *out;
  1594. {
  1595.     register struct pstunit *pst;
  1596.     void pst_compute_delay();
  1597.  
  1598.     if (unit >= MAXUNITS) {
  1599.         syslog(LOG_ERR, "pst clock: unit %d invalid (max %d)",
  1600.             unit, MAXUNITS-1);
  1601.         return;
  1602.     }
  1603.  
  1604.     if (in != 0) {
  1605.         int doqv = 0;
  1606.  
  1607.         if (in->haveflags & CLK_HAVETIME1)
  1608.             if (in->fudgetime1.l_ui == 0
  1609.                 && in->fudgetime1.l_uf <= PSTMAXPROP) {
  1610.                 wwv_prop_delay[unit] = in->fudgetime1;
  1611.                 doqv = 1;
  1612.                 pst_compute_delay(wwv_prop_delay[unit].l_uf,
  1613.                     &wwv_prop_data[unit]);
  1614.             }
  1615.         if (in->haveflags & CLK_HAVETIME2)
  1616.             if (in->fudgetime2.l_ui == 0
  1617.                 && in->fudgetime2.l_uf <= PSTMAXPROP) {
  1618.                 wwvh_prop_delay[unit] = in->fudgetime2;
  1619.                 doqv = 1;
  1620.                 pst_compute_delay(wwvh_prop_delay[unit].l_uf,
  1621.                     &wwvh_prop_data[unit]);
  1622.             }
  1623.         if (in->haveflags & CLK_HAVEVAL1) {
  1624.             stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
  1625.         }
  1626.         if (in->haveflags & CLK_HAVEVAL2) {
  1627.             if (in->fudgeval2 > 0 && in->fudgeval2 < 9990)
  1628.                 freerun[unit] = (u_short)in->fudgeval2;
  1629.         }
  1630.         if (in->haveflags & CLK_HAVEFLAG1) {
  1631.             sloppyclock[unit] = in->flags & CLK_FLAG1;
  1632.         }
  1633.         if (unitinuse[unit]) {
  1634.             /*
  1635.              * Should actually reselect clock, but
  1636.              * will wait for the next timecode
  1637.              */
  1638.             if (in->haveflags & CLK_HAVEVAL1) {
  1639.                 pstunits[unit]->peer->stratum
  1640.                     = stratumtouse[unit];
  1641.                 if (stratumtouse[unit] > 1)
  1642.                     pstunits[unit]->peer->refid
  1643.                         = htonl(PSTHSREFID);
  1644.             }
  1645.  
  1646.             if ((in->haveflags & CLK_HAVEFLAG3) &&
  1647.                 (in->flags & CLK_FLAG3)) {
  1648.                 pstunits[unit]->flags |= PST_DORESET;
  1649.             } else if (doqv || ((in->haveflags & CLK_HAVEFLAG2) &&
  1650.                 (in->flags & CLK_FLAG2))) {
  1651.                 pstunits[unit]->flags |= PST_DOQV;
  1652.             }
  1653.         }
  1654.     }
  1655.  
  1656.     if (out != 0) {
  1657.         out->type = REFCLK_WWV_PST;
  1658.         out->flags = 0;
  1659.         out->haveflags
  1660.             = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|
  1661.               CLK_HAVEVAL2|CLK_HAVEFLAG1;
  1662.         out->fudgetime1 = wwv_prop_delay[unit];
  1663.         out->fudgetime2 = wwvh_prop_delay[unit];
  1664.         out->fudgeval1 = (long)stratumtouse[unit];
  1665.         out->fudgeval2 = (long)freerun[unit];
  1666.         out->flags = sloppyclock[unit];
  1667.         if (unitinuse[unit]) {
  1668.             pst = pstunits[unit];
  1669.             out->clockdesc = pst->description;
  1670.             out->lencode = pst->lencode;
  1671.             out->lastcode = pst->lastcode;
  1672.             out->timereset = current_time - pst->timestarted;
  1673.             out->polls = pst->polls;
  1674.             out->noresponse = pst->noreply;
  1675.             out->badformat = pst->badformat;
  1676.             out->baddata = pst->baddata;
  1677.             out->lastevent = pst->lastevent;
  1678.             out->currentstatus = pst->status;
  1679.         } else {
  1680.             out->clockdesc = pstdefdesc;
  1681.             out->lencode = 0;
  1682.             out->lastcode = "";
  1683.             out->polls = out->noresponse = 0;
  1684.             out->badformat = out->baddata = 0;
  1685.             out->timereset = 0;
  1686.             out->currentstatus = out->lastevent = CEVNT_NOMINAL;
  1687.         }
  1688.     }
  1689. }
  1690.  
  1691.  
  1692. /*
  1693.  * pst_buginfo - return clock dependent debugging info
  1694.  */
  1695. void
  1696. pst_buginfo(unit, bug)
  1697.     int unit;
  1698.     register struct refclockbug *bug;
  1699. {
  1700.     register struct pstunit *pst;
  1701.     register int i;
  1702.  
  1703.     bug->nvalues = bug->ntimes = 0;
  1704.  
  1705.     if (unit >= MAXUNITS) {
  1706.         syslog(LOG_ERR, "pst clock: unit %d invalid (max %d)",
  1707.             unit, MAXUNITS-1);
  1708.         return;
  1709.     }
  1710.  
  1711.     if (!unitinuse[unit])
  1712.         return;
  1713.     pst = pstunits[unit];
  1714.  
  1715.     bug->nvalues = 14;
  1716.     bug->svalues = (1<<10);
  1717.     bug->values[0] = (u_long)pst->nextsample;
  1718.     bug->values[1] = (u_long)pst->state;
  1719.     bug->values[2] = (u_long)pst->reason;
  1720.     bug->values[3] = (u_long)pst->flags;
  1721.     bug->values[4] = (u_long)pst->yearday;
  1722.     bug->values[5] = (u_long)pst->hour;
  1723.     bug->values[6] = (u_long)pst->minute;
  1724.     bug->values[7] = (u_long)pst->second;
  1725.     bug->values[8] = (u_long)pst->millisecond;
  1726.     bug->values[9] = (u_long)pst->timezone;
  1727.     bug->values[10] = (u_long)((long)pst->tzoffset);
  1728.     bug->values[11] = (u_long)pst->timesincesync;
  1729.     bug->values[12] = pst->yearstart;
  1730.     bug->ntimes = ((NPSTSAMPS*2)+2) > NCLKBUGTIMES ? NCLKBUGTIMES :
  1731.         ((NPSTSAMPS*2)+2);
  1732.     bug->stimes = 0;
  1733.     for (i = 0; i < (bug->ntimes-2)/2; i++) {
  1734.         bug->times[2*i] = pst->rectimes[i];
  1735.         bug->times[(2*i) + 1] = pst->reftimes[i];
  1736.     }
  1737.     bug->times[bug->ntimes - 2] = pst->lastrec;
  1738.     bug->times[bug->ntimes - 1] = pst->lastref;
  1739. }
  1740. #endif
  1741.