diff options
Diffstat (limited to 'usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c')
-rw-r--r-- | usr.sbin/xntpd/xntpd/refclock_new/refclock_msfees.c | 1575 |
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) */ |