aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c')
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c1575
1 files changed, 0 insertions, 1575 deletions
diff --git a/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c b/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c
deleted file mode 100644
index 5a6307c3b6f6..000000000000
--- a/usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c
+++ /dev/null
@@ -1,1575 +0,0 @@
-/* refclock_ees - clock driver for the EES M201 receiver */
-
-#if defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM)
-
-/* Currently REQUIRES STREAM and PPSCD. CLK and CBREAK modes
- * were removed as the code was overly hairy, they weren't in use
- * (hence probably didn't work). Still in RCS file at cl.cam.ac.uk
- */
-
-#include <ctype.h>
-#include <sys/time.h>
-
-#include "ntpd.h"
-#include "ntp_io.h"
-#include "ntp_refclock.h"
-#include "ntp_unixtime.h"
-#include "ntp_calendar.h"
-#if defined(HAVE_BSD_TTYS)
-#include <sgtty.h>
-#endif /* HAVE_BSD_TTYS */
-#if defined(HAVE_SYSV_TTYS)
-#include <termio.h>
-#endif /* HAVE_SYSV_TTYS */
-#include <termios.h>
-#include <stropts.h>
-#include <sys/ppsclock.h>
-#include "ntp_stdlib.h"
-
- /*
- fudgefactor = fudgetime1;
- os_delay = fudgetime2;
- offset_fudge = os_delay + fudgefactor + inherent_delay;
- stratumtouse = fudgeval1 & 0xf
- debug = fudgeval2;
- sloppyclockflag = flags & CLK_FLAG1;
- 1 log smoothing summary when processing sample
- 4 dump the buffer from the clock
- 8 EIOGETKD the last n uS time stamps
- if (flags & CLK_FLAG2 && unitinuse) ees->leaphold = 0;
- ees->dump_vals = flags & CLK_FLAG3;
- ees->usealldata = flags & CLK_FLAG4;
-
-
- bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
- bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
- bug->values[2] = ees->status;
- bug->values[3] = ees->lastevent;
- bug->values[4] = ees->reason;
- bug->values[5] = ees->nsamples;
- bug->values[6] = ees->codestate;
- bug->values[7] = ees->day;
- bug->values[8] = ees->hour;
- bug->values[9] = ees->minute;
- bug->values[10] = ees->second;
- bug->values[11] = ees->tz;
- bug->values[12] = ees->yearstart;
- bug->values[13] = (ees->leaphold > current_time) ?
- ees->leaphold - current_time : 0;
- bug->values[14] = inherent_delay[unit].l_uf;
- bug->values[15] = offset_fudge[unit].l_uf;
-
- bug->times[0] = ees->reftime;
- bug->times[1] = ees->arrvtime;
- bug->times[2] = ees->lastsampletime;
- bug->times[3] = ees->offset;
- bug->times[4] = ees->lowoffset;
- bug->times[5] = ees->highoffset;
- bug->times[6] = inherent_delay[unit];
- bug->times[8] = os_delay[unit];
- bug->times[7] = fudgefactor[unit];
- bug->times[9] = offset_fudge[unit];
- bug->times[10]= ees->yearstart, 0;
- */
-
-/* This should support the use of an EES M201 receiver with RS232
- * output (modified to transmit time once per second).
- *
- * For the format of the message sent by the clock, see the EESM_
- * definitions below.
- *
- * It appears to run free for an integral number of minutes, until the error
- * reaches 4mS, at which point it steps at second = 01.
- * It appears that sometimes it steps 4mS (say at 7 min interval),
- * then the next minute it decides that it was an error, so steps back.
- * On the next minute it steps forward again :-(
- * This is typically 16.5uS/S then 3975uS at the 4min re-sync,
- * or 9.5uS/S then 3990.5uS at a 7min re-sync,
- * at which point it may loose the "00" second time stamp.
- * I assume that the most accurate time is just AFTER the re-sync.
- * Hence remember the last cycle interval,
- *
- * Can run in any one of:
- *
- * PPSCD PPS signal sets CD which interupts, and grabs the current TOD
- * (sun) *in the interupt code*, so as to avoid problems with
- * the STREAMS scheduling.
- *
- * It appears that it goes 16.5 uS slow each second, then every 4 mins it
- * generates no "00" second tick, and gains 3975 uS. Ho Hum ! (93/2/7)
- */
-
-/* Definitions */
-#ifndef MAXUNITS
-#define MAXUNITS 4 /* maximum number of EES units permitted */
-#endif
-
-#ifndef EES232
-#define EES232 "/dev/ees%d" /* Device to open to read the data */
-#endif
-
-/* Other constant stuff */
-#ifndef EESPRECISION
-#define EESPRECISION (-10) /* what the heck - 2**-10 = 1ms */
-#endif
-#ifndef EESREFID
-#define EESREFID "MSF\0" /* String to identify the clock */
-#endif
-#ifndef EESHSREFID
-#define EESHSREFID (0x7f7f0000 | ((REFCLK_MSF_EES) << 8)) /* Numeric refid */
-#endif
-
-/* Description of clock */
-#define EESDESCRIPTION "EES M201 MSF Receiver"
-
-/* Speed we run the clock port at. If this is changed the UARTDELAY
- * value should be recomputed to suit.
- */
-#ifndef SPEED232
-#define SPEED232 B9600 /* 9600 baud */
-#endif
-
-/* What is the inherent delay for this mode of working, i.e. when is the
- * data time stamped.
- */
-#define SAFETY_SHIFT 10 /* Split the shift to avoid overflow */
-#define BITS_TO_L_FP(bits, baud) \
- (((((bits)*2 +1) << (FRACTION_PREC-SAFETY_SHIFT)) / (2*baud)) << SAFETY_SHIFT)
-#define INH_DELAY_CBREAK BITS_TO_L_FP(119, 9600)
-#define INH_DELAY_PPS BITS_TO_L_FP( 0, 9600)
-
-#ifndef STREAM_PP1
-#define STREAM_PP1 "ppsclocd\0<-- patch space for module name1 -->"
-#endif
-#ifndef STREAM_PP2
-#define STREAM_PP2 "ppsclock\0<-- patch space for module name2 -->"
-#endif
-
-/* Offsets of the bytes of the serial line code. The clock gives
- * local time with a GMT/BST indication. The EESM_ definitions
- * give offsets into ees->lastcode.
- */
-#define EESM_CSEC 0 /* centiseconds - always zero in our clock */
-#define EESM_SEC 1 /* seconds in BCD */
-#define EESM_MIN 2 /* minutes in BCD */
-#define EESM_HOUR 3 /* hours in BCD */
-#define EESM_DAYWK 4 /* day of week (Sun = 0 etc) */
-#define EESM_DAY 5 /* day of month in BCD */
-#define EESM_MON 6 /* month in BCD */
-#define EESM_YEAR 7 /* year MOD 100 in BCD */
-#define EESM_LEAP 8 /* 0x0f if leap year, otherwise zero */
-#define EESM_BST 9 /* 0x03 if BST, 0x00 if GMT */
-#define EESM_MSFOK 10 /* 0x3f if radio good, otherwise zero */
- /* followed by a frame alignment byte (0xff) /
- / which is not put into the lastcode buffer*/
-
-/* Length of the serial time code, in characters. The first length
- * is less the frame alignment byte.
- */
-#define LENEESPRT (EESM_MSFOK+1)
-#define LENEESCODE (LENEESPRT+1)
-
-/* Code state. */
-#define EESCS_WAIT 0 /* waiting for start of timecode */
-#define EESCS_GOTSOME 1 /* have an incomplete time code buffered */
-
-/* Default fudge factor and character to receive */
-#define DEFFUDGETIME 0 /* Default user supplied fudge factor */
-#ifndef DEFOSTIME
-#define DEFOSTIME 0 /* Default OS delay -- passed by Make ? */
-#endif
-#define DEFINHTIME INH_DELAY_PPS /* inherent delay due to sample point*/
-
-/* Limits on things. Reduce the number of samples to SAMPLEREDUCE by median
- * elimination. If we're running with an accurate clock, chose the BESTSAMPLE
- * as the estimated offset, otherwise average the remainder.
- */
-#define FULLSHIFT 6 /* NCODES root 2 */
-#define NCODES (1<< FULLSHIFT) /* 64 */
-#define REDUCESHIFT (FULLSHIFT -1) /* SAMPLEREDUCE root 2 */
-
-/* Towards the high ( Why ?) end of half */
-#define BESTSAMPLE ((samplereduce * 3) /4) /* 24 */
-
-/* Leap hold time. After a leap second the clock will no longer be
- * reliable until it resynchronizes. Hope 40 minutes is enough. */
-#define EESLEAPHOLD (40 * 60)
-
-#define EES_STEP_F (1 << 24) /* the receiver steps in units of about 4ms */
-#define EES_STEP_F_GRACE (EES_STEP_F/8) /*Allow for slop of 1/8 which is .5ms*/
-#define EES_STEP_NOTE (1 << 21)/* Log any unexpected jumps, say .5 ms .... */
-#define EES_STEP_NOTES 50 /* Only do a limited number */
-#define MAX_STEP 16 /* Max number of steps to remember */
-
-/* debug is a bit mask of debugging that is wanted */
-#define DB_SYSLOG_SMPLI 0x0001
-#define DB_SYSLOG_SMPLE 0x0002
-#define DB_SYSLOG_SMTHI 0x0004
-#define DB_SYSLOG_NSMTHE 0x0008
-#define DB_SYSLOG_NSMTHI 0x0010
-#define DB_SYSLOG_SMTHE 0x0020
-#define DB_PRINT_EV 0x0040
-#define DB_PRINT_CDT 0x0080
-#define DB_PRINT_CDTC 0x0100
-#define DB_SYSLOG_KEEPD 0x0800
-#define DB_SYSLOG_KEEPE 0x1000
-#define DB_LOG_DELTAS 0x2000
-#define DB_PRINT_DELTAS 0x4000
-#define DB_LOG_AWAITMORE 0x8000
-#define DB_LOG_SAMPLES 0x10000
-#define DB_NO_PPS 0x20000
-#define DB_INC_PPS 0x40000
-#define DB_DUMP_DELTAS 0x80000
-
-struct eesunit { /* EES unit control structure. */
- struct peer *peer; /* associated peer structure */
- struct refclockio io; /* given to the I/O handler */
- l_fp reftime; /* reference time */
- l_fp lastsampletime; /* time as in txt from last EES msg */
- l_fp arrvtime; /* Time at which pkt arrived */
- l_fp codeoffsets[NCODES]; /* the time of arrival of 232 codes */
- l_fp offset; /* chosen offset (for clkbug) */
- l_fp lowoffset; /* lowest sample offset (for clkbug) */
- l_fp highoffset; /* highest " " (for clkbug) */
- char lastcode[LENEESCODE+6]; /* last time code we received */
- u_long lasttime; /* last time clock heard from */
- u_long clocklastgood; /* last time good radio seen */
- u_char lencode; /* length of code in buffer */
- u_char nsamples; /* number of samples we've collected */
- u_char codestate; /* state of 232 code reception */
- u_char unit; /* unit number for this guy */
- u_char status; /* clock status */
- u_char lastevent; /* last clock event */
- u_char reason; /* reason for last abort */
- u_char hour; /* hour of day */
- u_char minute; /* minute of hour */
- u_char second; /* seconds of minute */
- char tz; /* timezone from clock */
- u_char ttytype; /* method used */
- u_char dump_vals; /* Should clock values be dumped */
- u_char usealldata; /* Use ALL samples */
- u_short day; /* day of year from last code */
- u_long yearstart; /* start of current year */
- u_long leaphold; /* time of leap hold expiry */
- u_long badformat; /* number of bad format codes */
- u_long baddata; /* number of invalid time codes */
- u_long timestarted; /* time we started this */
- long last_pps_no; /* The serial # of the last PPS */
- char fix_pending; /* Is a "sync to time" pending ? */
- /* Fine tuning - compensate for 4 mS ramping .... */
- l_fp last_l; /* last time stamp */
- u_char last_steps[MAX_STEP]; /* Most recent n steps */
- int best_av_step; /* Best guess at average step */
- char best_av_step_count; /* # of steps over used above */
- char this_step; /* Current pos in buffer */
- int last_step_late; /* How late the last step was (0-59) */
- long jump_fsecs; /* # of fractions of a sec last jump */
- u_long last_step; /* time of last step */
- int last_step_secs; /* Number of seconds in last step */
- int using_ramp; /* 1 -> noemal, -1 -> over stepped */
-};
-#define last_sec last_l.l_ui
-#define last_sfsec last_l.l_f
-#define this_uisec ((ees->arrvtime).l_ui)
-#define this_sfsec ((ees->arrvtime).l_f)
-#define msec(x) ((x) / (1<<22))
-#define LAST_STEPS (sizeof ees->last_steps / sizeof ees->last_steps[0])
-#define subms(x) ((((((x < 0) ? (-(x)) : (x)) % (1<<22))/2) * 625) / (1<<(22 -5)))
-
-/* Bitmask for what methods to try to use -- currently only PPS enabled */
-#define T_CBREAK 1
-#define T_PPS 8
-/* macros to test above */
-#define is_cbreak(x) ((x)->ttytype & T_CBREAK)
-#define is_pps(x) ((x)->ttytype & T_PPS)
-#define is_any(x) ((x)->ttytype)
-
-#define CODEREASON 20 /* reason codes */
-
-/* Data space for the unit structures. Note that we allocate these on
- * the fly, but never give them back. */
-static struct eesunit *eesunits[MAXUNITS];
-static u_char unitinuse[MAXUNITS];
-
-/* Keep the fudge factors separately so they can be set even
- * when no clock is configured. */
-static l_fp inherent_delay[MAXUNITS]; /* when time stamp is taken */
-static l_fp fudgefactor[MAXUNITS]; /* fudgetime1 */
-static l_fp os_delay[MAXUNITS]; /* fudgetime2 */
-static l_fp offset_fudge[MAXUNITS]; /* Sum of above */
-static u_char stratumtouse[MAXUNITS];
-static u_char sloppyclockflag[MAXUNITS];
-
-static int deltas[60];
-
-static l_fp acceptable_slop; /* = { 0, 1 << (FRACTION_PREC -2) }; */
-static l_fp onesec; /* = { 1, 0 }; */
-
-/* Imported from the timer module */
-extern u_long current_time;
-
-#ifdef DEBUG
-static int debug;
-#endif
-
-#ifndef DUMP_BUF_SIZE /* Size of buffer to be used by dump_buf */
-#define DUMP_BUF_SIZE 10112
-#endif
-
-/* ees_reset - reset the count back to zero */
-#define ees_reset(ees) (ees)->nsamples = 0; \
- (ees)->codestate = EESCS_WAIT
-
-/* ees_event - record and report an event */
-#define ees_event(ees, evcode) if ((ees)->status != (u_char)(evcode)) \
- ees_report_event((ees), (evcode))
-
-/* Find the precision of the system clock by reading it */
-#define USECS 1000000
-#define MINSTEP 5 /* some systems increment uS on each call */
-#define MAXLOOPS (USECS/9)
-static int ees_get_precision()
-{
- struct timeval tp;
- struct timezone tzp;
- long last;
- int i;
- long diff;
- long val;
- gettimeofday(&tp, &tzp);
-
- last = tp.tv_usec;
- for (i=0; i< 100000; i++) {
- gettimeofday(&tp, &tzp);
- diff = tp.tv_usec - last;
- if (diff < 0) diff += USECS;
- if (diff > MINSTEP) break;
- last = tp.tv_usec;
- }
- syslog(LOG_INFO,
- "I: ees: precision calculation given %duS after %d loop%s",
- diff, i, (i==1) ? "" : "s");
-
- if (i == 0) return -20 /* assume 1uS */;
- if (i >= MAXLOOPS) return EESPRECISION /* Lies ! */;
- for (i=0, val=USECS; val > 0; i--, val /= 2) if (diff > val) return i;
- return EESPRECISION /* Lies ! */;
-}
-
-static void dump_buf(coffs, from, to, text)
-l_fp *coffs;
-int from;
-int to;
-char *text;
-{
- char buff[DUMP_BUF_SIZE + 80];
- int i;
- register char *ptr = buff;
- sprintf(ptr, text);
- for (i=from; i<to; i++)
- { while (*ptr) ptr++;
- if ((ptr-buff) > DUMP_BUF_SIZE) syslog(LOG_DEBUG, "D: %s", ptr=buff);
- sprintf(ptr, " %06d", ((int)coffs[i].l_f) / 4295);
- }
- syslog(LOG_DEBUG, "D: %s", buff);
-}
-
-/* msfees_init - initialize internal ees driver data */
-static void msfees_init()
-{
- register int i;
- /* Just zero the data arrays */
- memset((char *)eesunits, 0, sizeof eesunits);
- memset((char *)unitinuse, 0, sizeof unitinuse);
-
- acceptable_slop.l_ui = 0;
- acceptable_slop.l_uf = 1 << (FRACTION_PREC -2);
-
- onesec.l_ui = 1;
- onesec.l_uf = 0;
-
- /* Initialize fudge factors to default. */
- for (i = 0; i < MAXUNITS; i++) {
- fudgefactor[i].l_ui = 0;
- fudgefactor[i].l_uf = DEFFUDGETIME;
- os_delay[i].l_ui = 0;
- os_delay[i].l_uf = DEFOSTIME;
- inherent_delay[i].l_ui = 0;
- inherent_delay[i].l_uf = DEFINHTIME;
- offset_fudge[i] = os_delay[i];
- L_ADD(&offset_fudge[i], &fudgefactor[i]);
- L_ADD(&offset_fudge[i], &inherent_delay[i]);
- stratumtouse[i] = 0;
- sloppyclockflag[i] = 0;
- }
-}
-
-
-/* msfees_start - open the EES devices and initialize data for processing */
-static int msfees_start(unit, peer)
- u_int unit;
- struct peer *peer;
-{
- register struct eesunit *ees;
- register int i;
- int fd232 = -1;
- char eesdev[20];
- struct termios ttyb, *ttyp;
- static void ees_receive();
- extern int io_addclock();
- extern void io_closeclock();
- extern char *emalloc();
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "ees clock: unit number %d invalid (max %d)",
- unit, MAXUNITS-1);
- return 0;
- }
- if (unitinuse[unit]) {
- syslog(LOG_ERR, "ees clock: unit number %d in use", unit);
- return 0;
- }
-
- /* Unit okay, attempt to open the devices. We do them both at
- * once to make sure we can */
- (void) sprintf(eesdev, EES232, unit);
-
- fd232 = open(eesdev, O_RDWR, 0777);
- if (fd232 == -1) {
- syslog(LOG_ERR, "ees clock: open of %s failed: %m", eesdev);
- return 0;
- }
-
-#ifdef TIOCEXCL
- /* Set for exclusive use */
- if (ioctl(fd232, TIOCEXCL, (char *)0) < 0) {
- syslog(LOG_ERR, "ees clock: ioctl(%s, TIOCEXCL): %m", eesdev);
- goto screwed;
- }
-#endif
-
- /* STRIPPED DOWN VERSION: Only PPS CD is supported at the moment */
-
- /* Set port characteristics. If we don't have a STREAMS module or
- * a clock line discipline, cooked mode is just usable, even though it
- * strips the top bit. The only EES byte which uses the top
- * bit is the year, and we don't use that anyway. If we do
- * have the line discipline, we choose raw mode, and the
- * line discipline code will block up the messages.
- */
-
- /* STIPPED DOWN VERSION: Only PPS CD is supported at the moment */
-
- ttyp = &ttyb;
- if (tcgetattr(fd232, ttyp) < 0) {
- syslog(LOG_ERR, "msfees_start: tcgetattr(%s): %m", eesdev);
- goto screwed;
- }
-
- ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
- ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
- ttyp->c_oflag = 0;
- ttyp->c_lflag = ICANON;
- ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
- if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
- syslog(LOG_ERR, "msfees_start: tcsetattr(%s): %m", eesdev);
- goto screwed;
- }
-
- if (tcflush(fd232, TCIOFLUSH) < 0) {
- syslog(LOG_ERR, "msfees_start: tcflush(%s): %m", eesdev);
- goto screwed;
- }
-
- inherent_delay[unit].l_uf = INH_DELAY_PPS;
-
- /* offset fudge (how *late* the timestamp is) = fudge + os delays */
- offset_fudge[unit] = os_delay[unit];
- L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
- L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
-
- /* Looks like this might succeed. Find memory for the structure.
- * Look to see if there are any unused ones, if not we malloc() one.
- */
- if (eesunits[unit] != 0) /* The one we want is okay */
- ees = eesunits[unit];
- else {
- /* Look for an unused, but allocated struct */
- for (i = 0; i < MAXUNITS; i++) {
- if (!unitinuse[i] && eesunits[i] != 0)
- break;
- }
-
- if (i < MAXUNITS) { /* Reclaim this one */
- ees = eesunits[i];
- eesunits[i] = 0;
- } /* no spare -- make a new one */
- else ees = (struct eesunit *) emalloc(sizeof(struct eesunit));
- }
- memset((char *)ees, 0, sizeof(struct eesunit));
- eesunits[unit] = ees;
-
- /* Set up the structures */
- ees->peer = peer;
- ees->unit = (u_char)unit;
- ees->timestarted= current_time;
- ees->ttytype = 0;
- ees->io.clock_recv= ees_receive;
- ees->io.srcclock= (caddr_t)ees;
- ees->io.datalen = 0;
- ees->io.fd = fd232;
-
- /* Okay. Push one of the two (linked into the kernel, or dynamically
- * loaded) STREAMS module, and give it to the I/O code to start
- * receiving stuff.
- */
-
- {
- int rc1;
- /* Pop any existing onews first ... */
- while (ioctl(fd232, I_POP, 0 ) >= 0) ;
-
- /* Now try pushing either of the possible modules */
- if ((rc1=ioctl(fd232, I_PUSH, STREAM_PP1)) < 0 &&
- ioctl(fd232, I_PUSH, STREAM_PP2) < 0) {
- syslog(LOG_ERR,
- "ees clock: Push of `%s' and `%s' to %s failed %m",
- STREAM_PP1, STREAM_PP2, eesdev);
- goto screwed;
- }
- else {
- syslog(LOG_INFO, "I: ees clock: PUSHed %s on %s",
- (rc1 >= 0) ? STREAM_PP1 : STREAM_PP2, eesdev);
- ees->ttytype |= T_PPS;
- }
- }
-
- /* Add the clock */
- if (!io_addclock(&ees->io)) {
- /* Oh shit. Just close and return. */
- syslog(LOG_ERR, "ees clock: io_addclock(%s): %m", eesdev);
- goto screwed;
- }
-
-
- /* All done. Initialize a few random peer variables, then
- * return success. */
- peer->precision = ees_get_precision();
- peer->stratum = stratumtouse[unit];
- peer->rootdelay = 0; /* ++++ */
- peer->rootdispersion = 0; /* ++++ */
- if (stratumtouse[unit] <= 1) {
- memmove((char *)&peer->refid, EESREFID, 4);
- if (unit > 0 && unit < 10)
- ((char *)&peer->refid)[3] = '0' + unit;
- } else {
- peer->refid = htonl(EESHSREFID);
- }
- unitinuse[unit] = 1;
- syslog(LOG_ERR, "ees clock: %s OK on %d", eesdev, unit);
- return (1);
-
-screwed:
- if (fd232 != -1)
- (void) close(fd232);
- return (0);
-}
-
-
-/* msfees_shutdown - shut down a EES clock */
-static void msfees_shutdown(unit)
- int unit;
-{
- register struct eesunit *ees;
- extern void io_closeclock();
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR,
- "ees clock: INTERNAL ERROR, unit number %d invalid (max %d)",
- unit, MAXUNITS);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR,
- "ees clock: INTERNAL ERROR, unit number %d not in use", unit);
- return;
- }
-
- /* Tell the I/O module to turn us off. We're history. */
- ees = eesunits[unit];
- io_closeclock(&ees->io);
- unitinuse[unit] = 0;
-}
-
-
-/* ees_report_event - note the occurance of an event */
-static void ees_report_event(ees, code)
- struct eesunit *ees;
- int code;
-{
- if (ees->status != (u_char)code) {
- ees->status = (u_char)code;
- if (code != CEVNT_NOMINAL)
- ees->lastevent = (u_char)code;
- /* Should report event to trap handler in here.
- * Soon...
- */
- }
-}
-
-
-/* ees_receive - receive data from the serial interface on an EES clock */
-static void ees_receive(rbufp)
- struct recvbuf *rbufp;
-{
- register int n_sample;
- register int day;
- register struct eesunit *ees;
- register u_char *dpt; /* Data PoinTeR: move along ... */
- register u_char *dpend; /* Points just *after* last data char */
- register char *cp;
- l_fp tmp;
- static void ees_process();
- int call_pps_sample = 0;
- l_fp pps_arrvstamp;
- int sincelast;
- int pps_step = 0;
- int suspect_4ms_step = 0;
- struct ppsclockev ppsclockev;
- long *ptr = (long *) &ppsclockev;
- extern errno;
- int rc;
-
- /* Get the clock this applies to and a pointer to the data */
- ees = (struct eesunit *)rbufp->recv_srcclock;
- dpt = (u_char *)&rbufp->recv_space;
- dpend = dpt + rbufp->recv_length;
- if ((debug & DB_LOG_AWAITMORE) && (rbufp->recv_length != LENEESCODE))
- printf("[%d] ", rbufp->recv_length);
-
- /* Check out our state and process appropriately */
- switch (ees->codestate) {
- case EESCS_WAIT:
- /* Set an initial guess at the timestamp as the recv time.
- * If just running in CBREAK mode, we can't improve this.
- * If we have the CLOCK Line Discipline, PPSCD, or sime such,
- * then we will do better later ....
- */
- ees->arrvtime = rbufp->recv_time;
- ees->codestate = EESCS_GOTSOME;
- ees->lencode = 0;
- /*FALLSTHROUGH*/
-
- case EESCS_GOTSOME:
- cp = &(ees->lastcode[ees->lencode]);
-
- /* Gobble the bytes until the final (possibly stripped) 0xff */
- while (dpt < dpend && (*dpt & 0x7f) != 0x7f) {
- *cp++ = (char)*dpt++;
- ees->lencode++;
- /* Oh dear -- too many bytes .. */
- if (ees->lencode > LENEESPRT) {
- syslog(LOG_INFO,
-"I: ees clock: %d + %d > %d [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]",
- ees->lencode, dpend - dpt, LENEESPRT,
-#define D(x) (ees->lastcode[x])
- D(0), D(1), D(2), D(3), D(4), D(5), D(6),
- D(7), D(8), D(9), D(10), D(11), D(12));
-#undef D
- ees->badformat++;
- ees->reason = CODEREASON + 1;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
- }
- /* Gave up because it was end of the buffer, rather than ff */
- if (dpt == dpend) {
- /* Incomplete. Wait for more. */
- if (debug & DB_LOG_AWAITMORE) syslog(LOG_INFO,
- "I: ees clock %d: %d == %d: await more",
- ees->unit, dpt, dpend);
- return;
- }
-
- /* This shouldn't happen ... ! */
- if ((*dpt & 0x7f) != 0x7f) {
- syslog(LOG_INFO, "I: ees clock: %0x & 0x7f != 0x7f", *dpt);
- ees->badformat++;
- ees->reason = CODEREASON + 2;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- /* Skip the 0xff */
- dpt++;
-
- /* Finally, got a complete buffer. Mainline code will
- * continue on. */
- cp = ees->lastcode;
- break;
-
- default:
- syslog(LOG_ERR, "ees clock: INTERNAL ERROR: %d state %d",
- ees->unit, ees->codestate);
- ees->reason = CODEREASON + 5;
- ees_event(ees, CEVNT_FAULT);
- ees_reset(ees);
- return;
- }
-
- /* Boy! After all that crap, the lastcode buffer now contains
- * something we hope will be a valid time code. Do length
- * checks and sanity checks on constant data.
- */
- ees->codestate = EESCS_WAIT;
- ees->lasttime = current_time;
- if (ees->lencode != LENEESPRT) {
- ees->badformat++;
- ees->reason = CODEREASON + 6;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- cp = ees->lastcode;
-
- /* Check that centisecond is zero */
- if (cp[EESM_CSEC] != 0) {
- ees->baddata++;
- ees->reason = CODEREASON + 7;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- /* Check flag formats */
- if (cp[EESM_LEAP] != 0 && cp[EESM_LEAP] != 0x0f) {
- ees->badformat++;
- ees->reason = CODEREASON + 8;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- if (cp[EESM_BST] != 0 && cp[EESM_BST] != 0x03) {
- ees->badformat++;
- ees->reason = CODEREASON + 9;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- if (cp[EESM_MSFOK] != 0 && cp[EESM_MSFOK] != 0x3f) {
- ees->badformat++;
- ees->reason = CODEREASON + 10;
- ees_event(ees, CEVNT_BADREPLY);
- ees_reset(ees);
- return;
- }
-
- /* So far, so good. Compute day, hours, minutes, seconds,
- * time zone. Do range checks on these.
- */
-
-#define bcdunpack(val) ( (((val)>>4) & 0x0f) * 10 + ((val) & 0x0f) )
-#define istrue(x) ((x)?1:0)
-
- ees->second = bcdunpack(cp[EESM_SEC]); /* second */
- ees->minute = bcdunpack(cp[EESM_MIN]); /* minute */
- ees->hour = bcdunpack(cp[EESM_HOUR]); /* hour */
-
- day = bcdunpack(cp[EESM_DAY]); /* day of month */
-
- switch (bcdunpack(cp[EESM_MON])) { /* month */
-
- /* Add in lengths of all previous months. Add one more
- if it is a leap year and after February.
- */
- case 12: day += NOV; /*FALLSTHROUGH*/
- case 11: day += OCT; /*FALLSTHROUGH*/
- case 10: day += SEP; /*FALLSTHROUGH*/
- case 9: day += AUG; /*FALLSTHROUGH*/
- case 8: day += JUL; /*FALLSTHROUGH*/
- case 7: day += JUN; /*FALLSTHROUGH*/
- case 6: day += MAY; /*FALLSTHROUGH*/
- case 5: day += APR; /*FALLSTHROUGH*/
- case 4: day += MAR; /*FALLSTHROUGH*/
- case 3: day += FEB;
- if (istrue(cp[EESM_LEAP])) day++; /*FALLSTHROUGH*/
- case 2: day += JAN; /*FALLSTHROUGH*/
- case 1: break;
- default: ees->baddata++;
- ees->reason = CODEREASON + 11;
- ees_event(ees, CEVNT_BADDATE);
- ees_reset(ees);
- return;
- }
-
- ees->day = day;
-
- /* Get timezone. The clocktime routine wants the number
- * of hours to add to the delivered time to get UT.
- * Currently -1 if BST flag set, 0 otherwise. This
- * is the place to tweak things if double summer time
- * ever happens.
- */
- ees->tz = istrue(cp[EESM_BST]) ? -1 : 0;
-
- if (ees->day > 366 || ees->day < 1 ||
- ees->hour > 23 || ees->minute > 59 || ees->second > 59) {
- ees->baddata++;
- ees->reason = CODEREASON + 12;
- ees_event(ees, CEVNT_BADDATE);
- ees_reset(ees);
- return;
- }
-
- n_sample = ees->nsamples;
-
- /* Now, compute the reference time value: text -> tmp.l_ui */
- if (!clocktime(ees->day, ees->hour, ees->minute, ees->second,
- ees->tz, rbufp->recv_time.l_ui, &ees->yearstart,
- &tmp.l_ui)) {
- ees->baddata++;
- ees->reason = CODEREASON + 13;
- ees_event(ees, CEVNT_BADDATE);
- ees_reset(ees);
- return;
- }
- tmp.l_uf = 0;
-
- /* DON'T use ees->arrvtime -- it may be < reftime */
- ees->lastsampletime = tmp;
-
- /* If we are synchronised to the radio, update the reference time.
- * Also keep a note of when clock was last good.
- */
- if (istrue(cp[EESM_MSFOK])) {
- ees->reftime = tmp;
- ees->clocklastgood = current_time;
- }
-
-
- /* Compute the offset. For the fractional part of the
- * offset we use the expected delay for the message.
- */
- ees->codeoffsets[n_sample].l_ui = tmp.l_ui;
- ees->codeoffsets[n_sample].l_uf = 0;
-
- /* Number of seconds since the last step */
- sincelast = this_uisec - ees->last_step;
-
- memset(&ppsclockev, 0, sizeof ppsclockev);
-
- rc = ioctl(ees->io.fd, CIOGETEV, (char *) &ppsclockev);
- if (debug & DB_PRINT_EV) fprintf(stderr,
- "[%x] CIOGETEV u%d %d (%x %d) gave %d (%d): %08x %08x %d\n",
- DB_PRINT_EV, ees->unit, ees->io.fd, CIOGETEV, is_pps(ees),
- rc, errno, ptr[0], ptr[1], ptr[2]);
-
- /* If we managed to get the time of arrival, process the info */
- if (rc >= 0) {
- int conv = -1;
- pps_step = ppsclockev.serial - ees->last_pps_no;
-
- /* Possible that PPS triggered, but text message didn't */
- if (pps_step == 2) syslog(LOG_ERR, "pps step = 2 @ %02d", ees->second);
- if (pps_step == 2 && ees->second == 1) suspect_4ms_step |= 1;
- if (pps_step == 2 && ees->second == 2) suspect_4ms_step |= 4;
-
- /* allow for single loss of PPS only */
- if (pps_step != 1 && pps_step != 2)
- fprintf(stderr, "PPS step: %d too far off %d (%d)\n",
- ppsclockev.serial, ees->last_pps_no, pps_step);
- else if (!buftvtots((char *) &(ppsclockev.tv), &pps_arrvstamp))
- fprintf(stderr, "buftvtots failed\n");
- else { /* if ((ABS(time difference) - 0.25) < 0)
- * then believe it ...
- */
- l_fp diff;
- diff = pps_arrvstamp;
- conv = 0;
- L_SUB(&diff, &ees->arrvtime);
-if (debug & DB_PRINT_CDT) printf("[%x] Have %x.%08x and %x.%08x -> %x.%08x @ %s",
- DB_PRINT_CDT, ees->arrvtime.l_ui, ees->arrvtime.l_uf,
- pps_arrvstamp.l_ui, pps_arrvstamp.l_uf,
- diff.l_ui, diff.l_uf,
- ctime(&(ppsclockev.tv.tv_sec)));
- if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
- L_SUB(&diff, &acceptable_slop);
- if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
- ees->arrvtime = pps_arrvstamp;
- conv++;
- call_pps_sample++;
- }
- /* Some loss of some signals around sec = 1 */
- else if (ees->second == 1) {
- diff = pps_arrvstamp;
- L_ADD(&diff, &onesec);
- L_SUB(&diff, &ees->arrvtime);
- if (L_ISNEG(&diff)) M_NEG(diff.l_ui, diff.l_uf);
- L_SUB(&diff, &acceptable_slop);
-syslog(LOG_ERR, "Have sec==1 slip %ds a=%08x-p=%08x -> %x.%08x (u=%d) %s",
- pps_arrvstamp.l_ui - ees->arrvtime.l_ui,
- pps_arrvstamp.l_uf,
- ees->arrvtime.l_uf,
- diff.l_ui, diff.l_uf,
- ppsclockev.tv.tv_usec,
- ctime(&(ppsclockev.tv.tv_sec)));
- if (L_ISNEG(&diff)) { /* AOK -- pps_sample */
- suspect_4ms_step |= 2;
- ees->arrvtime = pps_arrvstamp;
- L_ADD(&ees->arrvtime, &onesec);
- conv++;
- call_pps_sample++;
- }
- }
- }
- ees->last_pps_no = ppsclockev.serial;
- if (debug & DB_PRINT_CDTC) printf(
- "[%x] %08x %08x %d u%d (%d %d)\n",
- DB_PRINT_CDTC, pps_arrvstamp.l_ui,
- pps_arrvstamp.l_uf, conv, ees->unit,
- call_pps_sample, pps_step);
- }
-
- /* See if there has been a 4ms jump at a minute boundry */
- { l_fp delta;
-#define delta_isec delta.l_ui
-#define delta_ssec delta.l_i
-#define delta_sfsec delta.l_f
- long delta_f_abs;
-
- delta.l_i = ees->arrvtime.l_i;
- delta.l_f = ees->arrvtime.l_f;
-
- L_SUB(&delta, &ees->last_l);
- delta_f_abs = delta_sfsec;
- if (delta_f_abs < 0) delta_f_abs = -delta_f_abs;
-
- /* Dump the deltas each minute */
- if (debug & DB_DUMP_DELTAS)
- { if (0 <= ees->second &&
- ees->second < ((sizeof deltas) / (sizeof deltas[0]))) deltas[ees->second] = delta_sfsec;
- /* Dump on second 1, as second 0 sometimes missed */
- if (ees->second == 1) {
- char text[16 * ((sizeof deltas) / (sizeof deltas[0]))];
- char *ptr=text;
- int i;
- for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) {
- sprintf(ptr, " %d.%04d",
- msec(deltas[i]), subms(deltas[i]));
- while (*ptr) ptr++;
- }
- syslog(LOG_ERR, "Deltas: %d.%04d<->%d.%04d: %s",
- msec(EES_STEP_F - EES_STEP_F_GRACE), subms(EES_STEP_F - EES_STEP_F_GRACE),
- msec(EES_STEP_F + EES_STEP_F_GRACE), subms(EES_STEP_F + EES_STEP_F_GRACE),
- text+1);
- for (i=0; i<((sizeof deltas) / (sizeof deltas[0])); i++) deltas[i] = 0;
- }
- }
-
- /* Lets see if we have a 4 mS step at a minute boundaary */
- if ( ((EES_STEP_F - EES_STEP_F_GRACE) < delta_f_abs) &&
- (delta_f_abs < (EES_STEP_F + EES_STEP_F_GRACE)) &&
- (ees->second == 0 || ees->second == 1 || ees->second == 2) &&
- (sincelast < 0 || sincelast > 122)
- ) { /* 4ms jump at min boundry */
- int old_sincelast;
- int count=0;
- int sum = 0;
- /* Yes -- so compute the ramp time */
- if (ees->last_step == 0) sincelast = 0;
- old_sincelast = sincelast;
-
- /* First time in, just set "ees->last_step" */
- if(ees->last_step) {
- int other_step = 0;
- int third_step = 0;
- int this_step = (sincelast + (60 /2)) / 60;
- int p_step = ees->this_step;
- int p;
- ees->last_steps[p_step] = this_step;
- p= p_step;
- p_step++;
- if (p_step >= LAST_STEPS) p_step = 0;
- ees->this_step = p_step;
- /* Find the "average" interval */
- while (p != p_step) {
- int this = ees->last_steps[p];
- if (this == 0) break;
- if (this != this_step) {
- if (other_step == 0 && (
- this== (this_step +2) ||
- this== (this_step -2) ||
- this== (this_step +1) ||
- this== (this_step -1)))
- other_step = this;
- if (other_step != this) {
- int delta = (this_step - other_step);
- if (delta < 0) delta = - delta;
- if (third_step == 0 && (
- (delta == 1) ? (
- this == (other_step +1) ||
- this == (other_step -1) ||
- this == (this_step +1) ||
- this == (this_step -1))
- :
- (
- this == (this_step + other_step)/2
- )
- )) third_step = this;
- if (third_step != this) break;
- }
- }
- sum += this;
- p--;
- if (p < 0) p += LAST_STEPS;
- count++;
- }
-syslog(LOG_ERR, "MSF%d: %d: This=%d (%d), other=%d/%d, sum=%d, count=%d, pps_step=%d, suspect=%x", ees->unit, p, ees->last_steps[p], this_step, other_step, third_step, sum, count, pps_step, suspect_4ms_step);
- if (count != 0) sum = ((sum * 60) + (count /2)) / count;
-#define SV(x) (ees->last_steps[(x + p_step) % LAST_STEPS])
-syslog(LOG_ERR, "MSF%d: %x steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
- ees->unit, suspect_4ms_step, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
- SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
-printf("MSF%d: steps %d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
- ees->unit, p_step, SV(0), SV(1), SV(2), SV(3), SV(4), SV(5), SV(6),
- SV(7), SV(8), SV(9), SV(10), SV(11), SV(12), SV(13), SV(14), SV(15));
-#undef SV
- ees->jump_fsecs = delta_sfsec;
- ees->using_ramp = 1;
- if (sincelast > 170)
- ees->last_step_late += sincelast - ((sum) ? sum : ees->last_step_secs);
- else ees->last_step_late = 30;
- if (ees->last_step_late < -60 || ees->last_step_late > 120) ees->last_step_late = 30;
- if (ees->last_step_late < 0) ees->last_step_late = 0;
- if (ees->last_step_late >= 60) ees->last_step_late = 59;
- sincelast = 0;
- }
- else { /* First time in -- just save info */
- ees->last_step_late = 30;
- ees->jump_fsecs = delta_sfsec;
- ees->using_ramp = 1;
- sum = 4 * 60;
- }
- ees->last_step = this_uisec;
-printf("MSF%d: d=%3d.%04d@%d :%d:%d:$%d:%d:%d\n",
-ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
-syslog(LOG_ERR, "MSF%d: d=%3d.%04d@%d :%d:%d:%d:%d:%d",
-ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, old_sincelast, ees->last_step_late, count, sum, ees->last_step_secs);
- if (sum) ees->last_step_secs = sum;
- }
- /* OK, so not a 4ms step at a minute boundry */
- else {
- if (suspect_4ms_step) syslog(LOG_ERR,
- "MSF%d: suspect = %x, but delta of %d.%04d [%d.%04d<%d.%04d<%d.%04d: %d %d]",
- ees->unit, suspect_4ms_step, msec(delta_sfsec), subms(delta_sfsec),
- msec(EES_STEP_F - EES_STEP_F_GRACE),
- subms(EES_STEP_F - EES_STEP_F_GRACE),
- msec(delta_f_abs),
- subms(delta_f_abs),
- msec(EES_STEP_F + EES_STEP_F_GRACE),
- subms(EES_STEP_F + EES_STEP_F_GRACE),
- ees->second,
- sincelast);
- if ((delta_f_abs > EES_STEP_NOTE) && ees->last_l.l_i) {
- static ees_step_notes = EES_STEP_NOTES;
- if (ees_step_notes > 0) {
- ees_step_notes--;
-printf("MSF%d: D=%3d.%04d@%02d :%d%s\n",
-ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, sincelast, ees_step_notes ? "" : " -- NO MORE !");
-syslog(LOG_ERR, "MSF%d: D=%3d.%04d@%02d :%d%s",
-ees->unit, msec(delta_sfsec), subms(delta_sfsec), ees->second, (ees->last_step) ? sincelast : -1, ees_step_notes ? "" : " -- NO MORE !");
- }
- }
- }
- }
- ees->last_l = ees->arrvtime;
-
- /* IF we have found that it's ramping
- * && it's within twice the expected ramp period
- * && there is a non zero step size (avoid /0 !)
- * THEN we twiddle things
- */
- if (ees->using_ramp &&
- sincelast < (ees->last_step_secs)*2 &&
- ees->last_step_secs)
- { long sec_of_ramp = sincelast + ees->last_step_late;
- long fsecs;
- l_fp inc;
-
- /* Ramp time may vary, so may ramp for longer than last time */
- if (sec_of_ramp > (ees->last_step_secs + 120))
- sec_of_ramp = ees->last_step_secs;
-
- /* sec_of_ramp * ees->jump_fsecs may overflow 2**32 */
- fsecs = sec_of_ramp * (ees->jump_fsecs / ees->last_step_secs);
-
- if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
- "[%x] MSF%d: %3d/%03d -> d=%11d (%d|%d)",
- DB_LOG_DELTAS,
- ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
- pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
- if (debug & DB_PRINT_DELTAS) printf(
- "MSF%d: %3d/%03d -> d=%11d (%d|%d)\n",
- ees->unit, sec_of_ramp, ees->last_step_secs, fsecs,
- pps_arrvstamp.l_f, pps_arrvstamp.l_f + fsecs);
-
- /* Must sign extend the result */
- inc.l_i = (fsecs < 0) ? -1 : 0;
- inc.l_f = fsecs;
- if (debug & DB_INC_PPS)
- { L_SUB(&pps_arrvstamp, &inc);
- L_SUB(&ees->arrvtime, &inc);
- }
- else
- { L_ADD(&pps_arrvstamp, &inc);
- L_ADD(&ees->arrvtime, &inc);
- }
- }
- else {
- if (debug & DB_LOG_DELTAS) syslog(LOG_ERR,
- "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x",
- DB_LOG_DELTAS,
- ees->unit, ees->using_ramp,
- sincelast,
- (ees->last_step_secs)*2,
- ees->last_step_secs);
- if (debug & DB_PRINT_DELTAS) printf(
- "[%x] MSF%d: ees->using_ramp=%d, sincelast=%x / %x, ees->last_step_secs=%x\n",
- DB_LOG_DELTAS,
- ees->unit, ees->using_ramp,
- sincelast,
- (ees->last_step_secs)*2,
- ees->last_step_secs);
- }
-
- L_SUB(&ees->arrvtime, &offset_fudge[ees->unit]);
- L_SUB(&pps_arrvstamp, &offset_fudge[ees->unit]);
-
- if (call_pps_sample && !(debug & DB_NO_PPS)) {
- /* Sigh -- it expects its args negated */
- L_NEG(&pps_arrvstamp);
- (void) pps_sample(&pps_arrvstamp);
- }
-
- /* Subtract off the local clock time stamp */
- L_SUB(&ees->codeoffsets[n_sample], &ees->arrvtime);
- if (debug & DB_LOG_SAMPLES) syslog(LOG_ERR,
- "MSF%d: [%x] %d (ees: %d %d) (pps: %d %d)%s",
- ees->unit, DB_LOG_DELTAS, n_sample,
- ees->codeoffsets[n_sample].l_f,
- ees->codeoffsets[n_sample].l_f / 4295,
- pps_arrvstamp.l_f,
- pps_arrvstamp.l_f /4295,
- (debug & DB_NO_PPS) ? " [no PPS]" : "");
-
- if (ees->nsamples++ == NCODES-1) ees_process(ees);
-
- /* Done! */
-}
-
-
-static void set_x(fp_offset)
-l_fp *fp_offset;
-{
- step_systime_real(fp_offset);
-}
-
-
-/* offcompare - auxiliary comparison routine for offset sort */
-
-static int
-offcompare(a, b)
-l_fp *a, *b;
-{
- return(L_ISGEQ(a, b) ? (L_ISEQU(a, b) ? 0 : 1) : -1);
-}
-
-
-/* ees_process - process a pile of samples from the clock */
-static void ees_process(ees)
- struct eesunit *ees;
-{
- static last_samples = -1;
- register int i, j;
- register int noff;
- register l_fp *coffs = ees->codeoffsets;
- l_fp offset, tmp;
- u_fp dispersion; /* ++++ */
- int lostsync, isinsync;
- int samples = ees->nsamples;
- int samplelog;
- int samplereduce = (samples + 1) / 2;
-
- /* Reset things to zero so we don't have to worry later */
- ees_reset(ees);
-
- if (sloppyclockflag[ees->unit]) {
- samplelog = (samples < 2) ? 0 :
- (samples < 5) ? 1 :
- (samples < 9) ? 2 :
- (samples < 17) ? 3 :
- (samples < 33) ? 4 : 5;
- samplereduce = (1 << samplelog);
- }
-
- if (samples != last_samples &&
- ((samples != (last_samples-1)) || samples < 3)) {
- syslog(LOG_ERR, "Samples=%d (%d), samplereduce=%d ....",
- samples, last_samples, samplereduce);
- last_samples = samples;
- }
- if (samples < 1) return;
-
- /* If requested, dump the raw data we have in the buffer */
- if (ees->dump_vals) dump_buf(coffs, 0, samples, "Raw data is:");
-
- /* Sort the offsets, trim off the extremes, then choose one. */
- qsort((char *) coffs, samples, sizeof(l_fp), offcompare);
-
- noff = samples;
- i = 0;
- while ((noff - i) > samplereduce) {
- /* Trim off the sample which is further away
- * from the median. We work this out by doubling
- * the median, subtracting off the end samples, and
- * looking at the sign of the answer, using the
- * identity (c-b)-(b-a) == 2*b-a-c
- */
- tmp = coffs[(noff + i)/2];
- L_ADD(&tmp, &tmp);
- L_SUB(&tmp, &coffs[i]);
- L_SUB(&tmp, &coffs[noff-1]);
- if (L_ISNEG(&tmp)) noff--; else i++;
- }
-
- /* If requested, dump the reduce data we have in the buffer */
- if (ees->dump_vals) dump_buf(coffs, i, noff, "Reduced to:");
-
- /* What we do next depends on the setting of the sloppy clock flag.
- * If it is on, average the remainder to derive our estimate.
- * Otherwise, just pick a representative value from the remaining stuff
- */
- if (sloppyclockflag[ees->unit]) {
- offset.l_ui = offset.l_uf = 0;
- for (j = i; j < noff; j++)
- L_ADD(&offset, &coffs[j]);
- for (j = samplelog; j > 0; j--)
- L_RSHIFTU(&offset);
- }
- else offset = coffs[i+BESTSAMPLE];
-
- /* Compute the dispersion as the difference between the
- * lowest and highest offsets that remain in the
- * consideration list.
- *
- * It looks like MOST clocks have MOD (max error), so halve it !
- */
- tmp = coffs[noff-1];
- L_SUB(&tmp, &coffs[i]);
-#define FRACT_SEC(n) ((1 << 30) / (n/2))
- dispersion = LFPTOFP(&tmp) / 2; /* ++++ */
- if (debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE)) syslog(
- (debug & DB_SYSLOG_SMPLE) ? LOG_ERR : LOG_INFO,
- "I: [%x] Offset=%06d (%d), disp=%06d%s [%d], %d %d=%d %d:%d %d=%d %d",
- debug & (DB_SYSLOG_SMPLI | DB_SYSLOG_SMPLE),
- offset.l_f / 4295, offset.l_f,
- (dispersion * 1526) / 100,
- (sloppyclockflag[ees->unit]) ? " by averaging" : "",
- FRACT_SEC(10) / 4295,
- (coffs[0].l_f) / 4295,
- i,
- (coffs[i].l_f) / 4295,
- (coffs[samples/2].l_f) / 4295,
- (coffs[i+BESTSAMPLE].l_f) / 4295,
- noff-1,
- (coffs[noff-1].l_f) / 4295,
- (coffs[samples-1].l_f) / 4295);
-
- /* Are we playing silly wotsits ?
- * If we are using all data, see if there is a "small" delta,
- * and if so, blurr this with 3/4 of the delta from the last value
- */
- if (ees->usealldata && ees->offset.l_uf) {
- long diff = (long) (ees->offset.l_uf - offset.l_uf);
-
- /* is the delta small enough ? */
- if ((- FRACT_SEC(100)) < diff && diff < FRACT_SEC(100)) {
- int samd = (64 * 4) / samples;
- long new;
- if (samd < 2) samd = 2;
- new = offset.l_uf + ((diff * (samd -1)) / samd);
-
- /* Sign change -> need to fix up int part */
- if ((new & (1 << 31)) !=
- (((long) offset.l_uf) & ( 1 << 31)))
- { syslog(LOG_INFO, "I: %x != %x (%x %x), so add %d",
- new & (1 << 31),
- ((long) offset.l_uf) & ( 1 << 31),
- new, (long) offset.l_uf,
- (new < 0) ? -1 : 1);
- offset.l_ui += (new < 0) ? -1 : 1;
- }
- dispersion /= 4;
- if (debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE)) syslog(
- (debug & DB_SYSLOG_SMTHE) ? LOG_ERR : LOG_INFO,
- "I: [%x] Smooth data: %d -> %d, dispersion now %d",
- debug & (DB_SYSLOG_SMTHI | DB_SYSLOG_SMTHE),
- ((long) offset.l_uf) / 4295, new / 4295,
- (dispersion * 1526) / 100);
- offset.l_uf = new;
- }
- else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
- (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
- "[%x] No smooth as delta not %d < %d < %d",
- debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
- - FRACT_SEC(100), diff, FRACT_SEC(100));
- }
- else if (debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE)) syslog(
- (debug & DB_SYSLOG_NSMTHE) ? LOG_ERR : LOG_INFO,
- "I: [%x] No smooth as flag=%x and old=%x=%d (%d:%d)",
- debug & (DB_SYSLOG_NSMTHI | DB_SYSLOG_NSMTHE),
- ees->usealldata, ees->offset.l_f, ees->offset.l_uf,
- offset.l_f, ees->offset.l_f - offset.l_f);
-
- /* Collect offset info for debugging info */
- ees->offset = offset;
- ees->lowoffset = coffs[i];
- ees->highoffset = coffs[noff-1];
-
- /* Determine synchronization status. Can be unsync'd either
- * by a report from the clock or by a leap hold.
- *
- * Loss of the radio signal for a short time does not cause
- * us to go unsynchronised, since the receiver keeps quite
- * good time on its own. The spec says 20ms in 4 hours; the
- * observed drift in our clock (Cambridge) is about a second
- * a day, but even that keeps us within the inherent tolerance
- * of the clock for about 15 minutes. Observation shows that
- * the typical "short" outage is 3 minutes, so to allow us
- * to ride out those, we will give it 5 minutes.
- */
- lostsync = current_time - ees->clocklastgood > 300 ? 1 : 0;
- isinsync = (lostsync || ees->leaphold > current_time) ? 0 : 1;
-
- /* Done. Use time of last good, synchronised code as the
- * reference time, and lastsampletime as the receive time.
- */
- if (ees->fix_pending) {
- syslog(LOG_ERR, "MSF%d: fix_pending=%d -> jump %x.%08x\n",
- ees->fix_pending, ees->unit, offset.l_i, offset.l_f);
- ees->fix_pending = 0;
- set_x(&offset);
- L_CLR(&offset);
- }
- refclock_receive(ees->peer,
- &offset,
- 0, /* delay */
- dispersion,
- &ees->reftime,
- &ees->lastsampletime, /* receive time */
- (isinsync) ? 0 : LEAP_NOTINSYNC);
- ees_event(ees, lostsync ? CEVNT_PROP : CEVNT_NOMINAL);
-}
-
-/* msfees_poll - called by the transmit procedure */
-static void msfees_poll(unit, peer)
- int unit;
- char *peer;
-{
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d invalid",
- unit);
- return;
- }
- if (!unitinuse[unit]) {
- syslog(LOG_ERR, "ees clock poll: INTERNAL: unit %d unused",
- unit);
- return;
- }
-
- ees_process(eesunits[unit]);
-
- if ((current_time - eesunits[unit]->lasttime) > 150)
- ees_event(eesunits[unit], CEVNT_FAULT);
-}
-
-/* msfees_leap - called when a leap second occurs */
-static void msfees_leap()
-{
- register int i;
-
- /* This routine should be entered a few seconds after
- * midnight UTC when a leap second occurs. To ensure we
- * don't believe foolish time from the clock(s) we set a
- * 40 minute hold on them. It shouldn't take anywhere
- * near this amount of time to adjust if the clock is getTING
- * data, but doing anything else is complicated.
- */
- for (i = 0; i < MAXUNITS; i++) if (unitinuse[i])
- eesunits[i]->leaphold = current_time + EESLEAPHOLD;
-}
-
-/* msfees_control - set fudge factors, return statistics */
-static void msfees_control(unit, in, out)
- u_int unit;
- struct refclockstat *in;
- struct refclockstat *out;
-{
- register struct eesunit *ees = eesunits[unit];
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
- unit, MAXUNITS-1);
- return;
- }
-
- if (in != 0) {
- if (in->haveflags & CLK_HAVETIME1)
- fudgefactor[unit] = in->fudgetime1;
- if (in->haveflags & CLK_HAVETIME2)
- os_delay[unit] = in->fudgetime2;
- offset_fudge[unit] = os_delay[unit];
- L_ADD(&offset_fudge[unit], &fudgefactor[unit]);
- L_ADD(&offset_fudge[unit], &inherent_delay[unit]);
- if (in->haveflags & CLK_HAVEVAL1) {
- stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
- if (unitinuse[unit]) {
- /* Should actually reselect clock, but
- * will wait for the next timecode
- */
- struct peer *peer = ees->peer;
- peer->stratum = stratumtouse[unit];
- if (stratumtouse[unit] <= 1) {
- memmove((char *)&peer->refid,
- EESREFID, 4);
- if (unit>0 && unit<10)
- ((char *)&peer->refid)[3] =
- '0' + unit;
- }
- else peer->refid = htonl(EESHSREFID);
- }
- }
- if (in->haveflags & CLK_HAVEVAL2) {
- printf("Debug: %x -> %x\n", debug, in->fudgeval2);
- syslog(LOG_ERR, "MSF%d: debug %x -> %x",
- unit, debug, in->fudgeval2);
- debug = in->fudgeval2;
- }
- if (in->haveflags & CLK_HAVEFLAG1) {
- sloppyclockflag[unit] = in->flags & CLK_FLAG1;
- }
- if (in->haveflags & CLK_HAVEFLAG2) {
- ees->fix_pending++;
- /* if (in->flags & CLK_FLAG2 && unitinuse[unit])
- ees->leaphold = 0; */
- }
- if (in->haveflags & CLK_HAVEFLAG3 && unitinuse[unit]) {
- printf("dump_vals: %x -> %x\n", ees->dump_vals, in->flags & CLK_FLAG3);
- ees->dump_vals = in->flags & CLK_FLAG3;
- }
- if (in->haveflags & CLK_HAVEFLAG4 && unitinuse[unit]) {
- ees->usealldata = in->flags & CLK_FLAG4;
- }
- }
-
- if (out != 0) {
- out->type = REFCLK_MSF_EES;
- out->haveflags
- = CLK_HAVETIME1|CLK_HAVETIME2|CLK_HAVEVAL1|CLK_HAVEVAL2|CLK_HAVEFLAG1|CLK_HAVEFLAG3|CLK_HAVEFLAG4;
- out->clockdesc = EESDESCRIPTION;
- out->fudgetime1 = fudgefactor[unit];
- out->fudgetime2 = os_delay[unit];
- out->fudgeval1 = stratumtouse[unit];
- /*out->fudgeval2= debug*/;
- memmove((char *)&out->fudgeval2, EESREFID, 4);
- if (unit > 0 && unit < 10)
- ((char *)&out->fudgeval2)[3] = '0' + unit;
- out->flags = sloppyclockflag[unit];
- if (unitinuse[unit]) {
- out->flags |= ees->dump_vals | ees->usealldata;
- out->lencode = ees->lencode;
- out->lastcode = ees->lastcode;
- out->timereset = current_time - ees->timestarted;
- out->polls = 0; /* we don't poll */
- out->noresponse = 0; /* ditto */
- out->badformat = ees->badformat;
- out->baddata = ees->baddata;
- out->lastevent = ees->lastevent;
- out->currentstatus = ees->status;
- } else {
- out->lencode = 0;
- out->lastcode = "";
- out->polls = out->noresponse = 0;
- out->badformat = out->baddata = 0;
- out->timereset = 0;
- out->currentstatus = out->lastevent = CEVNT_NOMINAL;
- }
- }
-}
-
-
-/* msfees_buginfo - return clock dependent debugging info */
-static void msfees_buginfo(unit, bug)
- int unit;
- register struct refclockbug *bug;
-{
- register struct eesunit *ees;
-
- bug->nvalues = bug->ntimes = 0;
-
- if (unit >= MAXUNITS) {
- syslog(LOG_ERR, "ees clock: unit %d invalid (max %d)",
- unit, MAXUNITS-1);
- return;
- }
-
- if (!unitinuse[unit])
- return;
- ees = eesunits[unit];
-
- bug->nvalues = 16;
- bug->svalues = 0x0800;
- bug->values[0] = (ees->lasttime) ? current_time - ees->lasttime : 0;
- bug->values[1] = (ees->clocklastgood)?current_time-ees->clocklastgood:0;
- bug->values[2] = ees->status;
- bug->values[3] = ees->lastevent;
- bug->values[4] = ees->reason;
- bug->values[5] = ees->nsamples;
- bug->values[6] = ees->codestate;
- bug->values[7] = ees->day;
- bug->values[8] = ees->hour;
- bug->values[9] = ees->minute;
- bug->values[10] = ees->second;
- bug->values[11] = ees->tz;
- bug->values[12] = ees->yearstart;
- bug->values[13] = (ees->leaphold > current_time) ?
- ees->leaphold - current_time : 0;
- bug->values[14] = inherent_delay[unit].l_uf;
- bug->values[15] = offset_fudge[unit].l_uf;
-
- bug->ntimes = 11;
- bug->stimes = 0x3f8;
- bug->times[0] = ees->reftime;
- bug->times[1] = ees->arrvtime;
- bug->times[2] = ees->lastsampletime;
- bug->times[3] = ees->offset;
- bug->times[4] = ees->lowoffset;
- bug->times[5] = ees->highoffset;
- bug->times[6] = inherent_delay[unit];
- bug->times[8] = os_delay[unit];
- bug->times[7] = fudgefactor[unit];
- bug->times[9] = offset_fudge[unit];
- bug->times[10].l_ui = ees->yearstart;
- bug->times[10].l_uf = 0;
-}
-
-struct refclock refclock_msfees = {
- msfees_start, msfees_shutdown, msfees_poll,
- msfees_control, msfees_init, msfees_buginfo, NOFLAGS
-};
-#endif /* defined(REFCLOCK) && defined(MSFEESPPS) && defined(STREAM) */